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
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      9 Feb 2008 14:31:53 -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,43 @@ static void php_load_zend_extension_cb(v
 }
 /* }}} */
 
+static void php_ini_dump_config(TSRMLS_D) /* {{{ */
+{
+#if HELLY_0
+       zval tmp;
+       array_init(&tmp);
+       zend_hash_apply_with_arguments(&configuration_hash, (apply_func_args_t) 
php_add_config_entry_cb, 1, &tmp TSRMLS_CC);
+       zend_print_hash(Z_ARRVAL(tmp), 0, 0 TSRMLS_CC);
+       zval_dtor(&tmp);
+#endif 
+} /* }}} */
+
+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 +385,20 @@ int php_init_config(TSRMLS_D)
                sapi_module.ini_defaults(&configuration_hash);
        }
 
+       php_ini_add_config_long("php.version", sizeof("php.version"), 
PHP_VERSION_ID TSRMLS_CC);
+       php_ini_add_config_string("php.sapi", sizeof("php.sapi"), 
sapi_module.name TSRMLS_CC);
+#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
+       php_ini_dump_config(TSRMLS_C);
+
        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 +610,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.c
===================================================================
RCS file: /repository/ZendEngine2/zend.c,v
retrieving revision 1.308.2.12.2.35.2.7
diff -u -p -d -r1.308.2.12.2.35.2.7 zend.c
--- Zend/zend.c 28 Jan 2008 20:34:02 -0000      1.308.2.12.2.35.2.7
+++ Zend/zend.c 9 Feb 2008 14:31:54 -0000
@@ -116,7 +116,7 @@ static uint zend_version_info_length;
 #define ZEND_CORE_VERSION_INFO "Zend Engine v" ZEND_VERSION ", Copyright (c) 
1998-2008 Zend Technologies\n"
 #define PRINT_ZVAL_INDENT 4
 
-static void print_hash(HashTable *ht, int indent, zend_bool is_object 
TSRMLS_DC) /* {{{ */
+ZEND_API void zend_print_hash(HashTable *ht, int indent, zend_bool is_object 
TSRMLS_DC) /* {{{ */
 {
        zval **tmp;
        char *string_key;
@@ -378,7 +378,7 @@ ZEND_API void zend_print_zval_r_ex(zend_
                                Z_ARRVAL_P(expr)->nApplyCount--;
                                return;
                        }
-                       print_hash(Z_ARRVAL_P(expr), indent, 0 TSRMLS_CC);
+                       zend_print_hash(Z_ARRVAL_P(expr), indent, 0 TSRMLS_CC);
                        Z_ARRVAL_P(expr)->nApplyCount--;
                        break;
                case IS_OBJECT:
@@ -407,7 +407,7 @@ ZEND_API void zend_print_zval_r_ex(zend_
                                        properties->nApplyCount--;
                                        return;
                                }
-                               print_hash(properties, indent, 1 TSRMLS_CC);
+                               zend_print_hash(properties, indent, 1 
TSRMLS_CC);
                                properties->nApplyCount--;
                                if (is_temp) {
                                        zend_hash_destroy(properties);
Index: Zend/zend.h
===================================================================
RCS file: /repository/ZendEngine2/zend.h,v
retrieving revision 1.293.2.11.2.9.2.16
diff -u -p -d -r1.293.2.11.2.9.2.16 zend.h
--- Zend/zend.h 22 Jan 2008 09:27:46 -0000      1.293.2.11.2.9.2.16
+++ Zend/zend.h 9 Feb 2008 14:31:54 -0000
@@ -537,6 +537,7 @@ END_EXTERN_C()
 
 BEGIN_EXTERN_C()
 ZEND_API char *get_zend_version(void);
+ZEND_API void zend_print_hash(HashTable *ht, int indent, zend_bool is_object 
TSRMLS_DC);
 ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int 
*use_copy);
 ZEND_API int zend_print_zval(zval *expr, int indent);
 ZEND_API int zend_print_zval_ex(zend_write_func_t write_func, zval *expr, int 
indent);
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 9 Feb 2008 14:31:54 -0000
@@ -52,6 +52,8 @@ END_EXTERN_C()
 #endif
 
 #define SYMTABLE_CACHE_SIZE 32
+#define ZEND_DEBUG_CFG_PARSER 1
+
 
 
 #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      9 Feb 2008 14:31:54 -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);
 }
 /* }}} */
 
@@ -244,12 +322,42 @@ ZEND_API int zend_parse_ini_string(char 
 }
 /* }}} */
 
