Since include_file was just added, why not go one extra step and<br>allow things like (adapted from etc/kamailio.cfg):<br><br>#!define PRESENCE<br><br>#!ifdef PRESENCE<br> loadmodule "presence.so"<br> loadmodule "presence_xml.so"<br>
#!else<br> #!ifndef KAMAILIO<br> ...<br> #!endif<br>#!endif<br><br>M4 is already used and a better alternative IMO, but cfg is clearly not a<br>typical language, so I imagine someone may find this useful. Patch against<br>
commit 7362f824.<br><br>For a minimal test input, this can be used:<br>=====<br>listen=::1<br><br>#!define xyz<br><br>#!ifdef xyz<br> listen=::2<br> #!ifndef abc<br> listen=::3<br> #!else<br> listen=::4<br> #!endif<br>
listen=::5<br>#!endif<br>=====<br><br>While wr're at it, the ID token seemed wrong -- it misses
<br>_ids_that_start_with_underscores (?).<br>
<br>Bogdan<br><br><br>diff --git a/cfg.lex b/cfg.lex<br>index 8490364..df4a2ee 100644<br>--- a/cfg.lex<br>+++ b/cfg.lex<br>@@ -105,6 +105,12 @@<br> #define PVAR_P_S 7 /* pvar: $(...) or $foo(...)*/<br>
#define PVARID_S 8 /* $foo.bar...*/<br> #define STR_BETWEEN_S 9<br>+ #define LINECOMMENT_S 10<br>+ #define DEFINE_S 11<br>+ #define DEFINE_EOL_S 12<br>
+ #define IFDEF_S 13<br>+ #define IFDEF_EOL_S 14<br>+ #define IFDEF_SKIP_S 15<br> <br> #define STR_BUF_ALLOC_UNIT 128<br> struct str_buf{<br>@@ -152,11 +158,18 @@<br>
struct sr_yy_fname *next;<br> } *sr_yy_fname_list = 0;<br> <br>+ static int pp_define(int len, const char * text);<br>+ static int pp_ifdef_type(int pos);<br>+ static void pp_ifdef_var(int len, const char * text);<br>
+ static void pp_ifdef();<br>+ static void pp_else();<br>+ static void pp_endif();<br> %}<br> <br> /* start conditions */<br> %x STRING1 STRING2 STR_BETWEEN COMMENT COMMENT_LN ATTR SELECT AVP_PVAR PVAR_P <br> %x PVARID INCLF<br>
+%x LINECOMMENT DEFINE_ID DEFINE_EOL IFDEF_ID IFDEF_EOL IFDEF_SKIP<br> <br> /* config script types : #!SER or #!KAMAILIO or #!MAX_COMPAT */<br> SER_CFG SER<br>@@ -474,8 +487,9 @@ TLSv1 "tlsv1"|"TLSv1"|"TLSV1"<br>
<br> LETTER [a-zA-Z]<br> DIGIT [0-9]<br>-ALPHANUM {LETTER}|{DIGIT}|[_]<br>-ID {LETTER}{ALPHANUM}*<br>+LETTER_ {LETTER}|[_]<br>+ALPHANUM {LETTER_}|{DIGIT}<br>+ID {LETTER_}{ALPHANUM}*<br>
NUM_ID {ALPHANUM}+<br> HEX [0-9a-fA-F]<br> HEXNUMBER 0x{HEX}+<br>@@ -506,6 +520,12 @@ COM_LINE #<br> COM_START "/\*"<br> COM_END "\*/"<br> <br>+DEFINE define<br>
+IFDEF ifdef<br>+IFNDEF ifndef<br>+ENDIF endif<br>+/* else is already defined */<br>+<br> EAT_ABLE [\ \t\b\r]<br> <br> %%<br>@@ -1121,7 +1141,36 @@ EAT_ABLE [\ \t\b\r]<br> sr_cfg_compat=SR_COMPAT_KAMAILIO;}<br>
<INITIAL>{COM_LINE}!{MAXCOMPAT_CFG}{CR} { count(); <br> sr_cfg_compat=SR_COMPAT_MAX;}<br>-<INITIAL>{COM_LINE}.*{CR} { count(); }<br>+<br>+<INITIAL>{COM_LINE}!{DEFINE}{EAT_ABLE}+ { count(); <br>
+ state = DEFINE_S; BEGIN(DEFINE_ID); }<br>+<DEFINE_ID>{ID} { count(); <br>+ if (pp_define(yyleng, yytext)) return 1;<br>
+ state = DEFINE_EOL_S; BEGIN(DEFINE_EOL); }<br>+<DEFINE_EOL>{EAT_ABLE}*{CR} { count(); <br>+ state = INITIAL; BEGIN(INITIAL); }<br>
+<br>+<INITIAL,IFDEF_SKIP>{COM_LINE}!{IFDEF}{EAT_ABLE}+ { count(); <br>+ if (pp_ifdef_type(1)) return 1;<br>+ state = IFDEF_S; BEGIN(IFDEF_ID); }<br>
+<INITIAL,IFDEF_SKIP>{COM_LINE}!{IFNDEF}{EAT_ABLE}+ { count(); <br>+ if (pp_ifdef_type(0)) return 1;<br>+ state = IFDEF_S; BEGIN(IFDEF_ID); }<br>
+<IFDEF_ID>{ID} { count(); <br>+ pp_ifdef_var(yyleng, yytext); <br>+ state = IFDEF_EOL_S; BEGIN(IFDEF_EOL); }<br>+<IFDEF_EOL>{EAT_ABLE}*{CR} { count(); pp_ifdef(); }<br>
+<br>+<INITIAL,IFDEF_SKIP>{COM_LINE}!{ELSE}{EAT_ABLE}*{CR} { count(); pp_else(); }<br>+<br>+<INITIAL,IFDEF_SKIP>{COM_LINE}!{ENDIF}{EAT_ABLE}*{CR} { count(); pp_endif(); }<br>+<br>+ /* we're in an ifdef that evaluated to false -- throw it away */<br>
+<IFDEF_SKIP>.|{CR} { count(); } <br>+<br>+ /* this is split so the shebangs match more, giving them priority */<br>+<INITIAL>{COM_LINE} { count(); state = LINECOMMENT_S; BEGIN(LINECOMMENT); }<br>+<LINECOMMENT>.*{CR} { count(); state = INITIAL_S; BEGIN(INITIAL); }<br>
<br> <INITIAL>{ID} { count(); addstr(&s_buf, yytext, yyleng);<br> yylval.strval=s_buf.s;<br>@@ -1472,3 +1521,102 @@ static int sr_pop_yy_state()<br> return 0;<br>
}<br> <br>+/* define/ifdef support */<br>+<br>+#define MAX_DEFINES 1024<br>+static str pp_defines[MAX_DEFINES];<br>+static int pp_num_defines = 0;<br>+<br>+/* pp_ifdef_stack[i] is 1 if the ifdef test at depth i is either <br>
+ * ifdef(defined), ifndef(undefined), or the opposite of these <br>+ * two, but in an else branch<br>+ */<br>+#define MAX_IFDEFS 16<br>+static int pp_ifdef_stack[MAX_IFDEFS];<br>+static int pp_sptr = 0; /* stack pointer */<br>
+<br>+static int pp_lookup(int len, const char * text)<br>+{<br>+ str var = {(char *)text, len};<br>+ int i;<br>+<br>+ for (i=0; i<pp_num_defines; i++)<br>+ if (STR_EQ(pp_defines[i], var))<br>+ return i;<br>
+<br>+ return -1;<br>+}<br>+<br>+static int pp_define(int len, const char * text)<br>+{<br>+ if (pp_num_defines == MAX_DEFINES) {<br>+ LOG(L_CRIT, "ERROR: too many defines -- adjust MAX_DEFINES\n");<br>
+ return -1;<br>+ }<br>+<br>+ if (pp_lookup(len, text) >= 0) {<br>+ LOG(L_CRIT, "ERROR: already defined: %.*s\n", len, text);<br>+ return -1;<br>+ }<br>+<br>+ pp_defines[pp_num_defines].len = len;<br>
+ pp_defines[pp_num_defines].s = (char*)pkg_malloc(len+1);<br>+ memcpy(pp_defines[pp_num_defines].s, text, len);<br>+ pp_num_defines++;<br>+<br>+ return 0;<br>+}<br>+<br>+static int pp_ifdef_type(int type)<br>
+{<br>+ if (pp_sptr == MAX_IFDEFS) {<br>+ LOG(L_CRIT, "ERROR: too many nested ifdefs -- adjust MAX_IFDEFS\n");<br>+ return -1;<br>+ }<br>+ <br>+ pp_ifdef_stack[pp_sptr] = type;<br>+ return 0;<br>
+}<br>+<br>+/* this sets the result of the if[n]def expr:<br>+ * ifdef defined -> 1<br>+ * ifdef undefined -> 0<br>+ * ifndef defined -> 0<br>+ * ifndef undefined -> 1<br>+ */<br>+static void pp_ifdef_var(int len, const char * text)<br>
+{<br>+ pp_ifdef_stack[pp_sptr] ^= (pp_lookup(len, text) < 0);<br>+}<br>+<br>+static void pp_update_state()<br>+{<br>+ int i;<br>+ <br>+ for (i=0; i<pp_sptr; i++)<br>+ if (! pp_ifdef_stack[i]) {<br>
+ state = IFDEF_SKIP_S; BEGIN(IFDEF_SKIP); <br>+ return;<br>+ }<br>+<br>+ state = INITIAL; BEGIN(INITIAL); <br>+}<br>+<br>+static void pp_ifdef()<br>+{<br>+ pp_sptr++;<br>+ pp_update_state();<br>
+}<br>+<br>+static void pp_else()<br>+{<br>+ pp_ifdef_stack[pp_sptr-1] ^= 1;<br>+ pp_update_state();<br>+}<br>+<br>+static void pp_endif() <br>+{<br>+ pp_sptr--;<br>+ pp_update_state();<br>+}<br>+<br><br>