Browse code

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 authored on 23/04/2010 21:58:43
Showing 4 changed files
... ...
@@ -97,6 +97,7 @@
97 97
 	#include "select.h"
98 98
 	#include "cfg.tab.h"
99 99
 	#include "sr_compat.h"
100
+	#include "ppcfg.h"
100 101
 
101 102
 	/* states */
102 103
 	#define INITIAL_S		0
... ...
@@ -109,12 +110,13 @@
109 109
 	#define PVAR_P_S                7  /* pvar: $(...)  or $foo(...)*/
110 110
 	#define PVARID_S                8  /* $foo.bar...*/
111 111
 	#define STR_BETWEEN_S		9
112
-	#define LINECOMMENT_S            10
112
+	#define LINECOMMENT_S           10
113 113
 	#define DEFINE_S                11
114 114
 	#define DEFINE_EOL_S            12
115
-	#define IFDEF_S                    13
116
-	#define IFDEF_EOL_S                14
115
+	#define IFDEF_S                 13
116
+	#define IFDEF_EOL_S             14
117 117
 	#define IFDEF_SKIP_S            15
118
+	#define DEFINE_DATA_S           16
118 119
 
119 120
 	#define STR_BUF_ALLOC_UNIT	128
120 121
 	struct str_buf{
... ...
@@ -136,6 +138,8 @@
136 136
 	static int ign_lines=0;
137 137
 	static int ign_columns=0;
138 138
 	char* yy_number_str=0; /* str correspondent for the current NUMBER token */
139
+	int r = 0;
140
+	str *sdef = 0;
139 141
 
140 142
 	static char* addchar(struct str_buf *, char);
141 143
 	static char* addstr(struct str_buf *, char*, int);
... ...
@@ -163,6 +167,8 @@
163 163
 	} *sr_yy_fname_list = 0;
164 164
 
165 165
 	static int  pp_define(int len, const char * text);
166
+	static int  pp_define_set(int len, char * text);
167
+	static str  *pp_define_get(int len, const char * text);
166 168
 	static int  pp_ifdef_type(int pos);
167 169
 	static void pp_ifdef_var(int len, const char * text);
168 170
 	static void pp_ifdef();
... ...
@@ -174,7 +180,7 @@
174 174
 /* start conditions */
175 175
 %x STRING1 STRING2 STR_BETWEEN COMMENT COMMENT_LN ATTR SELECT AVP_PVAR PVAR_P 
176 176
 %x PVARID INCLF
177
-%x LINECOMMENT DEFINE_ID DEFINE_EOL IFDEF_ID IFDEF_EOL IFDEF_SKIP
177
+%x LINECOMMENT DEFINE_ID DEFINE_EOL DEFINE_DATA IFDEF_ID IFDEF_EOL IFDEF_SKIP
178 178
 
179 179
 /* config script types : #!SER  or #!KAMAILIO or #!MAX_COMPAT */
180 180
 SER_CFG			SER
... ...
@@ -538,6 +544,9 @@ ENDIF        endif
538 538
 
539 539
 EAT_ABLE	[\ \t\b\r]
540 540
 
541
+/* pre-processing blocks */
542
+SUBST       subst
543
+
541 544
 %%
542 545
 
543 546
 
