aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcebka@mailsupport.rambler.ru <cebka@mailsupport.rambler.ru>2008-09-18 18:25:00 +0400
committercebka@mailsupport.rambler.ru <cebka@mailsupport.rambler.ru>2008-09-18 18:25:00 +0400
commitbb2e8a89d2e4caf5345e565f4da5aeb6fc39655b (patch)
treec586d56f6ba24e651fd4ad099a5c0397c33851d4
parent4ad814a6c631883bbb55ae3db2f8806c63f31c9a (diff)
downloadrspamd-bb2e8a89d2e4caf5345e565f4da5aeb6fc39655b.tar.gz
rspamd-bb2e8a89d2e4caf5345e565f4da5aeb6fc39655b.zip
* Add support of variables and variable substitution in config file
-rw-r--r--cfg_file.h3
-rw-r--r--cfg_file.l34
-rw-r--r--cfg_file.y10
-rw-r--r--cfg_utils.c78
4 files changed, 106 insertions, 19 deletions
diff --git a/cfg_file.h b/cfg_file.h
index 5fe89cf6d..1a211e680 100644
--- a/cfg_file.h
+++ b/cfg_file.h
@@ -114,6 +114,7 @@ struct config_file {
LIST_HEAD (modulesq, perl_module) perl_modules;
LIST_HEAD (cmodulesq, c_module) c_modules;
GHashTable* modules_opts;
+ GHashTable* variables;
};
int add_memcached_server (struct config_file *cf, char *str);
@@ -125,6 +126,8 @@ char* get_module_opt (struct config_file *cfg, char *module_name, char *opt_name
size_t parse_limit (const char *limit);
unsigned int parse_seconds (const char *t);
char parse_flag (const char *str);
+char* substitute_variable (struct config_file *cfg, char *str, u_char recursive);
+void post_load_config (struct config_file *cfg);
int yylex (void);
int yyparse (void);
diff --git a/cfg_file.l b/cfg_file.l
index 89ca8a171..fd5f3bc7f 100644
--- a/cfg_file.l
+++ b/cfg_file.l
@@ -13,6 +13,7 @@
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
+extern struct config_file *cfg;
%}
@@ -45,7 +46,6 @@ script_message return SCRIPT_MESSAGE;
script_url return SCRIPT_URL;
script_chain return SCRIPT_CHAIN;
-
\{ return OBRACE;
\} return EBRACE;
; return SEMICOLON;
@@ -56,6 +56,7 @@ yes|YES|no|NO|[yY]|[nN] yylval.flag=parse_flag(yytext); return FLAG;
[ \t]+ /* ignore whitespace */;
\"[^"]+\" yylval.string=strdup(yytext + 1); yylval.string[strlen(yylval.string) - 1] = '\0'; return QUOTEDSTRING;
\" return QUOTE;
+\$[a-zA-Z_][a-zA-Z0-9_]+ yylval.string=strdup(yytext + 1); return VARIABLE;
[0-9]+ yylval.number=strtol(yytext, NULL, 10); return NUMBER;
[0-9]+[kKmMgG]? yylval.limit=parse_limit(yytext); return SIZELIMIT;
[0-9]+[sS]|[0-9]+[mM][sS] yylval.seconds=parse_seconds(yytext); return SECONDS;
@@ -68,38 +69,34 @@ yes|YES|no|NO|[yY]|[nN] yylval.flag=parse_flag(yytext); return FLAG;
[a-zA-Z0-9].[a-zA-Z0-9\/.-]+ yylval.string=strdup(yytext); return DOMAIN;
<incl>[ \t]* /* eat the whitespace */
<incl>[^ \t\n]+ { /* got the include file name */
- if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) {
- yyerror ("yylex: includes nested too deeply" );
+ if (include_stack_ptr >= MAX_INCLUDE_DEPTH) {
+ yyerror ("yylex: includes nested too deeply");
return -1;
}
include_stack[include_stack_ptr++] =
YY_CURRENT_BUFFER;
- yyin = fopen( yytext, "r" );
+ yyin = fopen (yytext, "r");
- if ( ! yyin ) {
- yyerror("yylex: cannot open include file");
+ if (! yyin) {
+ yyerror ("yylex: cannot open include file");
return -1;
}
- yy_switch_to_buffer(
- yy_create_buffer( yyin, YY_BUF_SIZE ) );
+ yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE));
BEGIN(INITIAL);
}
<<EOF>> {
- if ( --include_stack_ptr < 0 )
- {
- yyterminate();
- }
-
- else
- {
- yy_delete_buffer( YY_CURRENT_BUFFER );
- yy_switch_to_buffer(
- include_stack[include_stack_ptr] );
+ if ( --include_stack_ptr < 0 ) {
+ post_load_config (cfg);
+ yyterminate ();
+ }
+ else {
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ yy_switch_to_buffer (include_stack[include_stack_ptr]);
}
}
@@ -110,6 +107,7 @@ yes|YES|no|NO|[yY]|[nN] yylval.flag=parse_flag(yytext); return FLAG;
<module>\} return EBRACE;
<module>\; return SEMICOLON;
<module>[a-zA-Z0-9_-] yylval.string=strdup(yytext); return PARAM;
+<module>\$[a-zA-Z_][a-zA-Z0-9_]+ yylval.string=strdup(yytext + 1); return VARIABLE;
<module>\"[^"]+\" yylval.string=strdup(yytext + 1); yylval.string[strlen(yylval.string) - 1] = '\0'; return QUOTEDSTRING;
%%
diff --git a/cfg_file.y b/cfg_file.y
index 8448933b4..fb31c4186 100644
--- a/cfg_file.y
+++ b/cfg_file.y
@@ -48,9 +48,10 @@ LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = NULL;
%token READ_SERVERS WRITE_SERVER DIRECTORY_SERVERS MAILBOX_QUERY USERS_QUERY LASTLOGIN_QUERY
%token MEMCACHED WORKERS REQUIRE MODULE
%token FILTER METRIC SCRIPT_HEADER SCRIPT_MIME SCRIPT_MESSAGE SCRIPT_URL SCRIPT_CHAIN SCRIPT_PARAM
-%token MODULE_OPT, PARAM
+%token MODULE_OPT PARAM VARIABLE
%type <string> STRING
+%type <string> VARIABLE
%type <string> QUOTEDSTRING MODULE_OPT PARAM
%type <string> FILENAME
%type <string> SOCKCRED
@@ -80,6 +81,7 @@ command :
| require
| filter
| module_opt
+ | variable
;
tempdir :
@@ -403,6 +405,12 @@ optcmd:
}
;
+variable:
+ VARIABLE EQSIGN QUOTEDSTRING {
+ g_hash_table_insert (cfg->variables, $1, $3);
+ }
+ ;
+
%%
/*
* vi:ts=4
diff --git a/cfg_utils.c b/cfg_utils.c
index 3339e2bd0..a00a075b3 100644
--- a/cfg_utils.c
+++ b/cfg_utils.c
@@ -149,6 +149,7 @@ init_defaults (struct config_file *cfg)
cfg->workers_number = DEFAULT_WORKERS_NUM;
cfg->modules_opts = g_hash_table_new (g_str_hash, g_str_equal);
+ cfg->variables = g_hash_table_new (g_str_hash, g_str_equal);
LIST_INIT (&cfg->filters);
LIST_INIT (&cfg->perl_modules);
@@ -205,6 +206,8 @@ free_config (struct config_file *cfg)
g_hash_table_foreach (cfg->modules_opts, clean_hash_bucket, NULL);
g_hash_table_remove_all (cfg->modules_opts);
g_hash_table_unref (cfg->modules_opts);
+ g_hash_table_remove_all (cfg->variables);
+ g_hash_table_unref (cfg->variables);
}
int
@@ -324,5 +327,80 @@ parse_flag (const char *str)
}
/*
+ * Try to substitute all variables in given string
+ * Return: newly allocated string with substituted variables (original string may be freed if variables are found)
+ */
+char *
+substitute_variable (struct config_file *cfg, char *str, u_char recursive)
+{
+ char *var, *new, *v_begin, *v_end;
+ size_t len;
+
+ while ((v_begin = strstr (str, "${")) != NULL) {
+ len = strlen (str);
+ *v_begin = '\0';
+ v_begin += 2;
+ if ((v_end = strstr (v_begin, "}")) == NULL) {
+ /* Not a variable, skip */
+ continue;
+ }
+ *v_end = '\0';
+ var = g_hash_table_lookup (cfg->variables, v_begin);
+ if (var == NULL) {
+ yywarn ("substitute_variable: variable %s is not defined", v_begin);
+ /* Substitute unknown variables with empty string */
+ var = "";
+ }
+ else if (recursive) {
+ var = substitute_variable (cfg, var, recursive);
+ }
+ /* Allocate new string */
+ new = g_malloc (len - strlen (v_begin) + strlen (var) + 1);
+
+ snprintf (new, len - strlen (v_begin) + strlen (var) + 1, "%s%s%s",
+ str, var, v_end + 1);
+ g_free (str);
+ str = new;
+ }
+
+ return str;
+}
+
+static void
+substitute_module_variables (gpointer key, gpointer value, gpointer data)
+{
+ struct config_file *cfg = (struct config_file *)data;
+ LIST_HEAD (moduleoptq, module_opt) *cur_module_opt = (struct moduleoptq *)value;
+ struct module_opt *cur, *tmp;
+
+ LIST_FOREACH_SAFE (cur, cur_module_opt, next, tmp) {
+ if (cur->value) {
+ cur->value = substitute_variable (cfg, cur->value, 0);
+ }
+ }
+}
+
+static void
+substitute_all_variables (gpointer key, gpointer value, gpointer data)
+{
+ struct config_file *cfg = (struct config_file *)data;
+ char *var;
+
+ var = value;
+ /* Do recursive substitution */
+ var = substitute_variable (cfg, var, 1);
+}
+
+/*
+ * Substitute all variables in strings
+ */
+void
+post_load_config (struct config_file *cfg)
+{
+ g_hash_table_foreach (cfg->variables, substitute_all_variables, cfg);
+ g_hash_table_foreach (cfg->modules_opts, substitute_module_variables, cfg);
+}
+
+/*
* vi:ts=4
*/