1999-04-17 00:37:12 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2004-01-08 08:18:22 +00:00
| PHP Version 5 |
1999-04-17 00:37:12 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2007-12-31 07:17:19 +00:00
| Copyright ( c ) 1997 - 2008 The PHP Group |
1999-04-17 00:37:12 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 12:51:34 +00:00
| This source file is subject to version 3.01 of the PHP license , |
1999-07-16 13:13:16 +00:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-10 20:04:29 +00:00
| available through the world - wide - web at the following url : |
2006-01-01 12:51:34 +00:00
| http : //www.php.net/license/3_01.txt |
1999-07-16 13:13:16 +00:00
| 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 . |
1999-04-17 00:37:12 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2002-02-28 08:29:35 +00:00
| Author : Zeev Suraski < zeev @ zend . com > |
1999-04-17 00:37:12 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2000-07-24 01:40:02 +00:00
/* $Id$ */
1999-04-17 00:37:12 +00:00
# include "php.h"
1999-12-04 19:19:57 +00:00
# include "php_browscap.h"
1999-04-17 00:37:12 +00:00
# include "php_ini.h"
2004-03-15 21:26:39 +00:00
# include "php_string.h"
2007-11-05 12:27:42 +00:00
# include "ext/ereg/php_regex.h"
2007-09-28 02:05:10 +00:00
# include "zend_ini_scanner.h"
1999-04-17 00:37:12 +00:00
# include "zend_globals.h"
2000-10-29 23:10:22 +00:00
static HashTable browser_hash ;
static zval * current_section ;
2007-09-28 02:05:10 +00:00
static char * current_section_name ;
1999-04-17 00:37:12 +00:00
2000-07-25 08:09:00 +00:00
# define DEFAULT_SECTION_NAME "Default Browser Capability Settings"
2000-07-23 11:11:35 +00:00
2001-07-29 08:40:41 +00:00
/* OBJECTS_FIXME: This whole extension needs going through. The use of objects looks pretty broken here */
2000-10-29 23:10:22 +00:00
2007-11-05 12:27:42 +00:00
static void browscap_entry_dtor ( zval * * zvalue ) /* { { { */
2000-10-29 23:10:22 +00:00
{
2005-12-05 22:54:01 +00:00
if ( Z_TYPE_PP ( zvalue ) = = IS_ARRAY ) {
zend_hash_destroy ( Z_ARRVAL_PP ( zvalue ) ) ;
free ( Z_ARRVAL_PP ( zvalue ) ) ;
} else if ( Z_TYPE_PP ( zvalue ) = = IS_STRING ) {
if ( Z_STRVAL_PP ( zvalue ) ) {
free ( Z_STRVAL_PP ( zvalue ) ) ;
2005-01-25 21:33:58 +00:00
}
2000-10-29 23:10:22 +00:00
}
2005-12-05 22:54:01 +00:00
free ( * zvalue ) ;
2000-10-29 23:10:22 +00:00
}
2007-11-05 12:27:42 +00:00
/* }}} */
2000-10-29 23:10:22 +00:00
2007-11-05 12:27:42 +00:00
static void convert_browscap_pattern ( zval * pattern ) /* { { { */
2000-10-29 23:10:22 +00:00
{
2001-08-11 17:03:37 +00:00
register int i , j ;
2000-10-29 23:10:22 +00:00
char * t ;
2004-03-15 21:26:39 +00:00
php_strtolower ( Z_STRVAL_P ( pattern ) , Z_STRLEN_P ( pattern ) ) ;
2003-03-14 17:54:38 +00:00
2007-03-07 00:52:40 +00:00
t = ( char * ) safe_pemalloc ( Z_STRLEN_P ( pattern ) , 2 , 3 , 1 ) ;
2004-03-15 21:26:39 +00:00
t [ 0 ] = ' ^ ' ;
for ( i = 0 , j = 1 ; i < Z_STRLEN_P ( pattern ) ; i + + , j + + ) {
2001-09-25 21:58:48 +00:00
switch ( Z_STRVAL_P ( pattern ) [ i ] ) {
2000-10-29 23:10:22 +00:00
case ' ? ' :
t [ j ] = ' . ' ;
break ;
case ' * ' :
t [ j + + ] = ' . ' ;
t [ j ] = ' * ' ;
break ;
case ' . ' :
t [ j + + ] = ' \\ ' ;
t [ j ] = ' . ' ;
break ;
default :
2001-09-25 21:58:48 +00:00
t [ j ] = Z_STRVAL_P ( pattern ) [ i ] ;
2000-10-29 23:10:22 +00:00
break ;
}
}
2003-04-28 21:49:47 +00:00
2004-03-15 21:26:39 +00:00
t [ j + + ] = ' $ ' ;
2003-04-28 21:49:47 +00:00
2000-10-29 23:10:22 +00:00
t [ j ] = 0 ;
2001-09-25 21:58:48 +00:00
Z_STRVAL_P ( pattern ) = t ;
Z_STRLEN_P ( pattern ) = j ;
2000-10-29 23:10:22 +00:00
}
2001-06-06 13:06:12 +00:00
/* }}} */
2000-10-29 23:10:22 +00:00
2007-11-05 12:27:42 +00:00
static void php_browscap_parser_cb ( zval * arg1 , zval * arg2 , zval * arg3 , int callback_type , void * arg TSRMLS_DC ) /* { { { */
2000-10-29 23:10:22 +00:00
{
2002-10-14 18:13:18 +00:00
if ( ! arg1 ) {
return ;
}
2000-10-29 23:10:22 +00:00
switch ( callback_type ) {
case ZEND_INI_PARSER_ENTRY :
2002-10-14 18:13:18 +00:00
if ( current_section & & arg2 ) {
2000-10-29 23:10:22 +00:00
zval * new_property ;
char * new_key ;
2007-09-28 02:05:10 +00:00
/* parent entry can not be same as current section -> causes infinite loop! */
if ( ! strcasecmp ( Z_STRVAL_P ( arg1 ) , " parent " ) & &
! strcasecmp ( current_section_name , Z_STRVAL_P ( arg2 ) )
) {
zend_error ( E_CORE_ERROR , " Invalid browscap ini file: 'Parent' value can not be same as the section name: %s (in file %s) " , current_section_name , INI_STR ( " browscap " ) ) ;
return ;
}
2007-03-07 00:52:40 +00:00
new_property = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2000-10-29 23:10:22 +00:00
INIT_PZVAL ( new_property ) ;
2001-09-25 21:58:48 +00:00
Z_TYPE_P ( new_property ) = IS_STRING ;
2003-04-28 21:49:47 +00:00
2007-09-28 02:05:10 +00:00
/* Set proper value for true/false settings */
if ( ( Z_STRLEN_P ( arg2 ) = = 2 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " on " , sizeof ( " on " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 3 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " yes " , sizeof ( " yes " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 4 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " true " , sizeof ( " true " ) - 1 ) )
) {
Z_STRVAL_P ( new_property ) = zend_strndup ( " 1 " , 1 ) ;
Z_STRLEN_P ( new_property ) = 1 ;
} else if (
( Z_STRLEN_P ( arg2 ) = = 2 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " no " , sizeof ( " no " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 3 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " off " , sizeof ( " off " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 4 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " none " , sizeof ( " none " ) - 1 ) ) | |
( Z_STRLEN_P ( arg2 ) = = 5 & & ! strncasecmp ( Z_STRVAL_P ( arg2 ) , " false " , sizeof ( " false " ) - 1 ) )
) {
Z_STRVAL_P ( new_property ) = zend_strndup ( " " , 0 ) ;
Z_STRLEN_P ( new_property ) = 0 ;
} else { /* Other than true/false setting */
Z_STRVAL_P ( new_property ) = zend_strndup ( Z_STRVAL_P ( arg2 ) , Z_STRLEN_P ( arg2 ) ) ;
Z_STRLEN_P ( new_property ) = Z_STRLEN_P ( arg2 ) ;
}
2000-10-29 23:10:22 +00:00
new_key = zend_strndup ( Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) ) ;
zend_str_tolower ( new_key , Z_STRLEN_P ( arg1 ) ) ;
2007-11-05 12:27:42 +00:00
zend_hash_update ( Z_ARRVAL_P ( current_section ) , new_key , Z_STRLEN_P ( arg1 ) + 1 , & new_property , sizeof ( zval * ) , NULL ) ;
2000-10-29 23:10:22 +00:00
free ( new_key ) ;
}
break ;
case ZEND_INI_PARSER_SECTION : {
zval * processed ;
2003-03-14 17:54:38 +00:00
zval * unprocessed ;
2002-04-30 11:30:07 +00:00
HashTable * section_properties ;
2000-10-29 23:10:22 +00:00
2007-11-05 12:27:42 +00:00
/*printf("'%s' (%d)\n",$1.value.str.val,$1.value.str.len + 1);*/
2007-03-07 00:52:40 +00:00
current_section = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2000-10-29 23:10:22 +00:00
INIT_PZVAL ( current_section ) ;
2007-03-07 00:52:40 +00:00
processed = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2000-10-29 23:10:22 +00:00
INIT_PZVAL ( processed ) ;
2007-03-07 00:52:40 +00:00
unprocessed = ( zval * ) pemalloc ( sizeof ( zval ) , 1 ) ;
2003-03-14 17:54:38 +00:00
INIT_PZVAL ( unprocessed ) ;
2000-10-29 23:10:22 +00:00
2007-03-07 00:52:40 +00:00
section_properties = ( HashTable * ) pemalloc ( sizeof ( HashTable ) , 1 ) ;
2002-04-30 11:30:07 +00:00
zend_hash_init ( section_properties , 0 , NULL , ( dtor_func_t ) browscap_entry_dtor , 1 ) ;
2007-09-28 02:05:10 +00:00
Z_ARRVAL_P ( current_section ) = section_properties ;
Z_TYPE_P ( current_section ) = IS_ARRAY ;
current_section_name = zend_strndup ( Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) ) ;
2007-11-05 12:27:42 +00:00
zend_hash_update ( & browser_hash , Z_STRVAL_P ( arg1 ) , Z_STRLEN_P ( arg1 ) + 1 , ( void * ) & current_section , sizeof ( zval * ) , NULL ) ;
2000-10-29 23:10:22 +00:00
2001-09-25 21:58:48 +00:00
Z_STRVAL_P ( processed ) = Z_STRVAL_P ( arg1 ) ;
Z_STRLEN_P ( processed ) = Z_STRLEN_P ( arg1 ) ;
Z_TYPE_P ( processed ) = IS_STRING ;
2003-03-14 17:54:38 +00:00
Z_STRVAL_P ( unprocessed ) = Z_STRVAL_P ( arg1 ) ;
Z_STRLEN_P ( unprocessed ) = Z_STRLEN_P ( arg1 ) ;
Z_TYPE_P ( unprocessed ) = IS_STRING ;
Z_STRVAL_P ( unprocessed ) = zend_strndup ( Z_STRVAL_P ( unprocessed ) , Z_STRLEN_P ( unprocessed ) ) ;
2000-10-29 23:10:22 +00:00
convert_browscap_pattern ( processed ) ;
2003-03-14 17:54:38 +00:00
zend_hash_update ( section_properties , " browser_name_regex " , sizeof ( " browser_name_regex " ) , ( void * ) & processed , sizeof ( zval * ) , NULL ) ;
zend_hash_update ( section_properties , " browser_name_pattern " , sizeof ( " browser_name_pattern " ) , ( void * ) & unprocessed , sizeof ( zval * ) , NULL ) ;
2000-10-29 23:10:22 +00:00
}
break ;
}
}
2001-06-06 13:06:12 +00:00
/* }}} */
2000-10-29 23:10:22 +00:00
2007-11-05 12:27:42 +00:00
PHP_MINIT_FUNCTION ( browscap ) /* {{{ */
2000-10-29 23:10:22 +00:00
{
char * browscap = INI_STR ( " browscap " ) ;
2003-06-30 20:31:57 +00:00
if ( browscap & & browscap [ 0 ] ) {
2000-10-29 23:10:22 +00:00
zend_file_handle fh ;
2003-03-14 17:54:38 +00:00
memset ( & fh , 0 , sizeof ( fh ) ) ;
2000-10-29 23:10:22 +00:00
2007-11-05 12:27:42 +00:00
if ( zend_hash_init_ex ( & browser_hash , 0 , NULL , ( dtor_func_t ) browscap_entry_dtor , 1 , 0 ) = = FAILURE ) {
2000-10-29 23:10:22 +00:00
return FAILURE ;
}
2001-04-30 12:45:02 +00:00
fh . handle . fp = VCWD_FOPEN ( browscap , " r " ) ;
2003-05-16 15:13:47 +00:00
fh . opened_path = NULL ;
fh . free_filename = 0 ;
2000-10-29 23:10:22 +00:00
if ( ! fh . handle . fp ) {
2003-05-27 17:24:59 +00:00
zend_error ( E_CORE_WARNING , " Cannot open '%s' for reading " , browscap ) ;
2000-10-29 23:10:22 +00:00
return FAILURE ;
}
2000-10-30 23:39:14 +00:00
fh . filename = browscap ;
2001-09-25 21:58:48 +00:00
Z_TYPE ( fh ) = ZEND_HANDLE_FP ;
2007-09-28 02:05:10 +00:00
zend_parse_ini_file ( & fh , 1 , ZEND_INI_SCANNER_RAW , ( zend_ini_parser_cb_t ) php_browscap_parser_cb , & browser_hash TSRMLS_CC ) ;
2000-10-29 23:10:22 +00:00
}
return SUCCESS ;
}
2001-06-06 13:06:12 +00:00
/* }}} */
2000-10-29 23:10:22 +00:00
2007-11-05 12:27:42 +00:00
PHP_MSHUTDOWN_FUNCTION ( browscap ) /* {{{ */
2000-10-29 23:10:22 +00:00
{
2003-06-30 20:31:57 +00:00
char * browscap = INI_STR ( " browscap " ) ;
if ( browscap & & browscap [ 0 ] ) {
2000-10-29 23:10:22 +00:00
zend_hash_destroy ( & browser_hash ) ;
}
return SUCCESS ;
}
2001-06-06 13:06:12 +00:00
/* }}} */
2000-10-29 23:10:22 +00:00
2008-07-24 19:52:24 +00:00
static int browser_reg_compare ( zval * * browser TSRMLS_DC , int num_args , va_list args , zend_hash_key * key ) /* { { { */
1999-04-17 00:37:12 +00:00
{
2004-03-15 21:26:39 +00:00
zval * * browser_regex , * * previous_match ;
1999-04-17 00:37:12 +00:00
regex_t r ;
2001-08-11 17:03:37 +00:00
char * lookup_browser_name = va_arg ( args , char * ) ;
zval * * found_browser_entry = va_arg ( args , zval * * ) ;
1999-04-17 00:37:12 +00:00
2004-03-15 21:26:39 +00:00
/* See if we have an exact match, if so, we're done... */
2003-05-20 17:59:16 +00:00
if ( * found_browser_entry ) {
2004-03-15 21:26:39 +00:00
if ( zend_hash_find ( Z_ARRVAL_PP ( found_browser_entry ) , " browser_name_pattern " , sizeof ( " browser_name_pattern " ) , ( void * * ) & previous_match ) = = FAILURE ) {
2003-05-20 17:59:16 +00:00
return 0 ;
}
2004-03-15 21:26:39 +00:00
else if ( ! strcasecmp ( Z_STRVAL_PP ( previous_match ) , lookup_browser_name ) ) {
2003-05-20 17:59:16 +00:00
return 0 ;
}
2000-07-23 11:32:18 +00:00
}
2004-03-15 21:26:39 +00:00
if ( zend_hash_find ( Z_ARRVAL_PP ( browser ) , " browser_name_regex " , sizeof ( " browser_name_regex " ) , ( void * * ) & browser_regex ) = = FAILURE ) {
return 0 ;
}
2007-11-05 12:27:42 +00:00
if ( regcomp ( & r , Z_STRVAL_PP ( browser_regex ) , REG_NOSUB ) ! = 0 ) {
1999-04-17 00:37:12 +00:00
return 0 ;
}
2007-11-05 12:27:42 +00:00
if ( regexec ( & r , lookup_browser_name , 0 , NULL , 0 ) = = 0 ) {
2004-03-15 21:26:39 +00:00
/* If we've found a possible browser, we need to do a comparison of the
number of characters changed in the user agent being checked versus
the previous match found and the current match . */
if ( * found_browser_entry ) {
int i , prev_len = 0 , curr_len = 0 , ua_len ;
zval * * current_match ;
if ( zend_hash_find ( Z_ARRVAL_PP ( browser ) , " browser_name_pattern " , sizeof ( " browser_name_pattern " ) , ( void * * ) & current_match ) = = FAILURE ) {
regfree ( & r ) ;
return 0 ;
}
ua_len = strlen ( lookup_browser_name ) ;
for ( i = 0 ; i < Z_STRLEN_PP ( previous_match ) ; i + + ) {
switch ( Z_STRVAL_PP ( previous_match ) [ i ] ) {
case ' ? ' :
case ' * ' :
/* do nothing, ignore these characters in the count */
break ;
default :
+ + prev_len ;
}
}
for ( i = 0 ; i < Z_STRLEN_PP ( current_match ) ; i + + ) {
switch ( Z_STRVAL_PP ( current_match ) [ i ] ) {
case ' ? ' :
case ' * ' :
/* do nothing, ignore these characters in the count */
break ;
default :
+ + curr_len ;
}
}
/* Pick which browser pattern replaces the least amount of
characters when compared to the original user agent string . . . */
if ( ua_len - prev_len > ua_len - curr_len ) {
* found_browser_entry = * browser ;
}
}
else {
* found_browser_entry = * browser ;
}
}
if ( & r ) {
regfree ( & r ) ;
1999-04-17 00:37:12 +00:00
}
2004-03-15 21:26:39 +00:00
1999-04-17 00:37:12 +00:00
return 0 ;
}
2001-06-06 13:06:12 +00:00
/* }}} */
1999-04-17 00:37:12 +00:00
2003-04-28 21:49:47 +00:00
/* {{{ proto mixed get_browser([string browser_name [, bool return_array]])
2007-11-05 12:27:42 +00:00
Get information about the capabilities of a browser . If browser_name is omitted or null , HTTP_USER_AGENT is used . Returns an object by default ; if return_array is true , returns an array . */
1999-05-16 11:19:26 +00:00
PHP_FUNCTION ( get_browser )
1999-04-17 00:37:12 +00:00
{
2007-11-05 12:27:42 +00:00
char * agent_name = NULL ;
int agent_name_len ;
zend_bool return_array = 0 ;
zval * * agent ;
2001-08-11 17:03:37 +00:00
zval * found_browser_entry , * tmp_copy ;
2000-07-23 11:11:35 +00:00
char * lookup_browser_name ;
2003-06-30 20:31:57 +00:00
char * browscap = INI_STR ( " browscap " ) ;
1999-04-17 00:37:12 +00:00
2003-06-30 20:31:57 +00:00
if ( ! browscap | | ! browscap [ 0 ] ) {
2007-09-30 05:49:45 +00:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " browscap ini directive not set " ) ;
1999-04-17 00:37:12 +00:00
RETURN_FALSE ;
}
2003-03-14 17:54:38 +00:00
2007-11-05 12:27:42 +00:00
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " |s!b " , & agent_name , & agent_name_len , & return_array ) = = FAILURE ) {
return ;
1999-04-17 00:37:12 +00:00
}
2004-03-15 21:26:39 +00:00
2007-11-05 12:27:42 +00:00
if ( agent_name = = NULL ) {
zend_is_auto_global ( " _SERVER " , sizeof ( " _SERVER " ) - 1 TSRMLS_CC ) ;
2003-03-14 17:54:38 +00:00
if ( ! PG ( http_globals ) [ TRACK_VARS_SERVER ]
2007-11-05 12:27:42 +00:00
| | zend_hash_find ( PG ( http_globals ) [ TRACK_VARS_SERVER ] - > value . ht , " HTTP_USER_AGENT " , sizeof ( " HTTP_USER_AGENT " ) , ( void * * ) & agent_name ) = = FAILURE ) {
2003-03-14 17:54:38 +00:00
php_error_docref ( NULL TSRMLS_CC , E_WARNING , " HTTP_USER_AGENT variable is not set, cannot determine user agent name " ) ;
RETURN_FALSE ;
}
}
2007-11-05 12:27:42 +00:00
lookup_browser_name = estrndup ( agent_name , agent_name_len ) ;
php_strtolower ( lookup_browser_name , agent_name_len ) ;
2003-03-14 17:54:38 +00:00
2007-11-05 12:27:42 +00:00
if ( zend_hash_find ( & browser_hash , lookup_browser_name , agent_name_len + 1 , ( void * * ) & agent ) = = FAILURE ) {
1999-04-24 00:12:00 +00:00
found_browser_entry = NULL ;
2008-07-24 19:52:24 +00:00
zend_hash_apply_with_arguments ( & browser_hash TSRMLS_CC , ( apply_func_args_t ) browser_reg_compare , 2 , lookup_browser_name , & found_browser_entry ) ;
2003-04-28 21:49:47 +00:00
1999-04-24 00:12:00 +00:00
if ( found_browser_entry ) {
2000-07-25 18:50:02 +00:00
agent = & found_browser_entry ;
2007-11-05 12:27:42 +00:00
} else if ( zend_hash_find ( & browser_hash , DEFAULT_SECTION_NAME , sizeof ( DEFAULT_SECTION_NAME ) , ( void * * ) & agent ) = = FAILURE ) {
2004-03-15 21:26:39 +00:00
efree ( lookup_browser_name ) ;
1999-04-17 00:37:12 +00:00
RETURN_FALSE ;
}
}
2003-03-14 17:54:38 +00:00
if ( return_array ) {
array_init ( return_value ) ;
zend_hash_copy ( Z_ARRVAL_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) ) ;
}
else {
object_init ( return_value ) ;
zend_hash_copy ( Z_OBJPROP_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) ) ;
}
2003-04-28 21:49:47 +00:00
2007-11-05 12:27:42 +00:00
while ( zend_hash_find ( Z_ARRVAL_PP ( agent ) , " parent " , sizeof ( " parent " ) , ( void * * ) & agent_name ) = = SUCCESS ) {
if ( zend_hash_find ( & browser_hash , agent_name , agent_name_len + 1 , ( void * * ) & agent ) = = FAILURE ) {
1999-04-17 00:37:12 +00:00
break ;
}
2003-03-14 17:54:38 +00:00
if ( return_array ) {
zend_hash_merge ( Z_ARRVAL_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) , 0 ) ;
}
else {
zend_hash_merge ( Z_OBJPROP_P ( return_value ) , Z_ARRVAL_PP ( agent ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) & tmp_copy , sizeof ( zval * ) , 0 ) ;
}
1999-04-17 00:37:12 +00:00
}
2004-03-15 21:26:39 +00:00
2006-12-21 21:37:45 +00:00
efree ( lookup_browser_name ) ;
1999-04-17 00:37:12 +00:00
}
2000-03-29 11:38:47 +00:00
/* }}} */
1999-04-17 00:37:12 +00:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
2001-09-09 13:29:31 +00:00
* vim600 : sw = 4 ts = 4 fdm = marker
* vim < 600 : sw = 4 ts = 4
1999-04-17 00:37:12 +00:00
*/