Hello Andi, Pierre,

Monday, February 11, 2008, 7:49:04 PM, you wrote:

> Hi Marcus,

> In general I think conditional INI support can benefit many of our
> users. We just need to make sure that we cover the most common needs and
> also that we keep it very basic and simple so that we don't boil the
> ocean and maintain two languages. So it's a balance we need to meet.

Right

> It would be very helpful that as part of the feedback loop you write
> something a bit more detailed about this feature and what is and isn't
> supported. I imagine most people on this list would have a hard time to
> figure that out from the patch. This includes:
> - What operators are supported in conditionals

<, <=, >, >=, ==, !=, &&, || all use atoi
[${left} < ${right}]  -> atoi(${left}) < atoi(${right})

=== and !== are string comparisons
[${left} === ${right}] -> !strcmp(${lect}, ${right})

Instead of === and !== I could have introduced functions like strcmp but I
wanted to keep it as simple as possible for the lexer as well as the user.

The only thing I might want to add is !. But that would be unary and
increase complexity.

> - Are there any "functions" like empty() or is the ternary operator the
> proposed solution for that?

None, though instead of empty() you can do: ${var}===""

> - Is it possible to get to environment variables from this? If so how is
> it namespaced? How about registry on Windows?

Anything the ini allows today is possible, no changes, values are evaluated
just as in assignments of the ini file.

> - What happens when you use a variable which is not set?


> - Do you propose a solution for concatenation of two values or is this
> outside the scope?

afaik th eini allows that already

> - Can each [IF] include multiple conditionals i.e. $(value) > 1 AND
> $(value) < 5 or just one condition with the expectation that people will
> use nesting.

Nesting is supported as well as braces. So the following works:
[(${a} < ${b}) && (${c} < ${d})]

> A few specific feedbacks:
> - Ternary operator's syntax is a bit weird. My preference would be not
> to have such an operator and require using [if ..] so that it's very
> clear what's pre-processed even if it requires a bit more works.  We
> don't want the INI files to become too cryptic. Also the syntax would be
> better formed as ${value}?1:2 but again I think it's better not to have
> it.

That seems the common response her. I'll drop it.

> - I would prefer to see [ELSEIF] instead of [ELIF] to be consistent with
> PHP. It would look weird for the same solution to have two approaches to
> this.

Both of you guys say the same for the same reasons., so I changed that
as well.

Also I reduced the number of added values to 'php.zts' and 'php.debug'.
Maybe we can add those two as consts (Pierre?).

regards
marcus

>> -----Original Message-----
>> From: Marcus Boerger [mailto:[EMAIL PROTECTED]
>> Sent: Saturday, February 09, 2008 6:33 AM
>> To: PHP Internals List
>> Subject: [PHP-DEV] [RFC] Conditional INI support
>> 
>> Hello PHPlers,
>> 
>>   attached is a patch against 5.3 that brings three feature additions
>> to INI parsing.
>> 
>> 1) Ternary support for values
>> 
>>   setting = ${value?1:2}
>> 
>> If ${value} evaluates to true then setting becomes 1 otherwise 2.
>> This cannot be nested and only works for values, not for setting
> names.
>> 
>> 2) if-elif-else-endif support
>> 
>> [IF ${value} == 1]
>> setting = 1
>> [ELIF ${value} == 2]
>> setting = 2
>> [ELSE]
>> setting = 3
>> [ENDIF]
>> 
>> This can be nested. Alternatively we could use apache style syntax
> that
>> looks more like XML. The reason I used square brackets is that this is
>> the smallest change to normal INI files.
>> 
>> 3) Add more values to INI parsing, namely:
>> 
>> ${php.version} = 50300
>> ${php.debug} = 0
>> ${php.zts} = 0
>> ${php.sapi} = CLI
>> 
>> Any comments?
>> 
>> Best regards,
>>  Marcus



Best regards,
 Marcus
Index: main/php_ini.c
===================================================================
RCS file: /repository/php-src/main/php_ini.c,v
retrieving revision 1.136.2.4.2.15.2.7
diff -u -p -d -r1.136.2.4.2.15.2.7 php_ini.c
--- main/php_ini.c      3 Feb 2008 14:35:59 -0000       1.136.2.4.2.15.2.7
+++ main/php_ini.c      13 Feb 2008 16:20:26 -0000
@@ -20,6 +20,7 @@
 
 #include "php.h"
 #include "ext/standard/info.h"
+#include "ext/standard/basic_functions.h"
 #include "zend_ini.h"
 #include "zend_ini_scanner.h"
 #include "php_ini.h"
@@ -328,6 +329,32 @@ static void php_load_zend_extension_cb(v
 }
 /* }}} */
 
