%{ /* +----------------------------------------------------------------------+ | PHP version 4.0 | +----------------------------------------------------------------------+ | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 2.02 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available at through the world-wide-web at | | http://www.php.net/license/2_02.txt. | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ | Authors: Zeev Suraski | +----------------------------------------------------------------------+ */ /* $Id$ */ #define DEBUG_CFG_PARSER 0 #include "php.h" #include "php_globals.h" #include "php_ini.h" #include "ext/standard/dl.h" #include "ext/standard/file.h" #include "ext/standard/php_browscap.h" #include "zend_extensions.h" #if WIN32 #define WIN32_LEAN_AND_MEAN #include #include #include "win32/wfile.h" #endif #define YYSTYPE zval #define PARSING_MODE_CFG 0 #define PARSING_MODE_BROWSCAP 1 #define PARSING_MODE_STANDALONE 2 static HashTable configuration_hash; extern HashTable browser_hash; PHPAPI extern char *php_ini_path; static HashTable *active_hash_table; static zval *current_section; static char *currently_parsed_filename; static int parsing_mode; zval yylval; extern int cfglex(zval *cfglval); extern FILE *cfgin; extern int cfglineno; extern void init_cfg_scanner(void); zval *cfg_get_entry(char *name, uint name_length) { zval *tmp; if (zend_hash_find(&configuration_hash, name, name_length, (void **) &tmp)==SUCCESS) { return tmp; } else { return NULL; } } PHPAPI int cfg_get_long(char *varname,long *result) { zval *tmp,var; if (zend_hash_find(&configuration_hash,varname,strlen(varname)+1,(void **) &tmp)==FAILURE) { *result=(long)NULL; return FAILURE; } var = *tmp; zval_copy_ctor(&var); convert_to_long(&var); *result = var.value.lval; return SUCCESS; } PHPAPI int cfg_get_double(char *varname,double *result) { zval *tmp,var; if (zend_hash_find(&configuration_hash,varname,strlen(varname)+1,(void **) &tmp)==FAILURE) { *result=(double)0; return FAILURE; } var = *tmp; zval_copy_ctor(&var); convert_to_double(&var); *result = var.value.dval; return SUCCESS; } PHPAPI int cfg_get_string(char *varname, char **result) { zval *tmp; if (zend_hash_find(&configuration_hash,varname,strlen(varname)+1,(void **) &tmp)==FAILURE) { *result=NULL; return FAILURE; } *result = tmp->value.str.val; return SUCCESS; } static void yyerror(char *str) { fprintf(stderr,"PHP: Error parsing %s on line %d\n",currently_parsed_filename,cfglineno); } static void pvalue_config_destructor(zval *pvalue) { if (pvalue->type == IS_STRING && pvalue->value.str.val != empty_string) { free(pvalue->value.str.val); } } static void pvalue_browscap_destructor(zval *pvalue) { if (pvalue->type == IS_OBJECT || pvalue->type == IS_ARRAY) { zend_hash_destroy(pvalue->value.obj.properties); free(pvalue->value.obj.properties); } } int php_init_config(void) { PLS_FETCH(); if (zend_hash_init(&configuration_hash, 0, NULL, (dtor_func_t) pvalue_config_destructor, 1)==FAILURE) { return FAILURE; } #if USE_CONFIG_FILE { char *env_location,*default_location,*php_ini_search_path; int safe_mode_state = PG(safe_mode); char *open_basedir = PG(open_basedir); char *opened_path; int free_default_location=0; env_location = getenv("PHPRC"); if (!env_location) { env_location=""; } #ifdef PHP_WIN32 { if (php_ini_path) { default_location = php_ini_path; } else { default_location = (char *) malloc(512); if (!GetWindowsDirectory(default_location,255)) { default_location[0]=0; } free_default_location=1; } } #else if (!php_ini_path) { default_location = CONFIGURATION_FILE_PATH; } else { default_location = php_ini_path; } #endif /* build a path */ php_ini_search_path = (char *) malloc(sizeof(".")+strlen(env_location)+strlen(default_location)+2+1); if (!php_ini_path) { #ifdef PHP_WIN32 sprintf(php_ini_search_path,".;%s;%s",env_location,default_location); #else sprintf(php_ini_search_path,".:%s:%s",env_location,default_location); #endif } else { /* if path was set via -c flag, only look there */ strcpy(php_ini_search_path,default_location); } PG(safe_mode) = 0; PG(open_basedir) = NULL; cfgin = php_fopen_with_path("php.ini","r",php_ini_search_path,&opened_path); free(php_ini_search_path); if (free_default_location) { free(default_location); } PG(safe_mode) = safe_mode_state; PG(open_basedir) = open_basedir; if (!cfgin) { return SUCCESS; /* having no configuration file is ok */ } if (opened_path) { zval tmp; tmp.value.str.val = opened_path; tmp.value.str.len = strlen(opened_path); tmp.type = IS_STRING; zend_hash_update(&configuration_hash,"cfg_file_path",sizeof("cfg_file_path"),(void *) &tmp,sizeof(zval),NULL); #if DEBUG_CFG_PARSER php_printf("INI file opened at '%s'\n",opened_path); #endif } init_cfg_scanner(); active_hash_table = &configuration_hash; parsing_mode = PARSING_MODE_CFG; currently_parsed_filename = "php.ini"; yyparse(); fclose(cfgin); } #endif return SUCCESS; } PHP_MINIT_FUNCTION(browscap) { char *browscap = INI_STR("browscap"); if (browscap) { if (zend_hash_init(&browser_hash, 0, NULL, (dtor_func_t) pvalue_browscap_destructor, 1)==FAILURE) { return FAILURE; } cfgin = V_FOPEN(browscap, "r"); if (!cfgin) { php_error(E_WARNING,"Cannot open '%s' for reading", browscap); return FAILURE; } init_cfg_scanner(); active_hash_table = &browser_hash; parsing_mode = PARSING_MODE_BROWSCAP; currently_parsed_filename = browscap; yyparse(); fclose(cfgin); } return SUCCESS; } PHP_FUNCTION(parse_ini_file) { #ifdef ZTS php_error(E_WARNING, "parse_ini_file() is not supported in multithreaded PHP"); RETURN_FALSE; #else zval **filename; if (ARG_COUNT(ht)!=1 || zend_get_parameters_ex(1, &filename)==FAILURE) { WRONG_PARAM_COUNT; } convert_to_string_ex(filename); cfgin = V_FOPEN((*filename)->value.str.val, "r"); if (!cfgin) { php_error(E_WARNING,"Cannot open '%s' for reading", (*filename)->value.str.val); return; } array_init(return_value); init_cfg_scanner(); active_hash_table = return_value->value.ht; parsing_mode = PARSING_MODE_STANDALONE; currently_parsed_filename = (*filename)->value.str.val; yyparse(); fclose(cfgin); #endif } int php_shutdown_config(void) { zend_hash_destroy(&configuration_hash); return SUCCESS; } PHP_MSHUTDOWN_FUNCTION(browscap) { if (INI_STR("browscap")) { zend_hash_destroy(&browser_hash); } return SUCCESS; } static void convert_browscap_pattern(zval *pattern) { register int i,j; char *t; for (i=0; ivalue.str.len; i++) { if (pattern->value.str.val[i]=='*' || pattern->value.str.val[i]=='?') { break; } } if (i==pattern->value.str.len) { /* no wildcards */ pattern->value.str.val = zend_strndup(pattern->value.str.val, pattern->value.str.len); } t = (char *) malloc(pattern->value.str.len*2); for (i=0,j=0; ivalue.str.len; i++,j++) { switch (pattern->value.str.val[i]) { case '?': t[j] = '.'; break; case '*': t[j++] = '.'; t[j] = '*'; break; case '.': t[j++] = '\\'; t[j] = '.'; break; default: t[j] = pattern->value.str.val[i]; break; } } t[j]=0; pattern->value.str.val = t; pattern->value.str.len = j; } void do_cfg_op(char type, zval *result, zval *op1, zval *op2) { int i_result; int i_op1, i_op2; char str_result[MAX_LENGTH_OF_LONG]; i_op1 = atoi(op1->value.str.val); free(op1->value.str.val); if (op2) { i_op2 = atoi(op2->value.str.val); free(op2->value.str.val); } else { i_op2 = 0; } switch (type) { case '|': i_result = i_op1 | i_op2; break; case '&': i_result = i_op1 & i_op2; break; case '~': i_result = ~i_op1; break; default: i_result = 0; break; } result->value.str.len = zend_sprintf(str_result, "%d", i_result); result->value.str.val = (char *) malloc(result->value.str.len+1); memcpy(result->value.str.val, str_result, result->value.str.len); result->value.str.val[result->value.str.len] = 0; result->type = IS_STRING; } void do_cfg_get_constant(zval *result, zval *name) { zval z_constant; if (zend_get_constant(name->value.str.val, name->value.str.len, &z_constant)) { /* z_constant is emalloc()'d */ convert_to_string(&z_constant); result->value.str.val = zend_strndup(z_constant.value.str.val, z_constant.value.str.len); result->value.str.len = z_constant.value.str.len; result->type = z_constant.type; zval_dtor(&z_constant); free(name->value.str.val); } else { *result = *name; } } %} %pure_parser %token TC_STRING %token TC_ENCAPSULATED_STRING %token SECTION %token CFG_TRUE %token CFG_FALSE %token EXTENSION %token T_ZEND_EXTENSION %token T_ZEND_EXTENSION_TS %token T_ZEND_EXTENSION_DEBUG %token T_ZEND_EXTENSION_DEBUG_TS %left '|' '&' %right '~' %% statement_list: statement_list statement | /* empty */ ; statement: TC_STRING '=' string_or_value { #if DEBUG_CFG_PARSER printf("'%s' = '%s'\n",$1.value.str.val,$3.value.str.val); #endif $3.type = IS_STRING; switch (parsing_mode) { case PARSING_MODE_CFG: zend_hash_update(active_hash_table, $1.value.str.val, $1.value.str.len+1, &$3, sizeof(zval), NULL); if (active_hash_table == &configuration_hash) { php_alter_ini_entry($1.value.str.val, $1.value.str.len+1, $3.value.str.val, $3.value.str.len+1, PHP_INI_SYSTEM, PHP_INI_STAGE_STARTUP); } break; case PARSING_MODE_BROWSCAP: if (current_section) { zval *new_property; new_property = (zval *) malloc(sizeof(zval)); INIT_PZVAL(new_property); new_property->value.str.val = $3.value.str.val; new_property->value.str.len = $3.value.str.len; new_property->type = IS_STRING; zend_str_tolower(new_property->value.str.val, new_property->value.str.len); zend_hash_update(current_section->value.obj.properties, $1.value.str.val, $1.value.str.len+1, &new_property, sizeof(zval *), NULL); } break; case PARSING_MODE_STANDALONE: { zval *entry; MAKE_STD_ZVAL(entry); entry->value.str.val = estrndup($3.value.str.val, $3.value.str.len); entry->value.str.len = $3.value.str.len; entry->type = IS_STRING; zend_hash_update(active_hash_table, $1.value.str.val, $1.value.str.len+1, &entry, sizeof(zval *), NULL); pvalue_config_destructor(&$3); } break; } free($1.value.str.val); } | TC_STRING { free($1.value.str.val); } | EXTENSION '=' cfg_string { if (parsing_mode==PARSING_MODE_CFG) { zval dummy; #if DEBUG_CFG_PARSER printf("Loading '%s'\n",$3.value.str.val); #endif php_dl(&$3,MODULE_PERSISTENT,&dummy); } } | T_ZEND_EXTENSION '=' cfg_string { if (parsing_mode==PARSING_MODE_CFG) { #if !defined(ZTS) && !ZEND_DEBUG zend_load_extension($3.value.str.val); #endif free($3.value.str.val); } } | T_ZEND_EXTENSION_TS '=' cfg_string { if (parsing_mode==PARSING_MODE_CFG) { #if defined(ZTS) && !ZEND_DEBUG zend_load_extension($3.value.str.val); #endif free($3.value.str.val); } } | T_ZEND_EXTENSION_DEBUG '=' cfg_string { if (parsing_mode==PARSING_MODE_CFG) { #if !defined(ZTS) && ZEND_DEBUG zend_load_extension($3.value.str.val); #endif free($3.value.str.val); } } | T_ZEND_EXTENSION_DEBUG_TS '=' cfg_string { if (parsing_mode==PARSING_MODE_CFG) { #if defined(ZTS) && ZEND_DEBUG zend_load_extension($3.value.str.val); #endif free($3.value.str.val); } } | SECTION { if (parsing_mode==PARSING_MODE_BROWSCAP) { zval *processed; /*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len+1);*/ current_section = (zval *) malloc(sizeof(zval)); INIT_PZVAL(current_section); processed = (zval *) malloc(sizeof(zval)); INIT_PZVAL(processed); current_section->value.obj.ce = &zend_standard_class_def; current_section->value.obj.properties = (HashTable *) malloc(sizeof(HashTable)); current_section->type = IS_OBJECT; zend_hash_init(current_section->value.obj.properties, 0, NULL, (dtor_func_t) pvalue_config_destructor, 1); zend_hash_update(active_hash_table, $1.value.str.val, $1.value.str.len+1, (void *) ¤t_section, sizeof(zval *), NULL); processed->value.str.val = $1.value.str.val; processed->value.str.len = $1.value.str.len; processed->type = IS_STRING; convert_browscap_pattern(processed); zend_hash_update(current_section->value.obj.properties, "browser_name_pattern", sizeof("browser_name_pattern"), (void *) &processed, sizeof(zval *), NULL); } free($1.value.str.val); } | '\n' ; cfg_string: TC_STRING { $$ = $1; } | TC_ENCAPSULATED_STRING { $$ = $1; } ; string_or_value: expr { $$ = $1; } | TC_ENCAPSULATED_STRING { $$ = $1; } | CFG_TRUE { $$ = $1; } | CFG_FALSE { $$ = $1; } | '\n' { $$.value.str.val = strdup(""); $$.value.str.len=0; $$.type = IS_STRING; } ; expr: constant_string { $$ = $1; } | expr '|' expr { do_cfg_op('|', &$$, &$1, &$3); } | expr '&' expr { do_cfg_op('&', &$$, &$1, &$3); } | '~' expr { do_cfg_op('~', &$$, &$2, NULL); } | '(' expr ')' { $$ = $2; } ; constant_string: TC_STRING { do_cfg_get_constant(&$$, &$1); } ; /* * Local variables: * tab-width: 4 * c-basic-offset: 4 * End: */