浏览代码

cfg: extended preprocessor directives

- you can define values for IDs
- defined IDs are replaced at startup, during config parsing, e.g.,:
$var(x) = 100 + MYINT;
- is interpreted as:
$var(x) = 100 + 123;
- you can have multi-line defined IDs
				while($var(i)<5) { \
					xlog("++++ $var(i)\n"); \
					$var(i) = $var(i) + 1; \
				}
- then in routing block
route {
    ...
    IDLOOP
    ...
}
- new preprocessor directive
- perform substitutions inside the strings of config (not that define is
  replacing only IDs - alphanumeric tokens not enclosed in quotes)
- #!subst offers an easy way to search and replace inside strings before
  cfg parsing. E.g.,:
modparam("acc", "db_url", "mysql://user:DBPASSWD@localhost/db")
- will do the substitution of db password in db_url parameter value
- number of allowed defines set to 256
- credits to Andrei for quick hints on ID defines
- notes:
	- multilines defines are reduced to single line, so line counter
	  should be fine
	- column counter goes inside the define value, but you have to omit
	  the \ and CR for the accurate inside-define position
Daniel-Constantin Mierla 15 年之前
父节点
当前提交
20cddb28e9
共有 4 个文件被更改,包括 270 次插入21 次删除
  1. 116 21
      cfg.lex
  2. 8 0
      cfg.y
  3. 116 0
      ppcfg.c
  4. 30 0
      ppcfg.h

+ 116 - 21
cfg.lex

@@ -97,6 +97,7 @@
 	#include "select.h"
 	#include "cfg.tab.h"
 	#include "sr_compat.h"
+	#include "ppcfg.h"
 
 	/* states */
 	#define INITIAL_S		0
@@ -109,12 +110,13 @@
 	#define PVAR_P_S                7  /* pvar: $(...)  or $foo(...)*/
 	#define PVARID_S                8  /* $foo.bar...*/
 	#define STR_BETWEEN_S		9
-	#define LINECOMMENT_S            10
+	#define LINECOMMENT_S           10
 	#define DEFINE_S                11
 	#define DEFINE_EOL_S            12
-	#define IFDEF_S                    13
-	#define IFDEF_EOL_S                14
+	#define IFDEF_S                 13
+	#define IFDEF_EOL_S             14
 	#define IFDEF_SKIP_S            15
+	#define DEFINE_DATA_S           16
 
 	#define STR_BUF_ALLOC_UNIT	128
 	struct str_buf{
@@ -136,6 +138,8 @@
 	static int ign_lines=0;
 	static int ign_columns=0;
 	char* yy_number_str=0; /* str correspondent for the current NUMBER token */
+	int r = 0;
+	str *sdef = 0;
 
 	static char* addchar(struct str_buf *, char);
 	static char* addstr(struct str_buf *, char*, int);
@@ -163,6 +167,8 @@
 	} *sr_yy_fname_list = 0;
 
 	static int  pp_define(int len, const char * text);
+	static int  pp_define_set(int len, char * text);
+	static str  *pp_define_get(int len, const char * text);
 	static int  pp_ifdef_type(int pos);
 	static void pp_ifdef_var(int len, const char * text);
 	static void pp_ifdef();
@@ -174,7 +180,7 @@
 /* start conditions */
 %x STRING1 STRING2 STR_BETWEEN COMMENT COMMENT_LN ATTR SELECT AVP_PVAR PVAR_P 
 %x PVARID INCLF
-%x LINECOMMENT DEFINE_ID DEFINE_EOL IFDEF_ID IFDEF_EOL IFDEF_SKIP
+%x LINECOMMENT DEFINE_ID DEFINE_EOL DEFINE_DATA IFDEF_ID IFDEF_EOL IFDEF_SKIP
 
 /* config script types : #!SER  or #!KAMAILIO or #!MAX_COMPAT */
 SER_CFG			SER
@@ -538,6 +544,9 @@ ENDIF        endif
 
 EAT_ABLE	[\ \t\b\r]
 
+/* pre-processing blocks */
+SUBST       subst
+
 %%
 
 