+PHPAPI void php_ini_add_config_stringl(const char* name, int name_size, const 
char *value, int value_len TSRMLS_DC) /* {{{*/
+{
+       zval tmp;
+       ZVAL_STRINGL(&tmp, zend_strndup(value, value_len), value_len, 0);
+       Z_SET_REFCOUNT(tmp, 0);
+       Z_UNSET_ISREF(tmp);
+       zend_hash_update(&configuration_hash, name, name_size, (void *) &tmp, 
sizeof(zval), NULL);
+} /* }}} */
+
+PHPAPI void php_ini_add_config_string(const char* name, int name_size, const 
char *value TSRMLS_DC) /* {{{*/
+{
+       php_ini_add_config_stringl(name, name_size, value, strlen(value) 
TSRMLS_CC);
+} /* }}} */
+
+PHPAPI void php_ini_add_config_long(const char* name, int name_size, long 
value TSRMLS_DC) /* {{{*/
+{
+       char str_val[32];
+       int value_len = slprintf(str_val, sizeof(str_val), "%ld", value);
+       php_ini_add_config_stringl(name, name_size, str_val, value_len 
TSRMLS_CC);
+} /* }}} */
+
+PHPAPI void php_ini_add_config_bool(const char* name, int name_size, int value 
TSRMLS_DC) /* {{{*/
+{
+       php_ini_add_config_stringl(name, name_size, value ? "1" : "0", 1 
TSRMLS_CC);
+} /* }}} */
+
 /* {{{ php_init_config
  */
 int php_init_config(TSRMLS_D)
@@ -347,6 +374,17 @@ int php_init_config(TSRMLS_D)
                sapi_module.ini_defaults(&configuration_hash);
        }
 
+#if ZTS
+       php_ini_add_config_bool("php.zts", sizeof("php.zts"), 1 TSRMLS_CC);
+#else
+       php_ini_add_config_bool("php.zts", sizeof("php.zts"), 0 TSRMLS_CC);
+#endif
+#if ZEND_DEBUG
+       php_ini_add_config_bool("php.debug", sizeof("php.debug"), 1 TSRMLS_CC);
+#else
+       php_ini_add_config_bool("php.debug", sizeof("php.debug"), 0 TSRMLS_CC);
+#endif
+
        zend_llist_init(&extension_lists.engine, sizeof(char *), 
(llist_dtor_func_t) free_estring, 1);
        zend_llist_init(&extension_lists.functions, sizeof(char *), 
(llist_dtor_func_t) free_estring, 1);
 