... ...
@@ -1118,6 +1127,7 @@ EAT_ABLE	[\ \t\b\r]
1118 1118
 <STRING2>{TICK}  { count_more(); state=old_state; BEGIN(old_initial);
1119 1119
 						yytext[yyleng-1]=0; yyleng--;
1120 1120
 						addstr(&s_buf, yytext, yyleng);
1121
+						r = pp_subst_run(&s_buf.s);
1121 1122
 						yylval.strval=s_buf.s;
1122 1123
 						memset(&s_buf, 0, sizeof(s_buf));
1123 1124
 						return STRING;
... ...
@@ -1147,6 +1157,7 @@ EAT_ABLE	[\ \t\b\r]
1147 1147
 									/* ignore the whitespace now that is
1148 1148
 									  counted, return saved string value */
1149 1149
 									state=old_state; BEGIN(old_initial);
1150
+									r = pp_subst_run(&s_buf.s);
1150 1151
 									yylval.strval=s_buf.s;
1151 1152
 									memset(&s_buf, 0, sizeof(s_buf));
1152 1153
 									return STRING;
... ...
@@ -1169,13 +1180,26 @@ EAT_ABLE	[\ \t\b\r]
1169 1169
 <INITIAL>{COM_LINE}!{MAXCOMPAT_CFG}{CR}	{ count(); 
1170 1170
 												sr_cfg_compat=SR_COMPAT_MAX;}
1171 1171
 
1172
-<INITIAL>{COM_LINE}!{DEFINE}{EAT_ABLE}+        { count();
1173
-										state = DEFINE_S; BEGIN(DEFINE_ID); }
1174
-<DEFINE_ID>{ID}                                { count();
1175
-								if (pp_define(yyleng, yytext)) return 1;
1176
-								state = DEFINE_EOL_S; BEGIN(DEFINE_EOL); }
1177
-<DEFINE_EOL>{EAT_ABLE}*{CR}                    { count();
1172
+<INITIAL>{COM_LINE}!{DEFINE}{EAT_ABLE}+	{	count();
1173
+											state = DEFINE_S; BEGIN(DEFINE_ID); }
1174
+<DEFINE_ID>{ID}                 {	count();
1175
+									if (pp_define(yyleng, yytext)) return 1;
1176
+									state = DEFINE_EOL_S; BEGIN(DEFINE_EOL); }
1177
+<DEFINE_EOL>{EAT_ABLE}			{	count(); }
1178
+<DEFINE_EOL>{CR}				{	count();
1178 1179
 									state = INITIAL; BEGIN(INITIAL); }
1180
+<DEFINE_EOL>.                   {	count();
1181
+									addstr(&s_buf, yytext, yyleng);
1182
+									state = DEFINE_DATA_S; BEGIN(DEFINE_DATA); }
1183
+<DEFINE_DATA>\\{CR}		{	count(); } /* eat the escaped CR */
1184
+<DEFINE_DATA>{CR}		{	count();
1185
+							if (pp_define_set(strlen(s_buf.s), s_buf.s)) return 1;
1186
+							memset(&s_buf, 0, sizeof(s_buf));
1187
+							state = INITIAL; BEGIN(INITIAL); }
1188
+<DEFINE_DATA>.          {	count();
1189
+							addstr(&s_buf, yytext, yyleng); }
1190
+
1191
+<INITIAL>{COM_LINE}!{SUBST}	{ count();  return SUBST;}
1179 1192
 
1180 1193
 <INITIAL,IFDEF_SKIP>{COM_LINE}!{IFDEF}{EAT_ABLE}+    { count();
1181 1194
 								if (pp_ifdef_type(1)) return 1;
... ...
@@ -1201,10 +1225,17 @@ EAT_ABLE	[\ \t\b\r]
1201 1201
 								BEGIN(LINECOMMENT); }
1202 1202
 <LINECOMMENT>.*{CR}        { count(); state = INITIAL_S; BEGIN(INITIAL); }
1203 1203
 
1204
-<INITIAL>{ID}			{ count(); addstr(&s_buf, yytext, yyleng);
1205
-									yylval.strval=s_buf.s;
1206
-									memset(&s_buf, 0, sizeof(s_buf));
1207
-									return ID; }
1204
+<INITIAL>{ID}		{	if ((sdef = pp_define_get(yyleng, yytext))!=NULL) {
1205
+							for (r=sdef->len-1; r>=0; r--)
1206
+								unput(sdef->s[r]); /* reverse order */
1207
+						} else {
1208
+							count();
1209
+							addstr(&s_buf, yytext, yyleng);
1210
+							yylval.strval=s_buf.s;
1211
+							memset(&s_buf, 0, sizeof(s_buf));
1212
+							return ID;
1213
+						}
1214
+					}
1208 1215
 <INITIAL>{NUM_ID}			{ count(); addstr(&s_buf, yytext, yyleng);
1209 1216
 									yylval.strval=s_buf.s;
1210 1217
 									memset(&s_buf, 0, sizeof(s_buf));
... ...
@@ -1225,6 +1256,7 @@ EAT_ABLE	[\ \t\b\r]
1225 1225
 										case STR_BETWEEN_S:
1226 1226
 											state=old_state;
1227 1227
 											BEGIN(old_initial);
1228
+											r = pp_subst_run(&s_buf.s);
1228 1229
 											yylval.strval=s_buf.s;
1229 1230
 											memset(&s_buf, 0, sizeof(s_buf));
1230 1231
 											return STRING;
... ...
@@ -1552,15 +1584,15 @@ static int sr_pop_yy_state()
1552 1552
 
1553 1553
 /* define/ifdef support */
1554 1554
 
1555
-#define MAX_DEFINES    1024
1556
-static str pp_defines[MAX_DEFINES];
1555
+#define MAX_DEFINES    256
1556
+static str pp_defines[MAX_DEFINES][2];
1557 1557
 static int pp_num_defines = 0;
1558 1558
 
1559 1559
 /* pp_ifdef_stack[i] is 1 if the ifdef test at depth i is either
1560 1560
  * ifdef(defined), ifndef(undefined), or the opposite of these
1561 1561
  * two, but in an else branch
1562 1562
  */
1563
-#define MAX_IFDEFS    128
1563
+#define MAX_IFDEFS    256
1564 1564
 static int pp_ifdef_stack[MAX_IFDEFS];
1565 1565
 static int pp_sptr = 0; /* stack pointer */
1566 1566
 
... ...
@@ -1570,7 +1602,7 @@ static int pp_lookup(int len, const char * text)
1570 1570
 	int i;
1571 1571
 
1572 1572
 	for (i=0; i<pp_num_defines; i++)
1573
-		if (STR_EQ(pp_defines[i], var))
1573
+		if (STR_EQ(pp_defines[i][0], var))
1574 1574
 			return i;
1575 1575
 
1576 1576
 	return -1;
... ...
@@ -1588,14 +1620,77 @@ static int pp_define(int len, const char * text)
1588 1588
 		return -1;
1589 1589
 	}
1590 1590
 
1591
-	pp_defines[pp_num_defines].len = len;
1592
-	pp_defines[pp_num_defines].s = (char*)pkg_malloc(len+1);
1593
-	memcpy(pp_defines[pp_num_defines].s, text, len);
1591
+	pp_defines[pp_num_defines][0].len = len;
1592
+	pp_defines[pp_num_defines][0].s = (char*)pkg_malloc(len+1);
1593
+	memcpy(pp_defines[pp_num_defines][0].s, text, len);
1594
+	pp_defines[pp_num_defines][1].len = 0;
1595
+	pp_defines[pp_num_defines][1].s = NULL;
1594 1596
 	pp_num_defines++;
1595 1597
 
1596 1598
 	return 0;
1597 1599
 }
1598 1600
 
1601
+static int  pp_define_set(int len, char *text)
1602
+{
1603
+	if(len<=0) {
1604
+		LOG(L_DBG, "no define value - ignoring\n");
1605
+		return 0;
1606
+	}
1607
+	if (pp_num_defines == MAX_DEFINES) {
1608
+		LOG(L_BUG, "BUG: setting define value, but no define id yet\n");
1609
+		return -1;
1610
+	}
1611
+	if (pp_num_defines == 0) {
1612
+		LOG(L_CRIT, "ERROR: too many defines -- adjust MAX_DEFINES\n");
1613
+		return -1;
1614
+	}
1615
+
1616
+	if (pp_defines[pp_num_defines-1][0].s == NULL) {
1617
+		LOG(L_BUG, "BUG: last define ID is null\n");
1618
+		return -1;
1619
+	}
1620
+
1621
+	if (pp_defines[pp_num_defines-1][1].s != NULL) {
1622
+		LOG(L_BUG, "BUG: ID %.*s redefined\n",
1623
+			pp_defines[pp_num_defines-1][0].len,
1624
+			pp_defines[pp_num_defines-1][0].s);
1625
+		return -1;
1626
+	}
1627
+
1628
+	pp_defines[pp_num_defines-1][1].len = len;
1629
+	pp_defines[pp_num_defines-1][1].s = text;
1630
+	LM_DBG("### setting define ID [%.*s] value [%.*s]\n",
1631
+			pp_defines[pp_num_defines-1][0].len,
1632
+			pp_defines[pp_num_defines-1][0].s,
1633
+			pp_defines[pp_num_defines-1][1].len,
1634
+			pp_defines[pp_num_defines-1][1].s);
1635
+	return 0;
1636
+}
1637
+
1638
+static str  *pp_define_get(int len, const char * text)
1639
+{
1640
+	str var = {(char *)text, len};
1641
+	int i;
1642
+
1643
+	for (i=0; i<pp_num_defines; i++)
1644
+	{
1645
+		if (STR_EQ(pp_defines[i][0], var))
1646
+		{
1647
+			if(pp_defines[i][0].s!=NULL)
1648
+			{
1649
+				LM_DBG("### returning define ID [%.*s] value [%.*s]\n",
1650
+					pp_defines[i][0].len,
1651
+					pp_defines[i][0].s,
1652
+					pp_defines[i][1].len,
1653
+					pp_defines[i][1].s);
1654
+				return &pp_defines[i][1];
1655
+			}
1656
+			return NULL;
1657
+		}
1658
+	}
1659
+	return NULL;
1660
+}
1661
+
1599 1662
 static int pp_ifdef_type(int type)
1600 1663
 {
1601 1664
 	if (pp_sptr == MAX_IFDEFS) {
... ...
@@ -141,6 +141,7 @@
141 141
 #include "sr_compat.h"
142 142
 #include "msg_translator.h"
143 143
 
144
+#include "ppcfg.h"
144 145
 #include "config.h"
145 146
 #include "cfg_core.h"
146 147
 #include "cfg/cfg.h"
... ...
@@ -542,6 +543,8 @@ extern char *finame;
542 542
 %token STUN_ALLOW_STUN
543 543
 %token STUN_ALLOW_FP
544 544
 
545
+/*pre-processor*/
546
+%token SUBST
545 547
 
546 548
 /* operators, C like precedence */
547 549
 %right EQUAL
... ...
@@ -644,6 +647,7 @@ statements:
644 644
 	;
645 645
 statement:
646 646
 	assign_stm
647
+	| preprocess_stm
647 648
 	| flags_decl
648 649
 	| avpflags_decl
649 650
 	| module_stm
... ...
@@ -1898,6 +1902,10 @@ event_route_stm: ROUTE_EVENT LBRACK EVENT_RT_NAME RBRACK LBRACE actions RBRACE {
1898 1898
 
1899 1899
 	| ROUTE_EVENT error { yyerror("invalid event_route statement"); }
1900 1900
 	;
1901
+preprocess_stm:
1902
+	SUBST STRING { if(pp_subst_add($2)<0) YYERROR; }
1903
+	| SUBST error { yyerror("invalid subst preprocess statement"); }
1904
+	;
1901 1905
 
1902 1906
 /*exp:	rval_expr
1903 1907
 		{
1904 1908
new file mode 100644
... ...
@@ -0,0 +1,116 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * ppcfg.c - config preprocessor directives
19
+ */
20
+
21
+#include <stdio.h>
22
+#include <string.h>
23
+#include <sys/types.h>
24
+#include <unistd.h>
25
+
26
+#include "mem/mem.h"
27
+#include "ut.h"
28
+#include "re.h"
29
+#include "dprint.h"
30
+
31
+#include "ppcfg.h"
32
+
33
+typedef struct _pp_subst_rule {
34
+	char *indata;
35
+	void *ppdata;
36
+	struct _pp_subst_rule *next;
37
+} pp_subst_rule_t;
38
+
39
+static pp_subst_rule_t *pp_subst_rules_head = NULL;
40
+static pp_subst_rule_t *pp_subst_rules_tail = NULL;
41
+
42
+int pp_subst_add(char *data)
43
+{
44
+	struct subst_expr* se;
45
+	str subst;
46
+	pp_subst_rule_t *pr;
47
+
48
+	subst.s = data;
49
+	subst.len = strlen(subst.s);
50
+	/* check for early invalid rule */
51
+	if(subst.len<=0)
52
+		return -1;
53
+	pr = (pp_subst_rule_t*)pkg_malloc(sizeof(pp_subst_rule_t));
54
+	if(pr==NULL)
55
+	{
56
+		LM_ERR("no more pkg\n");
57
+		return -1;
58
+	}
59
+	memset(pr, 0, sizeof(pp_subst_rule_t));
60
+
61
+	se=subst_parser(&subst);
62
+	if (se==0)
63
+	{
64
+		LM_ERR("bad subst expression:: %s\n", data);
65
+		pkg_free(pr);
66
+		return -2;
67
+	}
68
+	pr->indata = data;
69
+	pr->ppdata = (void*)se;
70
+	pr->next   = pp_subst_rules_tail;
71
+	if(pp_subst_rules_head==NULL)
72
+	{
73
+		pp_subst_rules_head = pr;
74
+		pp_subst_rules_tail = pr;
75
+	} else {
76
+		pp_subst_rules_tail->next = pr;
77
+	}
78
+
79
+	return 0;
80
+}
81
+
82
+int pp_subst_run(char **data)
83
+{
84
+	str* result;
85
+	pp_subst_rule_t *pr;
86
+
87
+	if(pp_subst_rules_head==NULL)
88
+		return 0;
89
+	if(data==NULL || *data==NULL)
90
+		return 0;
91
+
92
+	if(strlen(*data)==0)
93
+		return 0;
94
+	pr = pp_subst_rules_head;
95
+
96
+	while(pr)
97
+	{
98
+		result=subst_str(*data, 0,
99
+				(struct subst_expr*)pr->ppdata, 0); /* pkg malloc'ed result */
100
+		if(result!=NULL)
101
+		{
102
+			LM_DBG("### preprocess subst applied to [%s]"
103
+					" - returning new string [%s]\n", *data, result->s);
104
+			pkg_free(*data);
105
+			*data = result->s;
106
+			pkg_free(result);
107
+			return 1;
108
+		}
109
+		pr = pr->next;
110
+	}
111
+
112
+	return 0;
113
+}
114
+
115
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */
0 116
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+/* 
1
+ * $Id$
2
+ * 
3
+ * Copyright (C) 2010 Daniel-Constantin Mierla (asipto.com)
4
+ *
5
+ * Permission to use, copy, modify, and distribute this software for any
6
+ * purpose with or without fee is hereby granted, provided that the above
7
+ * copyright notice and this permission notice appear in all copies.
8
+ *
9
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
+ */
17
+/*
18
+ * ppcfg.h - config preprocessor directives
19
+ */
20
+
21
+#ifndef _PPCFG_H_
22
+#define _PPCFG_H_
23
+
24
+int pp_subst_add(char *data);
25
+int pp_subst_run(char **data);
26
+
27
+#endif /*_PPCFG_H_*/
28
+
29
+/* vi: set ts=4 sw=4 tw=79:ai:cindent: */