@@ -1118,6 +1127,7 @@ EAT_ABLE	[\ \t\b\r]
 <STRING2>{TICK}  { count_more(); state=old_state; BEGIN(old_initial);
 						yytext[yyleng-1]=0; yyleng--;
 						addstr(&s_buf, yytext, yyleng);
+						r = pp_subst_run(&s_buf.s);
 						yylval.strval=s_buf.s;
 						memset(&s_buf, 0, sizeof(s_buf));
 						return STRING;
@@ -1147,6 +1157,7 @@ EAT_ABLE	[\ \t\b\r]
 									/* ignore the whitespace now that is
 									  counted, return saved string value */
 									state=old_state; BEGIN(old_initial);
+									r = pp_subst_run(&s_buf.s);
 									yylval.strval=s_buf.s;
 									memset(&s_buf, 0, sizeof(s_buf));
 									return STRING;
@@ -1169,13 +1180,26 @@ EAT_ABLE	[\ \t\b\r]
 <INITIAL>{COM_LINE}!{MAXCOMPAT_CFG}{CR}	{ count(); 
 												sr_cfg_compat=SR_COMPAT_MAX;}
 
-<INITIAL>{COM_LINE}!{DEFINE}{EAT_ABLE}+        { count();
-										state = DEFINE_S; BEGIN(DEFINE_ID); }
-<DEFINE_ID>{ID}                                { count();
-								if (pp_define(yyleng, yytext)) return 1;
-								state = DEFINE_EOL_S; BEGIN(DEFINE_EOL); }
-<DEFINE_EOL>{EAT_ABLE}*{CR}                    { count();
+<INITIAL>{COM_LINE}!{DEFINE}{EAT_ABLE}+	{	count();
+											state = DEFINE_S; BEGIN(DEFINE_ID); }
+<DEFINE_ID>{ID}                 {	count();
+									if (pp_define(yyleng, yytext)) return 1;
+									state = DEFINE_EOL_S; BEGIN(DEFINE_EOL); }
+<DEFINE_EOL>{EAT_ABLE}			{	count(); }
+<DEFINE_EOL>{CR}				{	count();
 									state = INITIAL; BEGIN(INITIAL); }
+<DEFINE_EOL>.                   {	count();
+									addstr(&s_buf, yytext, yyleng);
+									state = DEFINE_DATA_S; BEGIN(DEFINE_DATA); }
+<DEFINE_DATA>\\{CR}		{	count(); } /* eat the escaped CR */
+<DEFINE_DATA>{CR}		{	count();
+							if (pp_define_set(strlen(s_buf.s), s_buf.s)) return 1;
+							memset(&s_buf, 0, sizeof(s_buf));
+							state = INITIAL; BEGIN(INITIAL); }
+<DEFINE_DATA>.          {	count();
+							addstr(&s_buf, yytext, yyleng); }
+
+<INITIAL>{COM_LINE}!{SUBST}	{ count();  return SUBST;}
 
 <INITIAL,IFDEF_SKIP>{COM_LINE}!{IFDEF}{EAT_ABLE}+    { count();
 								if (pp_ifdef_type(1)) return 1;
@@ -1201,10 +1225,17 @@ EAT_ABLE	[\ \t\b\r]
 								BEGIN(LINECOMMENT); }
 <LINECOMMENT>.*{CR}        { count(); state = INITIAL_S; BEGIN(INITIAL); }
 
-<INITIAL>{ID}			{ count(); addstr(&s_buf, yytext, yyleng);
-									yylval.strval=s_buf.s;
-									memset(&s_buf, 0, sizeof(s_buf));
-									return ID; }
+<INITIAL>{ID}		{	if ((sdef = pp_define_get(yyleng, yytext))!=NULL) {
+							for (r=sdef->len-1; r>=0; r--)
+								unput(sdef->s[r]); /* reverse order */
+						} else {
+							count();
+							addstr(&s_buf, yytext, yyleng);
+							yylval.strval=s_buf.s;
+							memset(&s_buf, 0, sizeof(s_buf));
+							return ID;
+						}
+					}
 <INITIAL>{NUM_ID}			{ count(); addstr(&s_buf, yytext, yyleng);
 									yylval.strval=s_buf.s;
 									memset(&s_buf, 0, sizeof(s_buf));
@@ -1225,6 +1256,7 @@ EAT_ABLE	[\ \t\b\r]
 										case STR_BETWEEN_S:
 											state=old_state;
 											BEGIN(old_initial);
+											r = pp_subst_run(&s_buf.s);
 											yylval.strval=s_buf.s;
 											memset(&s_buf, 0, sizeof(s_buf));
 											return STRING;
@@ -1552,15 +1584,15 @@ static int sr_pop_yy_state()
 
 /* define/ifdef support */
 
-#define MAX_DEFINES    1024
-static str pp_defines[MAX_DEFINES];
+#define MAX_DEFINES    256
+static str pp_defines[MAX_DEFINES][2];
 static int pp_num_defines = 0;
 
 /* pp_ifdef_stack[i] is 1 if the ifdef test at depth i is either
  * ifdef(defined), ifndef(undefined), or the opposite of these
  * two, but in an else branch
  */
-#define MAX_IFDEFS    128
+#define MAX_IFDEFS    256
 static int pp_ifdef_stack[MAX_IFDEFS];
 static int pp_sptr = 0; /* stack pointer */
 
@@ -1570,7 +1602,7 @@ static int pp_lookup(int len, const char * text)
 	int i;
 
 	for (i=0; i<pp_num_defines; i++)
-		if (STR_EQ(pp_defines[i], var))
+		if (STR_EQ(pp_defines[i][0], var))
 			return i;
 
 	return -1;
@@ -1588,14 +1620,77 @@ static int pp_define(int len, const char * text)
 		return -1;
 	}
 
-	pp_defines[pp_num_defines].len = len;
-	pp_defines[pp_num_defines].s = (char*)pkg_malloc(len+1);
-	memcpy(pp_defines[pp_num_defines].s, text, len);
+	pp_defines[pp_num_defines][0].len = len;
+	pp_defines[pp_num_defines][0].s = (char*)pkg_malloc(len+1);
+	memcpy(pp_defines[pp_num_defines][0].s, text, len);
+	pp_defines[pp_num_defines][1].len = 0;
+	pp_defines[pp_num_defines][1].s = NULL;
 	pp_num_defines++;
 
 	return 0;
 }
 
+static int  pp_define_set(int len, char *text)
+{
+	if(len<=0) {
+		LOG(L_DBG, "no define value - ignoring\n");
+		return 0;
+	}
+	if (pp_num_defines == MAX_DEFINES) {
+		LOG(L_BUG, "BUG: setting define value, but no define id yet\n");
+		return -1;
+	}
+	if (pp_num_defines == 0) {
+		LOG(L_CRIT, "ERROR: too many defines -- adjust MAX_DEFINES\n");
+		return -1;
+	}
+
+	if (pp_defines[pp_num_defines-1][0].s == NULL) {
+		LOG(L_BUG, "BUG: last define ID is null\n");
+		return -1;
+	}
+
+	if (pp_defines[pp_num_defines-1][1].s != NULL) {
+		LOG(L_BUG, "BUG: ID %.*s redefined\n",
+			pp_defines[pp_num_defines-1][0].len,
+			pp_defines[pp_num_defines-1][0].s);
+		return -1;
+	}
+
+	pp_defines[pp_num_defines-1][1].len = len;
+	pp_defines[pp_num_defines-1][1].s = text;
+	LM_DBG("### setting define ID [%.*s] value [%.*s]\n",
+			pp_defines[pp_num_defines-1][0].len,
+			pp_defines[pp_num_defines-1][0].s,
+			pp_defines[pp_num_defines-1][1].len,
+			pp_defines[pp_num_defines-1][1].s);
+	return 0;
+}
+
+static str  *pp_define_get(int len, const char * text)
+{
+	str var = {(char *)text, len};
+	int i;
+
+	for (i=0; i<pp_num_defines; i++)
+	{
+		if (STR_EQ(pp_defines[i][0], var))
+		{
+			if(pp_defines[i][0].s!=NULL)
+			{
+				LM_DBG("### returning define ID [%.*s] value [%.*s]\n",
+					pp_defines[i][0].len,
+					pp_defines[i][0].s,
+					pp_defines[i][1].len,
+					pp_defines[i][1].s);
+				return &pp_defines[i][1];
+			}
+			return NULL;
+		}
+	}
+	return NULL;
+}
+
 static int pp_ifdef_type(int type)
 {
 	if (pp_sptr == MAX_IFDEFS) {

+ 8 - 0
cfg.y

@@ -141,6 +141,7 @@
 #include "sr_compat.h"
 #include "msg_translator.h"
 
+#include "ppcfg.h"
 #include "config.h"
 #include "cfg_core.h"
 #include "cfg/cfg.h"
@@ -542,6 +543,8 @@ extern char *finame;
 %token STUN_ALLOW_STUN
 %token STUN_ALLOW_FP
 
+/*pre-processor*/
+%token SUBST
 
 /* operators, C like precedence */
 %right EQUAL
@@ -644,6 +647,7 @@ statements:
 	;
 statement:
 	assign_stm
+	| preprocess_stm
 	| flags_decl
 	| avpflags_decl
 	| module_stm
@@ -1898,6 +1902,10 @@ event_route_stm: ROUTE_EVENT LBRACK EVENT_RT_NAME RBRACK LBRACE actions RBRACE {
 
 	| ROUTE_EVENT error { yyerror("invalid event_route statement"); }
 	;
+preprocess_stm:
+	SUBST STRING { if(pp_subst_add($2)<0) YYERROR; }
+	| SUBST error { yyerror("invalid subst preprocess statement"); }
+	;
 
 /*exp:	rval_expr
 		{

+ 116 - 0
ppcfg.c

@@ -0,0 +1,116 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * ppcfg.c - config preprocessor directives
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "mem/mem.h"
+#include "ut.h"
+#include "re.h"
+#include "dprint.h"
+
+#include "ppcfg.h"
+
+typedef struct _pp_subst_rule {
+	char *indata;
+	void *ppdata;
+	struct _pp_subst_rule *next;
+} pp_subst_rule_t;
+
+static pp_subst_rule_t *pp_subst_rules_head = NULL;
+static pp_subst_rule_t *pp_subst_rules_tail = NULL;
+
+int pp_subst_add(char *data)
+{
+	struct subst_expr* se;
+	str subst;
+	pp_subst_rule_t *pr;
+
+	subst.s = data;
+	subst.len = strlen(subst.s);
+	/* check for early invalid rule */
+	if(subst.len<=0)
+		return -1;
+	pr = (pp_subst_rule_t*)pkg_malloc(sizeof(pp_subst_rule_t));
+	if(pr==NULL)
+	{
+		LM_ERR("no more pkg\n");
+		return -1;
+	}
+	memset(pr, 0, sizeof(pp_subst_rule_t));
+
+	se=subst_parser(&subst);
+	if (se==0)
+	{
+		LM_ERR("bad subst expression:: %s\n", data);
+		pkg_free(pr);
+		return -2;
+	}
+	pr->indata = data;
+	pr->ppdata = (void*)se;
+	pr->next   = pp_subst_rules_tail;
+	if(pp_subst_rules_head==NULL)
+	{
+		pp_subst_rules_head = pr;
+		pp_subst_rules_tail = pr;
+	} else {
+		pp_subst_rules_tail->next = pr;
+	}
+
+	return 0;
+}
+
+int pp_subst_run(char **data)
+{
+	str* result;
+	pp_subst_rule_t *pr;
+
+	if(pp_subst_rules_head==NULL)
+		return 0;
+	if(data==NULL || *data==NULL)
+		return 0;
+
+	if(strlen(*data)==0)
+		return 0;
+	pr = pp_subst_rules_head;
+
+	while(pr)
+	{
+		result=subst_str(*data, 0,
+				(struct subst_expr*)pr->ppdata, 0); /* pkg malloc'ed result */
+		if(result!=NULL)
+		{
+			LM_DBG("### preprocess subst applied to [%s]"
+					" - returning new string [%s]\n", *data, result->s);
+			pkg_free(*data);
+			*data = result->s;
+			pkg_free(result);
+			return 1;
+		}
+		pr = pr->next;
+	}
+
+	return 0;
+}
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */

+ 30 - 0
ppcfg.h

@@ -0,0 +1,30 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * ppcfg.h - config preprocessor directives
+ */
+
+#ifndef _PPCFG_H_
+#define _PPCFG_H_
+
+int pp_subst_add(char *data);
+int pp_subst_run(char **data);
+
+#endif /*_PPCFG_H_*/
+
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */