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