瀏覽代碼

* Add support of variables and variable substitution in config file

tags/0.2.7
cebka@mailsupport.rambler.ru 15 年之前
父節點
當前提交
bb2e8a89d2
共有 4 個檔案被更改,包括 106 行新增19 行删除
  1. 3
    0
      cfg_file.h
  2. 16
    18
      cfg_file.l
  3. 9
    1
      cfg_file.y
  4. 78
    0
      cfg_utils.c

+ 3
- 0
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);

+ 16
- 18
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;

%%

+ 9
- 1
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

+ 78
- 0
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
@@ -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
*/

Loading…
取消
儲存