@@ -558,24 +596,19 @@ int php_init_config(TSRMLS_D)
        PG(open_basedir) = open_basedir;
 
        if (fh.handle.fp) {
+               int filename_len;
+               char *ftmp;
                fh.type = ZEND_HANDLE_FP;
                RESET_ACTIVE_INI_HASH();
 
                zend_parse_ini_file(&fh, 1, ZEND_INI_SCANNER_NORMAL, 
(zend_ini_parser_cb_t) php_ini_parser_cb, &configuration_hash TSRMLS_CC);
 
-               {
-                       zval tmp;
-
-                       Z_STRLEN(tmp) = strlen(fh.filename);
-                       Z_STRVAL(tmp) = zend_strndup(fh.filename, 
Z_STRLEN(tmp));
-                       Z_TYPE(tmp) = IS_STRING;
-                       Z_SET_REFCOUNT(tmp, 0);
-
-                       zend_hash_update(&configuration_hash, "cfg_file_path", 
sizeof("cfg_file_path"), (void *) &tmp, sizeof(zval), NULL);
-                       if (php_ini_opened_path) {
-                               efree(php_ini_opened_path);
-                       }
-                       php_ini_opened_path = zend_strndup(Z_STRVAL(tmp), 
Z_STRLEN(tmp));
+               filename_len = strlen(fh.filename);
+               php_ini_add_config_stringl("cfg_file_path", 
sizeof("cfg_file_path"), fh.filename, filename_len TSRMLS_CC);
+               ftmp = php_ini_opened_path;
+               php_ini_opened_path = zend_strndup(fh.filename, filename_len);
+               if (ftmp) {
+                       efree(ftmp);
                }
        }
 
Index: Zend/zend_globals.h
===================================================================
RCS file: /repository/ZendEngine2/zend_globals.h,v
retrieving revision 1.141.2.3.2.7.2.7
diff -u -p -d -r1.141.2.3.2.7.2.7 zend_globals.h
--- Zend/zend_globals.h 24 Jan 2008 09:41:37 -0000      1.141.2.3.2.7.2.7
+++ Zend/zend_globals.h 13 Feb 2008 16:20:27 -0000
@@ -52,6 +52,8 @@ END_EXTERN_C()
 #endif
 
 #define SYMTABLE_CACHE_SIZE 32
+#define ZEND_DEBUG_CFG_PARSER 0
+
 
 
 #include "zend_compile.h"
@@ -272,6 +274,7 @@ struct _zend_scanner_globals {
 
        /* For ini scanner. Modes are: ZEND_INI_SCANNER_NORMAL, 
ZEND_INI_SCANNER_RAW */
        int scanner_mode;
+       int if_level;
 
 #ifdef ZEND_MULTIBYTE
        /* original (unfiltered) script */
@@ -290,6 +293,12 @@ struct _zend_scanner_globals {
 #endif /* ZEND_MULTIBYTE */
 };
 
+typedef enum {
+       ZEND_INI_COND_READ,
+       ZEND_INI_COND_IGNORE,
+       ZEND_INI_COND_DONE,
+} ZEND_INI_CONDITIONAL;
+
 #endif /* ZEND_GLOBALS_H */
 
 /*
Index: Zend/zend_ini_parser.y
===================================================================
RCS file: /repository/ZendEngine2/zend_ini_parser.y,v
retrieving revision 1.41.2.2.2.2.2.4
diff -u -p -d -r1.41.2.2.2.2.2.4 zend_ini_parser.y
--- Zend/zend_ini_parser.y      4 Feb 2008 20:45:20 -0000       1.41.2.2.2.2.2.4
+++ Zend/zend_ini_parser.y      13 Feb 2008 16:20:28 -0000
@@ -15,13 +15,12 @@
    +----------------------------------------------------------------------+
    | Authors: Zeev Suraski <[EMAIL PROTECTED]>                                |
    |          Jani Taskinen <[EMAIL PROTECTED]>                                
|
+   |          Marcus Boerger <[EMAIL PROTECTED]>                              |
    +----------------------------------------------------------------------+
 */
 
 /* $Id: zend_ini_parser.y,v 1.41.2.2.2.2.2.4 2008/02/04 20:45:20 jani Exp $ */
 
-#define DEBUG_CFG_PARSER 0
-
 #include "zend.h"
 #include "zend_API.h"
 #include "zend_ini.h"
@@ -29,6 +28,9 @@
 #include "zend_ini_scanner.h"
 #include "zend_extensions.h"
 
+extern void zend_ini_set_ignore(ZEND_INI_CONDITIONAL ignore TSRMLS_DC);
+extern void zend_ini_error(int severity TSRMLS_DC, char *error);
+
 #define YYERROR_VERBOSE
 #define YYSTYPE zval
 
@@ -86,6 +88,106 @@ static void zend_ini_do_op(char type, zv
 }
 /* }}} */
 
+static void zend_ini_compare(int type, zval *result, zval *op1, zval *op2) /* 
{{{ */
+{
+       int i_op1, i_op2, ret;
+       char *str2 = "";
+
+       if (type == T_IS_NOT_IDENTICAL || type == T_IS_NOT_IDENTICAL) {
+               if (op2) {
+                       ret = !strcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2));
+                       str2 = Z_STRVAL_P(op2);
+               } else {
+                       ret = Z_STRLEN_P(op1) > 0;
+               }
+               if (type == T_IS_NOT_IDENTICAL) {
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "INI compare('%s' !== '%s')\n", 
Z_STRVAL_P(op1), str2);
+#endif
+                       ret = ret ? 0 : 1;
+               } else {
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "INI compare('%s' === '%s')\n", 
Z_STRVAL_P(op1), str2);
+#endif
+                       ret = ret ? 1 : 0;
+               }
+       } else {
+               i_op1 = atoi(Z_STRVAL_P(op1));
+               if (op2) {
+                       i_op2 = atoi(Z_STRVAL_P(op2));
+               } else {
+                       i_op2 = 0;
+               }
+       
+               switch (type) {
+                       case T_IS_EQ:
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d == %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 == i_op2;
+                               break;
+                       case T_IS_NE:
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d != %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 != i_op2;
+                               break;
+                       case T_IS_GE:
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d >= %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 >= i_op2;
+                               break;
+                       case '>':
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d > %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 >  i_op2;
+                               break;
+                       case T_IS_LE:
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d <= %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 <= i_op2;
+                               break;
+                       case '<':
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d < %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 <  i_op2;
+                               break;
+                       case T_L_AND:
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d && %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 && i_op2;
+                               break;
+                       case T_L_OR:
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d || %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = i_op1 && i_op2;
+                               break;
+                       default:
+#if ZEND_DEBUG_CFG_PARSER
+                               fprintf(stderr, "INI compare(%d ? %d)\n", 
i_op1, i_op2);
+#endif
+                               ret = 0;
+                               break;
+               }
+       }
+       free(Z_STRVAL_P(op1));
+       if (op2) {
+               free(Z_STRVAL_P(op2));
+       }
+       Z_STRVAL_P(result) = malloc(2);
+       Z_STRVAL_P(result)[0] = ret ? '1' : '0';
+       Z_STRVAL_P(result)[1] = 0;
+       Z_STRLEN_P(result) = 1;
+       Z_TYPE_P(result) = IS_STRING;
+}
+/* }}} */
+
 /* {{{ zend_ini_init_string()
 */
 static void zend_ini_init_string(zval *result)
