]> source.dussan.org Git - rspamd.git/commitdiff
* Add support of variables and variable substitution in config file
authorcebka@mailsupport.rambler.ru <cebka@mailsupport.rambler.ru>
Thu, 18 Sep 2008 14:25:00 +0000 (18:25 +0400)
committercebka@mailsupport.rambler.ru <cebka@mailsupport.rambler.ru>
Thu, 18 Sep 2008 14:25:00 +0000 (18:25 +0400)
cfg_file.h
cfg_file.l
cfg_file.y
cfg_utils.c

index 5fe89cf6d508c71c2e09191ca960385777323ce4..1a211e6808d2da420f266d381f9e77dfcaf668e3 100644 (file)
@@ -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);
index 89ca8a171dadcce8e647e44f708b9d21addc7ba3..fd5f3bc7f10da58f140f32867fc6d171ffe0c688 100644 (file)
@@ -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;
 
 %%
index 8448933b490920f15cf3800ea6d07ad3b837d3c0..fb31c4186e4fa098bef9accf85bbed053b07023f 100644 (file)
@@ -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 
index 3339e2bd0dca9f5fd0995e929884499201d59931..a00a075b3eca9e2d7c62a8cf9f1dfd5fea41c4db 100644 (file)
@@ -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
@@ -323,6 +326,81 @@ parse_flag (const char *str)
        return -1;
 }
 
+/*
+ * 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
  */