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 &quot;presence.so&quot;<br>  loadmodule &quot;presence_xml.so&quot;<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&#39;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            &quot;tlsv1&quot;|&quot;TLSv1&quot;|&quot;TLSV1&quot;<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    &quot;/\*&quot;<br> COM_END        &quot;\*/&quot;<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>
 &lt;INITIAL&gt;{COM_LINE}!{MAXCOMPAT_CFG}{CR}    { count(); <br>                                                 sr_cfg_compat=SR_COMPAT_MAX;}<br>-&lt;INITIAL&gt;{COM_LINE}.*{CR}    { count(); }<br>+<br>+&lt;INITIAL&gt;{COM_LINE}!{DEFINE}{EAT_ABLE}+        { count(); <br>
+                                                state = DEFINE_S; BEGIN(DEFINE_ID); }<br>+&lt;DEFINE_ID&gt;{ID}                                { count(); <br>+                                                if (pp_define(yyleng, yytext)) return 1;<br>
+                                                state = DEFINE_EOL_S; BEGIN(DEFINE_EOL); }<br>+&lt;DEFINE_EOL&gt;{EAT_ABLE}*{CR}                    { count(); <br>+                                                state = INITIAL; BEGIN(INITIAL); }<br>
+<br>+&lt;INITIAL,IFDEF_SKIP&gt;{COM_LINE}!{IFDEF}{EAT_ABLE}+    { count(); <br>+                                                        if (pp_ifdef_type(1)) return 1;<br>+                                                        state = IFDEF_S; BEGIN(IFDEF_ID); }<br>
+&lt;INITIAL,IFDEF_SKIP&gt;{COM_LINE}!{IFNDEF}{EAT_ABLE}+    { count(); <br>+                                                        if (pp_ifdef_type(0)) return 1;<br>+                                                        state = IFDEF_S; BEGIN(IFDEF_ID); }<br>
+&lt;IFDEF_ID&gt;{ID}                { count(); <br>+                                pp_ifdef_var(yyleng, yytext); <br>+                                state = IFDEF_EOL_S; BEGIN(IFDEF_EOL); }<br>+&lt;IFDEF_EOL&gt;{EAT_ABLE}*{CR}    { count(); pp_ifdef(); }<br>
+<br>+&lt;INITIAL,IFDEF_SKIP&gt;{COM_LINE}!{ELSE}{EAT_ABLE}*{CR}    { count(); pp_else(); }<br>+<br>+&lt;INITIAL,IFDEF_SKIP&gt;{COM_LINE}!{ENDIF}{EAT_ABLE}*{CR}    { count(); pp_endif(); }<br>+<br>+ /* we&#39;re in an ifdef that evaluated to false -- throw it away */<br>
+&lt;IFDEF_SKIP&gt;.|{CR}    { count(); } <br>+<br>+ /* this is split so the shebangs match more, giving them priority */<br>+&lt;INITIAL&gt;{COM_LINE}        { count(); state = LINECOMMENT_S; BEGIN(LINECOMMENT); }<br>+&lt;LINECOMMENT&gt;.*{CR}        { count(); state = INITIAL_S; BEGIN(INITIAL); }<br>
 <br> &lt;INITIAL&gt;{ID}            { count(); addstr(&amp;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&lt;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, &quot;ERROR: too many defines -- adjust MAX_DEFINES\n&quot;);<br>
+        return -1;<br>+    }<br>+<br>+    if (pp_lookup(len, text) &gt;= 0) {<br>+        LOG(L_CRIT, &quot;ERROR: already defined: %.*s\n&quot;, 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, &quot;ERROR: too many nested ifdefs -- adjust MAX_IFDEFS\n&quot;);<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   -&gt; 1<br>+ * ifdef  undefined -&gt; 0<br>+ * ifndef defined   -&gt; 0<br>+ * ifndef undefined -&gt; 1<br>+ */<br>+static void pp_ifdef_var(int len, const char * text)<br>
+{<br>+    pp_ifdef_stack[pp_sptr] ^= (pp_lookup(len, text) &lt; 0);<br>+}<br>+<br>+static void pp_update_state()<br>+{<br>+    int i;<br>+    <br>+    for (i=0; i&lt;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>