@@ -159,31 +261,7 @@ static void zend_ini_get_var(zval *resul
 */
 static void ini_error(char *msg)
 {
-       char *error_buf;
-       int error_buf_len;
-       char *currently_parsed_filename;
-       TSRMLS_FETCH();
-
-       currently_parsed_filename = zend_ini_scanner_get_filename(TSRMLS_C);
-       if (currently_parsed_filename) {
-               error_buf_len = 128 + strlen(msg) + 
strlen(currently_parsed_filename); /* should be more than enough */
-               error_buf = (char *) emalloc(error_buf_len);
-
-               sprintf(error_buf, "%s in %s on line %d\n", msg, 
currently_parsed_filename, zend_ini_scanner_get_lineno(TSRMLS_C));
-       } else {
-               error_buf = estrdup("Invalid configuration directive\n");
-       }
-
-       if (CG(ini_parser_unbuffered_errors)) {
-#ifdef PHP_WIN32
-               MessageBox(NULL, error_buf, "PHP Error", 
MB_OK|MB_TOPMOST|0x00200000L);
-#else
-               fprintf(stderr, "PHP:  %s", error_buf);
-#endif
-       } else {
-               zend_error(E_WARNING, "%s", error_buf);
-       }
-       efree(error_buf);
+       zend_ini_error(E_WARNING TSRMLS_CC, msg);
 }
 /* }}} */
 
@@ -250,6 +328,7 @@ ZEND_API int zend_parse_ini_string(char 
 %pure_parser
 
 %token TC_SECTION
+%token TC_CONDITION
 %token TC_RAW
 %token TC_CONSTANT
 %token TC_NUMBER
@@ -263,7 +342,11 @@ ZEND_API int zend_parse_ini_string(char 
 %token BOOL_TRUE
 %token BOOL_FALSE
 %token END_OF_LINE
-%token '=' ':' ',' '.' '"' '\'' '^' '+' '-' '/' '*' '%' '$' '~' '<' '>' '?' 
'@' '{' '}'
+%left T_L_OR
+%left T_L_AND
+%left T_IS_EQ T_IS_NE T_IS_IDENTICAL T_IS_NOT_IDENTICAL
+%left T_IS_LE T_IS_GE
+%token '=' ':' ',' '.' '"' '\'' '^' '+' '-' '/' '*' '%' '$' '~' '<' '>' '?' 
'@' '{' '}' '(' ')'
 %left '|' '&'
 %right '~' '!'
 
@@ -276,33 +359,71 @@ statement_list:
 
 statement:
                TC_SECTION section_string_or_value ']' {
-#if DEBUG_CFG_PARSER
-                       printf("SECTION: [%s]\n", Z_STRVAL($2));
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "SECTION: [%s]\n", Z_STRVAL($2));
 #endif
                        ZEND_INI_PARSER_CB(&$2, NULL, NULL, 
ZEND_INI_PARSER_SECTION, ZEND_INI_PARSER_ARG TSRMLS_CC);
                        free(Z_STRVAL($2));
                }
+       |       TC_CONDITION compare ']' {
+                   int ignore = Z_STRVAL($2)[0] == '1' ? 0 : 1;
+                       free(Z_STRVAL($2));
+                       zend_ini_set_ignore(ignore ? ZEND_INI_COND_IGNORE : 
ZEND_INI_COND_READ TSRMLS_CC);
+               }
        |       TC_LABEL '=' string_or_value {
-#if DEBUG_CFG_PARSER
-                       printf("NORMAL: '%s' = '%s'\n", Z_STRVAL($1), 
Z_STRVAL($3));
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "NORMAL: '%s' = '%s'\n", Z_STRVAL($1), 
Z_STRVAL($3));
 #endif
                        ZEND_INI_PARSER_CB(&$1, &$3, NULL, 
ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
                        free(Z_STRVAL($1));
                        free(Z_STRVAL($3));
                }
        |       TC_OFFSET option_offset ']' '=' string_or_value {
-#if DEBUG_CFG_PARSER
-                       printf("OFFSET: '%s'[%s] = '%s'\n", Z_STRVAL($1), 
Z_STRVAL($2), Z_STRVAL($5));
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "OFFSET: '%s'[%s] = '%s'\n", 
Z_STRVAL($1), Z_STRVAL($2), Z_STRVAL($5));
 #endif
                        ZEND_INI_PARSER_CB(&$1, &$5, &$2, 
ZEND_INI_PARSER_POP_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
                        free(Z_STRVAL($1));
                        free(Z_STRVAL($2));
                        free(Z_STRVAL($5));
                }
-       |       TC_LABEL        { ZEND_INI_PARSER_CB(&$1, NULL, NULL, 
ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC); free(Z_STRVAL($1)); }
+       |       TC_LABEL        {
+                       ZEND_INI_PARSER_CB(&$1, NULL, NULL, 
ZEND_INI_PARSER_ENTRY, ZEND_INI_PARSER_ARG TSRMLS_CC);
+                       free(Z_STRVAL($1));
+               }
        |       END_OF_LINE
 ;
 
+compare:
+               compare_right T_L_AND compare_right { zend_ini_compare(T_L_AND, 
&$$, &$1, &$3); }
+       |       compare_right T_L_OR  compare_right { zend_ini_compare(T_L_OR,  
&$$, &$1, &$3); }
+       |       compare_right T_IS_GE compare_right { zend_ini_compare(T_IS_GE, 
&$$, &$1, &$3); }
+       |       compare_right '>'     compare_right { zend_ini_compare('>',     
&$$, &$1, &$3); }
+       |       compare_right T_IS_LE compare_right { zend_ini_compare(T_IS_LE, 
&$$, &$1, &$3); }
+       |       compare_right '<'     compare_right { zend_ini_compare('<',     
&$$, &$1, &$3); }
+       |       compare_right T_IS_EQ compare_right { zend_ini_compare(T_IS_EQ, 
&$$, &$1, &$3); }
+       |       compare_right T_IS_NE compare_right { zend_ini_compare(T_IS_NE, 
&$$, &$1, &$3); }
+       |       compare_right T_IS_IDENTICAL compare_right { 
zend_ini_compare(T_IS_IDENTICAL, &$$, &$1, &$3); }
+       |       compare_right T_IS_NOT_IDENTICAL compare_right { 
zend_ini_compare(T_IS_NOT_IDENTICAL, &$$, &$1, &$3); }
+;
+
+compare_right:
+               compare_value   { $$ = $1; }
+       |       '(' compare ')' { $$ = $2; }
+;
+
+compare_value:
+       |       TC_RAW                                                  { $$ = 
$1; }
+       |       TC_NUMBER                                               { $$ = 
$1; }
+       |       TC_STRING                                               { $$ = 
$1; }
+       |       BOOL_TRUE                                               { $$ = 
$1; }
+       |       BOOL_FALSE                                              { $$ = 
$1; }
+       |       TC_CONSTANT                                             { 
zend_ini_get_constant(&$$, &$1 TSRMLS_CC); }
+       |       '"' encapsed_list '"'                   { $$ = $2; }
+       |       cfg_var_ref                                             { $$ = 
$1; }
+       |       '(' expr ')'                                    { $$ = $2; }
+;
+               
 section_string_or_value:
                var_string_list                                 { $$ = $1; }
        |       /* empty */                                             { 
zend_ini_init_string(&$$); }
@@ -345,15 +466,18 @@ expr:
 ;
 
 cfg_var_ref:
-               TC_DOLLAR_CURLY TC_VARNAME '}'  { zend_ini_get_var(&$$, &$2 
TSRMLS_CC); free(Z_STRVAL($2)); }
+               TC_DOLLAR_CURLY TC_VARNAME '}' {
+                       zend_ini_get_var(&$$, &$2 TSRMLS_CC);
+                       free(Z_STRVAL($2));
+               }
 ;
 
 constant_string:
                TC_CONSTANT                                             { 
zend_ini_get_constant(&$$, &$1 TSRMLS_CC); }
-       |       TC_RAW                                                  { $$ = 
$1; /*printf("TC_RAW: '%s'\n", Z_STRVAL($1));*/ }
-       |       TC_NUMBER                                               { $$ = 
$1; /*printf("TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ }
-       |       TC_STRING                                               { $$ = 
$1; /*printf("TC_STRING: '%s'\n", Z_STRVAL($1));*/ }
-       |       TC_WHITESPACE                                   { $$ = $1; 
/*printf("TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ }
+       |       TC_RAW                                                  { $$ = 
$1; /*fprintf(stderr, "TC_RAW: '%s'\n", Z_STRVAL($1));*/ }
+       |       TC_NUMBER                                               { $$ = 
$1; /*fprintf(stderr, "TC_NUMBER: '%s'\n", Z_STRVAL($1));*/ }
+       |       TC_STRING                                               { $$ = 
$1; /*fprintf(stderr, "TC_STRING: '%s'\n", Z_STRVAL($1));*/ }
+       |       TC_WHITESPACE                                   { $$ = $1; 
/*fprintf(stderr, "TC_WHITESPACE: '%s'\n", Z_STRVAL($1));*/ }
 ;
 
 /*
Index: Zend/zend_ini_scanner.l
===================================================================
RCS file: /repository/ZendEngine2/zend_ini_scanner.l,v
retrieving revision 1.41.2.2.2.2.2.2
diff -u -p -d -r1.41.2.2.2.2.2.2 zend_ini_scanner.l
--- Zend/zend_ini_scanner.l     4 Feb 2008 20:45:20 -0000       1.41.2.2.2.2.2.2
+++ Zend/zend_ini_scanner.l     13 Feb 2008 16:20:28 -0000
@@ -15,6 +15,7 @@
    +----------------------------------------------------------------------+
    | Authors: Zeev Suraski <[EMAIL PROTECTED]>                                |
    |          Jani Taskinen <[EMAIL PROTECTED]>                                
|
+   |          Marcus Boerger <[EMAIL PROTECTED]>                              |
    +----------------------------------------------------------------------+
 */
 
@@ -68,11 +69,14 @@
 
 %}
 
+%x IGNORE
+%x IFDONE
 %x ST_DOUBLE_QUOTES
 %x ST_OFFSET
 %x ST_RAW
 %x ST_SECTION_RAW
 %x ST_SECTION_VALUE
+%x ST_CONDITION_VALUE
 %x ST_VALUE
 %x ST_VARNAME
 %option stack
@@ -122,6 +126,8 @@ ZEND_API zend_scanner_globals ini_scanne
        return type;                                 \
 }
 