+void zend_ini_ternary(zval *result, zval *condition, zval *first, zval *second 
TSRMLS_CC) /* {{{ */
+{
+       zval tmp;
+       int val;
+       zend_ini_get_var(&tmp, condition TSRMLS_CC);
+       free(Z_STRVAL_P(condition));
+       val = atoi(Z_STRVAL(tmp));
+       free(Z_STRVAL(tmp));
+       if (val) {
+               if (first) {
+                       *result = *first;
+               } else {
+                       ZVAL_STRINGL(result, "", 0, 1);
+               }
+               if (second) {
+                       free(Z_STRVAL_P(second));
+               }
+       } else {
+               if (second) {
+                       *result = *second;
+               } else {
+                       ZVAL_STRINGL(result, "", 0, 1);
+               }
+               if (first) {
+                       free(Z_STRVAL_P(first));
+               }
+       }
+} /* }}} */
+
 %}
 
 %expect 0
 %pure_parser
 
 %token TC_SECTION
+%token TC_CONDITION
 %token TC_RAW
 %token TC_CONSTANT
 %token TC_NUMBER
@@ -263,7 +371,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 +388,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 +495,30 @@ 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));
+               }
+       |       TC_DOLLAR_CURLY TC_VARNAME '?' TC_RAW ':' TC_RAW '}' {
+                       zend_ini_ternary(&$$, &$2, &$4, &$6 TSRMLS_CC);
+               }
+       |       TC_DOLLAR_CURLY TC_VARNAME '?' ':' TC_RAW '}' {
+                       zend_ini_ternary(&$$, &$2, NULL, &$5 TSRMLS_CC);
+               }
+       |       TC_DOLLAR_CURLY TC_VARNAME '?' TC_RAW ':' '}' {
+                       zend_ini_ternary(&$$, &$2, &$4, NULL TSRMLS_CC);
+               }
+       |       TC_DOLLAR_CURLY TC_VARNAME '?' ':' '}' {
+                       zend_ini_ternary(&$$, &$2, NULL, NULL TSRMLS_CC);
+               }
 ;
 
 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     9 Feb 2008 14:31:54 -0000
@@ -15,6 +15,7 @@
    +----------------------------------------------------------------------+
    | Authors: Zeev Suraski <[EMAIL PROTECTED]>                                |
    |          Jani Taskinen <[EMAIL PROTECTED]>                                
|
+   |          Marcus Boerger <[EMAIL PROTECTED]>                              |
    +----------------------------------------------------------------------+
 */
 
@@ -68,13 +69,18 @@
 
 %}
 
+%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
+%x ST_TERNARY_FIRST
+%x ST_TERNARY_SECOND
 %option stack
 
 %{
@@ -122,6 +128,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 +137,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 +208,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,7 +328,9 @@ 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})
+TERNARY_VALUE_CHARS ([^$"\\:?{}\r\n]|("\\"{ANY_CHAR})|{LITERAL_DOLLAR})
 
 /* " */
 
@@ -312,7 +352,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>"[ELIF"{TABS_AND_SPACES}+ { /* Condition elif */
+       if (SCNG(scanner_mode) != ZEND_INI_SCANNER_RAW) {
+               if (!SCNG(if_level)) {
+                       zend_error(E_WARNING, "[ELIF] without [IF]");
+                       yyterminate();
+               }
+               BEGIN(ST_CONDITION_VALUE);
+               return TC_CONDITION;
+       } else {
+               BEGIN(IFDONE);
+               return END_OF_LINE;
+       }
+}
+
+<IFDONE>"[ELIF"{TABS_AND_SPACES}+ { /* Condition elif */
+       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 +442,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 +503,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 +512,26 @@ DOUBLE_QUOTES_CHARS ([^$"\\]|("\\"{ANY_C
        RETURN_TOKEN(TC_VARNAME, yytext, yyleng);
 }
 
-<ST_VARNAME>"}" { /* Variable end */
+<ST_VARNAME>"?" { /* Variable ternary first value */
+       BEGIN(ST_TERNARY_FIRST);
+       return '?';
+}
+
+<ST_TERNARY_FIRST>":" { /* Variable ternary second value */
+       BEGIN(ST_TERNARY_SECOND);
+       return':';
+}
+
+<ST_TERNARY_FIRST,ST_TERNARY_SECOND>{TERNARY_VALUE_CHARS}* { /* ternary values 
*/
+       RETURN_TOKEN(TC_RAW, yytext, yyleng);
+}
+
+<ST_VARNAME,ST_TERNARY_SECOND>"}" { /* 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 +539,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 +576,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 +606,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 +651,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 +698,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