1999-11-14 04:31:54 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| PHP version 4.0 |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2001-02-26 14:11:02 +08:00
| Copyright ( c ) 1997 - 2001 The PHP Group |
1999-11-14 04:31:54 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2000-05-18 23:34:45 +08:00
| This source file is subject to version 2.02 of the PHP license , |
1999-11-14 04:31:54 +08:00
| that is bundled with this package in the file LICENSE , and is |
| available at through the world - wide - web at |
2000-05-18 23:34:45 +08:00
| http : //www.php.net/license/2_02.txt. |
1999-11-14 04:31:54 +08: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 . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Andi Gutmans < andi @ zend . com > |
| Zeev Suraski < zeev @ zend . com > |
2000-03-07 04:37:11 +08:00
| Rasmus Lerdorf < rasmus @ php . net > |
| Andrei Zmievski < andrei @ ispi . net > |
2000-10-22 01:48:11 +08:00
| Stig Venaas < venaas @ php . net > |
2001-02-20 13:36:40 +08:00
| Jason Greene < jason @ php . net > |
1999-11-14 04:31:54 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2000-07-24 09:40:02 +08:00
*/
/* $Id$ */
1999-11-14 04:31:54 +08:00
# include "php.h"
# include "php_ini.h"
# include "zend_operators.h"
# include <stdarg.h>
# include <stdlib.h>
# include <math.h>
# include <time.h>
# include <stdio.h>
# if HAVE_STRING_H
# include <string.h>
# else
# include <strings.h>
# endif
2000-02-11 23:59:30 +08:00
# ifdef PHP_WIN32
1999-11-14 04:31:54 +08:00
# include "win32/unistd.h"
# endif
# include "zend_globals.h"
# include "php_globals.h"
# include "php_array.h"
1999-12-02 01:21:52 +08:00
# include "basic_functions.h"
2000-04-13 03:39:02 +08:00
# include "php_string.h"
2000-05-10 03:27:00 +08:00
# include "php_rand.h"
1999-11-14 04:31:54 +08:00
1999-12-12 06:42:01 +08:00
# ifdef ZTS
int array_globals_id ;
# else
php_array_globals array_globals ;
# endif
1999-11-14 04:31:54 +08:00
# define EXTR_OVERWRITE 0
# define EXTR_SKIP 1
# define EXTR_PREFIX_SAME 2
# define EXTR_PREFIX_ALL 3
2001-01-23 01:27:02 +08:00
# define EXTR_PREFIX_INVALID 4
1999-11-14 04:31:54 +08:00
2000-05-18 08:47:57 +08:00
# define SORT_REGULAR 0
# define SORT_NUMERIC 1
# define SORT_STRING 2
2000-07-12 00:48:03 +08:00
# define SORT_DESC 3
# define SORT_ASC 4
1999-11-14 04:31:54 +08:00
PHP_MINIT_FUNCTION ( array )
{
1999-12-12 06:42:01 +08:00
# ifdef ZTS
2001-07-27 18:16:41 +08:00
ts_allocate_id ( & array_globals_id , sizeof ( php_array_globals ) , NULL , NULL ) ;
1999-12-12 06:42:01 +08:00
# endif
1999-11-14 04:31:54 +08:00
REGISTER_LONG_CONSTANT ( " EXTR_OVERWRITE " , EXTR_OVERWRITE , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " EXTR_SKIP " , EXTR_SKIP , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " EXTR_PREFIX_SAME " , EXTR_PREFIX_SAME , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " EXTR_PREFIX_ALL " , EXTR_PREFIX_ALL , CONST_CS | CONST_PERSISTENT ) ;
2001-01-23 01:27:02 +08:00
REGISTER_LONG_CONSTANT ( " EXTR_PREFIX_INVALID " , EXTR_PREFIX_INVALID , CONST_CS | CONST_PERSISTENT ) ;
1999-11-14 04:31:54 +08:00
1999-12-14 03:42:26 +08:00
REGISTER_LONG_CONSTANT ( " SORT_ASC " , SORT_ASC , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " SORT_DESC " , SORT_DESC , CONST_CS | CONST_PERSISTENT ) ;
2000-05-18 08:47:57 +08:00
REGISTER_LONG_CONSTANT ( " SORT_REGULAR " , SORT_REGULAR , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " SORT_NUMERIC " , SORT_NUMERIC , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " SORT_STRING " , SORT_STRING , CONST_CS | CONST_PERSISTENT ) ;
1999-11-14 04:31:54 +08:00
return SUCCESS ;
}
1999-12-12 06:42:01 +08:00
PHP_MSHUTDOWN_FUNCTION ( array )
{
# ifdef ZTS
ts_free_id ( array_globals_id ) ;
# endif
return SUCCESS ;
}
2001-08-06 11:50:52 +08:00
static void set_compare_func ( int sort_type TSRMLS_DC )
2000-05-18 08:47:57 +08:00
{
switch ( sort_type ) {
case SORT_NUMERIC :
ARRAYG ( compare_func ) = numeric_compare_function ;
break ;
case SORT_STRING :
ARRAYG ( compare_func ) = string_compare_function ;
break ;
case SORT_REGULAR :
default :
ARRAYG ( compare_func ) = compare_function ;
break ;
}
}
1999-11-14 04:31:54 +08:00
static int array_key_compare ( const void * a , const void * b )
{
1999-11-15 03:59:52 +08:00
Bucket * f ;
Bucket * s ;
pval result ;
pval first ;
pval second ;
2001-07-28 19:36:37 +08:00
TSRMLS_FETCH ( ) ;
1999-11-15 03:59:52 +08:00
f = * ( ( Bucket * * ) a ) ;
s = * ( ( Bucket * * ) b ) ;
1999-11-14 04:31:54 +08:00
1999-11-15 03:59:52 +08:00
if ( f - > nKeyLength = = 0 ) {
2000-11-27 21:31:21 +08:00
Z_TYPE ( first ) = IS_LONG ;
Z_LVAL ( first ) = f - > h ;
1999-11-15 03:59:52 +08:00
} else {
2000-11-27 21:31:21 +08:00
Z_TYPE ( first ) = IS_STRING ;
Z_STRVAL ( first ) = f - > arKey ;
Z_STRLEN ( first ) = f - > nKeyLength ;
1999-11-15 03:59:52 +08:00
}
if ( s - > nKeyLength = = 0 ) {
2000-11-27 21:31:21 +08:00
Z_TYPE ( second ) = IS_LONG ;
Z_LVAL ( second ) = s - > h ;
1999-11-15 03:59:52 +08:00
} else {
2000-11-27 21:31:21 +08:00
Z_TYPE ( second ) = IS_STRING ;
Z_STRVAL ( second ) = s - > arKey ;
Z_STRLEN ( second ) = s - > nKeyLength ;
1999-11-15 03:59:52 +08:00
}
2001-07-30 12:58:07 +08:00
if ( ARRAYG ( compare_func ) ( & result , & first , & second TSRMLS_CC ) = = FAILURE ) {
1999-11-15 03:59:52 +08:00
return 0 ;
}
1999-11-14 04:31:54 +08:00
2000-11-27 21:31:21 +08:00
if ( Z_TYPE ( result ) = = IS_DOUBLE ) {
if ( Z_DVAL ( result ) < 0 ) {
1999-11-22 01:13:39 +08:00
return - 1 ;
2000-11-27 21:31:21 +08:00
} else if ( Z_DVAL ( result ) > 0 ) {
1999-11-22 01:13:39 +08:00
return 1 ;
} else {
return 0 ;
}
}
1999-11-15 03:59:52 +08:00
convert_to_long ( & result ) ;
1999-11-22 01:13:39 +08:00
2000-11-27 21:31:21 +08:00
if ( Z_LVAL ( result ) < 0 ) {
1999-11-14 04:31:54 +08:00
return - 1 ;
2000-11-27 21:31:21 +08:00
} else if ( Z_LVAL ( result ) > 0 ) {
1999-11-14 04:31:54 +08:00
return 1 ;
1999-11-22 01:13:39 +08:00
}
return 0 ;
1999-11-14 04:31:54 +08:00
}
static int array_reverse_key_compare ( const void * a , const void * b )
{
2001-08-12 01:03:37 +08:00
return array_key_compare ( a , b ) * - 1 ;
1999-11-14 04:31:54 +08:00
}
2000-08-04 17:24:36 +08:00
/* {{{ proto int krsort(array array_arg [, int sort_flags])
2000-03-29 19:19:01 +08:00
Sort an array reverse by key */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( krsort )
{
2000-05-18 08:47:57 +08:00
zval * * array , * * sort_type ;
int sort_type_val = SORT_REGULAR ;
1999-11-14 04:31:54 +08:00
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & array , & sort_type ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in krsort() call " ) ;
return ;
}
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) = = 2 ) {
2000-05-18 08:47:57 +08:00
convert_to_long_ex ( sort_type ) ;
sort_type_val = Z_LVAL_PP ( sort_type ) ;
}
2001-08-06 11:50:52 +08:00
set_compare_func ( sort_type_val TSRMLS_CC ) ;
1999-11-14 04:31:54 +08:00
if ( zend_hash_sort ( target_hash , qsort , array_reverse_key_compare , 0 ) = = FAILURE ) {
return ;
}
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-08-04 17:24:36 +08:00
/* {{{ proto int ksort(array array_arg [, int sort_flags])
2000-03-29 19:19:01 +08:00
Sort an array by key */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( ksort )
{
2000-05-18 08:47:57 +08:00
zval * * array , * * sort_type ;
int sort_type_val = SORT_REGULAR ;
1999-11-14 04:31:54 +08:00
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & array , & sort_type ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in ksort() call " ) ;
return ;
}
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) = = 2 ) {
2000-05-18 08:47:57 +08:00
convert_to_long_ex ( sort_type ) ;
sort_type_val = Z_LVAL_PP ( sort_type ) ;
}
2001-08-06 11:50:52 +08:00
set_compare_func ( sort_type_val TSRMLS_CC ) ;
2001-08-12 01:03:37 +08:00
if ( zend_hash_sort ( target_hash , qsort , array_key_compare , 0 ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
return ;
}
RETURN_TRUE ;
}
2001-05-23 09:50:11 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto int count(mixed var)
Count the number of elements in a variable ( usually an array ) */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( count )
{
pval * * array ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( array ) = = IS_NULL ) {
1999-11-14 04:31:54 +08:00
RETURN_LONG ( 0 ) ;
} else {
RETURN_LONG ( 1 ) ;
}
}
RETURN_LONG ( zend_hash_num_elements ( target_hash ) ) ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
/* Numbers are always smaller than strings int this function as it
* anyway doesn ' t make much sense to compare two different data types .
* This keeps it consistant and simple .
2000-10-22 19:18:21 +08:00
*
2000-12-29 07:50:42 +08:00
* This is not correct any more , depends on what compare_func is set to .
1999-11-14 04:31:54 +08:00
*/
static int array_data_compare ( const void * a , const void * b )
{
Bucket * f ;
Bucket * s ;
pval result ;
pval * first ;
pval * second ;
2001-07-28 19:36:37 +08:00
TSRMLS_FETCH ( ) ;
1999-11-14 04:31:54 +08:00
f = * ( ( Bucket * * ) a ) ;
s = * ( ( Bucket * * ) b ) ;
first = * ( ( pval * * ) f - > pData ) ;
second = * ( ( pval * * ) s - > pData ) ;
2001-07-30 12:58:07 +08:00
if ( ARRAYG ( compare_func ) ( & result , first , second TSRMLS_CC ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
return 0 ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE ( result ) = = IS_DOUBLE ) {
if ( Z_DVAL ( result ) < 0 ) {
1999-11-22 01:13:39 +08:00
return - 1 ;
2000-11-27 21:31:21 +08:00
} else if ( Z_DVAL ( result ) > 0 ) {
1999-11-22 01:13:39 +08:00
return 1 ;
} else {
return 0 ;
}
}
1999-11-14 04:31:54 +08:00
convert_to_long ( & result ) ;
1999-11-22 01:13:39 +08:00
2000-11-27 21:31:21 +08:00
if ( Z_LVAL ( result ) < 0 ) {
1999-11-14 04:31:54 +08:00
return - 1 ;
2000-11-27 21:31:21 +08:00
} else if ( Z_LVAL ( result ) > 0 ) {
1999-11-14 04:31:54 +08:00
return 1 ;
1999-11-22 01:13:39 +08:00
}
return 0 ;
1999-11-14 04:31:54 +08:00
}
static int array_reverse_data_compare ( const void * a , const void * b )
{
2001-08-12 01:03:37 +08:00
return array_data_compare ( a , b ) * - 1 ;
1999-11-14 04:31:54 +08:00
}
2000-04-13 03:39:02 +08:00
static int array_natural_general_compare ( const void * a , const void * b , int fold_case )
{
Bucket * f , * s ;
zval * fval , * sval ;
zval first , second ;
int result ;
f = * ( ( Bucket * * ) a ) ;
s = * ( ( Bucket * * ) b ) ;
fval = * ( ( pval * * ) f - > pData ) ;
sval = * ( ( pval * * ) s - > pData ) ;
first = * fval ;
second = * sval ;
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( fval ) ! = IS_STRING ) {
2000-04-13 03:39:02 +08:00
zval_copy_ctor ( & first ) ;
convert_to_string ( & first ) ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( sval ) ! = IS_STRING ) {
2000-04-13 03:39:02 +08:00
zval_copy_ctor ( & first ) ;
convert_to_string ( & second ) ;
}
2000-11-27 21:31:21 +08:00
result = strnatcmp_ex ( Z_STRVAL ( first ) , Z_STRLEN ( first ) ,
Z_STRVAL ( second ) , Z_STRLEN ( second ) , fold_case ) ;
2000-04-13 03:39:02 +08:00
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( fval ) ! = IS_STRING )
2000-04-13 03:39:02 +08:00
zval_dtor ( & first ) ;
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( sval ) ! = IS_STRING )
2000-04-13 03:39:02 +08:00
zval_dtor ( & second ) ;
return result ;
}
static int array_natural_compare ( const void * a , const void * b )
{
return array_natural_general_compare ( a , b , 0 ) ;
}
static int array_natural_case_compare ( const void * a , const void * b )
{
return array_natural_general_compare ( a , b , 1 ) ;
}
static void php_natsort ( INTERNAL_FUNCTION_PARAMETERS , int fold_case )
{
zval * * array ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
2000-04-13 03:39:02 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in %s() call " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2000-04-13 03:39:02 +08:00
return ;
}
if ( fold_case ) {
if ( zend_hash_sort ( target_hash , qsort , array_natural_case_compare , 0 ) = = FAILURE ) {
return ;
}
} else {
if ( zend_hash_sort ( target_hash , qsort , array_natural_compare , 0 ) = = FAILURE ) {
return ;
}
}
RETURN_TRUE ;
}
/* {{{ proto void natsort(array array_arg)
Sort an array using natural sort */
PHP_FUNCTION ( natsort )
{
php_natsort ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 0 ) ;
}
/* }}} */
/* {{{ proto void natcasesort(array array_arg)
Sort an array using case - insensitive natural sort */
PHP_FUNCTION ( natcasesort )
{
php_natsort ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 1 ) ;
}
/* }}} */
2000-08-04 17:24:36 +08:00
/* {{{ proto void asort(array array_arg [, int sort_flags])
2000-03-29 19:19:01 +08:00
Sort an array and maintain index association */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( asort )
{
2000-05-18 08:47:57 +08:00
zval * * array , * * sort_type ;
int sort_type_val = SORT_REGULAR ;
1999-11-14 04:31:54 +08:00
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & array , & sort_type ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in asort() call " ) ;
return ;
}
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) = = 2 ) {
2000-05-18 08:47:57 +08:00
convert_to_long_ex ( sort_type ) ;
sort_type_val = Z_LVAL_PP ( sort_type ) ;
}
2001-08-06 11:50:52 +08:00
set_compare_func ( sort_type_val TSRMLS_CC ) ;
2001-08-12 01:03:37 +08:00
if ( zend_hash_sort ( target_hash , qsort , array_data_compare , 0 ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
return ;
}
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-08-04 17:24:36 +08:00
/* {{{ proto void arsort(array array_arg [, int sort_flags])
2000-03-29 19:19:01 +08:00
Sort an array in reverse order and maintain index association */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( arsort )
{
2000-05-18 08:47:57 +08:00
zval * * array , * * sort_type ;
int sort_type_val = SORT_REGULAR ;
1999-11-14 04:31:54 +08:00
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & array , & sort_type ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in arsort() call " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) = = 2 ) {
2000-05-18 08:47:57 +08:00
convert_to_long_ex ( sort_type ) ;
sort_type_val = Z_LVAL_PP ( sort_type ) ;
}
2001-08-06 11:50:52 +08:00
set_compare_func ( sort_type_val TSRMLS_CC ) ;
2001-08-12 01:03:37 +08:00
if ( zend_hash_sort ( target_hash , qsort , array_reverse_data_compare , 0 ) = = FAILURE ) {
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-08-04 17:24:36 +08:00
/* {{{ proto void sort(array array_arg [, int sort_flags])
2000-03-29 19:19:01 +08:00
Sort an array */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( sort )
{
2000-05-18 08:47:57 +08:00
zval * * array , * * sort_type ;
int sort_type_val = SORT_REGULAR ;
1999-11-14 04:31:54 +08:00
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & array , & sort_type ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in sort() call " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) = = 2 ) {
2000-05-18 08:47:57 +08:00
convert_to_long_ex ( sort_type ) ;
sort_type_val = Z_LVAL_PP ( sort_type ) ;
}
2001-08-06 11:50:52 +08:00
set_compare_func ( sort_type_val TSRMLS_CC ) ;
2001-08-12 01:03:37 +08:00
if ( zend_hash_sort ( target_hash , qsort , array_data_compare , 1 ) = = FAILURE ) {
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-08-04 17:24:36 +08:00
/* {{{ proto void rsort(array array_arg [, int sort_flags])
2000-03-29 19:19:01 +08:00
Sort an array in reverse order */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( rsort )
{
2000-05-18 08:47:57 +08:00
zval * * array , * * sort_type ;
int sort_type_val = SORT_REGULAR ;
1999-11-14 04:31:54 +08:00
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & array , & sort_type ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in rsort() call " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) = = 2 ) {
2000-05-18 08:47:57 +08:00
convert_to_long_ex ( sort_type ) ;
sort_type_val = Z_LVAL_PP ( sort_type ) ;
}
2001-08-06 11:50:52 +08:00
set_compare_func ( sort_type_val TSRMLS_CC ) ;
2001-08-12 01:03:37 +08:00
if ( zend_hash_sort ( target_hash , qsort , array_reverse_data_compare , 1 ) = = FAILURE ) {
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
RETURN_TRUE ;
}
static int array_user_compare ( const void * a , const void * b )
{
Bucket * f ;
Bucket * s ;
pval * * args [ 2 ] ;
1999-12-20 02:58:27 +08:00
pval * retval_ptr ;
2001-07-27 18:16:41 +08:00
TSRMLS_FETCH ( ) ;
1999-11-14 04:31:54 +08:00
f = * ( ( Bucket * * ) a ) ;
s = * ( ( Bucket * * ) b ) ;
args [ 0 ] = ( pval * * ) f - > pData ;
args [ 1 ] = ( pval * * ) s - > pData ;
2001-07-30 16:24:42 +08:00
if ( call_user_function_ex ( EG ( function_table ) , NULL , * BG ( user_compare_func_name ) , & retval_ptr , 2 , args , 0 , NULL TSRMLS_CC ) = = SUCCESS
1999-12-20 02:58:27 +08:00
& & retval_ptr ) {
long retval ;
convert_to_long_ex ( & retval_ptr ) ;
2000-11-27 21:31:21 +08:00
retval = Z_LVAL_P ( retval_ptr ) ;
1999-12-20 02:58:27 +08:00
zval_ptr_dtor ( & retval_ptr ) ;
return retval ;
1999-11-14 04:31:54 +08:00
} else {
return 0 ;
}
}
2000-03-29 19:19:01 +08:00
/* {{{ proto void usort(array array_arg, string cmp_function)
Sort an array by values using a user - defined comparison function */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( usort )
{
pval * * array ;
pval * * old_compare_func ;
HashTable * target_hash ;
1999-12-02 01:21:52 +08:00
old_compare_func = BG ( user_compare_func_name ) ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 2 | | zend_get_parameters_ex ( 2 , & array , & BG ( user_compare_func_name ) ) = = FAILURE ) {
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in usort() call " ) ;
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
if ( zend_hash_sort ( target_hash , qsort , array_user_compare , 1 ) = = FAILURE ) {
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
1999-11-14 04:31:54 +08:00
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto void uasort(array array_arg, string cmp_function)
Sort an array with a user - defined comparison function and maintain index association */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( uasort )
{
pval * * array ;
pval * * old_compare_func ;
HashTable * target_hash ;
1999-12-02 01:21:52 +08:00
old_compare_func = BG ( user_compare_func_name ) ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 2 | | zend_get_parameters_ex ( 2 , & array , & BG ( user_compare_func_name ) ) = = FAILURE ) {
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in uasort() call " ) ;
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
if ( zend_hash_sort ( target_hash , qsort , array_user_compare , 0 ) = = FAILURE ) {
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
1999-11-14 04:31:54 +08:00
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
static int array_user_key_compare ( const void * a , const void * b )
{
Bucket * f ;
Bucket * s ;
pval key1 , key2 ;
pval * args [ 2 ] ;
pval retval ;
int status ;
2001-07-27 18:16:41 +08:00
TSRMLS_FETCH ( ) ;
1999-11-14 04:31:54 +08:00
args [ 0 ] = & key1 ;
args [ 1 ] = & key2 ;
INIT_PZVAL ( & key1 ) ;
INIT_PZVAL ( & key2 ) ;
f = * ( ( Bucket * * ) a ) ;
s = * ( ( Bucket * * ) b ) ;
if ( f - > nKeyLength ) {
2000-11-27 21:31:21 +08:00
Z_STRVAL ( key1 ) = estrndup ( f - > arKey , f - > nKeyLength ) ;
Z_STRLEN ( key1 ) = f - > nKeyLength - 1 ;
Z_TYPE ( key1 ) = IS_STRING ;
1999-11-14 04:31:54 +08:00
} else {
2000-11-27 21:31:21 +08:00
Z_LVAL ( key1 ) = f - > h ;
Z_TYPE ( key1 ) = IS_LONG ;
1999-11-14 04:31:54 +08:00
}
if ( s - > nKeyLength ) {
2000-11-27 21:31:21 +08:00
Z_STRVAL ( key2 ) = estrndup ( s - > arKey , s - > nKeyLength ) ;
Z_STRLEN ( key2 ) = s - > nKeyLength - 1 ;
Z_TYPE ( key2 ) = IS_STRING ;
1999-11-14 04:31:54 +08:00
} else {
2000-11-27 21:31:21 +08:00
Z_LVAL ( key2 ) = s - > h ;
Z_TYPE ( key2 ) = IS_LONG ;
1999-11-14 04:31:54 +08:00
}
2001-07-30 16:24:42 +08:00
status = call_user_function ( EG ( function_table ) , NULL , * BG ( user_compare_func_name ) , & retval , 2 , args TSRMLS_CC ) ;
1999-11-14 04:31:54 +08:00
1999-11-21 20:13:44 +08:00
zval_dtor ( & key1 ) ;
zval_dtor ( & key2 ) ;
1999-11-14 04:31:54 +08:00
if ( status = = SUCCESS ) {
convert_to_long ( & retval ) ;
2000-11-27 21:31:21 +08:00
return Z_LVAL ( retval ) ;
1999-11-14 04:31:54 +08:00
} else {
return 0 ;
}
}
2000-03-29 19:19:01 +08:00
/* {{{ proto void uksort(array array_arg, string cmp_function)
Sort an array by keys using a user - defined comparison function */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( uksort )
{
pval * * array ;
pval * * old_compare_func ;
HashTable * target_hash ;
1999-12-02 01:21:52 +08:00
old_compare_func = BG ( user_compare_func_name ) ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 2 | | zend_get_parameters_ex ( 2 , & array , & BG ( user_compare_func_name ) ) = = FAILURE ) {
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in uksort() call " ) ;
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
if ( zend_hash_sort ( target_hash , qsort , array_user_key_compare , 0 ) = = FAILURE ) {
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
1999-12-02 01:21:52 +08:00
BG ( user_compare_func_name ) = old_compare_func ;
1999-11-14 04:31:54 +08:00
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto mixed end(array array_arg)
Advances array argument ' s internal pointer to the last element and return it */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( end )
{
pval * * array , * * entry ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Variable passed to end() is not an array or object " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
zend_hash_internal_pointer_end ( target_hash ) ;
1999-11-21 20:13:44 +08:00
if ( return_value_used ) {
if ( zend_hash_get_current_data ( target_hash , ( void * * ) & entry ) = = FAILURE ) {
RETURN_FALSE ;
}
* return_value = * * entry ;
zval_copy_ctor ( return_value ) ;
1999-11-14 04:31:54 +08:00
}
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto mixed prev(array array_arg)
Move array argument ' s internal pointer to the previous element and return it */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( prev )
{
pval * * array , * * entry ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Variable passed to prev() is not an array or object " ) ;
RETURN_FALSE ;
}
zend_hash_move_backwards ( target_hash ) ;
1999-11-21 20:13:44 +08:00
if ( return_value_used ) {
if ( zend_hash_get_current_data ( target_hash , ( void * * ) & entry ) = = FAILURE ) {
RETURN_FALSE ;
}
1999-11-14 04:31:54 +08:00
1999-11-21 20:13:44 +08:00
* return_value = * * entry ;
zval_copy_ctor ( return_value ) ;
}
1999-11-14 04:31:54 +08:00
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto mixed next(array array_arg)
Move array argument ' s internal pointer to the next element and return it */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( next )
{
pval * * array , * * entry ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Variable passed to next() is not an array or object " ) ;
RETURN_FALSE ;
}
zend_hash_move_forward ( target_hash ) ;
1999-11-21 20:13:44 +08:00
if ( return_value_used ) {
if ( zend_hash_get_current_data ( target_hash , ( void * * ) & entry ) = = FAILURE ) {
RETURN_FALSE ;
}
* return_value = * * entry ;
zval_copy_ctor ( return_value ) ;
1999-11-14 04:31:54 +08:00
}
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto mixed reset(array array_arg)
Set array argument ' s internal pointer to the first element and return it */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( reset )
{
pval * * array , * * entry ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Variable passed to reset() is not an array or object " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
zend_hash_internal_pointer_reset ( target_hash ) ;
1999-11-17 02:47:47 +08:00
1999-11-17 03:12:29 +08:00
if ( return_value_used ) {
1999-11-21 20:13:44 +08:00
if ( zend_hash_get_current_data ( target_hash , ( void * * ) & entry ) = = FAILURE ) {
RETURN_FALSE ;
}
1999-11-17 02:47:47 +08:00
* return_value = * * entry ;
1999-11-21 20:13:44 +08:00
zval_copy_ctor ( return_value ) ;
1999-11-17 02:47:47 +08:00
}
1999-11-14 04:31:54 +08:00
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto mixed current(array array_arg)
Return the element currently pointed to by the internal array pointer */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( current )
{
pval * * array , * * entry ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Variable passed to current() is not an array or object " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
if ( zend_hash_get_current_data ( target_hash , ( void * * ) & entry ) = = FAILURE ) {
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
* return_value = * * entry ;
1999-11-21 20:13:44 +08:00
zval_copy_ctor ( return_value ) ;
1999-11-14 04:31:54 +08:00
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-03-29 19:19:01 +08:00
/* {{{ proto mixed key(array array_arg)
Return the key of the element currently pointed to by the internal array pointer */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( key )
{
pval * * array ;
char * string_key ;
ulong num_key ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Variable passed to key() is not an array or object " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2000-12-22 20:57:09 +08:00
switch ( zend_hash_get_current_key ( target_hash , & string_key , & num_key , 1 ) ) {
1999-11-14 04:31:54 +08:00
case HASH_KEY_IS_STRING :
2000-11-27 21:31:21 +08:00
RETVAL_STRING ( string_key , 0 ) ;
1999-11-14 04:31:54 +08:00
break ;
case HASH_KEY_IS_LONG :
2000-11-27 21:31:21 +08:00
RETVAL_LONG ( num_key ) ;
1999-11-14 04:31:54 +08:00
break ;
case HASH_KEY_NON_EXISTANT :
return ;
}
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-06-25 21:21:37 +08:00
/* {{{ proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
2000-03-29 19:19:01 +08:00
Return the lowest value in an array or a series of arguments */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( min )
{
2000-06-06 03:47:54 +08:00
int argc = ZEND_NUM_ARGS ( ) ;
1999-11-14 04:31:54 +08:00
pval * * result ;
if ( argc < = 0 ) {
php_error ( E_WARNING , " min: must be passed at least 1 value " ) ;
2000-03-29 20:43:13 +08:00
RETURN_NULL ( ) ;
1999-11-14 04:31:54 +08:00
}
2001-08-06 11:50:52 +08:00
set_compare_func ( SORT_REGULAR TSRMLS_CC ) ;
1999-11-14 04:31:54 +08:00
if ( argc = = 1 ) {
pval * * arr ;
2000-11-27 21:31:21 +08:00
if ( zend_get_parameters_ex ( 1 , & arr ) = = FAILURE | | Z_TYPE_PP ( arr ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( zend_hash_minmax ( Z_ARRVAL_PP ( arr ) , array_data_compare , 0 , ( void * * ) & result ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
* return_value = * * result ;
1999-11-21 20:13:44 +08:00
zval_copy_ctor ( return_value ) ;
1999-11-14 04:31:54 +08:00
} else {
php_error ( E_WARNING , " min: array must contain at least 1 element " ) ;
RETURN_FALSE ;
}
} else {
2000-06-06 03:47:54 +08:00
pval * * * args = ( pval * * * ) emalloc ( sizeof ( pval * * ) * ZEND_NUM_ARGS ( ) ) ;
1999-11-14 04:31:54 +08:00
pval * * min , result ;
int i ;
2000-06-06 03:47:54 +08:00
if ( zend_get_parameters_array_ex ( ZEND_NUM_ARGS ( ) , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
min = args [ 0 ] ;
2000-06-06 03:47:54 +08:00
for ( i = 1 ; i < ZEND_NUM_ARGS ( ) ; i + + ) {
2001-07-30 12:58:07 +08:00
is_smaller_function ( & result , * args [ i ] , * min TSRMLS_CC ) ;
2000-11-27 21:31:21 +08:00
if ( Z_LVAL ( result ) = = 1 ) {
1999-11-14 04:31:54 +08:00
min = args [ i ] ;
}
}
* return_value = * * min ;
1999-11-21 20:13:44 +08:00
zval_copy_ctor ( return_value ) ;
1999-11-14 04:31:54 +08:00
efree ( args ) ;
}
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2000-06-25 21:21:37 +08:00
/* {{{ proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
2000-03-29 19:19:01 +08:00
Return the highest value in an array or a series of arguments */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( max )
{
2000-06-06 03:47:54 +08:00
int argc = ZEND_NUM_ARGS ( ) ;
1999-11-14 04:31:54 +08:00
pval * * result ;
if ( argc < = 0 ) {
php_error ( E_WARNING , " max: must be passed at least 1 value " ) ;
2000-03-29 20:43:13 +08:00
RETURN_NULL ( ) ;
1999-11-14 04:31:54 +08:00
}
2001-08-06 11:50:52 +08:00
set_compare_func ( SORT_REGULAR TSRMLS_CC ) ;
1999-11-14 04:31:54 +08:00
if ( argc = = 1 ) {
pval * * arr ;
2000-11-27 21:31:21 +08:00
if ( zend_get_parameters_ex ( 1 , & arr ) = = FAILURE | | Z_TYPE_PP ( arr ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( zend_hash_minmax ( Z_ARRVAL_PP ( arr ) , array_data_compare , 1 , ( void * * ) & result ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
* return_value = * * result ;
1999-11-21 20:13:44 +08:00
zval_copy_ctor ( return_value ) ;
1999-11-14 04:31:54 +08:00
} else {
php_error ( E_WARNING , " max: array must contain at least 1 element " ) ;
RETURN_FALSE ;
}
} else {
2000-06-06 03:47:54 +08:00
pval * * * args = ( pval * * * ) emalloc ( sizeof ( pval * * ) * ZEND_NUM_ARGS ( ) ) ;
1999-11-14 04:31:54 +08:00
pval * * max , result ;
int i ;
2000-06-06 03:47:54 +08:00
if ( zend_get_parameters_array_ex ( ZEND_NUM_ARGS ( ) , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
max = args [ 0 ] ;
2000-06-06 03:47:54 +08:00
for ( i = 1 ; i < ZEND_NUM_ARGS ( ) ; i + + ) {
2001-07-30 12:58:07 +08:00
is_smaller_or_equal_function ( & result , * args [ i ] , * max TSRMLS_CC ) ;
2000-11-27 21:31:21 +08:00
if ( Z_LVAL ( result ) = = 0 ) {
1999-11-14 04:31:54 +08:00
max = args [ i ] ;
}
}
* return_value = * * max ;
1999-11-21 20:13:44 +08:00
zval_copy_ctor ( return_value ) ;
1999-11-14 04:31:54 +08:00
efree ( args ) ;
}
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2001-08-06 11:50:52 +08:00
static int php_array_walk ( HashTable * target_hash , zval * * userdata TSRMLS_DC )
1999-11-14 04:31:54 +08:00
{
zval * * args [ 3 ] , /* Arguments to userland function */
1999-12-20 02:58:27 +08:00
* retval_ptr , /* Return value - unused */
1999-11-14 04:31:54 +08:00
* key ; /* Entry key */
char * string_key ;
2001-03-17 03:29:23 +08:00
ulong string_key_len ;
1999-11-14 04:31:54 +08:00
ulong num_key ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
1999-11-14 04:31:54 +08:00
/* Allocate space for key */
MAKE_STD_ZVAL ( key ) ;
/* Set up known arguments */
args [ 1 ] = & key ;
args [ 2 ] = userdata ;
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( target_hash , & pos ) ;
2000-04-14 02:57:37 +08:00
1999-11-14 04:31:54 +08:00
/* Iterate through hash */
2001-03-17 03:29:23 +08:00
while ( zend_hash_get_current_data_ex ( target_hash , ( void * * ) & args [ 0 ] , & pos ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
/* Set up the key */
2001-03-17 03:29:23 +08:00
if ( zend_hash_get_current_key_ex ( target_hash , & string_key , & string_key_len , & num_key , 0 , & pos ) = = HASH_KEY_IS_LONG ) {
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( key ) = IS_LONG ;
Z_LVAL_P ( key ) = num_key ;
1999-11-14 04:31:54 +08:00
} else {
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( key ) = IS_STRING ;
Z_STRVAL_P ( key ) = string_key ;
2001-03-17 03:29:23 +08:00
Z_STRLEN_P ( key ) = string_key_len - 1 ;
1999-11-14 04:31:54 +08:00
}
/* Call the userland function */
2001-03-17 03:29:23 +08:00
if ( call_user_function_ex ( EG ( function_table ) , NULL , * BG ( array_walk_func_name ) ,
2001-07-30 16:24:42 +08:00
& retval_ptr , userdata ? 3 : 2 , args , 0 , NULL TSRMLS_CC ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
1999-12-20 02:58:27 +08:00
zval_ptr_dtor ( & retval_ptr ) ;
2000-02-12 05:14:42 +08:00
} else
2001-08-12 01:03:37 +08:00
php_error ( E_WARNING , " Unable to call %s() - function does not exist " ,
2000-02-12 05:14:42 +08:00
( * BG ( array_walk_func_name ) ) - > value . str . val ) ;
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( target_hash , & pos ) ;
1999-11-14 04:31:54 +08:00
}
efree ( key ) ;
return 0 ;
}
2000-04-04 16:52:57 +08:00
/* {{{ proto int array_walk(array input, string funcname [, mixed userdata])
1999-11-14 04:31:54 +08:00
Apply a user function to every member of an array */
2001-07-28 19:36:37 +08:00
PHP_FUNCTION ( array_walk )
{
1999-11-14 04:31:54 +08:00
int argc ;
zval * * array ,
* * userdata = NULL ,
* * old_walk_func_name ;
HashTable * target_hash ;
2000-06-06 03:47:54 +08:00
argc = ZEND_NUM_ARGS ( ) ;
1999-12-02 01:21:52 +08:00
old_walk_func_name = BG ( array_walk_func_name ) ;
1999-11-14 04:31:54 +08:00
if ( argc < 2 | | argc > 3 | |
1999-12-19 06:40:35 +08:00
zend_get_parameters_ex ( argc , & array , & BG ( array_walk_func_name ) , & userdata ) = = FAILURE ) {
1999-12-02 01:21:52 +08:00
BG ( array_walk_func_name ) = old_walk_func_name ;
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
2000-08-23 02:39:29 +08:00
php_error ( E_WARNING , " Wrong datatype in %s() call " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2000-08-23 02:39:29 +08:00
BG ( array_walk_func_name ) = old_walk_func_name ;
RETURN_FALSE ;
}
if ( Z_TYPE_PP ( BG ( array_walk_func_name ) ) ! = IS_ARRAY & &
Z_TYPE_PP ( BG ( array_walk_func_name ) ) ! = IS_STRING ) {
php_error ( E_WARNING , " Wrong syntax for function name in %s() call " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
1999-12-02 01:21:52 +08:00
BG ( array_walk_func_name ) = old_walk_func_name ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2001-08-06 11:50:52 +08:00
php_array_walk ( target_hash , userdata TSRMLS_CC ) ;
1999-12-02 01:21:52 +08:00
BG ( array_walk_func_name ) = old_walk_func_name ;
1999-11-14 04:31:54 +08:00
RETURN_TRUE ;
}
2000-03-29 19:19:01 +08:00
/* }}} */
1999-11-14 04:31:54 +08:00
2001-02-20 13:36:40 +08:00
/* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
* 0 = return boolean
* 1 = return key
*/
static void php_search_array ( INTERNAL_FUNCTION_PARAMETERS , int behavior )
1999-11-14 04:31:54 +08:00
{
2001-02-20 13:36:40 +08:00
zval * * value , /* value to check for */
1999-11-14 04:31:54 +08:00
* * array , /* array to check in */
2000-06-01 21:52:08 +08:00
* * strict , /* strict comparison or not */
* * entry , /* pointer to array entry */
1999-11-14 04:31:54 +08:00
res ; /* comparison result */
HashTable * target_hash ; /* array hashtable */
2000-06-18 11:43:58 +08:00
HashPosition pos ; /* hash iterator */
2001-02-20 13:36:40 +08:00
ulong num_key ;
char * string_key ;
2001-07-30 12:58:07 +08:00
int ( * compare_func ) ( zval * , zval * , zval * TSRMLS_DC ) = is_equal_function ;
2001-02-21 00:44:57 +08:00
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 2 | | ZEND_NUM_ARGS ( ) > 3 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & value , & array , & strict ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( value ) = = IS_ARRAY | | Z_TYPE_PP ( value ) = = IS_OBJECT ) {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " Wrong datatype for first argument in call to %s " , get_active_function_name ( TSRMLS_C ) ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( array ) ! = IS_ARRAY ) {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " Wrong datatype for second argument in call to %s " , get_active_function_name ( TSRMLS_C ) ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) = = 3 ) {
2000-06-01 21:52:08 +08:00
convert_to_boolean_ex ( strict ) ;
2001-02-20 13:36:40 +08:00
if ( Z_LVAL_PP ( strict ) ) {
2000-06-01 21:52:08 +08:00
compare_func = is_identical_function ;
2001-07-30 12:58:07 +08:00
}
2000-06-01 21:52:08 +08:00
}
1999-11-14 04:31:54 +08:00
target_hash = HASH_OF ( * array ) ;
2000-06-18 11:43:58 +08:00
zend_hash_internal_pointer_reset_ex ( target_hash , & pos ) ;
2000-06-18 11:45:08 +08:00
while ( zend_hash_get_current_data_ex ( target_hash , ( void * * ) & entry , & pos ) = = SUCCESS ) {
2001-07-30 12:58:07 +08:00
compare_func ( & res , * value , * entry TSRMLS_CC ) ;
2000-06-01 21:52:08 +08:00
if ( Z_LVAL ( res ) = = 1 ) {
2001-02-20 13:36:40 +08:00
if ( behavior = = 0 ) {
RETURN_TRUE ;
} else {
/* Return current key */
switch ( zend_hash_get_current_key_ex ( target_hash , & string_key , NULL , & num_key , 1 , & pos ) ) {
case HASH_KEY_IS_STRING :
RETVAL_STRING ( string_key , 0 ) ;
break ;
case HASH_KEY_IS_LONG :
RETVAL_LONG ( num_key ) ;
break ;
}
}
1999-11-14 04:31:54 +08:00
}
2000-06-18 11:43:58 +08:00
zend_hash_move_forward_ex ( target_hash , & pos ) ;
1999-11-14 04:31:54 +08:00
}
2001-02-20 13:36:40 +08:00
2001-02-20 22:23:03 +08:00
if ( behavior = = 0 ) {
RETURN_FALSE ;
2001-02-20 13:36:40 +08:00
} else {
return ;
}
}
/* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
Checks if the given value exists in the array */
PHP_FUNCTION ( in_array )
{
php_search_array ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 0 ) ;
}
/* }}} */
2001-02-20 22:23:03 +08:00
/* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
2001-02-20 13:36:40 +08:00
Searches the array for a given value and returns the corresponding key if successful */
2001-02-20 22:23:03 +08:00
PHP_FUNCTION ( array_search )
2001-02-20 13:36:40 +08:00
{
php_search_array ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 1 ) ;
1999-11-14 04:31:54 +08:00
}
/* }}} */
2001-01-23 01:27:02 +08:00
static int php_valid_var_name ( char * var_name )
1999-11-14 04:31:54 +08:00
{
int len , i ;
2001-01-23 01:27:02 +08:00
if ( ! var_name )
1999-11-14 04:31:54 +08:00
return 0 ;
2001-01-23 01:27:02 +08:00
len = strlen ( var_name ) ;
1999-11-14 04:31:54 +08:00
2001-01-23 01:27:02 +08:00
if ( ! isalpha ( ( int ) var_name [ 0 ] ) & & var_name [ 0 ] ! = ' _ ' )
1999-11-14 04:31:54 +08:00
return 0 ;
if ( len > 1 ) {
for ( i = 1 ; i < len ; i + + ) {
2001-01-23 01:27:02 +08:00
if ( ! isalnum ( ( int ) var_name [ i ] ) & & var_name [ i ] ! = ' _ ' ) {
1999-11-14 04:31:54 +08:00
return 0 ;
}
}
}
return 1 ;
}
2001-01-23 01:27:02 +08:00
/* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
1999-11-14 04:31:54 +08:00
Imports variables into symbol table from an array */
PHP_FUNCTION ( extract )
{
2001-01-23 01:27:02 +08:00
zval * * var_array , * * z_extract_type , * * prefix ;
2000-03-24 22:56:19 +08:00
zval * * entry , * data ;
2001-01-23 01:27:02 +08:00
char * var_name , * final_name ;
ulong num_key , var_name_len ;
int var_exists , extract_type , key_type , count = 0 ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
1999-11-14 04:31:54 +08:00
2000-06-06 03:47:54 +08:00
switch ( ZEND_NUM_ARGS ( ) ) {
1999-11-14 04:31:54 +08:00
case 1 :
1999-12-19 06:40:35 +08:00
if ( zend_get_parameters_ex ( 1 , & var_array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2001-01-23 01:27:02 +08:00
extract_type = EXTR_OVERWRITE ;
1999-11-14 04:31:54 +08:00
break ;
case 2 :
2001-01-23 01:27:02 +08:00
if ( zend_get_parameters_ex ( 2 , & var_array , & z_extract_type ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2001-01-23 01:27:02 +08:00
convert_to_long_ex ( z_extract_type ) ;
extract_type = Z_LVAL_PP ( z_extract_type ) ;
if ( extract_type > EXTR_SKIP & & extract_type < = EXTR_PREFIX_INVALID ) {
php_error ( E_WARNING , " %s() expects a prefix to be specified " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2001-01-23 01:27:02 +08:00
return ;
1999-11-14 04:31:54 +08:00
}
break ;
case 3 :
2001-01-23 01:27:02 +08:00
if ( zend_get_parameters_ex ( 3 , & var_array , & z_extract_type , & prefix ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2001-01-23 01:27:02 +08:00
convert_to_long_ex ( z_extract_type ) ;
extract_type = Z_LVAL_PP ( z_extract_type ) ;
1999-11-14 04:31:54 +08:00
convert_to_string_ex ( prefix ) ;
break ;
default :
WRONG_PARAM_COUNT ;
break ;
}
2001-01-23 01:27:02 +08:00
if ( extract_type < EXTR_OVERWRITE | | extract_type > EXTR_PREFIX_INVALID ) {
php_error ( E_WARNING , " Unknown extract type in call to %s() " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2001-01-23 01:27:02 +08:00
return ;
1999-11-14 04:31:54 +08:00
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( var_array ) ! = IS_ARRAY ) {
2001-01-23 01:27:02 +08:00
php_error ( E_WARNING , " %s() expects first argument to be an array " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2001-01-23 01:27:02 +08:00
return ;
1999-11-14 04:31:54 +08:00
}
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( var_array ) , & pos ) ;
while ( zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( var_array ) , ( void * * ) & entry , & pos ) = = SUCCESS ) {
key_type = zend_hash_get_current_key_ex ( Z_ARRVAL_PP ( var_array ) , & var_name , & var_name_len , & num_key , 0 , & pos ) ;
2001-01-23 01:27:02 +08:00
final_name = NULL ;
var_exists = 0 ;
if ( key_type = = HASH_KEY_IS_STRING ) {
var_name_len - - ;
var_exists = zend_hash_exists ( EG ( active_symbol_table ) , var_name , var_name_len + 1 ) ;
} else if ( extract_type = = EXTR_PREFIX_ALL | | extract_type = = EXTR_PREFIX_INVALID ) {
final_name = emalloc ( MAX_LENGTH_OF_LONG + Z_STRLEN_PP ( prefix ) + 2 ) ;
zend_sprintf ( final_name , " %s_%ld " , Z_STRVAL_PP ( prefix ) , num_key ) ;
} else {
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( var_array ) , & pos ) ;
2001-01-23 01:27:02 +08:00
continue ;
}
switch ( extract_type ) {
case EXTR_OVERWRITE :
final_name = estrndup ( var_name , var_name_len ) ;
break ;
case EXTR_PREFIX_SAME :
if ( ! var_exists )
final_name = estrndup ( var_name , var_name_len ) ;
/* break omitted intentionally */
case EXTR_PREFIX_ALL :
if ( ! final_name ) {
final_name = emalloc ( var_name_len + Z_STRLEN_PP ( prefix ) + 2 ) ;
strcpy ( final_name , Z_STRVAL_PP ( prefix ) ) ;
strcat ( final_name , " _ " ) ;
strcat ( final_name , var_name ) ;
}
break ;
case EXTR_PREFIX_INVALID :
if ( ! final_name ) {
if ( ! php_valid_var_name ( var_name ) ) {
final_name = emalloc ( var_name_len + Z_STRLEN_PP ( prefix ) + 2 ) ;
strcpy ( final_name , Z_STRVAL_PP ( prefix ) ) ;
strcat ( final_name , " _ " ) ;
strcat ( final_name , var_name ) ;
} else
final_name = estrndup ( var_name , var_name_len ) ;
}
break ;
1999-11-14 04:31:54 +08:00
2001-01-23 01:27:02 +08:00
default :
if ( ! var_exists )
final_name = estrndup ( var_name , var_name_len ) ;
break ;
}
1999-11-14 04:31:54 +08:00
2001-01-23 01:27:02 +08:00
if ( final_name ) {
if ( php_valid_var_name ( final_name ) ) {
MAKE_STD_ZVAL ( data ) ;
* data = * * entry ;
zval_copy_ctor ( data ) ;
1999-11-14 04:31:54 +08:00
2001-01-23 01:27:02 +08:00
ZEND_SET_SYMBOL ( EG ( active_symbol_table ) , final_name , data ) ;
2001-01-09 04:57:59 +08:00
2001-01-23 01:27:02 +08:00
count + + ;
1999-11-14 04:31:54 +08:00
}
2001-01-23 01:27:02 +08:00
efree ( final_name ) ;
1999-11-14 04:31:54 +08:00
}
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( var_array ) , & pos ) ;
1999-11-14 04:31:54 +08:00
}
2001-01-09 04:57:59 +08:00
RETURN_LONG ( count ) ;
1999-11-14 04:31:54 +08:00
}
/* }}} */
2001-03-17 03:29:23 +08:00
static void php_compact_var ( HashTable * eg_active_symbol_table , zval * return_value , zval * entry )
1999-11-14 04:31:54 +08:00
{
zval * * value_ptr , * value , * data ;
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( entry ) = = IS_STRING ) {
if ( zend_hash_find ( eg_active_symbol_table , Z_STRVAL_P ( entry ) ,
Z_STRLEN_P ( entry ) + 1 , ( void * * ) & value_ptr ) ! = FAILURE ) {
1999-11-14 04:31:54 +08:00
value = * value_ptr ;
1999-12-27 05:21:33 +08:00
ALLOC_ZVAL ( data ) ;
1999-11-14 04:31:54 +08:00
* data = * value ;
zval_copy_ctor ( data ) ;
INIT_PZVAL ( data ) ;
2000-11-27 21:31:21 +08:00
zend_hash_update ( Z_ARRVAL_P ( return_value ) , Z_STRVAL_P ( entry ) ,
Z_STRLEN_P ( entry ) + 1 , & data , sizeof ( zval * ) , NULL ) ;
1999-11-14 04:31:54 +08:00
}
}
2000-11-27 21:31:21 +08:00
else if ( Z_TYPE_P ( entry ) = = IS_ARRAY ) {
2001-03-17 03:29:23 +08:00
HashPosition pos ;
1999-11-14 04:31:54 +08:00
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_P ( entry ) , & pos ) ;
while ( zend_hash_get_current_data_ex ( Z_ARRVAL_P ( entry ) , ( void * * ) & value_ptr , & pos ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
value = * value_ptr ;
2001-03-17 03:29:23 +08:00
php_compact_var ( eg_active_symbol_table , return_value , value ) ;
zend_hash_move_forward_ex ( Z_ARRVAL_P ( entry ) , & pos ) ;
1999-11-14 04:31:54 +08:00
}
}
}
2000-07-05 04:31:54 +08:00
/* {{{ proto array compact(mixed var_names [, mixed ...])
1999-11-14 04:31:54 +08:00
Creates a hash containing variables and their values */
PHP_FUNCTION ( compact )
{
zval * * * args ; /* function arguments array */
int i ;
2000-06-06 03:47:54 +08:00
args = ( zval * * * ) emalloc ( ZEND_NUM_ARGS ( ) * sizeof ( zval * * ) ) ;
1999-11-14 04:31:54 +08:00
2000-06-06 03:47:54 +08:00
if ( zend_get_parameters_array_ex ( ZEND_NUM_ARGS ( ) , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
array_init ( return_value ) ;
2001-03-17 03:29:23 +08:00
for ( i = 0 ; i < ZEND_NUM_ARGS ( ) ; i + + ) {
php_compact_var ( EG ( active_symbol_table ) , return_value , * args [ i ] ) ;
1999-11-14 04:31:54 +08:00
}
efree ( args ) ;
}
/* }}} */
2001-07-10 04:36:47 +08:00
/* {{{ proto array range(mixed low, mixed high)
Create an array containing the range of integers or characters from low to high ( inclusive ) */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( range )
{
zval * * zlow , * * zhigh ;
2001-08-12 01:03:37 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 2 | | zend_get_parameters_ex ( 2 , & zlow , & zhigh ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
/* allocate an array for return */
if ( array_init ( return_value ) = = FAILURE ) {
RETURN_FALSE ;
}
2001-07-10 04:36:47 +08:00
if ( Z_TYPE_PP ( zlow ) = = IS_STRING & & Z_TYPE_PP ( zhigh ) = = IS_STRING ) {
char * low , * high ;
convert_to_string_ex ( zlow ) ;
convert_to_string_ex ( zhigh ) ;
low = Z_STRVAL_PP ( zlow ) ;
high = Z_STRVAL_PP ( zhigh ) ;
if ( * low > * high ) {
for ( ; * low > = * high ; ( * low ) - - ) {
add_next_index_stringl ( return_value , low , 1 , 1 ) ;
}
} else {
for ( ; * low < = * high ; ( * low ) + + ) {
add_next_index_stringl ( return_value , low , 1 , 1 ) ;
}
}
} else {
int low , high ;
convert_to_long_ex ( zlow ) ;
convert_to_long_ex ( zhigh ) ;
low = Z_LVAL_PP ( zlow ) ;
high = Z_LVAL_PP ( zhigh ) ;
if ( low > high ) {
for ( ; low > = high ; low - - ) {
add_next_index_long ( return_value , low ) ;
}
} else {
for ( ; low < = high ; low + + ) {
add_next_index_long ( return_value , low ) ;
}
}
}
1999-11-14 04:31:54 +08:00
}
/* }}} */
static int array_data_shuffle ( const void * a , const void * b ) {
2001-02-22 08:24:19 +08:00
return ( php_rand ( ) % 2 ) ? 1 : - 1 ;
1999-11-14 04:31:54 +08:00
}
/* {{{ proto int shuffle(array array_arg)
Randomly shuffle the contents of an array */
PHP_FUNCTION ( shuffle )
{
zval * * array ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( array ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " Wrong datatype in shuffle() call " ) ;
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
2000-11-27 21:31:21 +08:00
if ( zend_hash_sort ( Z_ARRVAL_PP ( array ) , ( sort_func_t ) php_mergesort , array_data_shuffle , 1 ) = = FAILURE ) {
2000-03-29 19:19:01 +08:00
RETURN_FALSE ;
1999-11-14 04:31:54 +08:00
}
RETURN_TRUE ;
}
/* }}} */
2000-05-18 08:47:57 +08:00
/* HashTable* php_splice(HashTable *in_hash, int offset, int length,
zval * * * list , int list_count , HashTable * * removed ) */
HashTable * php_splice ( HashTable * in_hash , int offset , int length ,
zval * * * list , int list_count , HashTable * * removed )
1999-11-14 04:31:54 +08:00
{
HashTable * out_hash = NULL ; /* Output hashtable */
int num_in , /* Number of entries in the input hashtable */
pos , /* Current position in the hashtable */
i ; /* Loop counter */
Bucket * p ; /* Pointer to hash bucket */
zval * entry ; /* Hash entry */
/* If input hash doesn't exist, we have nothing to do */
if ( ! in_hash )
return NULL ;
/* Get number of entries in the input hash */
num_in = zend_hash_num_elements ( in_hash ) ;
/* Clamp the offset.. */
if ( offset > num_in )
offset = num_in ;
else if ( offset < 0 & & ( offset = num_in + offset ) < 0 )
offset = 0 ;
/* ..and the length */
if ( length < 0 )
length = num_in - offset + length ;
else if ( offset + length > num_in )
length = num_in - offset ;
/* Create and initialize output hash */
2001-06-20 00:03:35 +08:00
ALLOC_HASHTABLE ( out_hash ) ;
1999-12-22 01:14:31 +08:00
zend_hash_init ( out_hash , 0 , NULL , ZVAL_PTR_DTOR , 0 ) ;
1999-11-14 04:31:54 +08:00
/* Start at the beginning of the input hash and copy
entries to output hash until offset is reached */
for ( pos = 0 , p = in_hash - > pListHead ; pos < offset & & p ; pos + + , p = p - > pListNext ) {
/* Get entry and increase reference count */
entry = * ( ( zval * * ) p - > pData ) ;
entry - > refcount + + ;
/* Update output hash depending on key type */
if ( p - > nKeyLength )
zend_hash_update ( out_hash , p - > arKey , p - > nKeyLength , & entry , sizeof ( zval * ) , NULL ) ;
else
2000-06-29 04:09:04 +08:00
zend_hash_next_index_insert ( out_hash , & entry , sizeof ( zval * ) , NULL ) ;
1999-11-14 04:31:54 +08:00
}
/* If hash for removed entries exists, go until offset+length
and copy the entries to it */
if ( removed ! = NULL ) {
for ( ; pos < offset + length & & p ; pos + + , p = p - > pListNext ) {
entry = * ( ( zval * * ) p - > pData ) ;
entry - > refcount + + ;
if ( p - > nKeyLength )
zend_hash_update ( * removed , p - > arKey , p - > nKeyLength , & entry , sizeof ( zval * ) , NULL ) ;
else
2000-06-29 04:09:04 +08:00
zend_hash_next_index_insert ( * removed , & entry , sizeof ( zval * ) , NULL ) ;
1999-11-14 04:31:54 +08:00
}
} else /* otherwise just skip those entries */
for ( ; pos < offset + length & & p ; pos + + , p = p - > pListNext ) ;
/* If there are entries to insert.. */
if ( list ! = NULL ) {
/* ..for each one, create a new zval, copy entry into it
and copy it into the output hash */
for ( i = 0 ; i < list_count ; i + + ) {
entry = * list [ i ] ;
entry - > refcount + + ;
zend_hash_next_index_insert ( out_hash , & entry , sizeof ( zval * ) , NULL ) ;
}
}
/* Copy the remaining input hash entries to the output hash */
for ( ; p ; p = p - > pListNext ) {
entry = * ( ( zval * * ) p - > pData ) ;
entry - > refcount + + ;
if ( p - > nKeyLength )
zend_hash_update ( out_hash , p - > arKey , p - > nKeyLength , & entry , sizeof ( zval * ) , NULL ) ;
else
zend_hash_next_index_insert ( out_hash , & entry , sizeof ( zval * ) , NULL ) ;
}
zend_hash_internal_pointer_reset ( out_hash ) ;
return out_hash ;
}
/* }}} */
2000-06-25 21:21:37 +08:00
/* {{{ proto int array_push(array stack, mixed var [, mixed ...])
1999-11-14 04:31:54 +08:00
Pushes elements onto the end of the array */
PHP_FUNCTION ( array_push )
{
zval * * * args , /* Function arguments array */
* stack , /* Input array */
* new_var ; /* Variable to be pushed */
int i , /* Loop counter */
argc ; /* Number of function arguments */
/* Get the argument count and check it */
2000-06-06 03:47:54 +08:00
argc = ZEND_NUM_ARGS ( ) ;
1999-11-14 04:31:54 +08:00
if ( argc < 2 ) {
WRONG_PARAM_COUNT ;
}
/* Allocate arguments array and get the arguments, checking for errors. */
args = ( zval * * * ) emalloc ( argc * sizeof ( zval * * ) ) ;
1999-12-19 06:40:35 +08:00
if ( zend_get_parameters_array_ex ( argc , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
/* Get first argument and check that it's an array */
stack = * args [ 0 ] ;
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( stack ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " First argument to array_push() needs to be an array " ) ;
2001-02-22 01:22:26 +08:00
efree ( args ) ;
1999-11-14 04:31:54 +08:00
RETURN_FALSE ;
}
/* For each subsequent argument, make it a reference, increase refcount,
and add it to the end of the array */
for ( i = 1 ; i < argc ; i + + ) {
new_var = * args [ i ] ;
new_var - > refcount + + ;
2000-11-27 21:31:21 +08:00
zend_hash_next_index_insert ( Z_ARRVAL_P ( stack ) , & new_var , sizeof ( zval * ) , NULL ) ;
1999-11-14 04:31:54 +08:00
}
/* Clean up and return the number of values in the stack */
efree ( args ) ;
2000-11-27 21:31:21 +08:00
RETVAL_LONG ( zend_hash_num_elements ( Z_ARRVAL_P ( stack ) ) ) ;
1999-11-14 04:31:54 +08:00
}
/* }}} */
/* {{{ void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int which_end) */
static void _phpi_pop ( INTERNAL_FUNCTION_PARAMETERS , int off_the_end )
{
zval * * stack , /* Input stack */
* * val ; /* Value to be popped */
HashTable * new_hash ; /* New stack */
/* Get the arguments and do error-checking */
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & stack ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( stack ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " The argument needs to be an array " ) ;
return ;
}
2000-11-27 21:31:21 +08:00
if ( zend_hash_num_elements ( Z_ARRVAL_PP ( stack ) ) = = 0 ) {
1999-11-14 04:31:54 +08:00
return ;
}
/* Get the first or last value and copy it into the return value */
if ( off_the_end )
2000-11-27 21:31:21 +08:00
zend_hash_internal_pointer_end ( Z_ARRVAL_PP ( stack ) ) ;
1999-11-14 04:31:54 +08:00
else
2000-11-27 21:31:21 +08:00
zend_hash_internal_pointer_reset ( Z_ARRVAL_PP ( stack ) ) ;
zend_hash_get_current_data ( Z_ARRVAL_PP ( stack ) , ( void * * ) & val ) ;
1999-11-14 04:31:54 +08:00
* return_value = * * val ;
zval_copy_ctor ( return_value ) ;
INIT_PZVAL ( return_value ) ;
/* Delete the first or last value */
2000-11-27 21:31:21 +08:00
new_hash = php_splice ( Z_ARRVAL_PP ( stack ) , ( off_the_end ) ? - 1 : 0 , 1 , NULL , 0 , NULL ) ;
zend_hash_destroy ( Z_ARRVAL_PP ( stack ) ) ;
efree ( Z_ARRVAL_PP ( stack ) ) ;
Z_ARRVAL_PP ( stack ) = new_hash ;
1999-11-14 04:31:54 +08:00
}
/* }}} */
/* {{{ proto mixed array_pop(array stack)
Pops an element off the end of the array */
PHP_FUNCTION ( array_pop )
{
_phpi_pop ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 1 ) ;
}
/* }}} */
/* {{{ proto mixed array_shift(array stack)
Pops an element off the beginning of the array */
PHP_FUNCTION ( array_shift )
{
_phpi_pop ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 0 ) ;
}
/* }}} */
2000-06-25 21:21:37 +08:00
/* {{{ proto int array_unshift(array stack, mixed var [, mixed ...])
1999-11-14 04:31:54 +08:00
Pushes elements onto the beginning of the array */
PHP_FUNCTION ( array_unshift )
{
zval * * * args , /* Function arguments array */
* stack ; /* Input stack */
HashTable * new_hash ; /* New hashtable for the stack */
int argc ; /* Number of function arguments */
/* Get the argument count and check it */
2000-06-06 03:47:54 +08:00
argc = ZEND_NUM_ARGS ( ) ;
1999-11-14 04:31:54 +08:00
if ( argc < 2 ) {
WRONG_PARAM_COUNT ;
}
/* Allocate arguments array and get the arguments, checking for errors. */
args = ( zval * * * ) emalloc ( argc * sizeof ( zval * * ) ) ;
1999-12-19 06:40:35 +08:00
if ( zend_get_parameters_array_ex ( argc , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
/* Get first argument and check that it's an array */
stack = * args [ 0 ] ;
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( stack ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " First argument to array_unshift() needs to be an array " ) ;
2001-02-22 01:22:26 +08:00
efree ( args ) ;
1999-11-14 04:31:54 +08:00
RETURN_FALSE ;
}
/* Use splice to insert the elements at the beginning. Destroy old
hashtable and replace it with new one */
2000-11-27 21:31:21 +08:00
new_hash = php_splice ( Z_ARRVAL_P ( stack ) , 0 , 0 , & args [ 1 ] , argc - 1 , NULL ) ;
zend_hash_destroy ( Z_ARRVAL_P ( stack ) ) ;
efree ( Z_ARRVAL_P ( stack ) ) ;
Z_ARRVAL_P ( stack ) = new_hash ;
1999-11-14 04:31:54 +08:00
/* Clean up and return the number of elements in the stack */
efree ( args ) ;
2000-11-27 21:31:21 +08:00
RETVAL_LONG ( zend_hash_num_elements ( Z_ARRVAL_P ( stack ) ) ) ;
1999-11-14 04:31:54 +08:00
}
/* }}} */
/* {{{ proto array array_splice(array input, int offset [, int length [, array replacement]])
2000-02-24 16:39:02 +08:00
Removes the elements designated by offset and length and replace them with supplied array */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( array_splice )
{
zval * * * args , /* Function arguments array */
* array , /* Input array */
* * * repl = NULL ; /* Replacement elements */
HashTable * new_hash = NULL ; /* Output array's hash */
Bucket * p ; /* Bucket used for traversing hash */
int argc , /* Number of function arguments */
i ,
offset ,
length ,
repl_num = 0 ; /* Number of replacement elements */
/* Get the argument count and check it */
2000-06-06 03:47:54 +08:00
argc = ZEND_NUM_ARGS ( ) ;
1999-11-14 04:31:54 +08:00
if ( argc < 2 | | argc > 4 ) {
WRONG_PARAM_COUNT ;
}
/* Allocate arguments array and get the arguments, checking for errors. */
args = ( zval * * * ) emalloc ( argc * sizeof ( zval * * ) ) ;
1999-12-19 06:40:35 +08:00
if ( zend_get_parameters_array_ex ( argc , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
/* Get first argument and check that it's an array */
array = * args [ 0 ] ;
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_P ( array ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " First argument to array_splice() should be an array " ) ;
efree ( args ) ;
return ;
}
/* Get the next two arguments. If length is omitted,
it ' s assumed to be until the end of the array */
convert_to_long_ex ( args [ 1 ] ) ;
2000-11-27 21:31:21 +08:00
offset = Z_LVAL_PP ( args [ 1 ] ) ;
1999-11-14 04:31:54 +08:00
if ( argc > 2 ) {
convert_to_long_ex ( args [ 2 ] ) ;
2000-11-27 21:31:21 +08:00
length = Z_LVAL_PP ( args [ 2 ] ) ;
1999-11-14 04:31:54 +08:00
} else
2000-11-27 21:31:21 +08:00
length = zend_hash_num_elements ( Z_ARRVAL_P ( array ) ) ;
1999-11-14 04:31:54 +08:00
if ( argc = = 4 ) {
/* Make sure the last argument, if passed, is an array */
convert_to_array_ex ( args [ 3 ] ) ;
/* Create the array of replacement elements */
2000-11-27 21:31:21 +08:00
repl_num = zend_hash_num_elements ( Z_ARRVAL_PP ( args [ 3 ] ) ) ;
1999-11-14 04:31:54 +08:00
repl = ( zval * * * ) emalloc ( repl_num * sizeof ( zval * * ) ) ;
2000-11-27 21:31:21 +08:00
for ( p = Z_ARRVAL_PP ( args [ 3 ] ) - > pListHead , i = 0 ; p ; p = p - > pListNext , i + + ) {
1999-11-14 04:31:54 +08:00
repl [ i ] = ( ( zval * * ) p - > pData ) ;
}
}
/* Initialize return value */
array_init ( return_value ) ;
/* Perform splice */
2000-11-27 21:31:21 +08:00
new_hash = php_splice ( Z_ARRVAL_P ( array ) , offset , length ,
1999-11-14 04:31:54 +08:00
repl , repl_num ,
2000-11-27 21:31:21 +08:00
& Z_ARRVAL_P ( return_value ) ) ;
1999-11-14 04:31:54 +08:00
/* Replace input array's hashtable with the new one */
2000-11-27 21:31:21 +08:00
zend_hash_destroy ( Z_ARRVAL_P ( array ) ) ;
efree ( Z_ARRVAL_P ( array ) ) ;
Z_ARRVAL_P ( array ) = new_hash ;
1999-11-14 04:31:54 +08:00
/* Clean up */
if ( argc = = 4 )
efree ( repl ) ;
efree ( args ) ;
}
/* }}} */
/* {{{ proto array array_slice(array input, int offset [, int length])
Returns elements specified by offset and length */
PHP_FUNCTION ( array_slice )
{
zval * * input , /* Input array */
* * offset , /* Offset to get elements from */
* * length , /* How many elements to get */
* * entry ; /* An array entry */
int offset_val , /* Value of the offset argument */
length_val , /* Value of the length argument */
num_in , /* Number of elements in the input array */
pos , /* Current position in the array */
argc ; /* Number of function arguments */
char * string_key ;
2001-03-17 03:29:23 +08:00
ulong string_key_len ;
1999-11-14 04:31:54 +08:00
ulong num_key ;
2001-03-17 03:29:23 +08:00
HashPosition hpos ;
1999-11-14 04:31:54 +08:00
/* Get the arguments and do error-checking */
2000-06-06 03:47:54 +08:00
argc = ZEND_NUM_ARGS ( ) ;
1999-12-19 06:40:35 +08:00
if ( argc < 2 | | argc > 3 | | zend_get_parameters_ex ( argc , & input , & offset , & length ) ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " First argument to array_slice() should be an array " ) ;
return ;
}
/* Make sure offset and length are integers and assume
we want all entries from offset to the end if length
is not passed */
convert_to_long_ex ( offset ) ;
2000-11-27 21:31:21 +08:00
offset_val = Z_LVAL_PP ( offset ) ;
1999-11-14 04:31:54 +08:00
if ( argc = = 3 ) {
convert_to_long_ex ( length ) ;
2000-11-27 21:31:21 +08:00
length_val = Z_LVAL_PP ( length ) ;
1999-11-14 04:31:54 +08:00
} else
2000-11-27 21:31:21 +08:00
length_val = zend_hash_num_elements ( Z_ARRVAL_PP ( input ) ) ;
1999-11-14 04:31:54 +08:00
/* Initialize returned array */
array_init ( return_value ) ;
/* Get number of entries in the input hash */
2000-11-27 21:31:21 +08:00
num_in = zend_hash_num_elements ( Z_ARRVAL_PP ( input ) ) ;
1999-11-14 04:31:54 +08:00
/* Clamp the offset.. */
if ( offset_val > num_in )
return ;
else if ( offset_val < 0 & & ( offset_val = num_in + offset_val ) < 0 )
offset_val = 0 ;
/* ..and the length */
if ( length_val < 0 )
length_val = num_in - offset_val + length_val ;
else if ( offset_val + length_val > num_in )
length_val = num_in - offset_val ;
if ( length_val = = 0 )
return ;
/* Start at the beginning and go until we hit offset */
pos = 0 ;
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( input ) , & hpos ) ;
1999-11-14 04:31:54 +08:00
while ( pos < offset_val & &
2001-03-17 03:29:23 +08:00
zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & entry , & hpos ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
pos + + ;
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & hpos ) ;
1999-11-14 04:31:54 +08:00
}
/* Copy elements from input array to the one that's returned */
while ( pos < offset_val + length_val & &
2001-03-17 03:29:23 +08:00
zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & entry , & hpos ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
( * entry ) - > refcount + + ;
2001-03-17 03:29:23 +08:00
switch ( zend_hash_get_current_key_ex ( Z_ARRVAL_PP ( input ) , & string_key , & string_key_len , & num_key , 0 , & hpos ) ) {
1999-11-14 04:31:54 +08:00
case HASH_KEY_IS_STRING :
2001-03-17 03:29:23 +08:00
zend_hash_update ( Z_ARRVAL_P ( return_value ) , string_key , string_key_len ,
1999-11-14 04:31:54 +08:00
entry , sizeof ( zval * ) , NULL ) ;
break ;
case HASH_KEY_IS_LONG :
2000-11-27 21:31:21 +08:00
zend_hash_next_index_insert ( Z_ARRVAL_P ( return_value ) ,
1999-11-14 04:31:54 +08:00
entry , sizeof ( zval * ) , NULL ) ;
break ;
}
pos + + ;
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & hpos ) ;
1999-11-14 04:31:54 +08:00
}
}
/* }}} */
2000-12-11 13:36:24 +08:00
PHPAPI void php_array_merge ( HashTable * dest , HashTable * src , int recursive )
1999-11-14 04:31:54 +08:00
{
2000-05-31 01:03:56 +08:00
zval * * src_entry ,
* * dest_entry ;
char * string_key ;
2001-03-17 03:29:23 +08:00
ulong string_key_len ;
2000-05-31 01:03:56 +08:00
ulong num_key ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
2000-05-31 01:03:56 +08:00
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( src , & pos ) ;
while ( zend_hash_get_current_data_ex ( src , ( void * * ) & src_entry , & pos ) = = SUCCESS ) {
switch ( zend_hash_get_current_key_ex ( src , & string_key , & string_key_len , & num_key , 0 , & pos ) ) {
2000-05-31 01:03:56 +08:00
case HASH_KEY_IS_STRING :
if ( recursive & &
2001-03-17 03:29:23 +08:00
zend_hash_find ( dest , string_key , string_key_len ,
2000-05-31 01:03:56 +08:00
( void * * ) & dest_entry ) = = SUCCESS ) {
convert_to_array_ex ( dest_entry ) ;
convert_to_array_ex ( src_entry ) ;
2000-12-11 13:36:24 +08:00
php_array_merge ( Z_ARRVAL_PP ( dest_entry ) ,
Z_ARRVAL_PP ( src_entry ) , recursive ) ;
2000-05-31 01:03:56 +08:00
} else {
( * src_entry ) - > refcount + + ;
zend_hash_update ( dest , string_key , strlen ( string_key ) + 1 ,
src_entry , sizeof ( zval * ) , NULL ) ;
}
break ;
case HASH_KEY_IS_LONG :
( * src_entry ) - > refcount + + ;
zend_hash_next_index_insert ( dest , src_entry , sizeof ( zval * ) , NULL ) ;
break ;
}
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( src , & pos ) ;
2000-05-31 01:03:56 +08:00
}
}
2000-12-11 13:36:24 +08:00
static void php_array_merge_wrapper ( INTERNAL_FUNCTION_PARAMETERS , int recursive )
2000-05-31 01:03:56 +08:00
{
zval * * * args = NULL ;
1999-11-14 04:31:54 +08:00
int argc ,
i ;
/* Get the argument count and check it */
2000-06-06 03:47:54 +08:00
argc = ZEND_NUM_ARGS ( ) ;
1999-11-14 04:31:54 +08:00
if ( argc < 2 ) {
WRONG_PARAM_COUNT ;
}
/* Allocate arguments array and get the arguments, checking for errors. */
args = ( zval * * * ) emalloc ( argc * sizeof ( zval * * ) ) ;
1999-12-19 06:40:35 +08:00
if ( zend_get_parameters_array_ex ( argc , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
array_init ( return_value ) ;
for ( i = 0 ; i < argc ; i + + ) {
2000-05-31 01:03:56 +08:00
convert_to_array_ex ( args [ i ] ) ;
2000-12-11 13:36:24 +08:00
php_array_merge ( Z_ARRVAL_P ( return_value ) , Z_ARRVAL_PP ( args [ i ] ) , recursive ) ;
1999-11-14 04:31:54 +08:00
}
efree ( args ) ;
}
2000-05-31 01:03:56 +08:00
2000-07-05 04:31:54 +08:00
/* {{{ proto array array_merge(array arr1, array arr2 [, array ...])
2000-05-31 01:03:56 +08:00
Merges elements from passed arrays into one array */
PHP_FUNCTION ( array_merge )
{
2000-12-11 13:36:24 +08:00
php_array_merge_wrapper ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 0 ) ;
2000-05-31 01:03:56 +08:00
}
/* }}} */
2000-07-05 04:31:54 +08:00
/* {{{ proto array array_merge_recursive(array arr1, array arr2 [, array ...])
2000-05-31 01:03:56 +08:00
Recursively merges elements from passed arrays into one array */
PHP_FUNCTION ( array_merge_recursive )
{
2000-12-11 13:36:24 +08:00
php_array_merge_wrapper ( INTERNAL_FUNCTION_PARAM_PASSTHRU , 1 ) ;
2000-05-31 01:03:56 +08:00
}
1999-11-14 04:31:54 +08:00
/* }}} */
/* {{{ proto array array_keys(array input [, mixed search_value])
2000-02-24 16:39:02 +08:00
Return just the keys from the input array , optionally only for the specified search_value */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( array_keys )
{
zval * * input , /* Input array */
* * search_value , /* Value to search for */
* * entry , /* An entry in the input array */
res , /* Result of comparison */
* new_val ; /* New value */
int add_key ; /* Flag to indicate whether a key should be added */
char * string_key ; /* String key */
2001-03-17 03:29:23 +08:00
ulong string_key_len ;
1999-11-14 04:31:54 +08:00
ulong num_key ; /* Numeric key */
2001-03-17 03:29:23 +08:00
HashPosition pos ;
1999-11-14 04:31:54 +08:00
search_value = NULL ;
/* Get arguments and do error-checking */
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & input , & search_value ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " First argument to array_keys() should be an array " ) ;
return ;
}
/* Initialize return array */
array_init ( return_value ) ;
add_key = 1 ;
/* Go through input array and add keys to the return array */
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
while ( zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & entry , & pos ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
if ( search_value ! = NULL ) {
2001-07-30 12:58:07 +08:00
is_equal_function ( & res , * search_value , * entry TSRMLS_CC ) ;
1999-11-14 04:31:54 +08:00
add_key = zval_is_true ( & res ) ;
}
if ( add_key ) {
MAKE_STD_ZVAL ( new_val ) ;
2001-03-17 03:29:23 +08:00
switch ( zend_hash_get_current_key_ex ( Z_ARRVAL_PP ( input ) , & string_key , & string_key_len , & num_key , 1 , & pos ) ) {
1999-11-14 04:31:54 +08:00
case HASH_KEY_IS_STRING :
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( new_val ) = IS_STRING ;
Z_STRVAL_P ( new_val ) = string_key ;
2001-03-17 03:29:23 +08:00
Z_STRLEN_P ( new_val ) = string_key_len - 1 ;
2000-11-27 21:31:21 +08:00
zend_hash_next_index_insert ( Z_ARRVAL_P ( return_value ) , & new_val ,
1999-11-14 04:31:54 +08:00
sizeof ( zval * ) , NULL ) ;
break ;
case HASH_KEY_IS_LONG :
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( new_val ) = IS_LONG ;
Z_LVAL_P ( new_val ) = num_key ;
zend_hash_next_index_insert ( Z_ARRVAL_P ( return_value ) , & new_val ,
1999-11-14 04:31:54 +08:00
sizeof ( zval * ) , NULL ) ;
break ;
}
}
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
1999-11-14 04:31:54 +08:00
}
}
/* }}} */
/* {{{ proto array array_values(array input)
Return just the values from the input array */
PHP_FUNCTION ( array_values )
{
zval * * input , /* Input array */
* * entry ; /* An entry in the input array */
2001-03-17 03:29:23 +08:00
HashPosition pos ;
1999-11-14 04:31:54 +08:00
/* Get arguments and do error-checking */
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & input ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " Argument to array_values() should be an array " ) ;
return ;
}
/* Initialize return array */
array_init ( return_value ) ;
/* Go through input array and add values to the return array */
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
while ( zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & entry , & pos ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
( * entry ) - > refcount + + ;
2000-11-27 21:31:21 +08:00
zend_hash_next_index_insert ( Z_ARRVAL_P ( return_value ) , entry ,
1999-11-14 04:31:54 +08:00
sizeof ( zval * ) , NULL ) ;
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
1999-11-14 04:31:54 +08:00
}
}
/* }}} */
/* {{{ proto array array_count_values(array input)
2000-08-18 20:28:28 +08:00
Return the value as key and the frequency of that value in input as value */
1999-11-14 04:31:54 +08:00
PHP_FUNCTION ( array_count_values )
{
zval * * input , /* Input array */
* * entry ; /* An entry in the input array */
zval * * tmp ;
HashTable * myht ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
1999-11-14 04:31:54 +08:00
/* Get arguments and do error-checking */
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & input ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " Argument to array_count_values() should be an array " ) ;
return ;
}
/* Initialize return array */
array_init ( return_value ) ;
/* Go through input array and add values to the return array */
2000-11-27 21:31:21 +08:00
myht = Z_ARRVAL_PP ( input ) ;
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( myht , & pos ) ;
while ( zend_hash_get_current_data_ex ( myht , ( void * * ) & entry , & pos ) = = SUCCESS ) {
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( entry ) = = IS_LONG ) {
if ( zend_hash_index_find ( Z_ARRVAL_P ( return_value ) ,
Z_LVAL_PP ( entry ) ,
1999-11-14 04:31:54 +08:00
( void * * ) & tmp ) = = FAILURE ) {
zval * data ;
MAKE_STD_ZVAL ( data ) ;
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( data ) = IS_LONG ;
Z_LVAL_P ( data ) = 1 ;
2001-08-12 01:03:37 +08:00
zend_hash_index_update ( Z_ARRVAL_P ( return_value ) , Z_LVAL_PP ( entry ) , & data , sizeof ( data ) , NULL ) ;
1999-11-14 04:31:54 +08:00
} else {
2000-11-27 21:31:21 +08:00
Z_LVAL_PP ( tmp ) + + ;
1999-11-14 04:31:54 +08:00
}
2000-11-27 21:31:21 +08:00
} else if ( Z_TYPE_PP ( entry ) = = IS_STRING ) {
if ( zend_hash_find ( Z_ARRVAL_P ( return_value ) ,
Z_STRVAL_PP ( entry ) ,
Z_STRLEN_PP ( entry ) + 1 ,
1999-11-14 04:31:54 +08:00
( void * * ) & tmp ) = = FAILURE ) {
zval * data ;
MAKE_STD_ZVAL ( data ) ;
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( data ) = IS_LONG ;
Z_LVAL_P ( data ) = 1 ;
2001-08-12 01:03:37 +08:00
zend_hash_update ( Z_ARRVAL_P ( return_value ) , Z_STRVAL_PP ( entry ) , Z_STRLEN_PP ( entry ) + 1 , & data , sizeof ( data ) , NULL ) ;
1999-11-14 04:31:54 +08:00
} else {
2000-11-27 21:31:21 +08:00
Z_LVAL_PP ( tmp ) + + ;
1999-11-14 04:31:54 +08:00
}
} else {
php_error ( E_WARNING , " Can only count STRING and INTEGER values! " ) ;
}
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( myht , & pos ) ;
1999-11-14 04:31:54 +08:00
}
}
/* }}} */
2000-09-13 03:04:50 +08:00
/* {{{ proto array array_reverse(array input [, bool preserve keys])
1999-11-14 04:31:54 +08:00
Return input as a new array with the order of the entries reversed */
PHP_FUNCTION ( array_reverse )
{
2000-09-13 03:03:59 +08:00
zval * * input , /* Input array */
* * z_preserve_keys , /* Flag: whether to preserve keys */
* * entry ; /* An entry in the input array */
1999-11-14 04:31:54 +08:00
char * string_key ;
2001-03-17 03:29:23 +08:00
ulong string_key_len ;
1999-11-14 04:31:54 +08:00
ulong num_key ;
2000-09-13 03:03:59 +08:00
zend_bool preserve_keys = 0 ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
1999-11-14 04:31:54 +08:00
/* Get arguments and do error-checking */
2000-09-13 03:03:59 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & input , & z_preserve_keys ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
2000-09-13 03:03:59 +08:00
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " Argument to array_reverse() should be an array " ) ;
return ;
}
2000-09-13 03:03:59 +08:00
if ( ZEND_NUM_ARGS ( ) > 1 ) {
convert_to_boolean_ex ( z_preserve_keys ) ;
2000-09-20 02:19:02 +08:00
preserve_keys = Z_BVAL_PP ( z_preserve_keys ) ;
2000-09-13 03:03:59 +08:00
}
1999-11-14 04:31:54 +08:00
/* Initialize return array */
array_init ( return_value ) ;
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_end_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
while ( zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & entry , & pos ) = = SUCCESS ) {
1999-11-14 04:31:54 +08:00
( * entry ) - > refcount + + ;
2001-03-17 03:29:23 +08:00
switch ( zend_hash_get_current_key_ex ( Z_ARRVAL_PP ( input ) , & string_key , & string_key_len , & num_key , 0 , & pos ) ) {
1999-11-14 04:31:54 +08:00
case HASH_KEY_IS_STRING :
2001-03-17 03:29:23 +08:00
zend_hash_update ( Z_ARRVAL_P ( return_value ) , string_key , string_key_len ,
1999-11-14 04:31:54 +08:00
entry , sizeof ( zval * ) , NULL ) ;
break ;
case HASH_KEY_IS_LONG :
2000-09-13 03:03:59 +08:00
if ( preserve_keys )
zend_hash_index_update ( Z_ARRVAL_P ( return_value ) , num_key ,
entry , sizeof ( zval * ) , NULL ) ;
else
zend_hash_next_index_insert ( Z_ARRVAL_P ( return_value ) ,
entry , sizeof ( zval * ) , NULL ) ;
1999-11-14 04:31:54 +08:00
break ;
}
2001-03-17 03:29:23 +08:00
zend_hash_move_backwards_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
1999-11-14 04:31:54 +08:00
}
}
/* }}} */
/* {{{ proto array array_pad(array input, int pad_size, mixed pad_value)
Returns a copy of input array padded with pad_value to size pad_size */
PHP_FUNCTION ( array_pad )
{
zval * * input ; /* Input array */
zval * * pad_size ; /* Size to pad to */
zval * * pad_value ; /* Padding value obviously */
zval * * * pads ; /* Array to pass to splice */
HashTable * new_hash ; /* Return value from splice */
int input_size ; /* Size of the input array */
int pad_size_abs ; /* Absolute value of pad_size */
int num_pads ; /* How many pads do we need */
int do_pad ; /* Whether we should do padding at all */
int i ;
/* Get arguments and do error-checking */
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 3 | | zend_get_parameters_ex ( 3 , & input , & pad_size , & pad_value ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
WRONG_PARAM_COUNT ;
}
/* Make sure arguments are of the proper type */
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " Argument to %s() should be an array " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
1999-11-14 04:31:54 +08:00
return ;
}
convert_to_long_ex ( pad_size ) ;
/* Do some initial calculations */
2000-11-27 21:31:21 +08:00
input_size = zend_hash_num_elements ( Z_ARRVAL_PP ( input ) ) ;
pad_size_abs = abs ( Z_LVAL_PP ( pad_size ) ) ;
1999-11-14 04:31:54 +08:00
do_pad = ( input_size > = pad_size_abs ) ? 0 : 1 ;
/* Copy the original array */
* return_value = * * input ;
zval_copy_ctor ( return_value ) ;
/* If no need to pad, no need to continue */
if ( ! do_pad )
return ;
/* Populate the pads array */
num_pads = pad_size_abs - input_size ;
pads = ( zval * * * ) emalloc ( num_pads * sizeof ( zval * * ) ) ;
for ( i = 0 ; i < num_pads ; i + + )
pads [ i ] = pad_value ;
/* Pad on the right or on the left */
2000-11-27 21:31:21 +08:00
if ( Z_LVAL_PP ( pad_size ) > 0 )
new_hash = php_splice ( Z_ARRVAL_P ( return_value ) , input_size , 0 , pads , num_pads , NULL ) ;
1999-11-14 04:31:54 +08:00
else
2000-11-27 21:31:21 +08:00
new_hash = php_splice ( Z_ARRVAL_P ( return_value ) , 0 , 0 , pads , num_pads , NULL ) ;
1999-11-14 04:31:54 +08:00
/* Copy the result hash into return value */
2000-11-27 21:31:21 +08:00
zend_hash_destroy ( Z_ARRVAL_P ( return_value ) ) ;
efree ( Z_ARRVAL_P ( return_value ) ) ;
Z_ARRVAL_P ( return_value ) = new_hash ;
1999-11-14 04:31:54 +08:00
/* Clean up */
efree ( pads ) ;
}
/* }}} */
1999-11-21 20:37:53 +08:00
/* {{{ proto array array_flip(array input)
1999-11-21 22:06:30 +08:00
Return array with key < - > value flipped */
1999-11-21 20:37:53 +08:00
PHP_FUNCTION ( array_flip )
{
zval * * array , * * entry , * data ;
HashTable * target_hash ;
char * string_key ;
2001-03-12 16:07:00 +08:00
ulong str_key_len ;
1999-11-21 20:37:53 +08:00
ulong num_key ;
2001-03-12 16:07:00 +08:00
HashPosition pos ;
2000-06-06 03:47:54 +08:00
if ( ZEND_NUM_ARGS ( ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
1999-11-21 20:37:53 +08:00
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in array_flip() call " ) ;
RETURN_FALSE ;
}
array_init ( return_value ) ;
2001-03-12 16:07:00 +08:00
zend_hash_internal_pointer_reset_ex ( target_hash , & pos ) ;
while ( zend_hash_get_current_data_ex ( target_hash , ( void * * ) & entry , & pos ) = = SUCCESS ) {
1999-11-21 20:37:53 +08:00
MAKE_STD_ZVAL ( data ) ;
2001-03-12 16:07:00 +08:00
switch ( zend_hash_get_current_key_ex ( target_hash , & string_key , & str_key_len , & num_key , 1 , & pos ) ) {
1999-11-21 20:37:53 +08:00
case HASH_KEY_IS_STRING :
2000-11-27 21:31:21 +08:00
Z_STRVAL_P ( data ) = string_key ;
2001-04-02 21:20:16 +08:00
Z_STRLEN_P ( data ) = str_key_len - 1 ;
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( data ) = IS_STRING ;
1999-11-21 20:37:53 +08:00
break ;
case HASH_KEY_IS_LONG :
2000-11-27 21:31:21 +08:00
Z_TYPE_P ( data ) = IS_LONG ;
Z_LVAL_P ( data ) = num_key ;
1999-11-21 20:37:53 +08:00
break ;
}
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( entry ) = = IS_LONG ) {
2001-08-12 01:03:37 +08:00
zend_hash_index_update ( Z_ARRVAL_P ( return_value ) , Z_LVAL_PP ( entry ) , & data , sizeof ( data ) , NULL ) ;
2000-11-27 21:31:21 +08:00
} else if ( Z_TYPE_PP ( entry ) = = IS_STRING ) {
2001-08-12 01:03:37 +08:00
zend_hash_update ( Z_ARRVAL_P ( return_value ) , Z_STRVAL_PP ( entry ) , Z_STRLEN_PP ( entry ) + 1 , & data , sizeof ( data ) , NULL ) ;
1999-11-21 20:37:53 +08:00
} else {
2001-03-12 18:14:00 +08:00
zval_ptr_dtor ( & data ) ; /* will free also zval structure */
1999-11-21 20:37:53 +08:00
php_error ( E_WARNING , " Can only flip STRING and INTEGER values! " ) ;
}
2001-03-12 16:07:00 +08:00
zend_hash_move_forward_ex ( target_hash , & pos ) ;
1999-11-21 20:37:53 +08:00
}
}
/* }}} */
2000-06-11 02:58:45 +08:00
/* {{{ proto array array_unique(array input)
Removes duplicate values from array */
PHP_FUNCTION ( array_unique )
{
zval * * array ;
HashTable * target_hash ;
Bucket * * arTmp , * * cmpdata , * * lastkept ;
Bucket * p ;
int i ;
if ( ARG_COUNT ( ht ) ! = 1 | | zend_get_parameters_ex ( 1 , & array ) = = FAILURE ) {
WRONG_PARAM_COUNT ;
}
target_hash = HASH_OF ( * array ) ;
if ( ! target_hash ) {
php_error ( E_WARNING , " Wrong datatype in array_unique() call " ) ;
RETURN_FALSE ;
}
/* copy the argument array */
* return_value = * * array ;
zval_copy_ctor ( return_value ) ;
if ( target_hash - > nNumOfElements < = 1 ) /* nothing to do */
return ;
/* create and sort array with pointers to the target_hash buckets */
arTmp = ( Bucket * * ) pemalloc ( ( target_hash - > nNumOfElements + 1 ) * sizeof ( Bucket * ) , target_hash - > persistent ) ;
if ( ! arTmp )
RETURN_FALSE ;
for ( i = 0 , p = target_hash - > pListHead ; p ; i + + , p = p - > pListNext )
arTmp [ i ] = p ;
arTmp [ i ] = NULL ;
2001-08-06 11:50:52 +08:00
set_compare_func ( SORT_STRING TSRMLS_CC ) ;
2000-12-29 07:50:42 +08:00
qsort ( ( void * ) arTmp , i , sizeof ( Bucket * ) , array_data_compare ) ;
2000-06-11 02:58:45 +08:00
/* go through the sorted array and delete duplicates from the copy */
lastkept = arTmp ;
for ( cmpdata = arTmp + 1 ; * cmpdata ; cmpdata + + ) {
2000-12-29 07:50:42 +08:00
if ( array_data_compare ( lastkept , cmpdata ) ) {
2000-06-11 02:58:45 +08:00
lastkept = cmpdata ;
} else {
p = * cmpdata ;
if ( p - > nKeyLength )
2000-11-27 21:31:21 +08:00
zend_hash_del ( Z_ARRVAL_P ( return_value ) , p - > arKey , p - > nKeyLength ) ;
2000-06-11 02:58:45 +08:00
else
2000-11-27 21:31:21 +08:00
zend_hash_index_del ( Z_ARRVAL_P ( return_value ) , p - > h ) ;
2000-06-11 02:58:45 +08:00
}
}
pefree ( arTmp , target_hash - > persistent ) ;
}
/* }}} */
2000-07-05 04:31:54 +08:00
/* {{{ proto array array_intersect(array arr1, array arr2 [, array ...])
2000-06-25 21:21:37 +08:00
Returns the entries of arr1 that have values which are present in all the other arguments */
2000-06-11 02:58:45 +08:00
PHP_FUNCTION ( array_intersect )
{
2000-10-22 01:48:11 +08:00
zval * * * args = NULL ;
2000-06-11 02:58:45 +08:00
HashTable * hash ;
int argc , i , c = 0 ;
Bucket * * * lists , * * list , * * * ptrs , * p ;
/* Get the argument count and check it */
argc = ARG_COUNT ( ht ) ;
if ( argc < 2 ) {
WRONG_PARAM_COUNT ;
}
/* Allocate arguments array and get the arguments, checking for errors. */
args = ( zval * * * ) emalloc ( argc * sizeof ( zval * * ) ) ;
if ( zend_get_parameters_array_ex ( argc , args ) = = FAILURE ) {
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
/* for each argument, create and sort list with pointers to the hash buckets */
lists = ( Bucket * * * ) emalloc ( argc * sizeof ( Bucket * * ) ) ;
ptrs = ( Bucket * * * ) emalloc ( argc * sizeof ( Bucket * * ) ) ;
2001-08-06 11:50:52 +08:00
set_compare_func ( SORT_STRING TSRMLS_CC ) ;
2000-06-11 02:58:45 +08:00
for ( i = 0 ; i < argc ; i + + ) {
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( args [ i ] ) ! = IS_ARRAY ) {
2000-06-11 02:58:45 +08:00
php_error ( E_WARNING , " Argument #%d to array_intersect() is not an array " , i + 1 ) ;
argc = i ; /* only free up to i-1 */
goto out ;
}
hash = HASH_OF ( * args [ i ] ) ;
list = ( Bucket * * ) pemalloc ( ( hash - > nNumOfElements + 1 ) * sizeof ( Bucket * ) , hash - > persistent ) ;
if ( ! list )
2000-10-22 01:48:11 +08:00
RETURN_FALSE ;
2000-06-11 02:58:45 +08:00
lists [ i ] = list ;
ptrs [ i ] = list ;
for ( p = hash - > pListHead ; p ; p = p - > pListNext )
2000-10-22 01:48:11 +08:00
* list + + = p ;
2000-06-11 02:58:45 +08:00
* list = NULL ;
2000-12-29 07:50:42 +08:00
qsort ( ( void * ) lists [ i ] , hash - > nNumOfElements , sizeof ( Bucket * ) , array_data_compare ) ;
2000-06-11 02:58:45 +08:00
}
2000-10-22 01:48:11 +08:00
/* copy the argument array */
* return_value = * * args [ 0 ] ;
zval_copy_ctor ( return_value ) ;
2000-06-11 02:58:45 +08:00
/* go through the lists and look for common values */
while ( * ptrs [ 0 ] ) {
for ( i = 1 ; i < argc ; i + + ) {
2000-12-29 07:50:42 +08:00
while ( * ptrs [ i ] & & ( 0 < ( c = array_data_compare ( ptrs [ 0 ] , ptrs [ i ] ) ) ) )
2000-10-22 01:48:11 +08:00
ptrs [ i ] + + ;
if ( ! * ptrs [ i ] ) {
/* delete any values corresponding to remains of ptrs[0] */
/* and exit */
for ( ; ; ) {
p = * ptrs [ 0 ] + + ;
if ( ! p )
goto out ;
if ( p - > nKeyLength )
2000-11-27 21:31:21 +08:00
zend_hash_del ( Z_ARRVAL_P ( return_value ) , p - > arKey , p - > nKeyLength ) ;
2000-10-22 01:48:11 +08:00
else
2000-11-27 21:31:21 +08:00
zend_hash_index_del ( Z_ARRVAL_P ( return_value ) , p - > h ) ;
2000-10-22 01:48:11 +08:00
}
}
2000-06-11 02:58:45 +08:00
if ( c )
2000-10-22 01:48:11 +08:00
break ;
2000-06-11 02:58:45 +08:00
ptrs [ i ] + + ;
}
if ( c ) {
2000-10-22 01:48:11 +08:00
/* Value of ptrs[0] not in all arguments, delete all entries */
/* with value < value of ptrs[i] */
for ( ; ; ) {
p = * ptrs [ 0 ] ;
2000-06-11 02:58:45 +08:00
if ( p - > nKeyLength )
2000-11-27 21:31:21 +08:00
zend_hash_del ( Z_ARRVAL_P ( return_value ) , p - > arKey , p - > nKeyLength ) ;
2000-06-11 02:58:45 +08:00
else
2000-11-27 21:31:21 +08:00
zend_hash_index_del ( Z_ARRVAL_P ( return_value ) , p - > h ) ;
2000-06-11 02:58:45 +08:00
if ( ! * + + ptrs [ 0 ] )
2000-10-22 01:48:11 +08:00
goto out ;
2000-12-29 07:50:42 +08:00
if ( 0 < = array_data_compare ( ptrs [ 0 ] , ptrs [ i ] ) )
2000-10-22 01:48:11 +08:00
break ;
}
} else {
/* ptrs[0] is present in all the arguments */
/* Skip all entries with same value as ptrs[0] */
for ( ; ; ) {
if ( ! * + + ptrs [ 0 ] )
goto out ;
2000-12-29 07:50:42 +08:00
if ( array_data_compare ( ptrs [ 0 ] - 1 , ptrs [ 0 ] ) )
2000-10-22 01:48:11 +08:00
break ;
2000-06-11 02:58:45 +08:00
}
}
}
2000-10-22 01:48:11 +08:00
2000-06-11 02:58:45 +08:00
out :
for ( i = 0 ; i < argc ; i + + ) {
2000-12-29 07:50:42 +08:00
hash = HASH_OF ( * args [ i ] ) ;
2000-06-11 02:58:45 +08:00
pefree ( lists [ i ] , hash - > persistent ) ;
}
efree ( ptrs ) ;
efree ( lists ) ;
efree ( args ) ;
}
/* }}} */
2000-07-05 04:31:54 +08:00
/* {{{ proto array array_diff(array arr1, array arr2 [, array ...])
2000-07-05 03:41:31 +08:00
Returns the entries of arr1 that have values which are not present in any of the others arguments */
2000-06-11 03:09:56 +08:00
PHP_FUNCTION ( array_diff )
2000-06-11 02:58:45 +08:00
{
2000-12-29 07:50:42 +08:00
zval * * * args = NULL ;
2000-06-11 02:58:45 +08:00
HashTable * hash ;
int argc , i , c ;
Bucket * * * lists , * * list , * * * ptrs , * p ;
/* Get the argument count and check it */
argc = ARG_COUNT ( ht ) ;
if ( argc < 2 ) {
WRONG_PARAM_COUNT ;
}
/* Allocate arguments array and get the arguments, checking for errors. */
args = ( zval * * * ) emalloc ( argc * sizeof ( zval * * ) ) ;
if ( zend_get_parameters_array_ex ( argc , args ) = = FAILURE ) {
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
/* for each argument, create and sort list with pointers to the hash buckets */
lists = ( Bucket * * * ) emalloc ( argc * sizeof ( Bucket * * ) ) ;
ptrs = ( Bucket * * * ) emalloc ( argc * sizeof ( Bucket * * ) ) ;
2001-08-06 11:50:52 +08:00
set_compare_func ( SORT_STRING TSRMLS_CC ) ;
2000-06-11 02:58:45 +08:00
for ( i = 0 ; i < argc ; i + + ) {
2000-11-27 21:31:21 +08:00
if ( Z_TYPE_PP ( args [ i ] ) ! = IS_ARRAY ) {
2000-08-18 20:45:01 +08:00
php_error ( E_WARNING , " Argument #%d to array_diff() is not an array " , i + 1 ) ;
2000-06-11 02:58:45 +08:00
argc = i ; /* only free up to i-1 */
goto out ;
}
hash = HASH_OF ( * args [ i ] ) ;
list = ( Bucket * * ) pemalloc ( ( hash - > nNumOfElements + 1 ) * sizeof ( Bucket * ) , hash - > persistent ) ;
if ( ! list )
RETURN_FALSE ;
lists [ i ] = list ;
ptrs [ i ] = list ;
for ( p = hash - > pListHead ; p ; p = p - > pListNext )
* list + + = p ;
* list = NULL ;
2000-12-29 07:50:42 +08:00
qsort ( ( void * ) lists [ i ] , hash - > nNumOfElements , sizeof ( Bucket * ) , array_data_compare ) ;
2000-06-11 02:58:45 +08:00
}
2000-10-22 01:48:11 +08:00
/* copy the argument array */
* return_value = * * args [ 0 ] ;
zval_copy_ctor ( return_value ) ;
2000-06-11 02:58:45 +08:00
/* go through the lists and look for values of ptr[0]
that are not in the others */
while ( * ptrs [ 0 ] ) {
2000-12-29 07:50:42 +08:00
c = 1 ;
2000-06-11 02:58:45 +08:00
for ( i = 1 ; i < argc ; i + + ) {
2000-12-29 07:50:42 +08:00
while ( * ptrs [ i ] & & ( 0 < ( c = array_data_compare ( ptrs [ 0 ] , ptrs [ i ] ) ) ) )
ptrs [ i ] + + ;
2000-06-11 02:58:45 +08:00
if ( ! c ) {
2000-12-29 07:50:42 +08:00
if ( * ptrs [ i ] )
ptrs [ i ] + + ;
break ;
2000-06-11 02:58:45 +08:00
}
}
if ( ! c ) {
2000-10-22 01:48:11 +08:00
/* ptrs[0] in one of the other arguments */
/* delete all entries with value as ptrs[0] */
for ( ; ; ) {
p = * ptrs [ 0 ] ;
2000-06-11 02:58:45 +08:00
if ( p - > nKeyLength )
2000-11-27 21:31:21 +08:00
zend_hash_del ( Z_ARRVAL_P ( return_value ) , p - > arKey , p - > nKeyLength ) ;
2000-06-11 02:58:45 +08:00
else
2000-11-27 21:31:21 +08:00
zend_hash_index_del ( Z_ARRVAL_P ( return_value ) , p - > h ) ;
2000-06-11 02:58:45 +08:00
if ( ! * + + ptrs [ 0 ] )
2000-10-22 01:48:11 +08:00
goto out ;
2000-12-29 07:50:42 +08:00
if ( array_data_compare ( ptrs [ 0 ] - 1 , ptrs [ 0 ] ) )
2000-10-22 01:48:11 +08:00
break ;
}
} else {
/* ptrs[0] in none of the other arguments */
/* skip all entries with value as ptrs[0] */
for ( ; ; ) {
if ( ! * + + ptrs [ 0 ] )
goto out ;
2000-12-29 07:50:42 +08:00
if ( array_data_compare ( ptrs [ 0 ] - 1 , ptrs [ 0 ] ) )
2000-10-22 01:48:11 +08:00
break ;
2000-06-11 02:58:45 +08:00
}
}
}
out :
for ( i = 0 ; i < argc ; i + + ) {
hash = HASH_OF ( * args [ i ] ) ;
pefree ( lists [ i ] , hash - > persistent ) ;
}
efree ( ptrs ) ;
efree ( lists ) ;
efree ( args ) ;
}
/* }}} */
2000-07-12 00:48:03 +08:00
# define MULTISORT_ORDER 0
# define MULTISORT_TYPE 1
# define MULTISORT_LAST 2
1999-11-14 04:31:54 +08:00
int multisort_compare ( const void * a , const void * b )
{
Bucket * * ab = * ( Bucket * * * ) a ;
Bucket * * bb = * ( Bucket * * * ) b ;
int r ;
int result = 0 ;
zval temp ;
2001-07-28 19:36:37 +08:00
TSRMLS_FETCH ( ) ;
1999-12-12 18:50:30 +08:00
1999-11-14 04:31:54 +08:00
r = 0 ;
do {
2001-08-06 11:50:52 +08:00
set_compare_func ( ARRAYG ( multisort_flags ) [ MULTISORT_TYPE ] [ r ] TSRMLS_CC ) ;
2000-07-12 00:48:03 +08:00
2001-07-30 12:58:07 +08:00
ARRAYG ( compare_func ) ( & temp , * ( ( zval * * ) ab [ r ] - > pData ) , * ( ( zval * * ) bb [ r ] - > pData ) TSRMLS_CC ) ;
2000-11-27 21:31:21 +08:00
result = ARRAYG ( multisort_flags ) [ MULTISORT_ORDER ] [ r ] * Z_LVAL ( temp ) ;
1999-11-14 04:31:54 +08:00
if ( result ! = 0 )
return result ;
r + + ;
} while ( ab [ r ] ! = NULL ) ;
return result ;
}
1999-12-14 03:42:26 +08:00
# define MULTISORT_ABORT \
2000-07-12 00:48:03 +08:00
for ( k = 0 ; k < MULTISORT_LAST ; k + + ) \
efree ( ARRAYG ( multisort_flags ) [ k ] ) ; \
1999-12-14 03:42:26 +08:00
efree ( arrays ) ; \
efree ( args ) ; \
RETURN_FALSE ;
2000-07-17 21:37:26 +08:00
/* {{{ proto bool array_multisort(array ar1 [, SORT_ASC|SORT_DESC [, SORT_REGULAR|SORT_NUMERIC|SORT_STRING]] [, array ar2 [, SORT_ASC|SORT_DESC [, SORT_REGULAR|SORT_NUMERIC|SORT_STRING]], ...])
1999-12-14 03:42:26 +08:00
Sort multiple arrays at once similar to how ORDER BY clause works in SQL */
PHP_FUNCTION ( array_multisort )
1999-11-14 04:31:54 +08:00
{
zval * * * args ;
1999-12-14 03:42:26 +08:00
zval * * * arrays ;
1999-11-14 04:31:54 +08:00
Bucket * * * indirect ;
Bucket * p ;
HashTable * hash ;
int argc ;
int array_size ;
1999-12-14 03:42:26 +08:00
int num_arrays = 0 ;
2000-07-12 00:48:03 +08:00
int parse_state [ MULTISORT_LAST ] ; /* 0 - flag not allowed
1 - flag allowed */
1999-12-14 03:42:26 +08:00
int sort_order = SORT_ASC ;
2000-07-12 00:48:03 +08:00
int sort_type = SORT_REGULAR ;
1999-11-14 04:31:54 +08:00
int i , k ;
/* Get the argument count and check it */
2000-06-06 03:47:54 +08:00
argc = ZEND_NUM_ARGS ( ) ;
1999-11-14 04:31:54 +08:00
if ( argc < 1 ) {
WRONG_PARAM_COUNT ;
}
/* Allocate arguments array and get the arguments, checking for errors. */
args = ( zval * * * ) emalloc ( argc * sizeof ( zval * * ) ) ;
1999-12-19 06:40:35 +08:00
if ( zend_get_parameters_array_ex ( argc , args ) = = FAILURE ) {
1999-11-14 04:31:54 +08:00
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
2000-07-12 00:48:03 +08:00
/* Allocate space for storing pointers to input arrays and sort flags. */
1999-12-14 03:42:26 +08:00
arrays = ( zval * * * ) ecalloc ( argc , sizeof ( zval * * ) ) ;
2000-07-12 00:48:03 +08:00
for ( i = 0 ; i < MULTISORT_LAST ; i + + ) {
parse_state [ i ] = 0 ;
ARRAYG ( multisort_flags ) [ i ] = ( int * ) ecalloc ( argc , sizeof ( int ) ) ;
}
1999-12-14 03:42:26 +08:00
/* Here we go through the input arguments and parse them. Each one can
2000-07-12 00:51:04 +08:00
be either an array or a sort flag which follows an array . If not
specified , the sort flags defaults to SORT_ASC and SORT_REGULAR
accordingly . There can ' t be two sort flags of the same type after an
array , and the very first argument has to be an array .
1999-12-14 03:42:26 +08:00
*/
1999-11-14 04:31:54 +08:00
for ( i = 0 ; i < argc ; i + + ) {
2000-07-12 00:48:03 +08:00
if ( Z_TYPE_PP ( args [ i ] ) = = IS_ARRAY ) {
2000-07-12 00:51:04 +08:00
/* We see the next array, so we update the sort flags of
the previous array and reset the sort flags . */
1999-12-14 03:42:26 +08:00
if ( i > 0 ) {
2000-07-12 00:48:03 +08:00
ARRAYG ( multisort_flags ) [ MULTISORT_ORDER ] [ num_arrays - 1 ] = sort_order ;
ARRAYG ( multisort_flags ) [ MULTISORT_TYPE ] [ num_arrays - 1 ] = sort_type ;
1999-12-14 03:42:26 +08:00
sort_order = SORT_ASC ;
2000-07-12 00:48:03 +08:00
sort_type = SORT_REGULAR ;
1999-12-14 03:42:26 +08:00
}
arrays [ num_arrays + + ] = args [ i ] ;
2000-07-12 00:51:04 +08:00
/* Next one may be an array or a list of sort flags. */
2000-07-12 00:48:03 +08:00
for ( k = 0 ; k < MULTISORT_LAST ; k + + )
parse_state [ k ] = 1 ;
} else if ( Z_TYPE_PP ( args [ i ] ) = = IS_LONG ) {
switch ( Z_LVAL_PP ( args [ i ] ) ) {
case SORT_ASC :
case SORT_DESC :
/* flag allowed here */
if ( parse_state [ MULTISORT_ORDER ] = = 1 ) {
/* Save the flag and make sure then next arg is not the current flag. */
sort_order = Z_LVAL_PP ( args [ i ] ) = = SORT_DESC ? - 1 : 1 ;
parse_state [ MULTISORT_ORDER ] = 0 ;
} else {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " Argument %i to %s() is expected to be an array or sorting flag that has not already been specified " , i + 1 , get_active_function_name ( TSRMLS_C ) ) ;
2000-07-12 00:48:03 +08:00
MULTISORT_ABORT ;
}
break ;
case SORT_REGULAR :
case SORT_NUMERIC :
case SORT_STRING :
/* flag allowed here */
if ( parse_state [ MULTISORT_TYPE ] = = 1 ) {
/* Save the flag and make sure then next arg is not the current flag. */
sort_type = Z_LVAL_PP ( args [ i ] ) ;
parse_state [ MULTISORT_TYPE ] = 0 ;
} else {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " Argument %i to %s() is expected to be an array or sorting flag that has not already been specified " , i + 1 , get_active_function_name ( TSRMLS_C ) ) ;
2000-07-12 00:48:03 +08:00
MULTISORT_ABORT ;
}
break ;
default :
1999-12-14 03:42:26 +08:00
php_error ( E_WARNING , " Argument %i to %s() is an unknown sort flag " , i + 1 ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
1999-12-14 03:42:26 +08:00
MULTISORT_ABORT ;
2000-07-12 00:48:03 +08:00
break ;
1999-12-14 03:42:26 +08:00
}
} else {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " Argument %i to %s() is expected to be an array or a sort flag " , i + 1 , get_active_function_name ( TSRMLS_C ) ) ;
1999-12-14 03:42:26 +08:00
MULTISORT_ABORT ;
1999-11-14 04:31:54 +08:00
}
}
2000-07-12 00:48:03 +08:00
/* Take care of the last array sort flags. */
ARRAYG ( multisort_flags ) [ MULTISORT_ORDER ] [ num_arrays - 1 ] = sort_order ;
ARRAYG ( multisort_flags ) [ MULTISORT_TYPE ] [ num_arrays - 1 ] = sort_type ;
1999-11-14 04:31:54 +08:00
2000-07-12 00:51:04 +08:00
/* Make sure the arrays are of the same size. */
2000-07-12 00:48:03 +08:00
array_size = zend_hash_num_elements ( Z_ARRVAL_PP ( arrays [ 0 ] ) ) ;
1999-12-14 03:42:26 +08:00
for ( i = 0 ; i < num_arrays ; i + + ) {
2000-07-12 00:48:03 +08:00
if ( zend_hash_num_elements ( Z_ARRVAL_PP ( arrays [ i ] ) ) ! = array_size ) {
1999-11-14 04:31:54 +08:00
php_error ( E_WARNING , " Array sizes are inconsistent " ) ;
1999-12-14 03:42:26 +08:00
MULTISORT_ABORT ;
1999-11-14 04:31:54 +08:00
}
}
2000-04-28 22:01:08 +08:00
/* If all arrays are empty or have only one entry,
we don ' t need to do anything . */
2000-05-18 20:29:45 +08:00
if ( array_size < = 1 ) {
2000-07-12 00:48:03 +08:00
for ( k = 0 ; k < MULTISORT_LAST ; k + + )
efree ( ARRAYG ( multisort_flags ) [ k ] ) ;
2000-04-28 22:01:08 +08:00
efree ( arrays ) ;
efree ( args ) ;
RETURN_TRUE ;
}
1999-12-14 03:42:26 +08:00
/* Create the indirection array. This array is of size MxN, where
M is the number of entries in each input array and N is the number
of the input arrays + 1. The last column is NULL to indicate the end
of the row .
*/
1999-11-14 04:31:54 +08:00
indirect = ( Bucket * * * ) emalloc ( array_size * sizeof ( Bucket * * ) ) ;
for ( i = 0 ; i < array_size ; i + + )
1999-12-14 03:42:26 +08:00
indirect [ i ] = ( Bucket * * ) emalloc ( ( num_arrays + 1 ) * sizeof ( Bucket * ) ) ;
1999-11-14 04:31:54 +08:00
1999-12-14 03:42:26 +08:00
for ( i = 0 ; i < num_arrays ; i + + ) {
1999-11-14 04:31:54 +08:00
k = 0 ;
2000-07-12 00:48:03 +08:00
for ( p = Z_ARRVAL_PP ( arrays [ i ] ) - > pListHead ; p ; p = p - > pListNext , k + + ) {
1999-11-14 04:31:54 +08:00
indirect [ k ] [ i ] = p ;
}
}
for ( k = 0 ; k < array_size ; k + + )
1999-12-14 03:42:26 +08:00
indirect [ k ] [ num_arrays ] = NULL ;
1999-11-14 04:31:54 +08:00
2000-07-12 00:48:03 +08:00
/* Do the actual sort magic - bada-bim, bada-boom. */
1999-11-14 04:31:54 +08:00
qsort ( indirect , array_size , sizeof ( Bucket * * ) , multisort_compare ) ;
1999-12-14 03:42:26 +08:00
/* Restructure the arrays based on sorted indirect - this is mostly
2000-07-12 00:51:04 +08:00
taken from zend_hash_sort ( ) function . */
1999-11-14 04:31:54 +08:00
HANDLE_BLOCK_INTERRUPTIONS ( ) ;
1999-12-14 03:42:26 +08:00
for ( i = 0 ; i < num_arrays ; i + + ) {
2000-11-27 21:31:21 +08:00
hash = Z_ARRVAL_PP ( arrays [ i ] ) ;
1999-11-14 04:31:54 +08:00
hash - > pListHead = indirect [ 0 ] [ i ] ; ;
hash - > pListTail = NULL ;
hash - > pInternalPointer = hash - > pListHead ;
for ( k = 0 ; k < array_size ; k + + ) {
if ( hash - > pListTail ) {
hash - > pListTail - > pListNext = indirect [ k ] [ i ] ;
}
indirect [ k ] [ i ] - > pListLast = hash - > pListTail ;
indirect [ k ] [ i ] - > pListNext = NULL ;
hash - > pListTail = indirect [ k ] [ i ] ;
}
p = hash - > pListHead ;
k = 0 ;
while ( p ! = NULL ) {
if ( p - > nKeyLength = = 0 )
p - > h = k + + ;
p = p - > pListNext ;
}
hash - > nNextFreeElement = array_size ;
zend_hash_rehash ( hash ) ;
}
HANDLE_UNBLOCK_INTERRUPTIONS ( ) ;
2000-07-12 00:51:04 +08:00
/* Clean up. */
1999-11-14 04:31:54 +08:00
for ( i = 0 ; i < array_size ; i + + )
efree ( indirect [ i ] ) ;
efree ( indirect ) ;
2000-07-12 00:48:03 +08:00
for ( k = 0 ; k < MULTISORT_LAST ; k + + )
efree ( ARRAYG ( multisort_flags ) [ k ] ) ;
1999-12-14 03:42:26 +08:00
efree ( arrays ) ;
1999-11-14 04:31:54 +08:00
efree ( args ) ;
1999-12-14 03:42:26 +08:00
RETURN_TRUE ;
1999-11-14 04:31:54 +08:00
}
2000-03-29 19:19:01 +08:00
/* }}} */
2000-02-26 05:27:03 +08:00
2000-05-10 03:27:00 +08:00
2000-06-25 21:21:37 +08:00
/* {{{ proto mixed array_rand(array input [, int num_req])
2000-05-10 03:27:00 +08:00
Return key / keys for random entry / entries in the array */
PHP_FUNCTION ( array_rand )
{
zval * * input , * * num_req ;
long randval ;
int num_req_val , num_avail , key_type ;
char * string_key ;
2001-03-17 03:29:23 +08:00
ulong string_key_len ;
2000-05-10 03:27:00 +08:00
ulong num_key ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
2000-05-10 03:27:00 +08:00
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & input , & num_req ) = = FAILURE ) {
WRONG_PARAM_COUNT ;
}
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
zend_error ( E_WARNING , " Argument to %s() has to be an array " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2000-05-10 03:27:00 +08:00
return ;
}
num_avail = zend_hash_num_elements ( Z_ARRVAL_PP ( input ) ) ;
if ( ZEND_NUM_ARGS ( ) > 1 ) {
convert_to_long_ex ( num_req ) ;
num_req_val = Z_LVAL_PP ( num_req ) ;
if ( num_req_val < = 0 | | num_req_val > num_avail ) {
2001-07-30 16:24:42 +08:00
zend_error ( E_WARNING , " Second argument to %s() has to be between 1 and the number of elements in the array " , get_active_function_name ( TSRMLS_C ) ) ;
2000-05-10 03:27:00 +08:00
return ;
}
} else
num_req_val = 1 ;
/* Make the return value an array only if we need to pass back more than one
result . */
if ( num_req_val > 1 )
array_init ( return_value ) ;
/* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
while ( num_req_val & & ( key_type = zend_hash_get_current_key_ex ( Z_ARRVAL_PP ( input ) , & string_key , & string_key_len , & num_key , 0 , & pos ) ) ! = HASH_KEY_NON_EXISTANT ) {
2000-05-10 03:27:00 +08:00
# ifdef HAVE_RANDOM
randval = random ( ) ;
2001-02-07 00:27:08 +08:00
# else
# ifdef HAVE_LRAND48
randval = lrand48 ( ) ;
2000-05-10 03:27:00 +08:00
# else
randval = rand ( ) ;
# endif
# endif
if ( ( double ) ( randval / ( PHP_RAND_MAX + 1.0 ) ) < ( double ) num_req_val / ( double ) num_avail ) {
/* If we are returning a single result, just do it. */
if ( Z_TYPE_P ( return_value ) ! = IS_ARRAY ) {
if ( key_type = = HASH_KEY_IS_STRING ) {
2001-03-17 03:29:23 +08:00
RETURN_STRINGL ( string_key , string_key_len - 1 , 1 ) ;
2000-05-10 03:27:00 +08:00
} else {
RETURN_LONG ( num_key ) ;
}
} else {
/* Append the result to the return value. */
if ( key_type = = HASH_KEY_IS_STRING )
2001-03-17 03:29:23 +08:00
add_next_index_stringl ( return_value , string_key , string_key_len - 1 , 1 ) ;
2000-05-10 03:27:00 +08:00
else
add_next_index_long ( return_value , num_key ) ;
}
num_req_val - - ;
2000-12-22 20:57:09 +08:00
}
2000-05-10 03:27:00 +08:00
num_avail - - ;
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
2000-10-27 22:08:33 +08:00
}
if ( num_req_val = = num_avail ) {
2000-11-02 23:32:52 +08:00
if ( zend_hash_sort ( Z_ARRVAL_P ( return_value ) , ( sort_func_t ) php_mergesort , array_data_shuffle , 1 ) = = FAILURE ) {
2000-10-27 22:08:33 +08:00
zval_dtor ( return_value ) ;
RETURN_FALSE ;
}
2000-05-10 03:27:00 +08:00
}
}
/* }}} */
2000-10-26 01:40:11 +08:00
/* {{{ proto mixed array_sum(array input)
Returns the sum of the array entries */
PHP_FUNCTION ( array_sum )
{
zval * * input ,
* * entry ;
int argc = ZEND_NUM_ARGS ( ) ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
2001-08-04 03:18:51 +08:00
double dval ;
2000-10-26 01:40:11 +08:00
if ( argc ! = 1 | | zend_get_parameters_ex ( argc , & input ) = = FAILURE ) {
WRONG_PARAM_COUNT ;
}
2000-12-23 00:31:42 +08:00
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
php_error ( E_WARNING , " The argument to %s() should be an array " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2000-12-23 00:31:42 +08:00
return ;
}
2000-10-26 01:40:11 +08:00
ZVAL_LONG ( return_value , 0 ) ;
2001-03-17 03:29:23 +08:00
for ( zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & entry , & pos ) = = SUCCESS ;
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & pos ) ) {
2000-10-26 01:40:11 +08:00
if ( Z_TYPE_PP ( entry ) = = IS_ARRAY | | Z_TYPE_PP ( entry ) = = IS_OBJECT )
continue ;
SEPARATE_ZVAL ( entry ) ;
2001-07-30 12:58:07 +08:00
convert_scalar_to_number ( * entry TSRMLS_CC ) ;
2000-10-26 01:40:11 +08:00
if ( Z_TYPE_PP ( entry ) = = IS_LONG & & Z_TYPE_P ( return_value ) = = IS_LONG ) {
2001-08-04 03:18:51 +08:00
dval = ( double ) Z_LVAL_P ( return_value ) + ( double ) Z_LVAL_PP ( entry ) ;
if ( ( double ) LONG_MIN < = dval & & dval < = ( double ) LONG_MAX ) {
Z_LVAL_P ( return_value ) + = Z_LVAL_PP ( entry ) ;
continue ;
}
2000-10-26 01:40:11 +08:00
}
2001-08-04 03:18:51 +08:00
convert_to_double ( return_value ) ;
convert_to_double_ex ( entry ) ;
Z_DVAL_P ( return_value ) + = Z_DVAL_PP ( entry ) ;
2000-10-26 01:40:11 +08:00
}
}
/* }}} */
2001-03-12 11:06:53 +08:00
/* {{{ proto mixed array_reduce(array input, mixed callback [, int initial])
2001-03-12 11:10:15 +08:00
Iteratively reduce the array to a single value via the callback . */
2001-03-12 11:06:53 +08:00
PHP_FUNCTION ( array_reduce )
{
zval * * input , * * callback , * * initial ;
zval * * args [ 2 ] ;
zval * * operand ;
zval * result = NULL ;
zval * retval ;
char * callback_name ;
2001-03-17 03:29:23 +08:00
HashPosition pos ;
2001-03-12 11:06:53 +08:00
if ( ZEND_NUM_ARGS ( ) < 2 | | ZEND_NUM_ARGS ( ) > 3 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & input , & callback , & initial ) = = FAILURE ) {
WRONG_PARAM_COUNT ;
}
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
php_error ( E_WARNING , " %s() expects argument 1 to be an array " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2001-03-12 11:06:53 +08:00
return ;
}
if ( ! zend_is_callable ( * callback , 0 , & callback_name ) ) {
php_error ( E_WARNING , " %s() expects argument 2, '%s', to be a valid callback " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) , callback_name ) ;
2001-03-12 11:06:53 +08:00
efree ( callback_name ) ;
return ;
}
2001-05-11 00:30:12 +08:00
efree ( callback_name ) ;
2001-03-12 11:06:53 +08:00
2001-08-08 00:41:33 +08:00
if ( ZEND_NUM_ARGS ( ) > 2 ) {
2001-03-12 11:06:53 +08:00
result = * initial ;
2001-08-08 00:41:33 +08:00
zval_add_ref ( & result ) ;
}
2001-03-12 11:06:53 +08:00
if ( zend_hash_num_elements ( Z_ARRVAL_PP ( input ) ) = = 0 ) {
if ( result ) {
* return_value = * result ;
zval_copy_ctor ( return_value ) ;
}
return ;
}
2001-03-17 03:29:23 +08:00
zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
while ( zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & operand , & pos ) = = SUCCESS ) {
2001-03-12 11:06:53 +08:00
if ( result ) {
args [ 0 ] = & result ;
args [ 1 ] = operand ;
2001-07-30 16:24:42 +08:00
if ( call_user_function_ex ( EG ( function_table ) , NULL , * callback , & retval , 2 , args , 0 , NULL TSRMLS_CC ) = = SUCCESS & & retval ) {
2001-08-08 00:41:33 +08:00
zval_ptr_dtor ( & result ) ;
2001-03-12 11:06:53 +08:00
result = retval ;
} else {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " %s() had an error invoking the reduction callback " , get_active_function_name ( TSRMLS_C ) ) ;
2001-03-12 11:06:53 +08:00
return ;
}
2001-08-08 00:41:33 +08:00
} else {
2001-03-12 11:06:53 +08:00
result = * operand ;
2001-08-08 00:41:33 +08:00
zval_add_ref ( & result ) ;
}
2001-03-12 11:06:53 +08:00
2001-03-17 03:29:23 +08:00
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
2001-03-12 11:06:53 +08:00
}
* return_value = * result ;
2001-08-08 00:41:33 +08:00
zval_copy_ctor ( return_value ) ;
zval_ptr_dtor ( & result ) ;
2001-03-12 11:06:53 +08:00
}
2001-03-17 04:46:33 +08:00
/* }}} */
/* {{{ proto array array_filter(array input [, mixed callback])
Filters elements from the array via the callback . */
PHP_FUNCTION ( array_filter )
{
zval * * input , * * callback = NULL ;
zval * * operand ;
zval * * args [ 1 ] ;
zval * retval = NULL ;
char * callback_name ;
char * string_key ;
ulong string_key_len ;
ulong num_key ;
HashPosition pos ;
if ( ZEND_NUM_ARGS ( ) < 1 | | ZEND_NUM_ARGS ( ) > 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & input , & callback ) = = FAILURE ) {
WRONG_PARAM_COUNT ;
}
if ( Z_TYPE_PP ( input ) ! = IS_ARRAY ) {
php_error ( E_WARNING , " %s() expects argument 1 to be an array " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) ) ;
2001-03-17 04:46:33 +08:00
return ;
}
if ( ZEND_NUM_ARGS ( ) > 1 ) {
if ( ! zend_is_callable ( * callback , 0 , & callback_name ) ) {
php_error ( E_WARNING , " %s() expects argument 2, '%s', to be a valid callback " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) , callback_name ) ;
2001-03-17 04:46:33 +08:00
efree ( callback_name ) ;
return ;
}
2001-05-11 00:30:12 +08:00
efree ( callback_name ) ;
2001-03-17 04:46:33 +08:00
}
array_init ( return_value ) ;
if ( zend_hash_num_elements ( Z_ARRVAL_PP ( input ) ) = = 0 )
return ;
for ( zend_hash_internal_pointer_reset_ex ( Z_ARRVAL_PP ( input ) , & pos ) ;
zend_hash_get_current_data_ex ( Z_ARRVAL_PP ( input ) , ( void * * ) & operand , & pos ) = = SUCCESS ;
zend_hash_move_forward_ex ( Z_ARRVAL_PP ( input ) , & pos ) ) {
if ( callback ) {
args [ 0 ] = operand ;
2001-07-30 16:24:42 +08:00
if ( call_user_function_ex ( EG ( function_table ) , NULL , * callback , & retval , 1 , args , 0 , NULL TSRMLS_CC ) = = SUCCESS & & retval ) {
2001-03-17 04:46:33 +08:00
if ( ! zend_is_true ( retval ) ) {
zval_ptr_dtor ( & retval ) ;
continue ;
} else
zval_ptr_dtor ( & retval ) ;
} else {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " %s() had an error invoking the filter callback " , get_active_function_name ( TSRMLS_C ) ) ;
2001-03-17 04:46:33 +08:00
return ;
}
} else if ( ! zend_is_true ( * operand ) )
continue ;
zval_add_ref ( operand ) ;
switch ( zend_hash_get_current_key_ex ( Z_ARRVAL_PP ( input ) , & string_key , & string_key_len , & num_key , 0 , & pos ) ) {
case HASH_KEY_IS_STRING :
zend_hash_update ( Z_ARRVAL_P ( return_value ) , string_key ,
string_key_len , operand , sizeof ( zval * ) , NULL ) ;
break ;
case HASH_KEY_IS_LONG :
zend_hash_index_update ( Z_ARRVAL_P ( return_value ) , num_key ,
operand , sizeof ( zval * ) , NULL ) ;
break ;
}
}
}
/* }}} */
2001-03-12 11:06:53 +08:00
2001-03-20 05:20:02 +08:00
/* {{{ proto array array_map(mixed callback, array input1 [, array input2 ,...])
Applies the callback to the elements in given arrays . */
PHP_FUNCTION ( array_map )
{
zval * * * args = NULL ;
zval * * * params ;
zval * callback ;
zval * result , * null ;
char * callback_name ;
int i , k , maxlen = 0 ;
int * array_len ;
if ( ZEND_NUM_ARGS ( ) < 2 ) {
WRONG_PARAM_COUNT ;
}
args = ( zval * * * ) emalloc ( ZEND_NUM_ARGS ( ) * sizeof ( zval * * ) ) ;
if ( zend_get_parameters_array_ex ( ZEND_NUM_ARGS ( ) , args ) = = FAILURE ) {
efree ( args ) ;
WRONG_PARAM_COUNT ;
}
callback = * args [ 0 ] ;
2001-08-05 00:54:20 +08:00
if ( Z_TYPE_P ( callback ) ! = IS_NULL ) {
if ( ! zend_is_callable ( callback , 0 , & callback_name ) ) {
php_error ( E_WARNING , " %s() expects argument 1, '%s', to be either NULL or a valid callback " , get_active_function_name ( TSRMLS_C ) , callback_name ) ;
efree ( callback_name ) ;
efree ( args ) ;
return ;
}
2001-03-20 05:20:02 +08:00
efree ( callback_name ) ;
}
/* Cache array sizes. */
array_len = ( int * ) emalloc ( ( ZEND_NUM_ARGS ( ) - 1 ) * sizeof ( int ) ) ;
/* Check that arrays are indeed arrays and calculate maximum size. */
for ( i = 0 ; i < ZEND_NUM_ARGS ( ) - 1 ; i + + ) {
if ( Z_TYPE_PP ( args [ i + 1 ] ) ! = IS_ARRAY ) {
php_error ( E_WARNING , " %s() expects argument %d to be an array " ,
2001-07-30 16:24:42 +08:00
get_active_function_name ( TSRMLS_C ) , i + 2 ) ;
2001-03-20 05:20:02 +08:00
efree ( array_len ) ;
efree ( args ) ;
return ;
}
array_len [ i ] = zend_hash_num_elements ( Z_ARRVAL_PP ( args [ i + 1 ] ) ) ;
if ( array_len [ i ] > maxlen )
maxlen = array_len [ i ] ;
}
/* Short-circuit: if no callback and only one array, just return it. */
if ( Z_TYPE_P ( callback ) = = IS_NULL & & ZEND_NUM_ARGS ( ) = = 2 ) {
* return_value = * * args [ 1 ] ;
zval_copy_ctor ( return_value ) ;
efree ( array_len ) ;
efree ( args ) ;
return ;
}
array_init ( return_value ) ;
params = ( zval * * * ) emalloc ( ( ZEND_NUM_ARGS ( ) - 1 ) * sizeof ( zval * * ) ) ;
MAKE_STD_ZVAL ( null ) ;
ZVAL_NULL ( null ) ;
/* We iterate through all the arrays at once. */
for ( k = 0 ; k < maxlen ; k + + ) {
/*
* If no callback , the result will be an array , consisting of current
* entries from all arrays .
*/
if ( Z_TYPE_P ( callback ) = = IS_NULL ) {
MAKE_STD_ZVAL ( result ) ;
array_init ( result ) ;
}
for ( i = 0 ; i < ZEND_NUM_ARGS ( ) - 1 ; i + + ) {
/*
* If this array still hash elements , add the current one to the
* parameter list , otherwise use null value .
*/
if ( k < array_len [ i ] ) {
zend_hash_index_find ( Z_ARRVAL_PP ( args [ i + 1 ] ) , k , ( void * * ) & params [ i ] ) ;
} else {
if ( Z_TYPE_P ( callback ) = = IS_NULL )
zval_add_ref ( & null ) ;
params [ i ] = & null ;
}
if ( Z_TYPE_P ( callback ) = = IS_NULL )
add_next_index_zval ( result , * params [ i ] ) ;
}
if ( Z_TYPE_P ( callback ) ! = IS_NULL ) {
2001-07-30 16:24:42 +08:00
if ( ! call_user_function_ex ( EG ( function_table ) , NULL , callback , & result , ZEND_NUM_ARGS ( ) - 1 , params , 0 , NULL TSRMLS_CC ) = = SUCCESS & & result ) {
php_error ( E_WARNING , " %s() had an error invoking the map callback " , get_active_function_name ( TSRMLS_C ) ) ;
2001-03-20 05:20:02 +08:00
efree ( array_len ) ;
efree ( args ) ;
zval_dtor ( return_value ) ;
RETURN_NULL ( ) ;
}
}
add_next_index_zval ( return_value , result ) ;
}
zval_ptr_dtor ( & null ) ;
efree ( params ) ;
efree ( array_len ) ;
efree ( args ) ;
}
/* }}} */
2001-04-30 12:06:09 +08:00
/* {{{ proto bool key_exists(mixed key, array search)
Checks if the given key or index exists in the array */
PHP_FUNCTION ( key_exists )
{
zval * * key , /* key to check for */
* * array ; /* array to check in */
if ( ZEND_NUM_ARGS ( ) ! = 2 | |
zend_get_parameters_ex ( ZEND_NUM_ARGS ( ) , & key , & array ) = = FAILURE ) {
WRONG_PARAM_COUNT ;
}
if ( Z_TYPE_PP ( array ) ! = IS_ARRAY & & Z_TYPE_PP ( array ) ! = IS_OBJECT ) {
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " Wrong datatype for second argument in call to %s " , get_active_function_name ( TSRMLS_C ) ) ;
2001-04-30 12:06:09 +08:00
RETURN_FALSE ;
}
switch ( Z_TYPE_PP ( key ) ) {
case IS_STRING :
if ( zend_hash_exists ( HASH_OF ( * array ) , Z_STRVAL_PP ( key ) , Z_STRLEN_PP ( key ) + 1 ) ) {
RETURN_TRUE ;
}
RETURN_FALSE ;
case IS_LONG :
if ( zend_hash_index_exists ( HASH_OF ( * array ) , Z_LVAL_PP ( key ) ) ) {
RETURN_TRUE ;
}
RETURN_FALSE ;
default :
2001-07-30 16:24:42 +08:00
php_error ( E_WARNING , " Wrong datatype for first argument in call to %s " , get_active_function_name ( TSRMLS_C ) ) ;
2001-04-30 12:06:09 +08:00
RETURN_FALSE ;
}
}
/* }}} */
2000-02-26 05:27:03 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* End :
2001-06-06 21:06:12 +08:00
* vim600 : sw = 4 ts = 4 tw = 78 fdm = marker
* vim < 600 : sw = 4 ts = 4 tw = 78
2000-02-26 05:27:03 +08:00
*/