+void zend_ini_set_ignore(ZEND_INI_CONDITIONAL state TSRMLS_DC);
+
 static char *ini_filename;
 
 /* {{{ init_ini_scanner()
@@ -129,6 +135,7 @@ static char *ini_filename;
 static void init_ini_scanner(TSRMLS_D)
 {
        SCNG(lineno) = 1;
+       SCNG(if_level) = 0;
        SCNG(scanner_mode) = ZEND_INI_SCANNER_NORMAL;
        SCNG(yy_start_stack_ptr) = 0;
        SCNG(yy_start_stack_depth) = 0;
@@ -199,6 +206,35 @@ int zend_ini_prepare_string_for_scanning
 }
 /* }}} */
 
+void zend_ini_error(int severity TSRMLS_DC, char *error) /* {{{ */
+{
+       if (!error) {
+               error = "Error";
+       }
+       if (CG(ini_parser_unbuffered_errors)) {
+#ifdef PHP_WIN32
+               if (ini_filename) {
+                       zend_spprintf(&error, 0, "%s at line %d of ini file 
%s.", error, SCNG(lineno), ini_filename);
+               } else {
+                       zend_spprintf(&error, 0, "%s in invalid configuration 
directive.", error);
+               }
+               MessageBox(NULL, error, "PHP Error", 
MB_OK|MB_TOPMOST|0x00200000L);
+               efree(error);
+#else
+               if (ini_filename) {
+                       fprintf(stderr, "PHP: %s at line %d of ini file %s.\n", 
error, SCNG(lineno), ini_filename);
+               } else {
+                       fprintf(stderr, "PHP: %s in invalid configuration 
directive.\n", error);
+               }
+#endif
+       } else if (ini_filename) {
+               zend_error(severity, "%s at line %d of ini file %s", error, 
SCNG(lineno), ini_filename);
+       } else {
+               zend_error(severity, "%s in invalid configuration directive", 
error);
+       }
+}
+/* }}} */
+
 /* {{{ zend_ini_close_file()
 */
 void zend_ini_close_file(zend_file_handle *fh TSRMLS_DC)
@@ -290,6 +326,7 @@ RAW_VALUE_CHARS [^=\n\r;]
 LITERAL_DOLLAR ("$"([^a-zA-Z0-9{]|("\\"{ANY_CHAR})))
 VALUE_CHARS         ([^$= \t\n\r;&|~()!"']|{LITERAL_DOLLAR})
 SECTION_VALUE_CHARS ([^$\n\r;"'\]\\]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR})
+CONDITION_VALUE_CHARS ([^$ \t\n\r;"'\]\\]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR})
 DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR})
 
 /* " */
@@ -312,7 +349,81 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        return TC_SECTION;
 }
 
-<ST_VALUE,ST_SECTION_VALUE,ST_OFFSET>"'"{SINGLE_QUOTED_CHARS}+"'" { /* Raw 
string */
+<IGNORE>"[ELSE]"{TABS_AND_SPACES}*{NEWLINE} { /* End of condition */
+       zend_ini_set_ignore(ZEND_INI_COND_READ TSRMLS_CC);
+       BEGIN(INITIAL);
+       SCNG(lineno)++;
+       return END_OF_LINE;
+}
+
+<IFDONE,INITIAL>"[ELSE]"{TABS_AND_SPACES}*{NEWLINE} { /* End of condition */
+       if (SCNG(scanner_mode) != ZEND_INI_SCANNER_RAW) {
+               if (!SCNG(if_level)) {
+                       zend_ini_error(E_WARNING TSRMLS_CC, "[ELSE] without 
[IF]");
+                       yyterminate();
+               }
+               zend_ini_set_ignore(ZEND_INI_COND_IGNORE TSRMLS_CC);
+               BEGIN(IFDONE);
+       } else {
+               BEGIN(INITIAL);
+       }
+       SCNG(lineno)++;
+       return END_OF_LINE;
+}
+
+<INITIAL,IGNORE,IFDONE>"[ENDIF]"{TABS_AND_SPACES}*{NEWLINE} { /* End of 
condition */
+       if (SCNG(scanner_mode) != ZEND_INI_SCANNER_RAW) {
+               if (!SCNG(if_level)--) {
+                       zend_ini_error(E_WARNING TSRMLS_CC, "[ENDIF] without 
[IF]");
+                       yyterminate();
+               }
+               yy_pop_state(TSRMLS_C);
+#if ZEND_DEBUG_CFG_PARSER
+               fprintf(stderr, "ENDIF\n");
+#endif
+       }
+       SCNG(lineno)++;
+       return END_OF_LINE;
+}
+
+<INITIAL,IGNORE>"[ELSEIF"{TABS_AND_SPACES}+ { /* Condition elseif */
+       if (SCNG(scanner_mode) != ZEND_INI_SCANNER_RAW) {
+               if (!SCNG(if_level)) {
+                       zend_error(E_WARNING, "[ELSEIF] without [IF]");
+                       yyterminate();
+               }
+               BEGIN(ST_CONDITION_VALUE);
+               return TC_CONDITION;
+       } else {
+               BEGIN(IFDONE);
+               return END_OF_LINE;
+       }
+}
+
+<IFDONE>"[ELSEIF"{TABS_AND_SPACES}+ { /* Condition elseif */
+       return END_OF_LINE;
+}
+
+<INITIAL>"[IF"{TABS_AND_SPACES}+ { /* Condition if */
+       if (SCNG(scanner_mode) != ZEND_INI_SCANNER_RAW) {
+               SCNG(if_level)++;
+               yy_push_state(ST_CONDITION_VALUE TSRMLS_CC);
+               return TC_CONDITION;
+       } else {
+               BEGIN(IFDONE);
+               return END_OF_LINE;
+       }
+}
+
+<IGNORE,IFDONE>[^\[]{NEWLINE} {
+       SCNG(lineno)++;
+       if (SCNG(scanner_mode) == ZEND_INI_SCANNER_RAW) {
+               BEGIN(INITIAL);
+       }
+       return END_OF_LINE;
+}
+
+<ST_VALUE,ST_SECTION_VALUE,ST_CONDITION_VALUE,ST_OFFSET>"'"{SINGLE_QUOTED_CHARS}+"'"
 { /* Raw string */
        /* Eat leading and trailing single quotes */
        if (yytext[0] == '\'' && yytext[yyleng - 1] == '\'') {
                yytext++;
@@ -328,6 +439,52 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        return ']';
 }
 
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"]"{TABS_AND_SPACES}*{NEWLINE}? { /* End 
of condition */
+       BEGIN(INITIAL);
+       SCNG(lineno)++;
+       return ']';
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"||"{TABS_AND_SPACES}* {
+       return T_L_OR;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"&&"{TABS_AND_SPACES}* {
+       return T_L_AND;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"=="{TABS_AND_SPACES}* {
+       return T_IS_EQ;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"!="{TABS_AND_SPACES}* {
+       return T_IS_NE;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"==="{TABS_AND_SPACES}* {
+       return T_IS_IDENTICAL;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"!=="{TABS_AND_SPACES}* {
+       return T_IS_NOT_IDENTICAL;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"<="{TABS_AND_SPACES}* {
+       return T_IS_LE;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*">="{TABS_AND_SPACES}* {
+       return T_IS_GE;
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*"("{TABS_AND_SPACES}* {
+       return '(';
+}
+
+<ST_CONDITION_VALUE>{TABS_AND_SPACES}*")"{TABS_AND_SPACES}* {
+       return ')';
+}
+
 <INITIAL>{LABEL}"["{TABS_AND_SPACES}* { /* Start of option with offset */
        /* Eat trailing whitespace and [ */
        EAT_TRAILING_WHITESPACE_EX('[');
@@ -343,7 +500,7 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        return ']';
 }
 
-<ST_DOUBLE_QUOTES,ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{DOLLAR_CURLY} { /* 
Variable start */
+<ST_DOUBLE_QUOTES,ST_SECTION_VALUE,ST_CONDITION_VALUE,ST_VALUE,ST_OFFSET>{DOLLAR_CURLY}
 { /* Variable start */
        yy_push_state(ST_VARNAME TSRMLS_CC);
        return TC_DOLLAR_CURLY;
 }
@@ -352,12 +509,7 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        RETURN_TOKEN(TC_VARNAME, yytext, yyleng);
 }
 
-<ST_VARNAME>"}" { /* Variable end */
-       yy_pop_state(TSRMLS_C);
-       return '}';
-}
-
-<INITIAL,ST_VALUE>("true"|"on"|"yes"){TABS_AND_SPACES}* { /* TRUE value (when 
used outside option value/offset this causes parse error!) */
+<INITIAL,ST_CONDITION_VALUE,ST_VALUE>("true"|"on"|"yes"){TABS_AND_SPACES}* { 
/* TRUE value (when used outside option value/offset this causes parse error!) 
*/
        RETURN_TOKEN(BOOL_TRUE, "1", 1);
 }
 
@@ -365,6 +517,10 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        RETURN_TOKEN(BOOL_FALSE, "", 0);
 }
 
+<ST_CONDITION_VALUE>("false"|"off"|"no"|"none"|"null"){TABS_AND_SPACES}* { /* 
FALSE value (when used in conditions we want '0' rather than '')*/
+       RETURN_TOKEN(BOOL_FALSE, "0", 1);
+}
+
 <INITIAL>{LABEL} { /* Get option name */
        RETURN_TOKEN(TC_LABEL, yytext, yyleng);
 }
@@ -398,11 +554,11 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        return END_OF_LINE;
 }
 
-<ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{CONSTANT} { /* Get constant option value 
*/
+<ST_SECTION_VALUE,ST_CONDITION_VALUE,ST_VALUE,ST_OFFSET>{CONSTANT} { /* Get 
constant option value */
        RETURN_TOKEN(TC_CONSTANT, yytext, yyleng);
 }
 
-<ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{NUMBER} { /* Get number option value as 
string */
+<ST_SECTION_VALUE,ST_CONDITION_VALUE,ST_VALUE,ST_OFFSET>{NUMBER} { /* Get 
number option value as string */
        RETURN_TOKEN(TC_NUMBER, yytext, yyleng);
 }
 
@@ -428,7 +584,7 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        RETURN_TOKEN(TC_STRING, yytext, yyleng);
 }
 
-<ST_SECTION_VALUE,ST_VALUE,ST_OFFSET>{TABS_AND_SPACES}*["] { /* Double quoted 
'"' string start */
+<ST_SECTION_VALUE,ST_CONDITION_VALUE,ST_VALUE,ST_OFFSET>{TABS_AND_SPACES}*["] 
{ /* Double quoted '"' string start */
        yy_push_state(ST_DOUBLE_QUOTES TSRMLS_CC);
        return '"';
 }
@@ -473,37 +629,46 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
                switch (YYSTATE) {
                case INITIAL:
                        break;
+               
+               case IGNORE:
+               case IFDONE:
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated [IF] in 
ini");
+                       break;
 
                case ST_DOUBLE_QUOTES:
-                       fprintf(stderr, "ERROR: Unterminated ini option value 
double quotes\n");
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated ini 
option value double quotes");
                        break;
 
                case ST_OFFSET:
-                       fprintf(stderr, "ERROR: Unterminated ini option 
offset\n");
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated ini 
option offset");
                        break;
 
                case ST_RAW:
-                       fprintf(stderr, "ERROR: Unterminated raw ini option 
value\n");
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated raw ini 
option value");
                        break;
 
                case ST_SECTION_RAW:
-                       fprintf(stderr, "ERROR: Unterminated raw ini section 
value\n");
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated raw ini 
section value");
                        break;
 
                case ST_SECTION_VALUE:
-                       fprintf(stderr, "ERROR: Unterminated ini section 
value\n");
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated ini 
section value");
+                       break;
+
+               case ST_CONDITION_VALUE:
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated ini 
condition value");
                        break;
 
                case ST_VALUE:
-                       fprintf(stderr, "ERROR: Unterminated ini option 
value\n");
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated ini 
option value");
                        break;
 
                case ST_VARNAME:
-                       fprintf(stderr, "ERROR: Unterminated ini variable\n");
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unterminated ini 
variable");
                        break;
 
                default:
-                       fprintf(stderr, "BUG: Unknown state (%d)\n", YYSTATE);
+                       zend_ini_error(E_ERROR TSRMLS_CC, "Unknown state"); /* 
(%d)\n", YYSTATE); */
                        break;
                }
                yy_pop_state(TSRMLS_C);
@@ -511,3 +676,30 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
 #endif
        yyterminate();
 }
+
+%%
+
+void zend_ini_set_ignore(ZEND_INI_CONDITIONAL state TSRMLS_DC) /* {{{ */
+{
+       switch(state) {
+               case ZEND_INI_COND_READ:
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "READ\n");
+#endif
+                       BEGIN(INITIAL);
+                       break;
+               case ZEND_INI_COND_IGNORE:
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "IGNORE\n");
+#endif
+                       BEGIN(IGNORE);
+                       break;
+               case ZEND_INI_COND_DONE:
+#if ZEND_DEBUG_CFG_PARSER
+                       fprintf(stderr, "IF DONE\n");
+#endif
+                       BEGIN(IFDONE);
+                       break;
+       }
+}
+/* }}} */
-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to