PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - standard - array.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 2353
Code covered: 93.6 % Executed lines: 2202
Legend: not executed executed

       1                 : /* 
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 The PHP Group                                |
       6                 :    +----------------------------------------------------------------------+
       7                 :    | This source file is subject to version 3.01 of the PHP license,      |
       8                 :    | that is bundled with this package in the file LICENSE, and is        |
       9                 :    | available through the world-wide-web at the following url:           |
      10                 :    | http://www.php.net/license/3_01.txt                                  |
      11                 :    | If you did not receive a copy of the PHP license and are unable to   |
      12                 :    | obtain it through the world-wide-web, please send a note to          |
      13                 :    | license@php.net so we can mail you a copy immediately.               |
      14                 :    +----------------------------------------------------------------------+
      15                 :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16                 :    |          Zeev Suraski <zeev@zend.com>                                |
      17                 :    |          Rasmus Lerdorf <rasmus@php.net>                             |
      18                 :    |          Andrei Zmievski <andrei@php.net>                            |
      19                 :    |          Stig Venaas <venaas@php.net>                                |
      20                 :    |          Jason Greene <jason@php.net>                                |
      21                 :    +----------------------------------------------------------------------+
      22                 : */
      23                 : 
      24                 : /* $Id: array.c 290128 2009-11-01 17:30:55Z felipe $ */
      25                 : 
      26                 : #include "php.h"
      27                 : #include "php_ini.h"
      28                 : #include <stdarg.h>
      29                 : #include <stdlib.h>
      30                 : #include <math.h>
      31                 : #include <time.h>
      32                 : #include <stdio.h>
      33                 : #if HAVE_STRING_H
      34                 : #include <string.h>
      35                 : #else
      36                 : #include <strings.h>
      37                 : #endif
      38                 : #ifdef PHP_WIN32
      39                 : #include "win32/unistd.h"
      40                 : #endif
      41                 : #include "zend_globals.h"
      42                 : #include "zend_interfaces.h"
      43                 : #include "php_globals.h"
      44                 : #include "php_array.h"
      45                 : #include "basic_functions.h"
      46                 : #include "php_string.h"
      47                 : #include "php_rand.h"
      48                 : #include "php_smart_str.h"
      49                 : #ifdef HAVE_SPL
      50                 : #include "ext/spl/spl_array.h"
      51                 : #endif
      52                 : 
      53                 : /* {{{ defines */
      54                 : #define EXTR_OVERWRITE                  0
      55                 : #define EXTR_SKIP                               1
      56                 : #define EXTR_PREFIX_SAME                2
      57                 : #define EXTR_PREFIX_ALL                 3
      58                 : #define EXTR_PREFIX_INVALID             4
      59                 : #define EXTR_PREFIX_IF_EXISTS   5
      60                 : #define EXTR_IF_EXISTS                  6
      61                 : 
      62                 : #define EXTR_REFS                               0x100
      63                 : 
      64                 : #define SORT_REGULAR                    0
      65                 : #define SORT_NUMERIC                    1
      66                 : #define SORT_STRING                             2
      67                 : #define SORT_LOCALE_STRING      5
      68                 : 
      69                 : #define SORT_DESC                               3
      70                 : #define SORT_ASC                                4
      71                 : 
      72                 : #define CASE_LOWER                              0
      73                 : #define CASE_UPPER                              1
      74                 : 
      75                 : #define COUNT_NORMAL                    0
      76                 : #define COUNT_RECURSIVE                 1
      77                 : 
      78                 : #define DIFF_NORMAL                     1
      79                 : #define DIFF_KEY                        2
      80                 : #define DIFF_ASSOC                      6
      81                 : #define DIFF_COMP_DATA_NONE    -1
      82                 : #define DIFF_COMP_DATA_INTERNAL 0
      83                 : #define DIFF_COMP_DATA_USER     1
      84                 : #define DIFF_COMP_KEY_INTERNAL  0
      85                 : #define DIFF_COMP_KEY_USER      1
      86                 : 
      87                 : #define INTERSECT_NORMAL                1
      88                 : #define INTERSECT_KEY                   2
      89                 : #define INTERSECT_ASSOC                 6
      90                 : #define INTERSECT_COMP_DATA_NONE    -1
      91                 : #define INTERSECT_COMP_DATA_INTERNAL 0
      92                 : #define INTERSECT_COMP_DATA_USER     1
      93                 : #define INTERSECT_COMP_KEY_INTERNAL  0
      94                 : #define INTERSECT_COMP_KEY_USER      1
      95                 : 
      96                 : #define DOUBLE_DRIFT_FIX        0.000000000000001
      97                 : /* }}} */
      98                 : 
      99                 : ZEND_DECLARE_MODULE_GLOBALS(array)
     100                 : 
     101                 : /* {{{ php_array_init_globals
     102                 :  */
     103                 : static void php_array_init_globals(zend_array_globals *array_globals)
     104           13565 : {
     105           13565 :         memset(array_globals, 0, sizeof(zend_array_globals));
     106           13565 : }
     107                 : /* }}} */
     108                 : 
     109                 : PHP_MINIT_FUNCTION(array) /* {{{ */
     110           13565 : {
     111           13565 :         ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL); 
     112                 : 
     113           13565 :         REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
     114           13565 :         REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
     115           13565 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
     116           13565 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
     117           13565 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
     118           13565 :         REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
     119           13565 :         REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
     120           13565 :         REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
     121                 :         
     122           13565 :         REGISTER_LONG_CONSTANT("SORT_ASC", SORT_ASC, CONST_CS | CONST_PERSISTENT);
     123           13565 :         REGISTER_LONG_CONSTANT("SORT_DESC", SORT_DESC, CONST_CS | CONST_PERSISTENT);
     124                 : 
     125           13565 :         REGISTER_LONG_CONSTANT("SORT_REGULAR", SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
     126           13565 :         REGISTER_LONG_CONSTANT("SORT_NUMERIC", SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
     127           13565 :         REGISTER_LONG_CONSTANT("SORT_STRING", SORT_STRING, CONST_CS | CONST_PERSISTENT);
     128           13565 :         REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
     129                 : 
     130           13565 :         REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
     131           13565 :         REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
     132                 : 
     133           13565 :         REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
     134           13565 :         REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
     135                 :         
     136           13565 :         return SUCCESS;
     137                 : }
     138                 : /* }}} */
     139                 : 
     140                 : PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
     141           13597 : {
     142                 : #ifdef ZTS
     143                 :         ts_free_id(array_globals_id);
     144                 : #endif
     145                 : 
     146           13597 :         return SUCCESS;
     147                 : }
     148                 : /* }}} */
     149                 : 
     150                 : static void set_compare_func(int sort_type TSRMLS_DC) /* {{{ */
     151            2202 : {
     152            2202 :         switch (sort_type) {
     153                 :                 case SORT_NUMERIC:
     154             103 :                         ARRAYG(compare_func) = numeric_compare_function;
     155             103 :                         break;
     156                 : 
     157                 :                 case SORT_STRING:
     158            1445 :                         ARRAYG(compare_func) = string_compare_function;
     159            1445 :                         break;
     160                 : 
     161                 : #if HAVE_STRCOLL
     162                 :                 case SORT_LOCALE_STRING:
     163               1 :                         ARRAYG(compare_func) = string_locale_compare_function;
     164               1 :                         break;
     165                 : #endif
     166                 : 
     167                 :                 case SORT_REGULAR:
     168                 :                 default:
     169             653 :                         ARRAYG(compare_func) = compare_function;
     170                 :                         break;
     171                 :         }
     172            2202 : }
     173                 : /* }}} */
     174                 : 
     175                 : static int array_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     176            1993 : {
     177                 :         Bucket *f;
     178                 :         Bucket *s;
     179                 :         zval result;
     180                 :         zval first;
     181                 :         zval second;
     182                 :  
     183            1993 :         f = *((Bucket **) a);
     184            1993 :         s = *((Bucket **) b);
     185                 : 
     186            1993 :         if (f->nKeyLength == 0) {
     187            1252 :                 Z_TYPE(first) = IS_LONG;
     188            1252 :                 Z_LVAL(first) = f->h;
     189                 :         } else {
     190             741 :                 Z_TYPE(first) = IS_STRING;
     191             741 :                 Z_STRVAL(first) = f->arKey;
     192             741 :                 Z_STRLEN(first) = f->nKeyLength-1;
     193                 :         }
     194                 : 
     195            1993 :         if (s->nKeyLength == 0) {
     196            1262 :                 Z_TYPE(second) = IS_LONG;
     197            1262 :                 Z_LVAL(second) = s->h;
     198                 :         } else {
     199             731 :                 Z_TYPE(second) = IS_STRING;
     200             731 :                 Z_STRVAL(second) = s->arKey;
     201             731 :                 Z_STRLEN(second) = s->nKeyLength-1;
     202                 :         }
     203                 :  
     204            1993 :         if (ARRAYG(compare_func)(&result, &first, &second TSRMLS_CC) == FAILURE) {
     205               0 :                 return 0;
     206                 :         } 
     207                 : 
     208            1993 :         if (Z_TYPE(result) == IS_DOUBLE) {
     209               0 :                 if (Z_DVAL(result) < 0) {
     210               0 :                         return -1;
     211               0 :                 } else if (Z_DVAL(result) > 0) {
     212               0 :                         return 1;
     213                 :                 } else {
     214               0 :                         return 0;
     215                 :                 }
     216                 :         }
     217                 : 
     218            1993 :         convert_to_long(&result);
     219                 : 
     220            1993 :         if (Z_LVAL(result) < 0) {
     221             886 :                 return -1;
     222            1107 :         } else if (Z_LVAL(result) > 0) {
     223            1085 :                 return 1;
     224                 :         } 
     225                 : 
     226              22 :         return 0;
     227                 : }
     228                 : /* }}} */
     229                 : 
     230                 : static int array_reverse_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     231             809 : {
     232             809 :         return array_key_compare(a, b TSRMLS_CC) * -1;
     233                 : }
     234                 : /* }}} */
     235                 : 
     236                 : /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
     237                 :    Sort an array by key value in reverse order */
     238                 : PHP_FUNCTION(krsort)
     239             188 : {
     240                 :         zval *array;
     241             188 :         long sort_type = SORT_REGULAR;
     242                 :         HashTable *target_hash;
     243                 : 
     244             188 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
     245             104 :                 RETURN_FALSE;
     246                 :         }
     247                 :         
     248              84 :         target_hash = HASH_OF(array);
     249              84 :         set_compare_func(sort_type TSRMLS_CC);
     250                 :         
     251              84 :         if (zend_hash_sort(target_hash, zend_qsort, array_reverse_key_compare, 0 TSRMLS_CC) == FAILURE) {
     252               0 :                 RETURN_FALSE;
     253                 :         }
     254              84 :         RETURN_TRUE;
     255                 : }
     256                 : /* }}} */
     257                 : 
     258                 : /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
     259                 :    Sort an array by key */
     260                 : PHP_FUNCTION(ksort)
     261             217 : {
     262                 :         zval *array;
     263             217 :         long sort_type = SORT_REGULAR;
     264                 :         HashTable *target_hash;
     265                 : 
     266             217 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
     267             104 :                 RETURN_FALSE;
     268                 :         }
     269                 : 
     270             113 :         target_hash = HASH_OF(array);
     271             113 :         set_compare_func(sort_type TSRMLS_CC);
     272                 :         
     273             113 :         if (zend_hash_sort(target_hash, zend_qsort, array_key_compare, 0 TSRMLS_CC) == FAILURE) {
     274               0 :                 RETURN_FALSE;
     275                 :         }
     276             113 :         RETURN_TRUE;
     277                 : }
     278                 : /* }}} */
     279                 : 
     280                 : static int php_count_recursive(zval *array, long mode TSRMLS_DC) /* {{{ */
     281           12307 : {
     282           12307 :         long cnt = 0;
     283                 :         zval **element;
     284                 : 
     285           12307 :         if (Z_TYPE_P(array) == IS_ARRAY) {
     286           12171 :                 if (Z_ARRVAL_P(array)->nApplyCount > 1) {
     287               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
     288               1 :                         return 0;
     289                 :                 }
     290                 : 
     291           12170 :                 cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
     292           12170 :                 if (mode == COUNT_RECURSIVE) {
     293                 :                         HashPosition pos;
     294                 : 
     295              74 :                         for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
     296             326 :                                  zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS;
     297             178 :                                  zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)) {
     298             178 :                                 Z_ARRVAL_P(array)->nApplyCount++;
     299             178 :                                 cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC);
     300             178 :                                 Z_ARRVAL_P(array)->nApplyCount--;
     301                 :                         }
     302                 :                 }
     303                 :         }
     304                 : 
     305           12306 :         return cnt;
     306                 : }
     307                 : /* }}} */
     308                 : 
     309                 : /* {{{ proto int count(mixed var [, int mode])
     310                 :    Count the number of elements in a variable (usually an array) */
     311                 : PHP_FUNCTION(count)
     312          109224 : {
     313                 :         zval *array;
     314          109224 :         long mode = COUNT_NORMAL;
     315                 :         
     316          109224 :         if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE)
     317              18 :                 return;
     318                 :         
     319          109206 :         switch (Z_TYPE_P(array)) {
     320                 :                 case IS_NULL:
     321           79157 :                         RETURN_LONG(0);
     322                 :                         break;
     323                 :                 case IS_ARRAY:
     324           12129 :                         RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));
     325                 :                         break;
     326                 :                 case IS_OBJECT: {
     327                 : #ifdef HAVE_SPL
     328                 :                         /* it the object implements Countable we call its count() method */
     329                 :                         zval *retval;
     330                 : 
     331              68 :                         if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Countable TSRMLS_CC)) {
     332              33 :                                 zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);
     333              33 :                                 if (retval) {
     334              32 :                                         convert_to_long_ex(&retval);
     335              32 :                                         RETVAL_LONG(Z_LVAL_P(retval));
     336              32 :                                         zval_ptr_dtor(&retval);
     337                 :                                 }
     338              33 :                                 return;
     339                 :                         }
     340                 : #endif
     341                 :                         /* if not we return the number of properties (not taking visibility into account) */
     342              35 :                         if (Z_OBJ_HT_P(array)->count_elements) {
     343              19 :                                 RETVAL_LONG(1);
     344              19 :                                 if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {
     345              18 :                                         return;
     346                 :                                 }
     347                 :                         }
     348                 :                 }
     349                 :                 default:
     350           17869 :                         RETURN_LONG(1);
     351                 :                         break;
     352                 :         }
     353                 : }
     354                 : /* }}} */
     355                 : 
     356                 : /* Numbers are always smaller than strings int this function as it
     357                 :  * anyway doesn't make much sense to compare two different data types.
     358                 :  * This keeps it consistant and simple.
     359                 :  *
     360                 :  * This is not correct any more, depends on what compare_func is set to.
     361                 :  */
     362                 : static int array_data_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     363          639567 : {
     364                 :         Bucket *f;
     365                 :         Bucket *s;
     366                 :         zval result;
     367                 :         zval *first;
     368                 :         zval *second;
     369                 :  
     370          639567 :         f = *((Bucket **) a);
     371          639567 :         s = *((Bucket **) b);
     372                 :  
     373          639567 :         first = *((zval **) f->pData);
     374          639567 :         second = *((zval **) s->pData);
     375                 : 
     376          639567 :         if (ARRAYG(compare_func)(&result, first, second TSRMLS_CC) == FAILURE) {
     377               0 :                 return 0;
     378                 :         } 
     379                 : 
     380          639567 :         if (Z_TYPE(result) == IS_DOUBLE) {
     381               0 :                 if (Z_DVAL(result) < 0) {
     382               0 :                         return -1;
     383               0 :                 } else if (Z_DVAL(result) > 0) {
     384               0 :                         return 1;
     385                 :                 } else {
     386               0 :                         return 0;
     387                 :                 }
     388                 :         }
     389                 : 
     390          639567 :         convert_to_long(&result);
     391                 : 
     392          639567 :         if (Z_LVAL(result) < 0) {
     393           69772 :                 return -1;
     394          569795 :         } else if (Z_LVAL(result) > 0) {
     395          556717 :                 return 1;
     396                 :         } 
     397                 : 
     398           13078 :         return 0;
     399                 : }
     400                 : /* }}} */
     401                 : 
     402                 : static int array_reverse_data_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     403            1994 : {
     404            1994 :         return array_data_compare(a, b TSRMLS_CC)*-1;
     405                 : }
     406                 : /* }}} */
     407                 : 
     408                 : static int array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
     409             455 : {
     410                 :         Bucket *f, *s;
     411                 :         zval *fval, *sval;
     412                 :         zval first, second;
     413                 :         int result;
     414                 :  
     415             455 :         f = *((Bucket **) a);
     416             455 :         s = *((Bucket **) b);
     417                 :  
     418             455 :         fval = *((zval **) f->pData);
     419             455 :         sval = *((zval **) s->pData);
     420             455 :         first = *fval;
     421             455 :         second = *sval;
     422             455 :         if (Z_TYPE_P(fval) != IS_STRING) {
     423             214 :                 zval_copy_ctor(&first);
     424             214 :                 convert_to_string(&first);
     425                 :         }
     426             455 :         if (Z_TYPE_P(sval) != IS_STRING) {
     427             214 :                 zval_copy_ctor(&second);
     428             214 :                 convert_to_string(&second);
     429                 :         }
     430                 : 
     431             455 :         result = strnatcmp_ex(Z_STRVAL(first), Z_STRLEN(first), Z_STRVAL(second), Z_STRLEN(second), fold_case);
     432                 : 
     433             455 :         if (Z_TYPE_P(fval) != IS_STRING)
     434             214 :                 zval_dtor(&first);
     435             455 :         if (Z_TYPE_P(sval) != IS_STRING)
     436             214 :                 zval_dtor(&second);
     437                 :         
     438             455 :         return result;
     439                 : }
     440                 : /* }}} */
     441                 : 
     442                 : static int array_natural_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     443              59 : {
     444              59 :         return array_natural_general_compare(a, b, 0);
     445                 : }
     446                 : /* }}} */
     447                 : 
     448                 : static int array_natural_case_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     449             396 : {
     450             396 :         return array_natural_general_compare(a, b, 1);
     451                 : }
     452                 : /* }}} */
     453                 : 
     454                 : static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
     455              77 : {
     456                 :         zval **array;
     457                 :         HashTable *target_hash;
     458                 : 
     459              77 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
     460               2 :                 WRONG_PARAM_COUNT;
     461                 :         }
     462                 : 
     463              75 :         target_hash = HASH_OF(*array);
     464              75 :         if (!target_hash) {
     465              23 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
     466              23 :                 return;
     467                 :         }
     468                 : 
     469              52 :         if (fold_case) {
     470              47 :                 if (zend_hash_sort(target_hash, zend_qsort, array_natural_case_compare, 0 TSRMLS_CC) == FAILURE) {
     471               0 :                         return;
     472                 :                 }
     473                 :         } else {
     474               5 :                 if (zend_hash_sort(target_hash, zend_qsort, array_natural_compare, 0 TSRMLS_CC) == FAILURE) {
     475               0 :                         return;
     476                 :                 }
     477                 :         }
     478                 : 
     479              52 :         RETURN_TRUE;
     480                 : }
     481                 : /* }}} */
     482                 : 
     483                 : /* {{{ proto void natsort(array &array_arg)
     484                 :    Sort an array using natural sort */
     485                 : PHP_FUNCTION(natsort)
     486               5 : {
     487               5 :         php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
     488               5 : }
     489                 : /* }}} */
     490                 : 
     491                 : /* {{{ proto void natcasesort(array &array_arg)
     492                 :    Sort an array using case-insensitive natural sort */
     493                 : PHP_FUNCTION(natcasesort)
     494              72 : {
     495              72 :         php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     496              72 : }
     497                 : /* }}} */
     498                 : 
     499                 : /* {{{ proto bool asort(array &array_arg [, int sort_flags])
     500                 :    Sort an array and maintain index association */
     501                 : PHP_FUNCTION(asort)
     502             195 : {
     503                 :         zval *array;
     504             195 :         long sort_type = SORT_REGULAR;
     505                 :         HashTable *target_hash;
     506                 : 
     507             195 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
     508             104 :                 RETURN_FALSE;
     509                 :         }
     510                 :         
     511              91 :         target_hash = HASH_OF(array);
     512              91 :         set_compare_func(sort_type TSRMLS_CC);
     513                 :         
     514              91 :         if (zend_hash_sort(target_hash, zend_qsort, array_data_compare, 0 TSRMLS_CC) == FAILURE) {
     515               0 :                 RETURN_FALSE;
     516                 :         }
     517              91 :         RETURN_TRUE;
     518                 : }
     519                 : /* }}} */
     520                 : 
     521                 : /* {{{ proto bool arsort(array &array_arg [, int sort_flags])
     522                 :    Sort an array in reverse order and maintain index association */
     523                 : PHP_FUNCTION(arsort)
     524             181 : {
     525                 :         zval *array;
     526             181 :         long sort_type = SORT_REGULAR;
     527                 :         HashTable *target_hash;
     528                 : 
     529             181 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
     530             104 :                 RETURN_FALSE;
     531                 :         }
     532                 :         
     533              77 :         target_hash = HASH_OF(array);
     534              77 :         set_compare_func(sort_type TSRMLS_CC);
     535                 :         
     536              77 :         if (zend_hash_sort(target_hash, zend_qsort, array_reverse_data_compare, 0 TSRMLS_CC) == FAILURE) {
     537               0 :                 RETURN_FALSE;
     538                 :         }
     539              77 :         RETURN_TRUE;
     540                 : }
     541                 : /* }}} */
     542                 : 
     543                 : /* {{{ proto bool sort(array &array_arg [, int sort_flags])
     544                 :    Sort an array */
     545                 : PHP_FUNCTION(sort)
     546             211 : {
     547                 :         zval *array;
     548             211 :         long sort_type = SORT_REGULAR;
     549                 :         HashTable *target_hash;
     550                 : 
     551             211 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
     552             104 :                 RETURN_FALSE;
     553                 :         }
     554                 :         
     555             107 :         target_hash = HASH_OF(array);
     556             107 :         set_compare_func(sort_type TSRMLS_CC);
     557                 :         
     558             107 :         if (zend_hash_sort(target_hash, zend_qsort, array_data_compare, 1 TSRMLS_CC) == FAILURE) {
     559               0 :                 RETURN_FALSE;
     560                 :         }
     561             107 :         RETURN_TRUE;
     562                 : }
     563                 : /* }}} */
     564                 : 
     565                 : /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
     566                 :    Sort an array in reverse order */
     567                 : PHP_FUNCTION(rsort)
     568             191 : {
     569                 :         zval *array;
     570             191 :         long sort_type = SORT_REGULAR;
     571                 :         HashTable *target_hash;
     572                 : 
     573             191 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
     574             105 :                 RETURN_FALSE;
     575                 :         }
     576                 :         
     577              86 :         target_hash = HASH_OF(array);
     578              86 :         set_compare_func(sort_type TSRMLS_CC);
     579                 :         
     580              86 :         if (zend_hash_sort(target_hash, zend_qsort, array_reverse_data_compare, 1 TSRMLS_CC) == FAILURE) {
     581               0 :                 RETURN_FALSE;
     582                 :         }
     583              86 :         RETURN_TRUE;
     584                 : }
     585                 : /* }}} */
     586                 : 
     587                 : static int array_user_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     588          145058 : {
     589                 :         Bucket *f;
     590                 :         Bucket *s;
     591                 :         zval **args[2];
     592                 :         zval *retval_ptr;
     593                 :         zend_fcall_info fci;
     594                 : 
     595          145058 :         f = *((Bucket **) a);
     596          145058 :         s = *((Bucket **) b);
     597                 : 
     598          145058 :         args[0] = (zval **) f->pData;
     599          145058 :         args[1] = (zval **) s->pData;
     600                 : 
     601          145058 :         fci.size = sizeof(fci);
     602          145058 :         fci.function_table = EG(function_table);
     603          145058 :         fci.function_name = *BG(user_compare_func_name);
     604          145058 :         fci.symbol_table = NULL;
     605          145058 :         fci.object_pp = NULL;
     606          145058 :         fci.retval_ptr_ptr = &retval_ptr;
     607          145058 :         fci.param_count = 2;
     608          145058 :         fci.params = args;
     609          145058 :         fci.no_separation = 0;
     610                 : 
     611          145058 :         if (zend_call_function(&fci, &BG(user_compare_fci_cache) TSRMLS_CC)== SUCCESS
     612                 :                 && retval_ptr) {
     613                 :                 long retval;
     614                 : 
     615          145058 :                 convert_to_long_ex(&retval_ptr);
     616          145058 :                 retval = Z_LVAL_P(retval_ptr);
     617          145058 :                 zval_ptr_dtor(&retval_ptr);
     618          145058 :                 return retval < 0 ? -1 : retval > 0 ? 1 : 0;;
     619                 :         } else {
     620               0 :                 return 0;
     621                 :         }
     622                 : }
     623                 : /* }}} */
     624                 : 
     625                 : /* check if comparison function is valid */
     626                 : #define PHP_ARRAY_CMP_FUNC_CHECK(func_name)     \
     627                 :         if (!zend_is_callable(*func_name, 0, NULL)) {   \
     628                 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid comparison function");   \
     629                 :         BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
     630                 :                 BG(user_compare_func_name) = old_compare_func;  \
     631                 :                 RETURN_FALSE;   \
     632                 :         }       \
     633                 : 
     634                 :     /* clear FCI cache otherwise : for example the same or other array with
     635                 :        (partly) the same key values has been sorted with uasort() or
     636                 :        other sorting function the comparison is cached, however the the name
     637                 :        of the function for comparison is not respected. see bug #28739 AND #33295
     638                 : 
     639                 :        following defines will assist in backup / restore values.
     640                 :     */
     641                 : 
     642                 : #define PHP_ARRAY_CMP_FUNC_VARS \
     643                 :     zval **old_compare_func; \
     644                 :     zend_fcall_info_cache old_user_compare_fci_cache \
     645                 : 
     646                 : #define PHP_ARRAY_CMP_FUNC_BACKUP() \
     647                 :     old_compare_func = BG(user_compare_func_name); \
     648                 :     old_user_compare_fci_cache = BG(user_compare_fci_cache); \
     649                 :     BG(user_compare_fci_cache) = empty_fcall_info_cache; \
     650                 : 
     651                 : #define PHP_ARRAY_CMP_FUNC_RESTORE() \
     652                 :         BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
     653                 :         BG(user_compare_func_name) = old_compare_func; \
     654                 : 
     655                 : /* {{{ proto bool usort(array array_arg, string cmp_function)
     656                 :    Sort an array by values using a user-defined comparison function */
     657                 : PHP_FUNCTION(usort)
     658              95 : {
     659                 :         zval **array;
     660                 :         int refcount;
     661                 :         HashTable *target_hash;
     662                 :         PHP_ARRAY_CMP_FUNC_VARS;
     663                 : 
     664              95 :         PHP_ARRAY_CMP_FUNC_BACKUP();
     665                 : 
     666                 : 
     667              95 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &array, &BG(user_compare_func_name)) == FAILURE) {
     668               3 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     669               3 :                 WRONG_PARAM_COUNT;
     670                 :         }
     671                 : 
     672              92 :         target_hash = HASH_OF(*array);
     673              92 :         if (!target_hash) {
     674              23 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
     675              23 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     676              23 :                 RETURN_FALSE;
     677                 :         }
     678                 : 
     679              69 :         PHP_ARRAY_CMP_FUNC_CHECK(BG(user_compare_func_name))
     680              38 :         BG(user_compare_fci_cache).initialized = 0;
     681                 :         
     682                 :         /* Clear the is_ref flag, so the attemts to modify the array in user
     683                 :          * comaprison function will create a copy of array and won't affect the
     684                 :          * original array. The fact of modification is detected using refcount
     685                 :          * comparison. The result of sorting in such case is undefined and the
     686                 :          * function returns FALSE.
     687                 :          */
     688              38 :         (*array)->is_ref = 0;
     689              38 :         refcount = (*array)->refcount;
     690                 : 
     691              38 :         if (zend_hash_sort(target_hash, zend_qsort, array_user_compare, 1 TSRMLS_CC) == FAILURE) {
     692               0 :                 RETVAL_FALSE;
     693                 :         } else {
     694              38 :                 if (refcount > (*array)->refcount) {
     695               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
     696               1 :                         RETVAL_FALSE;
     697                 :                 } else {
     698              37 :                         RETVAL_TRUE;
     699                 :                 }
     700                 :         }
     701                 : 
     702              38 :         if ((*array)->refcount > 1) {
     703              37 :                 (*array)->is_ref = 1;
     704                 :         }
     705                 :         
     706              38 :         PHP_ARRAY_CMP_FUNC_RESTORE();
     707                 : }
     708                 : /* }}} */
     709                 : 
     710                 : /* {{{ proto bool uasort(array array_arg, string cmp_function)
     711                 :    Sort an array with a user-defined comparison function and maintain index association */
     712                 : PHP_FUNCTION(uasort)
     713              91 : {
     714                 :         zval **array;
     715                 :         int refcount;
     716                 :         HashTable *target_hash;
     717                 :         PHP_ARRAY_CMP_FUNC_VARS;
     718                 : 
     719              91 :         PHP_ARRAY_CMP_FUNC_BACKUP();
     720                 : 
     721              91 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &array, &BG(user_compare_func_name)) == FAILURE) {
     722               4 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     723               4 :                 WRONG_PARAM_COUNT;
     724                 :         }
     725              87 :         target_hash = HASH_OF(*array);
     726              87 :         if (!target_hash) {
     727              22 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
     728              22 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     729              22 :                 RETURN_FALSE;
     730                 :         }
     731                 : 
     732              65 :         PHP_ARRAY_CMP_FUNC_CHECK(BG(user_compare_func_name))
     733              34 :         BG(user_compare_fci_cache).initialized = 0;
     734                 : 
     735                 :         /* Clear the is_ref flag, so the attemts to modify the array in user
     736                 :          * comaprison function will create a copy of array and won't affect the
     737                 :          * original array. The fact of modification is detected using refcount
     738                 :          * comparison. The result of sorting in such case is undefined and the
     739                 :          * function returns FALSE.
     740                 :          */
     741              34 :         (*array)->is_ref = 0;
     742              34 :         refcount = (*array)->refcount;
     743                 : 
     744              34 :         if (zend_hash_sort(target_hash, zend_qsort, array_user_compare, 0 TSRMLS_CC) == FAILURE) {
     745               0 :                 RETVAL_FALSE;
     746                 :         } else {
     747              34 :                 if (refcount > (*array)->refcount) {
     748               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
     749               0 :                         RETVAL_FALSE;
     750                 :                 } else {
     751              34 :                         RETVAL_TRUE;
     752                 :                 }
     753                 :         }
     754                 : 
     755              34 :         if ((*array)->refcount > 1) {
     756              34 :                 (*array)->is_ref = 1;
     757                 :         }
     758                 : 
     759              34 :         PHP_ARRAY_CMP_FUNC_RESTORE();
     760                 : }
     761                 : /* }}} */
     762                 : 
     763                 : static int array_user_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
     764            4831 : {
     765                 :         zend_fcall_info fci;
     766                 :         Bucket *f;
     767                 :         Bucket *s;
     768                 :         zval *key1, *key2;
     769                 :         zval **args[2];
     770            4831 :         zval *retval_ptr = NULL;
     771                 : 
     772            4831 :         ALLOC_INIT_ZVAL(key1);
     773            4831 :         ALLOC_INIT_ZVAL(key2);
     774            4831 :         args[0] = &key1;
     775            4831 :         args[1] = &key2;
     776                 :         
     777            4831 :         f = *((Bucket **) a);
     778            4831 :         s = *((Bucket **) b);
     779                 : 
     780            4831 :         if (f->nKeyLength) {
     781            2617 :                 Z_STRVAL_P(key1) = estrndup(f->arKey, f->nKeyLength-1);
     782            2617 :                 Z_STRLEN_P(key1) = f->nKeyLength-1;
     783            2617 :                 Z_TYPE_P(key1) = IS_STRING;
     784                 :         } else {
     785            2214 :                 Z_LVAL_P(key1) = f->h;
     786            2214 :                 Z_TYPE_P(key1) = IS_LONG;
     787                 :         }
     788            4831 :         if (s->nKeyLength) {
     789            2609 :                 Z_STRVAL_P(key2) = estrndup(s->arKey, s->nKeyLength-1);
     790            2609 :                 Z_STRLEN_P(key2) = s->nKeyLength-1;
     791            2609 :                 Z_TYPE_P(key2) = IS_STRING;
     792                 :         } else {
     793            2222 :                 Z_LVAL_P(key2) = s->h;
     794            2222 :                 Z_TYPE_P(key2) = IS_LONG;
     795                 :         }
     796                 :         
     797            4831 :         fci.size = sizeof(fci);
     798            4831 :         fci.function_table = EG(function_table);
     799            4831 :         fci.function_name = *BG(user_compare_func_name);
     800            4831 :         fci.symbol_table = NULL;
     801            4831 :         fci.object_pp = NULL;
     802            4831 :         fci.retval_ptr_ptr = &retval_ptr;
     803            4831 :         fci.param_count = 2;
     804            4831 :         fci.params = args;
     805            4831 :         fci.no_separation = 0;
     806                 : 
     807            4831 :         if (zend_call_function(&fci, &BG(user_compare_fci_cache) TSRMLS_CC)== SUCCESS
     808                 :                 && retval_ptr) {
     809                 :                 long retval;
     810                 : 
     811            4831 :                 convert_to_long_ex(&retval_ptr);
     812            4831 :                 retval = Z_LVAL_P(retval_ptr);
     813            4831 :                 zval_ptr_dtor(&retval_ptr);
     814            4831 :                 zval_ptr_dtor(&key1);
     815            4831 :                 zval_ptr_dtor(&key2);
     816            4831 :                 return retval;
     817                 :         } else {
     818               0 :                 zval_ptr_dtor(&key1);
     819               0 :                 zval_ptr_dtor(&key2);
     820               0 :                 return 0;
     821                 :         }
     822                 : }
     823                 : /* }}} */
     824                 : 
     825                 : /* {{{ proto bool uksort(array array_arg, string cmp_function)
     826                 :    Sort an array by keys using a user-defined comparison function */
     827                 : PHP_FUNCTION(uksort)
     828              58 : {
     829                 :         zval **array;
     830                 :         HashTable *target_hash;
     831                 :         PHP_ARRAY_CMP_FUNC_VARS;
     832                 : 
     833                 : 
     834              58 :         PHP_ARRAY_CMP_FUNC_BACKUP();
     835                 : 
     836              58 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &array, &BG(user_compare_func_name)) == FAILURE) {
     837               3 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     838               3 :                 WRONG_PARAM_COUNT;
     839                 :         }
     840              55 :         target_hash = HASH_OF(*array);
     841              55 :         if (!target_hash) {
     842              23 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
     843              23 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     844                 : 
     845              23 :                 RETURN_FALSE;
     846                 :         }
     847                 : 
     848              32 :         PHP_ARRAY_CMP_FUNC_CHECK(BG(user_compare_func_name))
     849               5 :         BG(user_compare_fci_cache).initialized = 0;
     850                 : 
     851               5 :         if (zend_hash_sort(target_hash, zend_qsort, array_user_key_compare, 0 TSRMLS_CC) == FAILURE) {
     852               0 :                 PHP_ARRAY_CMP_FUNC_RESTORE();
     853                 : 
     854               0 :                 RETURN_FALSE;
     855                 :         }
     856                 : 
     857               5 :         PHP_ARRAY_CMP_FUNC_RESTORE();
     858               5 :         RETURN_TRUE;
     859                 : }
     860                 : /* }}} */
     861                 : 
     862                 : /* {{{ proto mixed end(array array_arg)
     863                 :    Advances array argument's internal pointer to the last element and return it */
     864                 : PHP_FUNCTION(end)
     865              74 : {
     866                 :         zval **array, **entry;
     867                 :         HashTable *target_hash;
     868                 : 
     869              74 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
     870               4 :                 WRONG_PARAM_COUNT;
     871                 :         }
     872              70 :         target_hash = HASH_OF(*array);
     873              70 :         if (!target_hash) {
     874              25 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passed variable is not an array or object");
     875              25 :                 RETURN_FALSE;
     876                 :         }
     877              45 :         zend_hash_internal_pointer_end(target_hash);
     878                 : 
     879              45 :         if (return_value_used) {        
     880              33 :                 if (zend_hash_get_current_data(target_hash, (void **) &entry) == FAILURE) {
     881               2 :                         RETURN_FALSE;
     882                 :                 }
     883                 : 
     884              31 :                 RETURN_ZVAL(*entry, 1, 0);
     885                 :         }
     886                 : }
     887                 : /* }}} */
     888                 : 
     889                 : /* {{{ proto mixed prev(array array_arg)
     890                 :    Move array argument's internal pointer to the previous element and return it */
     891                 : PHP_FUNCTION(prev)
     892              43 : {
     893                 :         zval **array, **entry;
     894                 :         HashTable *target_hash;
     895                 : 
     896              43 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
     897               2 :                 WRONG_PARAM_COUNT;
     898                 :         }
     899              41 :         target_hash = HASH_OF(*array);
     900              41 :         if (!target_hash) {
     901              23 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passed variable is not an array or object");
     902              23 :                 RETURN_FALSE;
     903                 :         }
     904              18 :         zend_hash_move_backwards(target_hash);
     905                 : 
     906              18 :         if (return_value_used) {        
     907              18 :                 if (zend_hash_get_current_data(target_hash, (void **) &entry) == FAILURE) {
     908               6 :                         RETURN_FALSE;
     909                 :                 }
     910                 :         
     911              12 :                 RETURN_ZVAL(*entry, 1, 0);
     912                 :         }
     913                 : }
     914                 : /* }}} */
     915                 : 
     916                 : /* {{{ proto mixed next(array array_arg)
     917                 :    Move array argument's internal pointer to the next element and return it */
     918                 : PHP_FUNCTION(next)
     919             552 : {
     920                 :         zval **array, **entry;
     921                 :         HashTable *target_hash;
     922                 : 
     923             552 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
     924               4 :                 WRONG_PARAM_COUNT;
     925                 :         }
     926             548 :         target_hash = HASH_OF(*array);
     927             548 :         if (!target_hash) {
     928              27 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passed variable is not an array or object");
     929              27 :                 RETURN_FALSE;
     930                 :         }
     931             521 :         zend_hash_move_forward(target_hash);
     932                 : 
     933             521 :         if (return_value_used) {
     934             485 :                 if (zend_hash_get_current_data(target_hash, (void **) &entry) == FAILURE) {
     935              93 :                         RETURN_FALSE;
     936                 :                 }
     937                 : 
     938             392 :                 RETURN_ZVAL(*entry, 1, 0);
     939                 :         }
     940                 : }
     941                 : /* }}} */
     942                 : 
     943                 : /* {{{ proto mixed reset(array array_arg)
     944                 :    Set array argument's internal pointer to the first element and return it */  
     945                 : PHP_FUNCTION(reset)
     946             141 : {
     947                 :         zval **array, **entry;
     948                 :         HashTable *target_hash;
     949                 : 
     950             141 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
     951               4 :                 WRONG_PARAM_COUNT;
     952                 :         }
     953             137 :         target_hash = HASH_OF(*array);
     954             137 :         if (!target_hash) {
     955              27 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passed variable is not an array or object");
     956              27 :                 RETURN_FALSE;
     957                 :         }
     958             110 :         zend_hash_internal_pointer_reset(target_hash);
     959                 : 
     960             110 :         if (return_value_used) {        
     961              27 :                 if (zend_hash_get_current_data(target_hash, (void **) &entry) == FAILURE) {
     962               5 :                         RETURN_FALSE;
     963                 :                 }
     964                 : 
     965              22 :                 RETURN_ZVAL(*entry, 1, 0);
     966                 :         }
     967                 : }
     968                 : /* }}} */
     969                 : 
     970                 : /* {{{ proto mixed current(array array_arg)
     971                 :    Return the element currently pointed to by the internal array pointer */
     972                 : PHP_FUNCTION(current)
     973             603 : {
     974                 :         zval **array, **entry;
     975                 :         HashTable *target_hash;
     976                 : 
     977             603 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
     978               4 :                 WRONG_PARAM_COUNT;
     979                 :         }
     980             599 :         target_hash = HASH_OF(*array);
     981             599 :         if (!target_hash) {
     982              27 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passed variable is not an array or object");
     983              27 :                 RETURN_FALSE;
     984                 :         }
     985             572 :         if (zend_hash_get_current_data(target_hash, (void **) &entry) == FAILURE) {
     986              23 :                 RETURN_FALSE;
     987                 :         }
     988             549 :         RETURN_ZVAL(*entry, 1, 0);
     989                 : }
     990                 : /* }}} */
     991                 : 
     992                 : /* {{{ proto mixed key(array array_arg)
     993                 :    Return the key of the element currently pointed to by the internal array pointer */
     994                 : PHP_FUNCTION(key)
     995             643 : {
     996                 :         zval **array;
     997                 :         char *string_key;
     998                 :         uint string_length;
     999                 :         ulong num_key;
    1000                 :         HashTable *target_hash;
    1001                 : 
    1002             643 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
    1003               4 :                 WRONG_PARAM_COUNT;
    1004                 :         }
    1005             639 :         target_hash = HASH_OF(*array);
    1006             639 :         if (!target_hash) {
    1007              27 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passed variable is not an array or object");
    1008              27 :                 RETURN_FALSE;
    1009                 :         }
    1010             612 :         switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_length, &num_key, 0, NULL)) {
    1011                 :                 case HASH_KEY_IS_STRING:
    1012              48 :                         RETVAL_STRINGL(string_key, string_length - 1, 1);
    1013              48 :                         break;
    1014                 :                 case HASH_KEY_IS_LONG:
    1015             527 :                         RETVAL_LONG(num_key);
    1016             527 :                         break;
    1017                 :                 case HASH_KEY_NON_EXISTANT:
    1018              37 :                         return;
    1019                 :         }
    1020                 : }
    1021                 : /* }}} */
    1022                 : 
    1023                 : /* {{{ proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
    1024                 :    Return the lowest value in an array or a series of arguments */
    1025                 : PHP_FUNCTION(min)
    1026              53 : {
    1027              53 :         int argc=ZEND_NUM_ARGS();
    1028                 :         zval **result;
    1029                 : 
    1030              53 :         if (argc<=0) {
    1031               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "At least one value should be passed");
    1032               2 :                 RETURN_NULL();
    1033                 :         }
    1034              51 :         set_compare_func(SORT_REGULAR TSRMLS_CC);
    1035              51 :         if (argc == 1) {
    1036                 :                 zval **arr;
    1037                 : 
    1038              21 :                 if (zend_get_parameters_ex(1, &arr) == FAILURE || Z_TYPE_PP(arr) != IS_ARRAY) {
    1039               4 :                         WRONG_PARAM_COUNT;
    1040                 :                 }
    1041              17 :                 if (zend_hash_minmax(Z_ARRVAL_PP(arr), array_data_compare, 0, (void **) &result TSRMLS_CC) == SUCCESS) {
    1042              15 :                         RETVAL_ZVAL(*result, 1, 0);
    1043                 :                 } else {
    1044               2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
    1045               2 :                         RETURN_FALSE;
    1046                 :                 }
    1047                 :         } else {
    1048              30 :                 zval ***args = (zval ***) safe_emalloc(sizeof(zval **), ZEND_NUM_ARGS(), 0);
    1049                 :                 zval **min, result;
    1050                 :                 int i;
    1051                 : 
    1052              30 :                 if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args)==FAILURE) {
    1053               0 :                         efree(args);
    1054               0 :                         WRONG_PARAM_COUNT;
    1055                 :                 }
    1056                 : 
    1057              30 :                 min = args[0];
    1058                 : 
    1059            1311 :                 for (i=1; i<ZEND_NUM_ARGS(); i++) {
    1060            1281 :                         is_smaller_function(&result, *args[i], *min TSRMLS_CC);
    1061            1281 :                         if (Z_LVAL(result) == 1) {
    1062              13 :                                 min = args[i];
    1063                 :                         }
    1064                 :                 }
    1065                 : 
    1066              30 :                 RETVAL_ZVAL(*min, 1, 0);
    1067                 : 
    1068              30 :                 efree(args);
    1069                 :         }
    1070                 : }
    1071                 : /* }}} */
    1072                 : 
    1073                 : /* {{{ proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
    1074                 :    Return the highest value in an array or a series of arguments */
    1075                 : PHP_FUNCTION(max)
    1076              91 : {
    1077              91 :         int argc=ZEND_NUM_ARGS();
    1078                 :         zval **result;
    1079                 : 
    1080              91 :         if (argc<=0) {
    1081               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "At least one value should be passed");
    1082               2 :                 RETURN_NULL();
    1083                 :         }
    1084              89 :         set_compare_func(SORT_REGULAR TSRMLS_CC);
    1085              89 :         if (argc == 1) {
    1086                 :                 zval **arr;
    1087                 : 
    1088              65 :                 if (zend_get_parameters_ex(1, &arr) == FAILURE || Z_TYPE_PP(arr) != IS_ARRAY) {
    1089               4 :                         WRONG_PARAM_COUNT;
    1090                 :                 }
    1091              61 :                 if (zend_hash_minmax(Z_ARRVAL_PP(arr), array_data_compare, 1, (void **) &result TSRMLS_CC) == SUCCESS) {
    1092              59 :                         RETVAL_ZVAL(*result, 1, 0);
    1093                 :                 } else {
    1094               2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
    1095               2 :                         RETURN_FALSE;
    1096                 :                 }
    1097                 :         } else {
    1098              24 :                 zval ***args = (zval ***) safe_emalloc(sizeof(zval **), ZEND_NUM_ARGS(), 0);
    1099                 :                 zval **max, result;
    1100                 :                 int i;
    1101                 : 
    1102              24 :                 if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
    1103               0 :                         efree(args);
    1104               0 :                         WRONG_PARAM_COUNT;
    1105                 :                 }
    1106                 : 
    1107              24 :                 max = args[0];
    1108                 : 
    1109            1299 :                 for (i=1; i<ZEND_NUM_ARGS(); i++) {
    1110            1275 :                         is_smaller_or_equal_function(&result, *args[i], *max TSRMLS_CC);
    1111            1275 :                         if (Z_LVAL(result) == 0) {
    1112              40 :                                 max = args[i];
    1113                 :                         }
    1114                 :                 }
    1115                 : 
    1116              24 :                 RETVAL_ZVAL(*max, 1, 0);
    1117              24 :                 efree(args);
    1118                 :         }
    1119                 : }
    1120                 : /* }}} */
    1121                 : 
    1122                 : static int php_array_walk(HashTable *target_hash, zval **userdata, int recursive TSRMLS_DC) /* {{{ */
    1123             271 : {
    1124                 :         zval **args[3],                 /* Arguments to userland function */
    1125                 :                   *retval_ptr,                  /* Return value - unused */
    1126             271 :                   *key=NULL;                            /* Entry key */
    1127                 :         char  *string_key;
    1128                 :         uint   string_key_len;
    1129                 :         ulong  num_key;
    1130                 :         HashPosition pos;
    1131             271 :         zend_fcall_info_cache array_walk_fci_cache = empty_fcall_info_cache;
    1132                 : 
    1133                 :         /* Set up known arguments */
    1134             271 :         args[1] = &key;
    1135             271 :         args[2] = userdata;
    1136                 : 
    1137             271 :         zend_hash_internal_pointer_reset_ex(target_hash, &pos);
    1138                 : 
    1139                 :         /* Iterate through hash */
    1140            1353 :         while (!EG(exception) && zend_hash_get_current_data_ex(target_hash, (void **)&args[0], &pos) == SUCCESS) {
    1141             946 :                 if (recursive && Z_TYPE_PP(args[0]) == IS_ARRAY) {
    1142                 :                         HashTable *thash;
    1143                 :                         
    1144             105 :                         SEPARATE_ZVAL_IF_NOT_REF(args[0]);
    1145             105 :                         thash = HASH_OF(*(args[0]));
    1146             105 :                         if (thash->nApplyCount > 1) {
    1147               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
    1148               0 :                                 return 0;
    1149                 :                         }
    1150             105 :                         thash->nApplyCount++;
    1151             105 :                         php_array_walk(thash, userdata, recursive TSRMLS_CC);
    1152             105 :                         thash->nApplyCount--;
    1153                 :                 } else {
    1154                 :                         zend_fcall_info fci;
    1155                 : 
    1156                 :                         /* Allocate space for key */
    1157             736 :                         MAKE_STD_ZVAL(key);
    1158                 : 
    1159                 :                         /* Set up the key */
    1160             736 :                         if (zend_hash_get_current_key_ex(target_hash, &string_key, &string_key_len, &num_key, 0, &pos) == HASH_KEY_IS_LONG) {
    1161             342 :                                 Z_TYPE_P(key) = IS_LONG;
    1162             342 :                                 Z_LVAL_P(key) = num_key;
    1163                 :                         } else {
    1164             394 :                                 ZVAL_STRINGL(key, string_key, string_key_len-1, 1);
    1165                 :                         }
    1166                 : 
    1167             736 :                         fci.size = sizeof(fci);
    1168             736 :                         fci.function_table = EG(function_table);
    1169             736 :                         fci.function_name = *BG(array_walk_func_name);
    1170             736 :                         fci.symbol_table = NULL;
    1171             736 :                         fci.object_pp = NULL;
    1172             736 :                         fci.retval_ptr_ptr = &retval_ptr;
    1173             736 :                         fci.param_count = userdata ? 3 : 2;
    1174             736 :                         fci.params = args;
    1175             736 :                         fci.no_separation = 0;
    1176                 : 
    1177                 :                         /* Call the userland function */
    1178             736 :                         if (zend_call_function(&fci, &array_walk_fci_cache TSRMLS_CC) == SUCCESS) {
    1179             706 :                                 if (retval_ptr) {
    1180             703 :                                         zval_ptr_dtor(&retval_ptr);
    1181                 :                                 }
    1182                 :                         } else {
    1183                 :                                 char *func_name;
    1184                 : 
    1185              29 :                                 if (zend_is_callable(*BG(array_walk_func_name), 0, &func_name)) {
    1186               0 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call %s()", func_name);
    1187                 :                                 } else {
    1188              29 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call %s() - function does not exist", func_name);
    1189                 :                                 }
    1190              29 :                                 if (key) {
    1191              29 :                                         zval_ptr_dtor(&key);
    1192              29 :                                         key = NULL;
    1193                 :                                 }
    1194              29 :                                 efree(func_name);
    1195              29 :                                 break;
    1196                 :                         }
    1197                 :                 }
    1198                 : 
    1199             811 :                 if (key) {
    1200             706 :                         zval_ptr_dtor(&key);
    1201             706 :                         key = NULL;
    1202                 :                 }
    1203             811 :                 zend_hash_move_forward_ex(target_hash, &pos);
    1204                 :         }
    1205                 :         
    1206             270 :         return 0;
    1207                 : }
    1208                 : /* }}} */
    1209                 : 
    1210                 : /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
    1211                 :    Apply a user function to every member of an array */
    1212                 : PHP_FUNCTION(array_walk)
    1213             192 : {
    1214                 :         zval *array,
    1215             192 :                  *userdata = NULL,
    1216                 :                  *tmp,
    1217                 :                  **old_walk_func_name;
    1218                 :         HashTable *target_hash;
    1219                 : 
    1220             192 :         old_walk_func_name = BG(array_walk_func_name);
    1221             192 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz/|z/", &array, &tmp, &userdata) == FAILURE) {
    1222               5 :                 return;
    1223                 :         }
    1224             187 :         target_hash = HASH_OF(array);
    1225             187 :         if (!target_hash) {
    1226              46 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    1227              46 :                 RETURN_FALSE;
    1228                 :         }
    1229             141 :         if (Z_TYPE_P(tmp) != IS_ARRAY && Z_TYPE_P(tmp) != IS_STRING) {
    1230              38 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong syntax for function name");
    1231              38 :                 RETURN_FALSE;
    1232                 :         } else {
    1233             103 :                 BG(array_walk_func_name) = &tmp;
    1234                 :         }
    1235             103 :         php_array_walk(target_hash, userdata ? &userdata: NULL, 0 TSRMLS_CC);
    1236             102 :         BG(array_walk_func_name) = old_walk_func_name;
    1237             102 :         RETURN_TRUE;
    1238                 : }
    1239                 : /* }}} */
    1240                 : 
    1241                 : /* {{{ proto bool array_walk_recursive(array input, string funcname [, mixed userdata])
    1242                 :    Apply a user function recursively to every member of an array */
    1243                 : PHP_FUNCTION(array_walk_recursive)
    1244             152 : {
    1245                 :         zval *array,
    1246             152 :                  *userdata = NULL,
    1247                 :                  *tmp,
    1248                 :                  **old_walk_func_name;
    1249                 :         HashTable *target_hash;
    1250                 : 
    1251             152 :         old_walk_func_name = BG(array_walk_func_name);
    1252             152 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz/|z/", &array, &tmp, &userdata) == FAILURE) {
    1253               5 :                 return;
    1254                 :         }
    1255             147 :         target_hash = HASH_OF(array);
    1256             147 :         if (!target_hash) {
    1257              46 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    1258              46 :                 RETURN_FALSE;
    1259                 :         }
    1260             101 :         if (Z_TYPE_P(tmp) != IS_ARRAY && Z_TYPE_P(tmp) != IS_STRING) {
    1261              38 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong syntax for function name");
    1262              38 :                 RETURN_FALSE;
    1263                 :         } else {
    1264              63 :                 BG(array_walk_func_name) = &tmp;
    1265                 :         }
    1266              63 :         php_array_walk(target_hash, userdata ? &userdata : NULL, 1 TSRMLS_CC);
    1267              63 :         BG(array_walk_func_name) = old_walk_func_name;
    1268              63 :         RETURN_TRUE;
    1269                 : }
    1270                 : /* }}} */
    1271                 : 
    1272                 : /* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) {{{ 
    1273                 :  *        0 = return boolean
    1274                 :  *        1 = return key
    1275                 :  */
    1276                 : static void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
    1277            8219 : {
    1278                 :         zval **value,                           /* value to check for */
    1279                 :                  **array,                               /* array to check in */
    1280                 :                  **strict,                              /* strict comparison or not */
    1281                 :                  **entry,                               /* pointer to array entry */
    1282                 :                   res;                                  /* comparison result */
    1283                 :         HashTable *target_hash;         /* array hashtable */
    1284                 :         HashPosition pos;                       /* hash iterator */
    1285                 :         ulong num_key;
    1286                 :         uint str_key_len;
    1287                 :         char *string_key;
    1288            8219 :         int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
    1289                 : 
    1290            8219 :         if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 3 ||
    1291                 :                 zend_get_parameters_ex(ZEND_NUM_ARGS(), &value, &array, &strict) == FAILURE) {
    1292               7 :                 WRONG_PARAM_COUNT;
    1293                 :         }
    1294                 : 
    1295                 :         
    1296            8212 :         if (Z_TYPE_PP(array) != IS_ARRAY) {
    1297               9 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong datatype for second argument");
    1298               9 :                 RETURN_FALSE;
    1299                 :         }
    1300                 : 
    1301            8203 :         if (ZEND_NUM_ARGS() == 3) {
    1302             637 :                 convert_to_boolean_ex(strict);
    1303             637 :                 if (Z_LVAL_PP(strict)) {
    1304             325 :                         is_equal_func = is_identical_function;
    1305                 :                 }
    1306                 :         }
    1307                 : 
    1308            8203 :         target_hash = HASH_OF(*array);
    1309            8203 :         zend_hash_internal_pointer_reset_ex(target_hash, &pos);
    1310           41509 :         while (zend_hash_get_current_data_ex(target_hash, (void **)&entry, &pos) == SUCCESS) {
    1311           30285 :                 is_equal_func(&res, *value, *entry TSRMLS_CC);
    1312           30285 :                 if (Z_LVAL(res)) {
    1313            5182 :                         if (behavior == 0) {             
    1314            5001 :                                 RETURN_TRUE;
    1315                 :                         } else {
    1316                 :                                 /* Return current key */
    1317             181 :                                 switch (zend_hash_get_current_key_ex(target_hash, &string_key, &str_key_len, &num_key, 0, &pos)) {
    1318                 :                                         case HASH_KEY_IS_STRING:
    1319              29 :                                                 RETURN_STRINGL(string_key, str_key_len-1, 1);
    1320                 :                                                 break;
    1321                 :                                         case HASH_KEY_IS_LONG:
    1322             152 :                                                 RETURN_LONG(num_key);
    1323                 :                                                 break;
    1324                 :                                 }
    1325                 :                         }
    1326                 :                 }
    1327                 :                 
    1328           25103 :                 zend_hash_move_forward_ex(target_hash, &pos);
    1329                 :         }
    1330                 : 
    1331            3021 :         RETURN_FALSE;
    1332                 : }
    1333                 : /* }}} */
    1334                 : 
    1335                 : /* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
    1336                 :    Checks if the given value exists in the array */
    1337                 : PHP_FUNCTION(in_array)
    1338            7707 : {
    1339            7707 :         php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    1340            7707 : }
    1341                 : /* }}} */
    1342                 : 
    1343                 : /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
    1344                 :    Searches the array for a given value and returns the corresponding key if successful */
    1345                 : PHP_FUNCTION(array_search)
    1346             512 : {
    1347             512 :         php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    1348             512 : }
    1349                 : /* }}} */
    1350                 : 
    1351                 : static int php_valid_var_name(char *var_name, int len) /* {{{ */
    1352             404 : {
    1353                 :         int i, ch;
    1354                 :         
    1355             404 :         if (!var_name)
    1356               0 :                 return 0;
    1357                 : 
    1358                 :         /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
    1359             404 :         ch = (int)((unsigned char *)var_name)[0];
    1360             404 :         if (var_name[0] != '_' &&
    1361                 :                 (ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
    1362                 :                 (ch < 97  /* a    */ || /* z    */ ch > 122) &&
    1363                 :                 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
    1364                 :         ) {
    1365              16 :                 return 0;
    1366                 :         }
    1367                 : 
    1368                 :         /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
    1369             388 :         if (len > 1) {
    1370            1709 :                 for (i = 1; i < len; i++) {
    1371            1379 :                         ch = (int)((unsigned char *)var_name)[i];
    1372            1379 :                         if (var_name[i] != '_' &&
    1373                 :                                 (ch < 48  /* 0    */ || /* 9    */ ch > 57)  &&
    1374                 :                                 (ch < 65  /* A    */ || /* Z    */ ch > 90)  &&
    1375                 :                                 (ch < 97  /* a    */ || /* z    */ ch > 122) &&
    1376                 :                                 (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
    1377                 :                         ) {     
    1378               6 :                                 return 0;
    1379                 :                         }
    1380                 :                 }
    1381                 :         }
    1382             382 :         return 1;
    1383                 : }
    1384                 : /* }}} */
    1385                 : 
    1386                 : /* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
    1387                 :    Imports variables into symbol table from an array */
    1388                 : PHP_FUNCTION(extract)
    1389             135 : {
    1390                 :         zval **var_array, *orig_var_array, **z_extract_type, **prefix;
    1391                 :         zval **entry, *data;
    1392                 :         char *var_name;
    1393             135 :         smart_str final_name = {0};
    1394                 :         ulong num_key;
    1395                 :         uint var_name_len;
    1396             135 :         int var_exists, extract_type, key_type, count = 0;
    1397             135 :         int extract_refs = 0;
    1398                 :         HashPosition pos;
    1399                 : 
    1400             135 :         switch (ZEND_NUM_ARGS()) {
    1401                 :                 case 1:
    1402              18 :                         if (zend_get_parameters_ex(1, &var_array) == FAILURE) {
    1403               0 :                                 WRONG_PARAM_COUNT;
    1404                 :                         }
    1405              18 :                         extract_type = EXTR_OVERWRITE;
    1406              18 :                         break;
    1407                 : 
    1408                 :                 case 2:
    1409              51 :                         if (zend_get_parameters_ex(2, &var_array, &z_extract_type) == FAILURE) {
    1410               0 :                                 WRONG_PARAM_COUNT;
    1411                 :                         }
    1412              51 :                         convert_to_long_ex(z_extract_type);
    1413              51 :                         extract_type = Z_LVAL_PP(z_extract_type);
    1414              51 :                         extract_refs = (extract_type & EXTR_REFS);
    1415              51 :                         extract_type &= 0xff;
    1416              51 :                         if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS) {
    1417               1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Prefix expected to be specified");
    1418               1 :                                 return;
    1419                 :                         }
    1420              50 :                         break;
    1421                 :                         
    1422                 :                 case 3:
    1423              64 :                         if (zend_get_parameters_ex(3, &var_array, &z_extract_type, &prefix) == FAILURE) {
    1424               0 :                                 WRONG_PARAM_COUNT;
    1425                 :                         }
    1426              64 :                         convert_to_long_ex(z_extract_type);
    1427              64 :                         extract_type = Z_LVAL_PP(z_extract_type);
    1428              64 :                         extract_refs = (extract_type & EXTR_REFS);
    1429              64 :                         extract_type &= 0xff;
    1430              64 :                         convert_to_string_ex(prefix);
    1431              64 :                         break;
    1432                 : 
    1433                 :                 default:
    1434               2 :                         WRONG_PARAM_COUNT;
    1435                 :                         break;
    1436                 :         }
    1437                 :         
    1438             132 :         if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
    1439               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown extract type");
    1440               2 :                 return;
    1441                 :         }
    1442                 :         
    1443             130 :         if (Z_TYPE_PP(var_array) != IS_ARRAY) {
    1444               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument should be an array");
    1445               2 :                 return;
    1446                 :         }
    1447                 : 
    1448                 :         /* var_array is passed by ref for the needs of EXTR_REFS (needs to
    1449                 :          * work on the original array to create refs to its members)
    1450                 :          * simulate pass_by_value if EXTR_REFS is not used */
    1451             128 :         if (!extract_refs) {
    1452             112 :                 orig_var_array = *var_array;
    1453             112 :                 SEPARATE_ARG_IF_REF((*var_array));
    1454                 :         }
    1455                 : 
    1456             128 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(var_array), &pos);
    1457             984 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(var_array), (void **)&entry, &pos) == SUCCESS) {
    1458             728 :                 key_type = zend_hash_get_current_key_ex(Z_ARRVAL_PP(var_array), &var_name, &var_name_len, &num_key, 0, &pos);
    1459             728 :                 var_exists = 0;
    1460                 : 
    1461             728 :                 if (key_type == HASH_KEY_IS_STRING) {
    1462             249 :                         var_name_len--;
    1463             249 :                         var_exists = zend_hash_exists(EG(active_symbol_table), var_name, var_name_len + 1);
    1464             650 :                 } else if (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID) {
    1465             171 :                         smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
    1466             171 :                         smart_str_appendc(&final_name, '_');
    1467             171 :                         smart_str_append_long(&final_name, num_key);
    1468                 :                 } else {
    1469             308 :                         zend_hash_move_forward_ex(Z_ARRVAL_PP(var_array), &pos);
    1470             308 :                         continue;
    1471                 :                 }
    1472                 :                         
    1473             420 :                 switch (extract_type) {
    1474                 :                         case EXTR_IF_EXISTS:
    1475              15 :                                 if (!var_exists) break;
    1476                 :                                 /* break omitted intentionally */
    1477                 : 
    1478                 :                         case EXTR_OVERWRITE:
    1479                 :                                 /* GLOBALS protection */
    1480             139 :                                 if (var_exists && !strcmp(var_name, "GLOBALS")) {
    1481               2 :                                         break;
    1482                 :                                 }
    1483             137 :                                 smart_str_appendl(&final_name, var_name, var_name_len);
    1484             137 :                                 break;
    1485                 : 
    1486                 :                         case EXTR_PREFIX_IF_EXISTS:
    1487              15 :                                 if (var_exists) {
    1488              11 :                                         smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
    1489              11 :                                         smart_str_appendc(&final_name, '_');
    1490              11 :                                         smart_str_appendl(&final_name, var_name, var_name_len);
    1491                 :                                 }
    1492              15 :                                 break;
    1493                 : 
    1494                 :                         case EXTR_PREFIX_SAME:
    1495              17 :                                 if (!var_exists)
    1496               5 :                                         smart_str_appendl(&final_name, var_name, var_name_len);
    1497                 :                                 /* break omitted intentionally */
    1498                 : 
    1499                 :                         case EXTR_PREFIX_ALL:
    1500             181 :                                 if (final_name.len == 0 && var_name_len != 0) {
    1501              51 :                                         smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
    1502              51 :                                         smart_str_appendc(&final_name, '_');
    1503              51 :                                         smart_str_appendl(&final_name, var_name, var_name_len);
    1504                 :                                 }
    1505             181 :                                 break;
    1506                 : 
    1507                 :                         case EXTR_PREFIX_INVALID:
    1508              66 :                                 if (final_name.len == 0) {
    1509              15 :                                         if (!php_valid_var_name(var_name, var_name_len)) {
    1510               4 :                                                 smart_str_appendl(&final_name, Z_STRVAL_PP(prefix), Z_STRLEN_PP(prefix));
    1511               4 :                                                 smart_str_appendc(&final_name, '_');
    1512               4 :                                                 smart_str_appendl(&final_name, var_name, var_name_len);
    1513                 :                                         } else
    1514              11 :                                                 smart_str_appendl(&final_name, var_name, var_name_len);
    1515                 :                                 }
    1516              66 :                                 break;
    1517                 : 
    1518                 :                         default:
    1519              15 :                                 if (!var_exists)
    1520               4 :                                         smart_str_appendl(&final_name, var_name, var_name_len);
    1521                 :                                 break;
    1522                 :                 }
    1523                 : 
    1524             420 :                 if (final_name.len) {
    1525             389 :                         smart_str_0(&final_name);
    1526             389 :                         if (php_valid_var_name(final_name.c, final_name.len)) {
    1527             371 :                                 if (extract_refs) {
    1528                 :                                         zval **orig_var;
    1529                 : 
    1530              86 :                                         SEPARATE_ZVAL_TO_MAKE_IS_REF(entry);
    1531              86 :                                         zval_add_ref(entry);
    1532                 : 
    1533              86 :                                         if (zend_hash_find(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) &orig_var) == SUCCESS) {
    1534              40 :                                                 zval_ptr_dtor(orig_var);
    1535              40 :                                                 *orig_var = *entry;
    1536                 :                                         } else {
    1537              46 :                                                 zend_hash_update(EG(active_symbol_table), final_name.c, final_name.len+1, (void **) entry, sizeof(zval *), NULL);
    1538                 :                                         }
    1539                 :                                 } else {
    1540             285 :                                         MAKE_STD_ZVAL(data);
    1541             285 :                                         *data = **entry;
    1542             285 :                                         zval_copy_ctor(data);
    1543                 : 
    1544             285 :                                         ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table), final_name.c, final_name.len+1, data, 1, 0);
    1545                 :                                 }
    1546                 : 
    1547             371 :                                 count++;
    1548                 :                         }
    1549             389 :                         final_name.len = 0;
    1550                 :                 }
    1551                 : 
    1552             420 :                 zend_hash_move_forward_ex(Z_ARRVAL_PP(var_array), &pos);
    1553                 :         }
    1554                 : 
    1555             128 :         if (!extract_refs) {
    1556             112 :                 zval_ptr_dtor(var_array);
    1557             112 :                 *var_array = orig_var_array;
    1558                 :         }
    1559             128 :         smart_str_free(&final_name);
    1560                 : 
    1561             128 :         RETURN_LONG(count);
    1562                 : }
    1563                 : /* }}} */
    1564                 : 
    1565                 : static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry) /* {{{ */
    1566              59 : {
    1567                 :         zval **value_ptr, *value, *data;
    1568                 :         
    1569              59 :         if (Z_TYPE_P(entry) == IS_STRING) {
    1570              34 :                 if (zend_hash_find(eg_active_symbol_table, Z_STRVAL_P(entry),
    1571                 :                                                    Z_STRLEN_P(entry)+1, (void **)&value_ptr) != FAILURE) {
    1572              27 :                         value = *value_ptr;
    1573              27 :                         ALLOC_ZVAL(data);
    1574              27 :                         *data = *value;
    1575              27 :                         zval_copy_ctor(data);
    1576              27 :                         INIT_PZVAL(data);
    1577                 :                         
    1578              27 :                         zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(entry),
    1579                 :                                                          Z_STRLEN_P(entry)+1, &data, sizeof(zval *), NULL);
    1580                 :                 }
    1581                 :         }
    1582              25 :         else if (Z_TYPE_P(entry) == IS_ARRAY) {
    1583                 :                 HashPosition pos;
    1584                 : 
    1585              12 :                 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos);
    1586              52 :                 while (zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), (void**)&value_ptr, &pos) == SUCCESS) {
    1587              28 :                         value = *value_ptr;
    1588                 : 
    1589              28 :                         php_compact_var(eg_active_symbol_table, return_value, value);
    1590              28 :                         zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos);
    1591                 :                 }
    1592                 :         }
    1593              59 : }
    1594                 : /* }}} */
    1595                 : 
    1596                 : /* {{{ proto array compact(mixed var_names [, mixed ...])
    1597                 :    Creates a hash containing variables and their values */
    1598                 : PHP_FUNCTION(compact)
    1599              18 : {
    1600                 :         zval ***args;                   /* function arguments array */
    1601                 :         int i;
    1602                 :         
    1603              18 :         if (ZEND_NUM_ARGS() < 1) {
    1604               1 :                 WRONG_PARAM_COUNT;
    1605                 :         }
    1606              17 :         args = (zval ***)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval **), 0);
    1607                 :         
    1608              17 :         if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
    1609               0 :                 efree(args);
    1610               0 :                 WRONG_PARAM_COUNT;
    1611                 :         }
    1612                 : 
    1613              17 :         array_init(return_value);
    1614                 :         
    1615              48 :         for (i=0; i<ZEND_NUM_ARGS(); i++) {
    1616              31 :                 php_compact_var(EG(active_symbol_table), return_value, *args[i]);
    1617                 :         }
    1618                 :         
    1619              17 :         efree(args);
    1620                 : }
    1621                 : /* }}} */
    1622                 : 
    1623                 : /* {{{ proto array array_fill(int start_key, int num, mixed val)
    1624                 :    Create an array containing num elements starting with index start_key each initialized to val */
    1625                 : PHP_FUNCTION(array_fill)
    1626             158 : {
    1627                 :         zval **start_key, **num, **val, *newval;
    1628                 :         long i;
    1629                 : 
    1630             158 :         if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &start_key, &num, &val) == FAILURE) {
    1631               3 :                 WRONG_PARAM_COUNT;
    1632                 :         }
    1633                 : 
    1634             155 :         switch (Z_TYPE_PP(start_key)) {
    1635                 :                 case IS_STRING:
    1636                 :                 case IS_LONG:
    1637                 :                 case IS_DOUBLE:
    1638                 :                         /* allocate an array for return */
    1639             140 :                         array_init(return_value);
    1640                 :                         
    1641             140 :                         if (PZVAL_IS_REF(*val)) {
    1642               0 :                                 SEPARATE_ZVAL(val);
    1643                 :                         }
    1644             140 :                         convert_to_long_ex(start_key);
    1645             140 :                         zval_add_ref(val);
    1646             140 :                         zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(start_key), val, sizeof(val), NULL);
    1647                 :                         break;
    1648                 :                 default:
    1649              15 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Wrong data type for start key");
    1650              15 :                         RETURN_FALSE;
    1651                 :                         break;
    1652                 :         }       
    1653                 : 
    1654             199 :         convert_to_long_ex(num);
    1655             140 :         i = Z_LVAL_PP(num) - 1; 
    1656             140 :         if (i < 0) {
    1657              34 :                 zend_hash_destroy(Z_ARRVAL_P(return_value));
    1658              34 :                 efree(Z_ARRVAL_P(return_value));
    1659              34 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive");
    1660              34 :                 RETURN_FALSE;
    1661                 :         }
    1662             106 :         newval = *val;
    1663             295 :         while (i--) {
    1664              83 :                 zval_add_ref(&newval);
    1665              83 :                 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &newval, sizeof(zval *), NULL);
    1666                 :         }
    1667                 : }
    1668                 : /* }}} */
    1669                 : 
    1670                 : /* {{{ proto array array_fill_keys(array keys, mixed val)
    1671                 :    Create an array using the elements of the first parameter as keys each initialized to val */
    1672                 : PHP_FUNCTION(array_fill_keys)
    1673              24 : {
    1674                 :         zval *keys, *val, **entry;
    1675                 :         HashPosition pos;
    1676                 : 
    1677              24 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &keys, &val) == FAILURE) {
    1678               6 :                 return;
    1679                 :         }
    1680                 : 
    1681                 :         /* Initialize return array */
    1682              18 :         array_init(return_value);
    1683                 : 
    1684              18 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
    1685              76 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&entry, &pos) == SUCCESS) {
    1686                 : 
    1687              40 :                 if (Z_TYPE_PP(entry) == IS_LONG) {
    1688               8 :                         zval_add_ref(&val);
    1689               8 :                         zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &val, sizeof(zval *), NULL);
    1690                 :                 } else {
    1691              32 :                         zval key, *key_ptr = *entry;
    1692                 : 
    1693              32 :                         if (Z_TYPE_PP(entry) != IS_STRING) {
    1694               7 :                                 key = **entry;
    1695               7 :                                 zval_copy_ctor(&key);
    1696               7 :                                 convert_to_string(&key);
    1697               7 :                                 key_ptr = &key;
    1698                 :                         }
    1699                 : 
    1700              32 :                         zval_add_ref(&val);
    1701              32 :                         zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(key_ptr), Z_STRLEN_P(key_ptr) + 1, &val, sizeof(zval *), NULL);
    1702                 : 
    1703              32 :                         if (key_ptr != *entry) {
    1704               7 :                                 zval_dtor(&key);
    1705                 :                         }
    1706                 :                 }
    1707                 : 
    1708              40 :                 zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
    1709                 :         }
    1710                 : }
    1711                 : /* }}} */
    1712                 : 
    1713                 : /* {{{ proto array range(mixed low, mixed high[, int step])
    1714                 :    Create an array containing the range of integers or characters from low to high (inclusive) */
    1715                 : PHP_FUNCTION(range)
    1716           90178 : {
    1717           90178 :         zval *zlow, *zhigh, *zstep = NULL;
    1718           90178 :         int err = 0, is_step_double = 0;
    1719           90178 :         double step = 1.0;
    1720                 : 
    1721           90178 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/|z/", &zlow, &zhigh, &zstep) == FAILURE) {
    1722               3 :                 RETURN_FALSE;
    1723                 :         }
    1724                 : 
    1725           90175 :         if (zstep) {
    1726              30 :                 if (Z_TYPE_P(zstep) == IS_DOUBLE || (Z_TYPE_P(zstep) == IS_STRING && is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0) == IS_DOUBLE)) {
    1727               6 :                         is_step_double = 1;
    1728                 :                 }
    1729                 : 
    1730              30 :                 convert_to_double_ex(&zstep);
    1731              30 :                 step = Z_DVAL_P(zstep);
    1732                 : 
    1733                 :                 /* We only want positive step values. */
    1734              30 :                 if (step < 0.0) {
    1735               0 :                         step *= -1;
    1736                 :                 }
    1737                 :         }       
    1738                 : 
    1739                 :         /* Initialize the return_value as an array. */
    1740           90175 :         array_init(return_value);
    1741                 : 
    1742                 :         /* If the range is given as strings, generate an array of characters. */
    1743           90182 :         if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
    1744                 :                 int type1, type2;
    1745                 :                 unsigned char *low, *high;
    1746              18 :                 long lstep = (long) step;
    1747                 : 
    1748              18 :                 type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
    1749              18 :                 type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
    1750                 :                 
    1751              18 :                 if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) {
    1752                 :                         goto double_str;
    1753              15 :                 } else if (type1 == IS_LONG || type2 == IS_LONG) {
    1754                 :                         goto long_str;
    1755                 :                 }
    1756                 :                 
    1757              10 :                 convert_to_string(zlow);
    1758              10 :                 convert_to_string(zhigh);
    1759              10 :                 low = (unsigned char *)Z_STRVAL_P(zlow);
    1760              10 :                 high = (unsigned char *)Z_STRVAL_P(zhigh);
    1761                 : 
    1762              10 :                 if (*low > *high) {          /* Negative Steps */
    1763               2 :                         if (lstep <= 0) {
    1764               1 :                                 err = 1;
    1765               1 :                                 goto err;
    1766                 :                         }
    1767              27 :                         for (; *low >= *high; (*low) -= (unsigned int)lstep) {
    1768              26 :                                 add_next_index_stringl(return_value, low, 1, 1);
    1769              26 :                                 if (((signed int)*low - lstep) < 0) {
    1770               0 :                                         break;
    1771                 :                                 }
    1772                 :                         }
    1773               8 :                 } else if (*high > *low) {   /* Positive Steps */
    1774               6 :                         if (lstep <= 0) {
    1775               2 :                                 err = 1;
    1776               2 :                                 goto err;
    1777                 :                         }
    1778              76 :                         for (; *low <= *high; (*low) += (unsigned int)lstep) {
    1779              72 :                                 add_next_index_stringl(return_value, low, 1, 1);
    1780              72 :                                 if (((signed int)*low + lstep) > 255) {
    1781               0 :                                         break;
    1782                 :                                 }
    1783                 :                         }
    1784                 :                 } else {
    1785               2 :                         add_next_index_stringl(return_value, low, 1, 1);
    1786                 :                 }
    1787                 : 
    1788           90186 :         } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
    1789                 :                 double low, high;
    1790              31 : double_str:             
    1791              31 :                 convert_to_double(zlow);
    1792              31 :                 convert_to_double(zhigh);
    1793              31 :                 low = Z_DVAL_P(zlow);
    1794              31 :                 high = Z_DVAL_P(zhigh);
    1795                 :                 
    1796              31 :                 if (low > high) {            /* Negative steps */
    1797              13 :                         if (low - high < step || step <= 0) {
    1798               1 :                                 err = 1;
    1799               1 :                                 goto err;
    1800                 :                         }
    1801             116 :                         for (; low >= (high - DOUBLE_DRIFT_FIX); low -= step) {
    1802             104 :                                 add_next_index_double(return_value, low);
    1803                 :                         }       
    1804              18 :                 } else if (high > low) {     /* Positive steps */
    1805              17 :                         if (high - low < step || step <= 0) {
    1806               1 :                                 err = 1;
    1807               1 :                                 goto err;
    1808                 :                         }
    1809             152 :                         for (; low <= (high + DOUBLE_DRIFT_FIX); low += step) {
    1810             136 :                                 add_next_index_double(return_value, low);
    1811                 :                         }       
    1812                 :                 } else {
    1813               1 :                         add_next_index_double(return_value, low);
    1814                 :                 }
    1815                 :         } else {
    1816                 :                 double low, high;
    1817                 :                 long lstep;
    1818           90134 : long_str:
    1819           90134 :                 convert_to_double(zlow);
    1820           90134 :                 convert_to_double(zhigh);
    1821           90134 :                 low = Z_DVAL_P(zlow);
    1822           90134 :                 high = Z_DVAL_P(zhigh);
    1823           90134 :                 lstep = (long) step;
    1824                 :                                 
    1825           90134 :                 if (low > high) {            /* Negative steps */
    1826              16 :                         if (low - high < lstep || lstep <= 0) {
    1827               2 :                                 err = 1;
    1828               2 :                                 goto err;
    1829                 :                         }
    1830              77 :                         for (; low >= high; low -= lstep) {
    1831              63 :                                 add_next_index_long(return_value, (long)low);
    1832                 :                         }       
    1833           90118 :                 } else if (high > low) {     /* Positive steps */
    1834           90097 :                         if (high - low < lstep || lstep <= 0) {
    1835               6 :                                 err = 1;
    1836               6 :                                 goto err;
    1837                 :                         }
    1838          460566 :                         for (; low <= high; low += lstep) {
    1839          370475 :                                 add_next_index_long(return_value, (long)low);
    1840                 :                         }       
    1841                 :                 } else {
    1842              21 :                         add_next_index_long(return_value, (long)low);
    1843                 :                 }
    1844                 :         }
    1845           90175 : err:
    1846           90175 :         if (err) {
    1847              13 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "step exceeds the specified range");
    1848              13 :                 zval_dtor(return_value);
    1849              13 :                 RETURN_FALSE;
    1850                 :         }               
    1851                 : }
    1852                 : /* }}} */
    1853                 : 
    1854                 : static void array_data_shuffle(zval *array TSRMLS_DC) /* {{{ */
    1855           90044 : {
    1856                 :         Bucket **elems, *temp;
    1857                 :         HashTable *hash;
    1858                 :         int j, n_elems, rnd_idx, n_left;
    1859                 : 
    1860           90044 :         n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
    1861                 :         
    1862           90044 :         if (n_elems < 1) {
    1863               1 :                 return;
    1864                 :         }
    1865                 : 
    1866           90043 :         elems = (Bucket **)safe_emalloc(n_elems, sizeof(Bucket *), 0);
    1867           90043 :         hash = Z_ARRVAL_P(array);
    1868           90043 :         n_left = n_elems;
    1869                 : 
    1870          451011 :         for (j = 0, temp = hash->pListHead; temp; temp = temp->pListNext)
    1871          360968 :                 elems[j++] = temp;
    1872          451011 :         while (--n_left) {
    1873          270925 :                 rnd_idx = php_rand(TSRMLS_C);
    1874          270925 :                 RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    1875          270925 :                 if (rnd_idx != n_left) {
    1876          173269 :                         temp = elems[n_left];
    1877          173269 :                         elems[n_left] = elems[rnd_idx];
    1878          173269 :                         elems[rnd_idx] = temp;
    1879                 :                 }
    1880                 :         }
    1881                 : 
    1882           90043 :         HANDLE_BLOCK_INTERRUPTIONS();
    1883           90043 :         hash->pListHead = elems[0];
    1884           90043 :         hash->pListTail = NULL;
    1885           90043 :         hash->pInternalPointer = hash->pListHead;
    1886                 : 
    1887          451011 :         for (j = 0; j < n_elems; j++) {
    1888          360968 :                 if (hash->pListTail) {
    1889          270925 :                         hash->pListTail->pListNext = elems[j];
    1890                 :                 }
    1891          360968 :                 elems[j]->pListLast = hash->pListTail;
    1892          360968 :                 elems[j]->pListNext = NULL;
    1893          360968 :                 hash->pListTail = elems[j];
    1894                 :         }
    1895           90043 :         temp = hash->pListHead;
    1896           90043 :         j = 0;
    1897          541054 :         while (temp != NULL) {
    1898          360968 :                 temp->nKeyLength = 0;
    1899          360968 :                 temp->h = j++;
    1900          360968 :                 temp = temp->pListNext;
    1901                 :         }
    1902           90043 :         hash->nNextFreeElement = n_elems;
    1903           90043 :         zend_hash_rehash(hash);
    1904           90043 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1905                 : 
    1906           90043 :         efree(elems);
    1907                 : }
    1908                 : /* }}} */
    1909                 : 
    1910                 : /* {{{ proto bool shuffle(array array_arg)
    1911                 :    Randomly shuffle the contents of an array */
    1912                 : PHP_FUNCTION(shuffle)
    1913           90069 : {
    1914                 :         zval *array;
    1915                 : 
    1916           90069 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
    1917              25 :                 RETURN_FALSE;
    1918                 :         }
    1919                 : 
    1920           90044 :         array_data_shuffle(array TSRMLS_CC);
    1921                 : 
    1922           90044 :         RETURN_TRUE;
    1923                 : }
    1924                 : /* }}} */
    1925                 : 
    1926                 : HashTable* php_splice(HashTable *in_hash, int offset, int length, zval ***list, int list_count, HashTable **removed) /* {{{ */
    1927             434 : {
    1928             434 :         HashTable       *out_hash = NULL;       /* Output hashtable */
    1929                 :         int                      num_in,                        /* Number of entries in the input hashtable */
    1930                 :                                  pos,                           /* Current position in the hashtable */
    1931                 :                                  i;                                     /* Loop counter */
    1932                 :         Bucket          *p;                                     /* Pointer to hash bucket */
    1933                 :         zval            *entry;                         /* Hash entry */
    1934                 :         
    1935                 :         /* If input hash doesn't exist, we have nothing to do */
    1936             434 :         if (!in_hash)
    1937               0 :                 return NULL;
    1938                 :         
    1939                 :         /* Get number of entries in the input hash */
    1940             434 :         num_in = zend_hash_num_elements(in_hash);
    1941                 :         
    1942                 :         /* Clamp the offset.. */
    1943             434 :         if (offset > num_in)
    1944               0 :                 offset = num_in;
    1945             434 :         else if (offset < 0 && (offset = (num_in + offset)) < 0)
    1946               0 :                 offset = 0;
    1947                 :         
    1948                 :         /* ..and the length */
    1949             434 :         if (length < 0) {
    1950              15 :                 length = num_in - offset + length;
    1951             419 :         } else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
    1952              10 :                 length = num_in - offset;
    1953                 :         }
    1954                 : 
    1955                 :         /* Create and initialize output hash */
    1956             434 :         ALLOC_HASHTABLE(out_hash);
    1957             434 :         zend_hash_init(out_hash, 0, NULL, ZVAL_PTR_DTOR, 0);
    1958                 :         
    1959                 :         /* Start at the beginning of the input hash and copy entries to output hash until offset is reached */
    1960             666 :         for (pos=0, p=in_hash->pListHead; pos<offset && p ; pos++, p=p->pListNext) {
    1961                 :                 /* Get entry and increase reference count */
    1962             232 :                 entry = *((zval **)p->pData);
    1963             232 :                 entry->refcount++;
    1964                 :                 
    1965                 :                 /* Update output hash depending on key type */
    1966             232 :                 if (p->nKeyLength)
    1967              23 :                         zend_hash_quick_update(out_hash, p->arKey, p->nKeyLength, p->h, &entry, sizeof(zval *), NULL);
    1968                 :                 else
    1969             209 :                         zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL);
    1970                 :         }
    1971                 :         
    1972                 :         /* If hash for removed entries exists, go until offset+length and copy the entries to it */
    1973             434 :         if (removed != NULL) {
    1974             169 :                 for ( ; pos<offset+length && p; pos++, p=p->pListNext) {
    1975             113 :                         entry = *((zval **)p->pData);
    1976             113 :                         entry->refcount++;
    1977             113 :                         if (p->nKeyLength)
    1978              18 :                                 zend_hash_quick_update(*removed, p->arKey, p->nKeyLength, p->h, &entry, sizeof(zval *), NULL);
    1979                 :                         else
    1980              95 :                                 zend_hash_next_index_insert(*removed, &entry, sizeof(zval *), NULL);
    1981                 :                 }
    1982                 :         } else /* otherwise just skip those entries */
    1983             378 :                 for ( ; pos<offset+length && p; pos++, p=p->pListNext);
    1984                 :         
    1985                 :         /* If there are entries to insert.. */
    1986             434 :         if (list != NULL) {
    1987                 :                 /* ..for each one, create a new zval, copy entry into it and copy it into the output hash */
    1988            2219 :                 for (i=0; i<list_count; i++) {
    1989            1813 :                         entry = *list[i];
    1990            1813 :                         entry->refcount++;
    1991            1813 :                         zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL);
    1992                 :                 }
    1993                 :         }
    1994                 :         
    1995                 :         /* Copy the remaining input hash entries to the output hash */
    1996            1670 :         for ( ; p ; p=p->pListNext) {
    1997            1236 :                 entry = *((zval **)p->pData);
    1998            1236 :                 entry->refcount++;
    1999            1236 :                 if (p->nKeyLength)
    2000             337 :                         zend_hash_quick_update(out_hash, p->arKey, p->nKeyLength, p->h, &entry, sizeof(zval *), NULL);
    2001                 :                 else
    2002             899 :                         zend_hash_next_index_insert(out_hash, &entry, sizeof(zval *), NULL);
    2003                 :         }
    2004                 : 
    2005             434 :         zend_hash_internal_pointer_reset(out_hash);
    2006             434 :         return out_hash;
    2007                 : }
    2008                 : /* }}} */
    2009                 : 
    2010                 : /* {{{ proto int array_push(array stack, mixed var [, mixed ...])
    2011                 :    Pushes elements onto the end of the array */
    2012                 : PHP_FUNCTION(array_push)
    2013             176 : {
    2014                 :         zval      ***args,              /* Function arguments array */
    2015                 :                     *stack,             /* Input array */
    2016                 :                     *new_var;           /* Variable to be pushed */
    2017                 :         int          i,                 /* Loop counter */
    2018                 :                      argc;              /* Number of function arguments */
    2019                 : 
    2020                 :         /* Get the argument count and check it */
    2021             176 :         argc = ZEND_NUM_ARGS();
    2022             176 :         if (argc < 2) {
    2023               1 :                 WRONG_PARAM_COUNT;
    2024                 :         }
    2025                 :         
    2026                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    2027             175 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    2028             175 :         if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
    2029               0 :                 efree(args);
    2030               0 :                 WRONG_PARAM_COUNT;
    2031                 :         }
    2032                 : 
    2033                 :         /* Get first argument and check that it's an array */   
    2034             175 :         stack = *args[0];
    2035             175 :         if (Z_TYPE_P(stack) != IS_ARRAY) {
    2036              24 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument should be an array");
    2037              24 :                 efree(args);
    2038              24 :                 RETURN_FALSE;
    2039                 :         }
    2040                 : 
    2041                 :         /* For each subsequent argument, make it a reference, increase refcount, and add it to the end of the array */
    2042             308 :         for (i=1; i<argc; i++) {
    2043             158 :                 new_var = *args[i];
    2044             158 :                 new_var->refcount++;
    2045                 :         
    2046             158 :                 if (zend_hash_next_index_insert(Z_ARRVAL_P(stack), &new_var, sizeof(zval *), NULL) == FAILURE) {
    2047               1 :                         new_var->refcount--;
    2048               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to the array as the next element is already occupied");
    2049               1 :                         efree(args);
    2050               1 :                         RETURN_FALSE;
    2051                 :                 }
    2052                 :         }
    2053                 :         
    2054                 :         /* Clean up and return the number of values in the stack */
    2055             150 :         efree(args);
    2056             150 :         RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
    2057                 : }
    2058                 : /* }}} */
    2059                 : 
    2060                 : /* {{{ void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int which_end) */
    2061                 : static void _phpi_pop(INTERNAL_FUNCTION_PARAMETERS, int off_the_end)
    2062             275 : {
    2063                 :         zval **stack,                   /* Input stack */
    2064                 :              **val;                     /* Value to be popped */
    2065             275 :         char *key = NULL;
    2066             275 :         uint key_len = 0;
    2067                 :         ulong index;
    2068                 :         
    2069                 :         /* Get the arguments and do error-checking */
    2070             275 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &stack) == FAILURE) {
    2071               6 :                 WRONG_PARAM_COUNT;
    2072                 :         }
    2073                 :         
    2074             269 :         if (Z_TYPE_PP(stack) != IS_ARRAY) {
    2075              28 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2076              28 :                 return;
    2077                 :         }
    2078                 : 
    2079             241 :         if (zend_hash_num_elements(Z_ARRVAL_PP(stack)) == 0) {
    2080               5 :                 return;
    2081                 :         }
    2082                 :                 
    2083                 :         /* Get the first or last value and copy it into the return value */
    2084             236 :         if (off_the_end) {
    2085              70 :                 zend_hash_internal_pointer_end(Z_ARRVAL_PP(stack));
    2086                 :         } else {
    2087             166 :                 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(stack));
    2088                 :         }
    2089             236 :         zend_hash_get_current_data(Z_ARRVAL_PP(stack), (void **)&val);
    2090             236 :         RETVAL_ZVAL(*val, 1, 0);
    2091                 :         
    2092                 :         /* Delete the first or last value */
    2093             236 :         zend_hash_get_current_key_ex(Z_ARRVAL_PP(stack), &key, &key_len, &index, 0, NULL);
    2094             240 :         if (key && Z_ARRVAL_PP(stack) == &EG(symbol_table)) {
    2095               4 :                 zend_delete_global_variable(key, key_len-1 TSRMLS_CC);
    2096                 :         } else {
    2097             232 :                 zend_hash_del_key_or_index(Z_ARRVAL_PP(stack), key, key_len, index, (key) ? HASH_DEL_KEY : HASH_DEL_INDEX);
    2098                 :         }
    2099                 :         
    2100                 :         /* If we did a shift... re-index like it did before */
    2101             236 :         if (!off_the_end) {
    2102             166 :                 unsigned int k = 0;
    2103             166 :                 int should_rehash = 0;
    2104             166 :                 Bucket *p = Z_ARRVAL_PP(stack)->pListHead;
    2105             702 :                 while (p != NULL) {
    2106             370 :                         if (p->nKeyLength == 0) {
    2107             337 :                                 if (p->h != k) {
    2108             330 :                                         p->h = k++;
    2109             330 :                                         should_rehash = 1;
    2110                 :                                 } else {
    2111               7 :                                         k++;
    2112                 :                                 }
    2113                 :                         }
    2114             370 :                         p = p->pListNext;
    2115                 :                 }
    2116             166 :                 Z_ARRVAL_PP(stack)->nNextFreeElement = k;
    2117             166 :                 if (should_rehash) {
    2118             126 :                         zend_hash_rehash(Z_ARRVAL_PP(stack));
    2119                 :                 }
    2120              70 :         } else if (!key_len && index >= Z_ARRVAL_PP(stack)->nNextFreeElement-1) {
    2121              60 :                 Z_ARRVAL_PP(stack)->nNextFreeElement = Z_ARRVAL_PP(stack)->nNextFreeElement - 1;
    2122                 :         }
    2123                 : 
    2124             236 :         zend_hash_internal_pointer_reset(Z_ARRVAL_PP(stack));
    2125                 : }
    2126                 : /* }}} */
    2127                 : 
    2128                 : /* {{{ proto mixed array_pop(array stack)
    2129                 :    Pops an element off the end of the array */
    2130                 : PHP_FUNCTION(array_pop)
    2131              76 : {
    2132              76 :         _phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    2133              76 : }
    2134                 : /* }}} */
    2135                 : 
    2136                 : /* {{{ proto mixed array_shift(array stack)
    2137                 :    Pops an element off the beginning of the array */
    2138                 : PHP_FUNCTION(array_shift)
    2139             199 : {
    2140             199 :         _phpi_pop(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    2141             199 : }
    2142                 : /* }}} */
    2143                 : 
    2144                 : /* {{{ proto int array_unshift(array stack, mixed var [, mixed ...])
    2145                 :    Pushes elements onto the beginning of the array */
    2146                 : PHP_FUNCTION(array_unshift)
    2147             311 : {
    2148                 :         zval      ***args,              /* Function arguments array */
    2149                 :                     *stack;             /* Input stack */
    2150                 :         HashTable   *new_hash;          /* New hashtable for the stack */
    2151                 :         int          argc;              /* Number of function arguments */
    2152                 :         
    2153                 : 
    2154                 :         /* Get the argument count and check it */       
    2155             311 :         argc = ZEND_NUM_ARGS();
    2156             311 :         if (argc < 2) {
    2157               2 :                 WRONG_PARAM_COUNT;
    2158                 :         }
    2159                 :         
    2160                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    2161             309 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    2162             309 :         if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
    2163               0 :                 efree(args);
    2164               0 :                 WRONG_PARAM_COUNT;
    2165                 :         }
    2166                 :         
    2167                 :         /* Get first argument and check that it's an array */
    2168             309 :         stack = *args[0];
    2169             309 :         if (Z_TYPE_P(stack) != IS_ARRAY) {
    2170              49 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array");
    2171              49 :                 efree(args);
    2172              49 :                 RETURN_FALSE;
    2173                 :         }
    2174                 : 
    2175                 :         /* Use splice to insert the elements at the beginning. Destroy old
    2176                 :            hashtable and replace it with new one */
    2177             260 :         new_hash = php_splice(Z_ARRVAL_P(stack), 0, 0, &args[1], argc-1, NULL);
    2178             260 :         zend_hash_destroy(Z_ARRVAL_P(stack));
    2179             260 :         if (Z_ARRVAL_P(stack) == &EG(symbol_table)) {
    2180               0 :                 zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC);
    2181                 :         }
    2182             260 :         *Z_ARRVAL_P(stack) = *new_hash;
    2183             260 :         FREE_HASHTABLE(new_hash);
    2184                 : 
    2185                 :         /* Clean up and return the number of elements in the stack */
    2186             260 :         efree(args);
    2187             260 :         RETVAL_LONG(zend_hash_num_elements(Z_ARRVAL_P(stack)));
    2188                 : }
    2189                 : /* }}} */
    2190                 : 
    2191                 : /* {{{ proto array array_splice(array input, int offset [, int length [, array replacement]])
    2192                 :    Removes the elements designated by offset and length and replace them with supplied array */
    2193                 : PHP_FUNCTION(array_splice)
    2194              62 : {
    2195                 :         zval    ***args,                                /* Function arguments array */
    2196                 :                   *array,                               /* Input array */
    2197              62 :                 ***repl = NULL;                         /* Replacement elements */
    2198              62 :         HashTable       *new_hash = NULL;               /* Output array's hash */
    2199                 :         Bucket          *p;                             /* Bucket used for traversing hash */
    2200                 :         int              argc,                          /* Number of function arguments */
    2201                 :                          i,
    2202                 :                          offset,
    2203                 :                          length,
    2204              62 :                          repl_num = 0;                  /* Number of replacement elements */
    2205                 : 
    2206                 :         /* Get the argument count and check it */
    2207              62 :         argc = ZEND_NUM_ARGS();
    2208              62 :         if (argc < 2 || argc > 4) {
    2209               4 :                 WRONG_PARAM_COUNT;
    2210                 :         }
    2211                 :         
    2212                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    2213              58 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    2214              58 :         if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
    2215               0 :                 efree(args);
    2216               0 :                 WRONG_PARAM_COUNT;
    2217                 :         }       
    2218                 : 
    2219                 :         /* Get first argument and check that it's an array */
    2220              58 :         array = *args[0];
    2221              58 :         if (Z_TYPE_P(array) != IS_ARRAY) {
    2222               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array");
    2223               2 :                 efree(args);
    2224               2 :                 return;
    2225                 :         }
    2226                 :         
    2227                 :         /* Get the next two arguments.  If length is omitted, it's assumed to be until the end of the array */
    2228              56 :         convert_to_long_ex(args[1]);
    2229              56 :         offset = Z_LVAL_PP(args[1]);
    2230              56 :         if (argc > 2) {
    2231              55 :                 convert_to_long_ex(args[2]);
    2232              55 :                 length = Z_LVAL_PP(args[2]);
    2233                 :         } else
    2234               1 :                 length = zend_hash_num_elements(Z_ARRVAL_P(array));
    2235                 : 
    2236              56 :         if (argc == 4) {
    2237                 :                 /* Make sure the last argument, if passed, is an array */
    2238              28 :                 convert_to_array_ex(args[3]);
    2239                 :                 
    2240                 :                 /* Create the array of replacement elements */
    2241              28 :                 repl_num = zend_hash_num_elements(Z_ARRVAL_PP(args[3]));
    2242              28 :                 repl = (zval ***)safe_emalloc(repl_num, sizeof(zval **), 0);
    2243              96 :                 for (p=Z_ARRVAL_PP(args[3])->pListHead, i=0; p; p=p->pListNext, i++) {
    2244              68 :                         repl[i] = ((zval **)p->pData);
    2245                 :                 }
    2246                 :         }
    2247                 :         
    2248                 :         /* Initialize return value */
    2249              56 :         array_init(return_value);
    2250                 :         
    2251                 :         /* Perform splice */
    2252              56 :         new_hash = php_splice(Z_ARRVAL_P(array), offset, length,
    2253                 :                                                         repl, repl_num,
    2254                 :                                                         &Z_ARRVAL_P(return_value));
    2255                 :         
    2256                 :         /* Replace input array's hashtable with the new one */
    2257              56 :         zend_hash_destroy(Z_ARRVAL_P(array));
    2258              56 :         if (Z_ARRVAL_P(array) == &EG(symbol_table)) {
    2259               1 :                 zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC);
    2260                 :         }
    2261              56 :         *Z_ARRVAL_P(array) = *new_hash;
    2262              56 :         FREE_HASHTABLE(new_hash);
    2263                 :         
    2264                 :         /* Clean up */
    2265              56 :         if (argc == 4)
    2266              28 :                 efree(repl);
    2267              56 :         efree(args);
    2268                 : }
    2269                 : /* }}} */
    2270                 : 
    2271                 : /* {{{ proto array array_slice(array input, int offset [, int length [, bool preserve_keys]])
    2272                 :    Returns elements specified by offset and length */
    2273                 : PHP_FUNCTION(array_slice)
    2274             131 : {
    2275                 :         zval     *input,                /* Input array */
    2276                 :                         **z_length,             /* How many elements to get */
    2277                 :                         **entry;                /* An array entry */
    2278                 :         long     offset,                /* Offset to get elements from */
    2279             131 :                          length = 0;
    2280             131 :         zend_bool preserve_keys = 0; /* Whether to preserve keys while copying to the new array or not */
    2281                 :         int              num_in,                /* Number of elements in the input array */
    2282                 :                          pos;                   /* Current position in the array */
    2283                 :         char *string_key;
    2284                 :         uint string_key_len;
    2285                 :         ulong num_key;
    2286                 :         HashPosition hpos;
    2287                 : 
    2288             131 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "al|Zb", &input, &offset, &z_length, &preserve_keys) == FAILURE) {
    2289              10 :                 return;
    2290                 :         }
    2291                 : 
    2292                 :         /* Get number of entries in the input hash */
    2293             121 :         num_in = zend_hash_num_elements(Z_ARRVAL_P(input));
    2294                 : 
    2295                 :         /* We want all entries from offset to the end if length is not passed or is null */
    2296             166 :         if (ZEND_NUM_ARGS() < 3 || Z_TYPE_PP(z_length) == IS_NULL) {
    2297              45 :                 length = num_in;
    2298                 :         } else {
    2299              76 :                 convert_to_long_ex(z_length);
    2300              76 :                 length = Z_LVAL_PP(z_length);
    2301                 :         }
    2302                 : 
    2303                 :         /* Initialize returned array */
    2304             121 :         array_init(return_value);
    2305                 : 
    2306                 :         /* Clamp the offset.. */
    2307             121 :         if (offset > num_in) {
    2308               5 :                 return;
    2309             116 :         } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
    2310               6 :                 offset = 0;
    2311                 :         }
    2312                 : 
    2313                 :         /* ..and the length */
    2314             116 :         if (length < 0) {
    2315               7 :                 length = num_in - offset + length;
    2316             109 :         } else if (((unsigned long) offset + (unsigned long) length) > (unsigned) num_in) {
    2317              50 :                 length = num_in - offset;
    2318                 :         }
    2319                 : 
    2320             116 :         if (length == 0) {
    2321               9 :                 return;
    2322                 :         }
    2323                 : 
    2324                 :         /* Start at the beginning and go until we hit offset */
    2325             107 :         pos = 0;
    2326             107 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &hpos);
    2327             275 :         while (pos < offset && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) {
    2328              61 :                 pos++;
    2329              61 :                 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos);
    2330                 :         }
    2331                 : 
    2332                 :         /* Copy elements from input array to the one that's returned */
    2333             499 :         while (pos < offset + length && zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &hpos) == SUCCESS) {
    2334                 : 
    2335             285 :                 zval_add_ref(entry);
    2336                 : 
    2337             285 :                 switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &hpos)) {
    2338                 :                         case HASH_KEY_IS_STRING:
    2339              95 :                                 zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, entry, sizeof(zval *), NULL);
    2340              95 :                                 break;
    2341                 : 
    2342                 :                         case HASH_KEY_IS_LONG:
    2343             190 :                                 if (preserve_keys) {
    2344              51 :                                         zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(zval *), NULL);
    2345                 :                                 } else {
    2346             139 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry, sizeof(zval *), NULL);
    2347                 :                                 }
    2348                 :                                 break;
    2349                 :                 }
    2350             285 :                 pos++;
    2351             285 :                 zend_hash_move_forward_ex(Z_ARRVAL_P(input), &hpos);
    2352                 :         }
    2353                 : }
    2354                 : /* }}} */
    2355                 : 
    2356                 : PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS_DC) /* {{{ */
    2357             375 : {
    2358                 :         zval **src_entry, **dest_entry;
    2359                 :         char *string_key;
    2360                 :         uint string_key_len;
    2361                 :         ulong num_key;
    2362                 :         HashPosition pos;
    2363                 : 
    2364             375 :         zend_hash_internal_pointer_reset_ex(src, &pos);
    2365            2184 :         while (zend_hash_get_current_data_ex(src, (void **)&src_entry, &pos) == SUCCESS) {
    2366            1444 :                 switch (zend_hash_get_current_key_ex(src, &string_key, &string_key_len, &num_key, 0, &pos)) {
    2367                 :                         case HASH_KEY_IS_STRING:
    2368             591 :                                 if (recursive && zend_hash_find(dest, string_key, string_key_len, (void **)&dest_entry) == SUCCESS) {
    2369              36 :                                         HashTable *thash = HASH_OF(*dest_entry);
    2370                 : 
    2371              36 :                                         if ((thash && thash->nApplyCount > 1) || (*src_entry == *dest_entry && (*dest_entry)->is_ref && ((*dest_entry)->refcount % 2))) {
    2372               2 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
    2373               2 :                                                 return 0;
    2374                 :                                         }
    2375              34 :                                         SEPARATE_ZVAL(dest_entry);
    2376              34 :                                         SEPARATE_ZVAL(src_entry);
    2377                 :                                         
    2378              34 :                                         if (Z_TYPE_PP(dest_entry) == IS_NULL) {
    2379               2 :                                                 convert_to_array_ex(dest_entry);
    2380               2 :                                                 add_next_index_null(*dest_entry);
    2381                 :                                         } else {
    2382              32 :                                                 convert_to_array_ex(dest_entry);
    2383                 :                                         }
    2384              34 :                                         if (Z_TYPE_PP(src_entry) == IS_NULL) {
    2385               1 :                                                 convert_to_array_ex(src_entry);
    2386               1 :                                                 add_next_index_null(*src_entry);
    2387                 :                                         } else {
    2388              33 :                                                 convert_to_array_ex(src_entry);
    2389                 :                                         }                       
    2390              34 :                                         if (thash) {
    2391              15 :                                                 thash->nApplyCount++;
    2392                 :                                         }
    2393              34 :                                         if (!php_array_merge(Z_ARRVAL_PP(dest_entry), Z_ARRVAL_PP(src_entry), recursive TSRMLS_CC)) {
    2394               8 :                                                 if (thash) {
    2395               8 :                                                         thash->nApplyCount--;
    2396                 :                                                 }
    2397               8 :                                                 return 0;
    2398                 :                                         }
    2399              26 :                                         if (thash) {
    2400               7 :                                                 thash->nApplyCount--;
    2401                 :                                         }
    2402                 :                                 } else {
    2403             529 :                                         (*src_entry)->refcount++;
    2404                 : 
    2405             529 :                                         zend_hash_update(dest, string_key, string_key_len,
    2406                 :                                                                          src_entry, sizeof(zval *), NULL);
    2407                 :                                 }
    2408             555 :                                 break;
    2409                 : 
    2410                 :                         case HASH_KEY_IS_LONG:
    2411             879 :                                 (*src_entry)->refcount++;
    2412             879 :                                 zend_hash_next_index_insert(dest, src_entry, sizeof(zval *), NULL);
    2413                 :                                 break;
    2414                 :                 }
    2415                 : 
    2416            1434 :                 zend_hash_move_forward_ex(src, &pos);
    2417                 :         }
    2418                 : 
    2419             365 :         return 1;
    2420                 : }
    2421                 : /* }}} */
    2422                 : 
    2423                 : static void php_array_merge_wrapper(INTERNAL_FUNCTION_PARAMETERS, int recursive) /* {{{ */
    2424             313 : {
    2425             313 :         zval ***args = NULL;
    2426             313 :         int argc, i, params_ok = 1;
    2427                 : 
    2428                 :         /* Get the argument count and check it */       
    2429             313 :         argc = ZEND_NUM_ARGS();
    2430             313 :         if (argc < 1) {
    2431               2 :                 WRONG_PARAM_COUNT;
    2432                 :         }
    2433                 :         
    2434                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    2435             311 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    2436             311 :         if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
    2437               0 :                 efree(args);
    2438               0 :                 WRONG_PARAM_COUNT;
    2439                 :         }
    2440                 : 
    2441             868 :         for (i = 0; i < argc; i++) {
    2442             557 :                 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
    2443             120 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i+1);
    2444             120 :                         params_ok = 0;
    2445                 :                 }
    2446                 :         }
    2447             311 :         if (params_ok == 0) {
    2448             120 :                 efree(args);
    2449             120 :                 return;
    2450                 :         }
    2451                 : 
    2452             191 :         array_init(return_value);
    2453                 :         
    2454             532 :         for (i=0; i<argc; i++) {
    2455             341 :                 SEPARATE_ZVAL(args[i]);
    2456             341 :                 convert_to_array_ex(args[i]);
    2457             341 :                 php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_PP(args[i]), recursive TSRMLS_CC);
    2458                 :         }
    2459                 :         
    2460             191 :         efree(args);
    2461                 : }
    2462                 : /* }}} */
    2463                 : 
    2464                 : /* {{{ proto array array_merge(array arr1, array arr2 [, array ...])
    2465                 :    Merges elements from passed arrays into one array */
    2466                 : PHP_FUNCTION(array_merge)
    2467             136 : {
    2468             136 :         php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    2469             136 : }
    2470                 : /* }}} */
    2471                 : 
    2472                 : /* {{{ proto array array_merge_recursive(array arr1, array arr2 [, array ...])
    2473                 :    Recursively merges elements from passed arrays into one array */
    2474                 : PHP_FUNCTION(array_merge_recursive)
    2475             177 : {
    2476             177 :         php_array_merge_wrapper(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    2477             177 : }
    2478                 : /* }}} */
    2479                 : 
    2480                 : /* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])
    2481                 :    Return just the keys from the input array, optionally only for the specified search_value */
    2482                 : PHP_FUNCTION(array_keys)
    2483              66 : {
    2484                 :         zval **input,           /* Input array */
    2485                 :              **search_value,    /* Value to search for */
    2486                 :              **entry,           /* An entry in the input array */
    2487                 :                res,             /* Result of comparison */
    2488                 :              **strict,          /* be strict */
    2489                 :               *new_val;         /* New value */
    2490                 :         int    add_key;         /* Flag to indicate whether a key should be added */
    2491                 :         char  *string_key;      /* String key */
    2492                 :         uint   string_key_len;
    2493                 :         ulong  num_key;         /* Numeric key */
    2494                 :         HashPosition pos;
    2495              66 :         int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
    2496                 : 
    2497                 : 
    2498              66 :         search_value = NULL;
    2499                 :         
    2500                 :         /* Get arguments and do error-checking */
    2501              66 :         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 3 ||
    2502                 :                 zend_get_parameters_ex(ZEND_NUM_ARGS(), &input, &search_value, &strict) == FAILURE) {
    2503               2 :                 WRONG_PARAM_COUNT;
    2504                 :         }
    2505                 :         
    2506              64 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    2507               3 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array");
    2508               3 :                 return;
    2509                 :         }
    2510              61 :         if (ZEND_NUM_ARGS() == 3) {
    2511              14 :                 convert_to_boolean_ex(strict);
    2512              14 :                 if (Z_LVAL_PP(strict)) {
    2513              14 :                         is_equal_func = is_identical_function;
    2514                 :                 }
    2515                 :         }
    2516                 :         
    2517                 :         /* Initialize return array */
    2518              61 :         array_init(return_value);
    2519              61 :         add_key = 1;
    2520                 :         
    2521                 :         /* Go through input array and add keys to the return array */
    2522              61 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos);
    2523             954 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, &pos) == SUCCESS) {
    2524             832 :                 if (search_value != NULL) {
    2525             176 :                         is_equal_func(&res, *search_value, *entry TSRMLS_CC);
    2526             176 :                         add_key = zval_is_true(&res);
    2527                 :                 }
    2528                 :         
    2529             832 :                 if (add_key) {  
    2530             691 :                         MAKE_STD_ZVAL(new_val);
    2531                 : 
    2532             691 :                         switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(input), &string_key, &string_key_len, &num_key, 1, &pos)) {
    2533                 :                                 case HASH_KEY_IS_STRING:
    2534             618 :                                         Z_TYPE_P(new_val) = IS_STRING;
    2535             618 :                                         Z_STRVAL_P(new_val) = string_key;
    2536             618 :                                         Z_STRLEN_P(new_val) = string_key_len-1;
    2537             618 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val,
    2538                 :                                                                                                 sizeof(zval *), NULL);
    2539             618 :                                         break;
    2540                 : 
    2541                 :                                 case HASH_KEY_IS_LONG:
    2542              73 :                                         Z_TYPE_P(new_val) = IS_LONG;
    2543              73 :                                         Z_LVAL_P(new_val) = num_key;
    2544              73 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val,
    2545                 :                                                                                                 sizeof(zval *), NULL);
    2546                 :                                         break;
    2547                 :                         }
    2548                 :                 }
    2549                 : 
    2550             832 :                 zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos);
    2551                 :         }
    2552                 : }
    2553                 : /* }}} */
    2554                 : 
    2555                 : /* {{{ proto array array_values(array input)
    2556                 :    Return just the values from the input array */
    2557                 : PHP_FUNCTION(array_values)
    2558              84 : {
    2559                 :         zval    **input,                /* Input array */
    2560                 :                 **entry;                /* An entry in the input array */
    2561                 :         HashPosition pos;
    2562                 :         
    2563                 :         /* Get arguments and do error-checking */
    2564              84 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &input) == FAILURE) {
    2565               4 :                 WRONG_PARAM_COUNT;
    2566                 :         }
    2567                 :         
    2568              80 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    2569              27 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2570              27 :                 return;
    2571                 :         }
    2572                 :         
    2573                 :         /* Initialize return array */
    2574              53 :         array_init(return_value);
    2575                 : 
    2576                 :         /* Go through input array and add values to the return array */ 
    2577              53 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos);
    2578             242 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, &pos) == SUCCESS) {
    2579                 :                 
    2580             136 :                 (*entry)->refcount++;
    2581             136 :                 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry,
    2582                 :                                                                                         sizeof(zval *), NULL);
    2583                 : 
    2584             136 :                 zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos);
    2585                 :         }
    2586                 : }
    2587                 : /* }}} */
    2588                 : 
    2589                 : /* {{{ proto array array_count_values(array input)
    2590                 :    Return the value as key and the frequency of that value in input as value */
    2591                 : PHP_FUNCTION(array_count_values)
    2592              19 : {
    2593                 :         zval    **input,                /* Input array */
    2594                 :                 **entry,                /* An entry in the input array */
    2595                 :                 **tmp;
    2596                 :         HashTable *myht;
    2597                 :         HashPosition pos;
    2598                 :         
    2599                 :         /* Get arguments and do error-checking */
    2600              19 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &input) == FAILURE) {
    2601               2 :                 WRONG_PARAM_COUNT;
    2602                 :         }
    2603                 :         
    2604              17 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    2605               1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2606               1 :                 return;
    2607                 :         }
    2608                 :         
    2609                 :         /* Initialize return array */
    2610              16 :         array_init(return_value);
    2611                 : 
    2612                 :         /* Go through input array and add values to the return array */ 
    2613              16 :         myht = Z_ARRVAL_PP(input);
    2614              16 :         zend_hash_internal_pointer_reset_ex(myht, &pos);
    2615              89 :         while (zend_hash_get_current_data_ex(myht, (void **)&entry, &pos) == SUCCESS) {
    2616              57 :                 if (Z_TYPE_PP(entry) == IS_LONG) {
    2617              17 :                         if (zend_hash_index_find(Z_ARRVAL_P(return_value), 
    2618                 :                                                                          Z_LVAL_PP(entry), 
    2619                 :                                                                          (void**)&tmp) == FAILURE) {
    2620                 :                                 zval *data;
    2621              13 :                                 MAKE_STD_ZVAL(data);
    2622              13 :                                 ZVAL_LONG(data, 1);
    2623              13 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &data, sizeof(data), NULL);
    2624                 :                         } else {
    2625               4 :                                 Z_LVAL_PP(tmp)++;
    2626                 :                         }
    2627              40 :                 } else if (Z_TYPE_PP(entry) == IS_STRING) {
    2628              31 :                         if (zend_symtable_find(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, (void**)&tmp) == FAILURE) {
    2629                 :                                 zval *data;
    2630              22 :                                 MAKE_STD_ZVAL(data);
    2631              22 :                                 ZVAL_LONG(data, 1);
    2632              22 :                                 zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, &data, sizeof(data), NULL);
    2633                 :                         } else {
    2634               9 :                                 Z_LVAL_PP(tmp)++;
    2635                 :                         }
    2636                 :                 } else {
    2637               9 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only count STRING and INTEGER values!");
    2638                 :                 }
    2639                 : 
    2640              57 :                 zend_hash_move_forward_ex(myht, &pos);
    2641                 :         }
    2642                 : }
    2643                 : /* }}} */
    2644                 : 
    2645                 : /* {{{ proto array array_reverse(array input [, bool preserve keys])
    2646                 :    Return input as a new array with the order of the entries reversed */
    2647                 : PHP_FUNCTION(array_reverse)
    2648             234 : {
    2649                 :         zval    **input,                          /* Input array */
    2650                 :                 **z_preserve_keys, /* Flag: whether to preserve keys */
    2651                 :                 **entry;                          /* An entry in the input array */
    2652                 :         char     *string_key;
    2653                 :         uint      string_key_len;
    2654                 :         ulong     num_key;
    2655             234 :         zend_bool preserve_keys = 0;
    2656                 :         HashPosition pos;
    2657                 :         
    2658                 :         /* Get arguments and do error-checking */
    2659             234 :         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &input, &z_preserve_keys) == FAILURE) {
    2660               3 :                 WRONG_PARAM_COUNT;
    2661                 :         }
    2662                 :         
    2663             231 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    2664              72 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2665              72 :                 return;
    2666                 :         }
    2667                 : 
    2668             159 :         if (ZEND_NUM_ARGS() > 1) {
    2669             114 :                 convert_to_boolean_ex(z_preserve_keys);
    2670             114 :                 preserve_keys = Z_BVAL_PP(z_preserve_keys);
    2671                 :         }
    2672                 :         
    2673                 :         /* Initialize return array */
    2674             159 :         array_init(return_value);
    2675                 :         
    2676             159 :         zend_hash_internal_pointer_end_ex(Z_ARRVAL_PP(input), &pos);
    2677             872 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, &pos) == SUCCESS) {
    2678             554 :                 (*entry)->refcount++;
    2679                 :                 
    2680             554 :                 switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(input), &string_key, &string_key_len, &num_key, 0, &pos)) {
    2681                 :                         case HASH_KEY_IS_STRING:
    2682             182 :                                 zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, entry, sizeof(zval *), NULL);
    2683             182 :                                 break;
    2684                 : 
    2685                 :                         case HASH_KEY_IS_LONG:
    2686             372 :                                 if (preserve_keys) {
    2687             159 :                                         zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(zval *), NULL);
    2688                 :                                 } else {
    2689             213 :                                         zend_hash_next_index_insert(Z_ARRVAL_P(return_value), entry, sizeof(zval *), NULL);
    2690                 :                                 }
    2691                 :                                 break;
    2692                 :                 }
    2693                 :                 
    2694             554 :                 zend_hash_move_backwards_ex(Z_ARRVAL_PP(input), &pos);
    2695                 :         }
    2696                 : }
    2697                 : /* }}} */
    2698                 : 
    2699                 : /* {{{ proto array array_pad(array input, int pad_size, mixed pad_value)
    2700                 :    Returns a copy of input array padded with pad_value to size pad_size */
    2701                 : PHP_FUNCTION(array_pad)
    2702             204 : {
    2703                 :         zval  **input;          /* Input array */
    2704                 :         zval  **pad_size;       /* Size to pad to */
    2705                 :         zval  **pad_value;      /* Padding value obviously */
    2706                 :         zval ***pads;           /* Array to pass to splice */
    2707                 :         HashTable *new_hash;    /* Return value from splice */
    2708                 :         int     input_size;     /* Size of the input array */
    2709                 :         int     pad_size_abs;   /* Absolute value of pad_size */
    2710                 :         int     num_pads;       /* How many pads do we need */
    2711                 :         int     do_pad;         /* Whether we should do padding at all */
    2712                 :         int     i;
    2713                 :         
    2714                 :         /* Get arguments and do error-checking */
    2715             204 :         if (ZEND_NUM_ARGS() != 3 || zend_get_parameters_ex(3, &input, &pad_size, &pad_value) == FAILURE) {
    2716               7 :                 WRONG_PARAM_COUNT;
    2717                 :         }
    2718                 :         
    2719                 :         /* Make sure arguments are of the proper type */
    2720             197 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    2721              49 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2722              49 :                 return;
    2723                 :         }
    2724             148 :         convert_to_long_ex(pad_size);
    2725                 :         
    2726                 :         /* Do some initial calculations */
    2727             148 :         input_size = zend_hash_num_elements(Z_ARRVAL_PP(input));
    2728             148 :         pad_size_abs = abs(Z_LVAL_PP(pad_size));
    2729             148 :         if (pad_size_abs < 0) {
    2730               1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "You may only pad up to 1048576 elements at a time");
    2731               1 :                 zval_dtor(return_value);
    2732               1 :                 RETURN_FALSE;
    2733                 :         }
    2734             147 :         do_pad = (input_size >= pad_size_abs) ? 0 : 1;
    2735                 :         
    2736                 :         /* Copy the original array */
    2737             147 :         RETVAL_ZVAL(*input, 1, 0);
    2738                 :         
    2739                 :         /* If no need to pad, no need to continue */
    2740             147 :         if (!do_pad) {
    2741              27 :                 return;
    2742                 :         }
    2743                 : 
    2744                 :         /* Populate the pads array */
    2745             120 :         num_pads = pad_size_abs - input_size;
    2746             120 :         if(num_pads > 1048576) {
    2747               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "You may only pad up to 1048576 elements at a time");
    2748               2 :                 zval_dtor(return_value);
    2749               2 :                 RETURN_FALSE;
    2750                 :         }
    2751             118 :         pads = (zval ***)safe_emalloc(num_pads, sizeof(zval **), 0);
    2752            1413 :         for (i = 0; i < num_pads; i++) {
    2753            1295 :                 pads[i] = pad_value;
    2754                 :         }
    2755                 : 
    2756                 :         /* Pad on the right or on the left */
    2757             118 :         if (Z_LVAL_PP(pad_size) > 0) {
    2758              60 :                 new_hash = php_splice(Z_ARRVAL_P(return_value), input_size, 0, pads, num_pads, NULL);
    2759                 :         } else {
    2760              58 :                 new_hash = php_splice(Z_ARRVAL_P(return_value), 0, 0, pads, num_pads, NULL);
    2761                 :         }
    2762                 : 
    2763                 :         /* Copy the result hash into return value */
    2764             118 :         zend_hash_destroy(Z_ARRVAL_P(return_value));
    2765             118 :         if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) {
    2766               0 :                 zend_reset_all_cv(&EG(symbol_table) TSRMLS_CC);
    2767                 :         }
    2768             118 :         *Z_ARRVAL_P(return_value) = *new_hash;
    2769             118 :         FREE_HASHTABLE(new_hash);
    2770                 :         
    2771                 :         /* Clean up */
    2772             118 :         efree(pads);
    2773                 : }
    2774                 : /* }}} */
    2775                 : 
    2776                 : /* {{{ proto array array_flip(array input)
    2777                 :    Return array with key <-> value flipped */
    2778                 : PHP_FUNCTION(array_flip)
    2779              53 : {
    2780                 :         zval **array, **entry, *data;
    2781                 :         HashTable *target_hash;
    2782                 :         char *string_key;
    2783                 :         uint str_key_len;
    2784                 :         ulong num_key;
    2785                 :         HashPosition pos;
    2786                 :                                         
    2787              53 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
    2788               3 :                 WRONG_PARAM_COUNT;
    2789                 :         }
    2790                 : 
    2791              50 :         target_hash = HASH_OF(*array);
    2792              50 :         if (!target_hash) {
    2793              22 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2794              22 :                 RETURN_FALSE;
    2795                 :         }
    2796                 :         
    2797              28 :         array_init(return_value);
    2798                 : 
    2799              28 :         zend_hash_internal_pointer_reset_ex(target_hash, &pos);
    2800             208 :         while (zend_hash_get_current_data_ex(target_hash, (void **)&entry, &pos) == SUCCESS) {
    2801             152 :                 MAKE_STD_ZVAL(data);
    2802             152 :                 switch (zend_hash_get_current_key_ex(target_hash, &string_key, &str_key_len, &num_key, 1, &pos)) {
    2803                 :                         case HASH_KEY_IS_STRING:
    2804              68 :                                 Z_STRVAL_P(data) = string_key;
    2805              68 :                                 Z_STRLEN_P(data) = str_key_len-1;
    2806              68 :                                 Z_TYPE_P(data) = IS_STRING;
    2807              68 :                                 break;
    2808                 :                         case HASH_KEY_IS_LONG:
    2809              84 :                                 Z_TYPE_P(data) = IS_LONG;
    2810              84 :                                 Z_LVAL_P(data) = num_key;
    2811                 :                                 break;
    2812                 :                 }
    2813                 : 
    2814             152 :                 if (Z_TYPE_PP(entry) == IS_LONG) {
    2815              81 :                         zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &data, sizeof(data), NULL);
    2816              71 :                 } else if (Z_TYPE_PP(entry) == IS_STRING) {
    2817              55 :                         zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, &data, sizeof(data), NULL);
    2818                 :                 } else {
    2819              16 :                         zval_ptr_dtor(&data); /* will free also zval structure */
    2820              16 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only flip STRING and INTEGER values!");
    2821                 :                 }
    2822                 :         
    2823             152 :                 zend_hash_move_forward_ex(target_hash, &pos);
    2824                 :         }
    2825                 : }
    2826                 : /* }}} */
    2827                 : 
    2828                 : /* {{{ proto array array_change_key_case(array input [, int case=CASE_LOWER])
    2829                 :    Retuns an array with all string keys lowercased [or uppercased] */
    2830                 : PHP_FUNCTION(array_change_key_case)
    2831             201 : {
    2832                 :         zval **array, **entry, **to_upper;
    2833                 :         char *string_key;
    2834                 :         char *new_key;
    2835                 :         uint str_key_len;
    2836                 :         ulong num_key;
    2837             201 :         ulong change_to_upper=0;
    2838                 : 
    2839                 :         HashPosition pos;
    2840                 :                                         
    2841             201 :         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 || 
    2842                 :                 zend_get_parameters_ex(ZEND_NUM_ARGS(), &array, &to_upper) == FAILURE) {
    2843               2 :                 WRONG_PARAM_COUNT;
    2844                 :         }
    2845                 : 
    2846             199 :         if (ZEND_NUM_ARGS() > 1) {
    2847             133 :                 convert_to_long_ex(to_upper);
    2848             133 :                 change_to_upper = Z_LVAL_PP(to_upper);
    2849                 :         }
    2850                 : 
    2851             199 :         if (Z_TYPE_PP(array) != IS_ARRAY) {
    2852              26 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2853              26 :                 RETURN_FALSE;
    2854                 :         }
    2855                 : 
    2856             173 :         array_init(return_value);
    2857                 : 
    2858             173 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(array), &pos);
    2859             777 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(array), (void **)&entry, &pos) == SUCCESS) {
    2860             431 :                 (*entry)->refcount++; 
    2861                 : 
    2862             431 :                 switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(array), &string_key, &str_key_len, &num_key, 0, &pos)) {
    2863                 :                         case HASH_KEY_IS_LONG:
    2864              64 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, entry, sizeof(entry), NULL);
    2865              64 :                                 break;
    2866                 :                         case HASH_KEY_IS_STRING:
    2867             367 :                                 new_key=estrndup(string_key,str_key_len - 1);
    2868             367 :                                 if (change_to_upper)
    2869             169 :                                         php_strtoupper(new_key, str_key_len - 1);
    2870                 :                                 else
    2871             198 :                                         php_strtolower(new_key, str_key_len - 1);
    2872             367 :                                 zend_hash_update(Z_ARRVAL_P(return_value), new_key, str_key_len, entry, sizeof(entry), NULL);
    2873             367 :                                 efree(new_key);
    2874                 :                                 break;
    2875                 :                 }
    2876                 : 
    2877             431 :                 zend_hash_move_forward_ex(Z_ARRVAL_PP(array), &pos);
    2878                 :         }
    2879                 : }
    2880                 : /* }}} */
    2881                 : 
    2882                 : /* {{{ proto array array_unique(array input [, int sort_flags])
    2883                 :    Removes duplicate values from array */
    2884                 : PHP_FUNCTION(array_unique)
    2885              71 : {
    2886                 :         zval **array, *tmp;
    2887                 :         HashTable *target_hash;
    2888                 :         Bucket *p;
    2889                 :         struct bucketindex {
    2890                 :                 Bucket *b;
    2891                 :                 unsigned int i;
    2892                 :         };
    2893                 :         struct bucketindex *arTmp, *cmpdata, *lastkept;
    2894                 :         unsigned int i;
    2895              71 :         long sort_type = SORT_STRING;
    2896                 : 
    2897              71 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &array, &sort_type) == FAILURE) {
    2898               2 :                 return;
    2899                 :         }
    2900              69 :         target_hash = HASH_OF(*array);
    2901              69 :         if (!target_hash) {
    2902              23 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    2903              23 :                 RETURN_FALSE;
    2904                 :         }
    2905                 : 
    2906              46 :         set_compare_func(sort_type TSRMLS_CC);
    2907                 : 
    2908              46 :         array_init(return_value);
    2909              46 :         zend_hash_copy(Z_ARRVAL_P(return_value), target_hash, (copy_ctor_func_t) zval_add_ref, (void *)&tmp, sizeof(zval*));
    2910                 : 
    2911              46 :         if (target_hash->nNumOfElements <= 1) {   /* nothing to do */
    2912               3 :                 return;
    2913                 :         }
    2914                 : 
    2915                 :         /* create and sort array with pointers to the target_hash buckets */
    2916              43 :         arTmp = (struct bucketindex *) pemalloc((target_hash->nNumOfElements + 1) * sizeof(struct bucketindex), target_hash->persistent);
    2917              43 :         if (!arTmp) {
    2918               0 :                 RETURN_FALSE;
    2919                 :         }
    2920            8813 :         for (i = 0, p = target_hash->pListHead; p; i++, p = p->pListNext) {
    2921            8770 :                 arTmp[i].b = p;
    2922            8770 :                 arTmp[i].i = i;
    2923                 :         }
    2924              43 :         arTmp[i].b = NULL;
    2925              43 :         zend_qsort((void *) arTmp, i, sizeof(struct bucketindex), array_data_compare TSRMLS_CC);
    2926                 : 
    2927                 :         /* go through the sorted array and delete duplicates from the copy */
    2928              43 :         lastkept = arTmp;
    2929            8770 :         for (cmpdata = arTmp + 1; cmpdata->b; cmpdata++) {
    2930            8727 :                 if (array_data_compare(lastkept, cmpdata TSRMLS_CC)) {
    2931            8662 :                         lastkept = cmpdata;
    2932                 :                 } else {
    2933              65 :                         if (lastkept->i > cmpdata->i) {
    2934              43 :                                 p = lastkept->b;
    2935              43 :                                 lastkept = cmpdata;
    2936                 :                         } else {
    2937              22 :                                 p = cmpdata->b;
    2938                 :                         }
    2939              65 :                         if (p->nKeyLength) {
    2940              24 :                                 if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) {
    2941               0 :                                         zend_delete_global_variable(p->arKey, p->nKeyLength-1 TSRMLS_CC);
    2942                 :                                 } else {
    2943              24 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength);
    2944                 :                                 }
    2945                 :                         } else {
    2946              41 :                                 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    2947                 :                         }
    2948                 :                 }
    2949                 :         }
    2950              43 :         pefree(arTmp, target_hash->persistent);
    2951                 : }
    2952                 : /* }}} */
    2953                 : 
    2954                 : static int zval_compare(zval **a, zval **b TSRMLS_DC) /* {{{ */
    2955            1117 : {
    2956                 :         zval result;
    2957                 :         zval *first;
    2958                 :         zval *second;
    2959                 :  
    2960            1117 :         first = *((zval **) a);
    2961            1117 :         second = *((zval **) b);
    2962                 : 
    2963            1117 :         if (string_compare_function(&result, first, second TSRMLS_CC) == FAILURE) {
    2964               0 :                 return 0;
    2965                 :         } 
    2966                 : 
    2967            1117 :         if (Z_TYPE(result) == IS_DOUBLE) {
    2968               0 :                 if (Z_DVAL(result) < 0) {
    2969               0 :                         return -1;
    2970               0 :                 } else if (Z_DVAL(result) > 0) {
    2971               0 :                         return 1;
    2972                 :                 } else {
    2973               0 :                         return 0;
    2974                 :                 }
    2975                 :         }
    2976                 : 
    2977            1117 :         convert_to_long(&result);
    2978                 : 
    2979            1117 :         if (Z_LVAL(result) < 0) {
    2980             358 :                 return -1;
    2981             759 :         } else if (Z_LVAL(result) > 0) {
    2982             374 :                 return 1;
    2983                 :         } 
    2984                 : 
    2985             385 :         return 0;
    2986                 : }
    2987                 : /* }}} */
    2988                 : 
    2989                 : static int zval_user_compare(zval **a, zval **b TSRMLS_DC) /* {{{ */
    2990              44 : {
    2991                 :         zval **args[2];
    2992                 :         zval *retval_ptr;
    2993                 :         zend_fcall_info fci;
    2994                 : 
    2995              44 :         args[0] = (zval **) a;
    2996              44 :         args[1] = (zval **) b;
    2997                 : 
    2998              44 :         fci.size = sizeof(fci);
    2999              44 :         fci.function_table = EG(function_table);
    3000              44 :         fci.function_name = *BG(user_compare_func_name);
    3001              44 :         fci.symbol_table = NULL;
    3002              44 :         fci.object_pp = NULL;
    3003              44 :         fci.retval_ptr_ptr = &retval_ptr;
    3004              44 :         fci.param_count = 2;
    3005              44 :         fci.params = args;
    3006              44 :         fci.no_separation = 0;
    3007                 : 
    3008              44 :         if (zend_call_function(&fci, &BG(user_compare_fci_cache) TSRMLS_CC)== SUCCESS
    3009                 :                 && retval_ptr) {
    3010                 :                 long retval;
    3011                 : 
    3012              44 :                 convert_to_long_ex(&retval_ptr);
    3013              44 :                 retval = Z_LVAL_P(retval_ptr);
    3014              44 :                 zval_ptr_dtor(&retval_ptr);
    3015              44 :                 return retval < 0 ? -1 : retval > 0 ? 1 : 0;;
    3016                 :         } else {
    3017               0 :                 return 0;
    3018                 :         }
    3019                 : }
    3020                 : /* }}} */
    3021                 : 
    3022                 : static void php_array_intersect_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
    3023             552 : {
    3024                 :         Bucket *p;
    3025                 :         int argc, i;
    3026                 :         zval ***args;
    3027             552 :         int (*intersect_data_compare_func)(zval **, zval ** TSRMLS_DC) = NULL;
    3028                 :         zend_bool ok;
    3029                 :         zval **data;
    3030                 : 
    3031                 :         /* Get the argument count */
    3032             552 :         argc = ZEND_NUM_ARGS();
    3033                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    3034             552 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    3035             552 :         if (argc < 2 || zend_get_parameters_array_ex(argc, args) == FAILURE) {
    3036               4 :                 efree(args);
    3037               4 :                 WRONG_PARAM_COUNT;
    3038                 :         }
    3039             548 :         if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3040                 :                 char *callback_name;
    3041                 : 
    3042             111 :                 if (argc < 3) {
    3043               1 :                         efree(args);
    3044               1 :                         WRONG_PARAM_COUNT;
    3045                 :                 }
    3046             110 :                 argc--;
    3047             110 :                 if (!zend_is_callable(*args[argc], 0, &callback_name)) {
    3048              29 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3049              29 :                         efree(callback_name);
    3050              29 :                         efree(args);
    3051              29 :                         return;
    3052                 :                 } 
    3053              81 :                 efree(callback_name);
    3054              81 :                 intersect_data_compare_func = zval_user_compare;
    3055              81 :                 BG(user_compare_func_name) = args[argc];
    3056              81 :                 BG(user_compare_fci_cache).initialized = 0;
    3057             437 :         } else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
    3058             278 :                 intersect_data_compare_func = zval_compare;
    3059                 :         }
    3060                 : 
    3061            1275 :         for (i = 0; i < argc; i++) {
    3062            1058 :                 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
    3063             301 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
    3064             301 :                         RETVAL_NULL();
    3065             301 :                         goto out;
    3066                 :                 }
    3067                 :         }
    3068                 : 
    3069             217 :         array_init(return_value);
    3070                 : 
    3071            1935 :         for (p = Z_ARRVAL_PP(args[0])->pListHead; p != NULL; p = p->pListNext) {
    3072            1718 :                 if (p->nKeyLength == 0) {
    3073            1144 :                         ok = 1;
    3074            1351 :                         for (i = 1; i < argc; i++) {
    3075            1211 :                                 if (zend_hash_index_find(Z_ARRVAL_PP(args[i]), p->h, (void**)&data) == FAILURE ||
    3076                 :                                     (intersect_data_compare_func &&
    3077                 :                                      intersect_data_compare_func((zval**)p->pData, data TSRMLS_CC) != 0)) {
    3078            1004 :                                         ok = 0;
    3079            1004 :                                         break;
    3080                 :                                 }
    3081                 :                         }
    3082            1144 :                         if (ok) {
    3083             140 :                                 (*((zval**)p->pData))->refcount++;
    3084             140 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, p->pData, sizeof(zval*), NULL);
    3085                 :                         }
    3086                 :                 } else {
    3087             574 :                         ok = 1;
    3088             702 :                         for (i = 1; i < argc; i++) {
    3089             614 :                                 if (zend_hash_quick_find(Z_ARRVAL_PP(args[i]), p->arKey, p->nKeyLength, p->h, (void**)&data) == FAILURE ||
    3090                 :                                     (intersect_data_compare_func &&
    3091                 :                                      intersect_data_compare_func((zval**)p->pData, data TSRMLS_CC) != 0)) {
    3092             486 :                                         ok = 0;
    3093             486 :                                         break;
    3094                 :                                 }
    3095                 :                         }
    3096             574 :                         if (ok) {
    3097              88 :                                 (*((zval**)p->pData))->refcount++;
    3098              88 :                                 zend_hash_quick_update(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h, p->pData, sizeof(zval*), NULL);
    3099                 :                         }
    3100                 :                 }
    3101                 :         }
    3102             518 : out:
    3103             518 :         efree(args);
    3104                 : }
    3105                 : /* }}} */
    3106                 : 
    3107                 : static void php_array_intersect(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
    3108             960 : {
    3109             960 :         zval ***args = NULL;
    3110                 :         HashTable *hash;
    3111             960 :         int argc, arr_argc, i, c = 0;
    3112                 :         Bucket ***lists, **list, ***ptrs, *p;
    3113                 :         
    3114                 :         char *callback_name;
    3115                 :         PHP_ARRAY_CMP_FUNC_VARS;
    3116                 : 
    3117                 :         
    3118                 :         int (*intersect_key_compare_func)(const void *, const void * TSRMLS_DC);
    3119                 :         int (*intersect_data_compare_func)(const void *, const void * TSRMLS_DC);
    3120                 : 
    3121                 :         /* Get the argument count */
    3122             960 :         argc = ZEND_NUM_ARGS();
    3123                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    3124             960 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    3125             960 :         if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
    3126               0 :                 efree(args);
    3127               0 :                 WRONG_PARAM_COUNT;
    3128                 :         }
    3129                 : 
    3130             960 :         PHP_ARRAY_CMP_FUNC_BACKUP();
    3131                 : 
    3132             960 :         if (behavior == INTERSECT_NORMAL) {
    3133             397 :                 intersect_key_compare_func = array_key_compare;
    3134             397 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL) {
    3135                 :                         /* array_intersect() */
    3136                 : 
    3137             284 :                         if (argc < 2) {
    3138               2 :                                 efree(args);
    3139               2 :                                 WRONG_PARAM_COUNT;
    3140                 :                         }
    3141             282 :                         arr_argc = argc;
    3142             282 :                         intersect_data_compare_func = array_data_compare;
    3143             113 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3144                 :                         /* array_uintersect() */
    3145             113 :                         if (argc < 3) {
    3146               1 :                                 efree(args);
    3147               1 :                                 WRONG_PARAM_COUNT;
    3148                 :                         }
    3149             112 :                         arr_argc = argc - 1;
    3150             112 :                         intersect_data_compare_func = array_user_compare;
    3151             112 :                         if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3152              29 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3153              29 :                                 efree(callback_name);
    3154              29 :                                 efree(args);
    3155              29 :                                 return;
    3156                 :                         }
    3157              83 :                         efree(callback_name);
    3158                 : 
    3159              83 :                         BG(user_compare_func_name) = args[arr_argc];
    3160              83 :                         BG(user_compare_fci_cache).initialized = 0;
    3161                 :                 } else {
    3162               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
    3163               0 :                         return;
    3164                 :                 }
    3165             563 :         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3166                 :                 /*
    3167                 :                         INTERSECT_KEY is subset of INTERSECT_ASSOC. When having the former
    3168                 :                         no comparison of the data is done (part of INTERSECT_ASSOC)
    3169                 :                 */
    3170             563 :                 intersect_key_compare_func = array_key_compare;
    3171             563 :                 if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL
    3172                 :                                 &&
    3173                 :                         key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
    3174                 :                         /* array_intersect_assoc() or array_intersect_key() */
    3175                 :                         
    3176               0 :                         if (argc < 2) {
    3177               0 :                                 efree(args);
    3178               0 :                                 WRONG_PARAM_COUNT;
    3179                 :                         }
    3180               0 :                         arr_argc = argc;
    3181               0 :                         intersect_key_compare_func = array_key_compare;
    3182               0 :                         intersect_data_compare_func = array_data_compare;
    3183             563 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER 
    3184                 :                                 &&
    3185                 :                                 key_compare_type == INTERSECT_COMP_KEY_INTERNAL) {
    3186                 :                         /* array_uintersect_assoc() */
    3187                 :                         
    3188               0 :                         if (argc < 3) {
    3189               0 :                                 efree(args);
    3190               0 :                                 WRONG_PARAM_COUNT;
    3191                 :                         }
    3192               0 :                         arr_argc = argc - 1;
    3193               0 :                         if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3194               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3195               0 :                                 efree(callback_name);
    3196               0 :                                 efree(args);
    3197               0 :                                 return;
    3198                 :                         }
    3199               0 :                         efree(callback_name);
    3200               0 :                         intersect_key_compare_func = array_key_compare;
    3201               0 :                         intersect_data_compare_func = array_user_compare;
    3202             886 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_INTERNAL
    3203                 :                                 &&
    3204                 :                                 key_compare_type == INTERSECT_COMP_KEY_USER) {
    3205                 :                                 /* array_intersect_uassoc() or array_intersect_ukey() */
    3206                 :                                 
    3207             424 :                                 if (argc < 3) {
    3208               4 :                                         efree(args);
    3209               4 :                                         WRONG_PARAM_COUNT;
    3210                 :                                 }
    3211             420 :                                 arr_argc = argc - 1;
    3212             420 :                                 if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3213              97 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3214              97 :                                         efree(callback_name);
    3215              97 :                                         efree(args);
    3216              97 :                                         return;
    3217                 :                                 }
    3218             323 :                                 efree(callback_name);
    3219             323 :                                 intersect_key_compare_func = array_user_key_compare;
    3220             323 :                                 intersect_data_compare_func = array_data_compare;
    3221             323 :                                 BG(user_compare_func_name) = args[arr_argc];
    3222             323 :                                 BG(user_compare_fci_cache).initialized = 0;
    3223             220 :                 } else if (data_compare_type == INTERSECT_COMP_DATA_USER
    3224                 :                                 &&
    3225                 :                                 key_compare_type == INTERSECT_COMP_KEY_USER) {
    3226                 :                                 /* array_uintersect_uassoc() */
    3227                 : 
    3228             139 :                                 if (argc < 4) {
    3229               1 :                                         efree(args);
    3230               1 :                                         WRONG_PARAM_COUNT;
    3231                 :                                 }
    3232             138 :                                 arr_argc = argc - 2;
    3233             138 :                                 if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3234              28 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3235              28 :                                         efree(callback_name);
    3236              28 :                                         efree(args);
    3237              28 :                                         return;
    3238                 :                                 } 
    3239             110 :                                 efree(callback_name);
    3240             110 :                                 if (!zend_is_callable(*args[arr_argc + 1], 0, &callback_name)) {
    3241              29 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3242              29 :                                         efree(callback_name);
    3243              29 :                                         efree(args);
    3244              29 :                                         return;
    3245                 :                                 }
    3246              81 :                                 efree(callback_name);
    3247              81 :                                 intersect_key_compare_func = array_user_key_compare;
    3248              81 :                                 intersect_data_compare_func = array_user_compare;
    3249              81 :                                 BG(user_compare_func_name) = args[arr_argc + 1];/* data - key */
    3250              81 :                                 BG(user_compare_fci_cache).initialized = 0;
    3251                 :                 } else {
    3252               0 :                         efree(args);
    3253               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
    3254               0 :                         return;
    3255                 :                 }               
    3256                 :         } else {
    3257               0 :                 efree(args);
    3258               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
    3259               0 :                 return;
    3260                 :         }
    3261                 : 
    3262                 : 
    3263                 :         /* for each argument, create and sort list with pointers to the hash buckets */
    3264             769 :         lists = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
    3265             769 :         ptrs = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
    3266             769 :         set_compare_func(SORT_STRING TSRMLS_CC);
    3267            1801 :         for (i = 0; i < arr_argc; i++) {
    3268            1564 :                 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
    3269             532 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i+1);
    3270             532 :                         arr_argc = i; /* only free up to i-1 */
    3271             532 :                         goto out;
    3272                 :                 }
    3273            1032 :                 hash = HASH_OF(*args[i]);
    3274            1032 :                 list = (Bucket **) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket *), hash->persistent);
    3275            1032 :                 if (!list) {
    3276               0 :                         efree(args);
    3277               0 :                         efree(lists);
    3278               0 :                         efree(ptrs);
    3279               0 :                         RETURN_FALSE;
    3280                 :                 }
    3281            1032 :                 lists[i] = list;
    3282            1032 :                 ptrs[i] = list;
    3283            6582 :                 for (p = hash->pListHead; p; p = p->pListNext) {
    3284            5550 :                         *list++ = p;
    3285                 :                 }
    3286            1032 :                 *list = NULL;
    3287            1032 :                 if (behavior == INTERSECT_NORMAL) {
    3288             606 :                         zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), intersect_data_compare_func TSRMLS_CC);
    3289             426 :                 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3290             426 :                         zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), intersect_key_compare_func TSRMLS_CC);
    3291                 :                 }
    3292                 :         }
    3293                 : 
    3294                 :         /* copy the argument array */
    3295             237 :         RETVAL_ZVAL(*args[0], 1, 0);
    3296             237 :         if (return_value->value.ht == &EG(symbol_table)) {
    3297                 :                 HashTable *ht;
    3298                 :                 zval *tmp;
    3299                 : 
    3300               0 :                 ALLOC_HASHTABLE(ht);
    3301               0 :                 zend_hash_init(ht, zend_hash_num_elements(return_value->value.ht), NULL, ZVAL_PTR_DTOR, 0);
    3302               0 :                 zend_hash_copy(ht, return_value->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
    3303               0 :                 return_value->value.ht = ht;         
    3304                 :         }
    3305                 : 
    3306             237 :         if ((behavior & INTERSECT_NORMAL) && data_compare_type == INTERSECT_COMP_DATA_USER) {
    3307                 :                 /* array_uintersect() */
    3308               8 :                 BG(user_compare_func_name) = args[arr_argc];
    3309               8 :                 BG(user_compare_fci_cache).initialized = 0;
    3310                 :         }
    3311                 :         
    3312                 :         /* go through the lists and look for common values */
    3313             996 :         while (*ptrs[0]) {
    3314             753 :                 if ((behavior & INTERSECT_ASSOC) /* triggered also when INTERSECT_KEY */
    3315                 :                                 &&
    3316                 :                         key_compare_type == INTERSECT_COMP_KEY_USER) {
    3317                 : 
    3318             153 :                         BG(user_compare_func_name) = args[argc - 1];
    3319             153 :                         BG(user_compare_fci_cache).initialized = 0;
    3320                 :                 }
    3321                 : 
    3322            1261 :                 for (i = 1; i < arr_argc; i++) {
    3323             912 :                         if (behavior & INTERSECT_NORMAL) {
    3324            2360 :                                 while (*ptrs[i] && (0 < (c = intersect_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)))) {
    3325             874 :                                         ptrs[i]++;
    3326                 :                                 }
    3327             169 :                         } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3328             413 :                                 while (*ptrs[i] && (0 < (c = intersect_key_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)))) {
    3329              75 :                                         ptrs[i]++;
    3330                 :                                 }
    3331             169 :                                 if ((!c && *ptrs[i]) && (behavior == INTERSECT_ASSOC)) { /* only when INTERSECT_ASSOC */
    3332                 :                                         /* 
    3333                 :                                                 this means that ptrs[i] is not NULL so we can compare
    3334                 :                                                 and "c==0" is from last operation
    3335                 :                                                 in this branch of code we enter only when INTERSECT_ASSOC
    3336                 :                                                 since when we have INTERSECT_KEY compare of data is not
    3337                 :                                                 wanted. 
    3338                 :                                         */ 
    3339              44 :                                         if (data_compare_type == INTERSECT_COMP_DATA_USER) {
    3340              12 :                                                 BG(user_compare_func_name) = args[arr_argc];
    3341              12 :                                                 BG(user_compare_fci_cache).initialized = 0;
    3342                 :                                         }
    3343              44 :                                         if (intersect_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC) != 0) {
    3344              19 :                                                 c = 1;
    3345              19 :                                                 if (key_compare_type == INTERSECT_COMP_KEY_USER) {
    3346              19 :                                                         BG(user_compare_func_name) = args[argc - 1];
    3347              19 :                                                         BG(user_compare_fci_cache).initialized = 0;
    3348                 :                                                         /* When KEY_USER, the last parameter is always the callback */
    3349                 :                                                 }
    3350                 :                                                 /* we are going to the break */
    3351                 :                                         } else {
    3352                 :                                                 /* continue looping */
    3353                 :                                         }
    3354                 :                                 }
    3355                 :                         }
    3356             912 :                         if (!*ptrs[i]) {
    3357                 :                                 /* delete any values corresponding to remains of ptrs[0] */
    3358                 :                                 /* and exit because they do not present in at least one of */
    3359                 :                                 /* the other arguments */
    3360                 :                                 for (;;) {
    3361             698 :                                         p = *ptrs[0]++;
    3362             698 :                                         if (!p) {
    3363             109 :                                                 goto out;
    3364                 :                                         }
    3365             589 :                                         if (p->nKeyLength) {
    3366              67 :                                                 zend_hash_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength);
    3367                 :                                         } else {
    3368             522 :                                                 zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    3369                 :                                         }
    3370             589 :                                 }
    3371                 :                         }
    3372             803 :                         if (c) /* here we get if not all are equal */
    3373             295 :                                 break;
    3374             508 :                         ptrs[i]++;
    3375                 :                 }
    3376             644 :                 if (c) {
    3377                 :                         /* Value of ptrs[0] not in all arguments, delete all entries */
    3378                 :                         /* with value < value of ptrs[i] */
    3379                 :                         for (;;) {
    3380             679 :                                 p = *ptrs[0];
    3381             679 :                                 if (p->nKeyLength) {
    3382             115 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength);  
    3383                 :                                 } else {
    3384             564 :                                         zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);  
    3385                 :                                 }
    3386             679 :                                 if (!*++ptrs[0]) { 
    3387              54 :                                         goto out;
    3388                 :                                 }
    3389             625 :                                 if (behavior == INTERSECT_NORMAL) {
    3390             567 :                                         if (0 <= intersect_data_compare_func(ptrs[0], ptrs[i] TSRMLS_CC)) {
    3391             183 :                                                 break;
    3392                 :                                         }
    3393              58 :                                 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3394                 :                                         /* no need of looping because indexes are unique */
    3395              58 :                                         break;
    3396                 :                                 }
    3397             384 :                         }
    3398                 :                 } else {
    3399                 :                         /* ptrs[0] is present in all the arguments */
    3400                 :                         /* Skip all entries with same value as ptrs[0] */
    3401                 :                         for (;;) {
    3402             411 :                                 if (!*++ptrs[0]) {
    3403              68 :                                         goto out;
    3404                 :                                 }
    3405             343 :                                 if (behavior == INTERSECT_NORMAL) {
    3406             291 :                                         if (intersect_data_compare_func(ptrs[0]-1, ptrs[0] TSRMLS_CC)) {
    3407             229 :                                                 break;
    3408                 :                                         }
    3409              52 :                                 } else if (behavior & INTERSECT_ASSOC) { /* triggered also when INTERSECT_KEY */
    3410                 :                                         /* no need of looping because indexes are unique */
    3411              52 :                                         break;
    3412                 :                                 }
    3413              62 :                         }
    3414                 :                 }
    3415                 :         }
    3416             769 : out:
    3417            1801 :         for (i = 0; i < arr_argc; i++) {
    3418            1032 :                 hash = HASH_OF(*args[i]);
    3419            1032 :                 pefree(lists[i], hash->persistent);
    3420                 :         }
    3421                 :         
    3422             769 :         PHP_ARRAY_CMP_FUNC_RESTORE();
    3423                 : 
    3424                 :         
    3425             769 :         efree(ptrs);
    3426             769 :         efree(lists);
    3427             769 :         efree(args);
    3428                 : }
    3429                 : /* }}} */
    3430                 : 
    3431                 : /* {{{ proto array array_intersect_key(array arr1, array arr2 [, array ...])
    3432                 :    Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). Equivalent of array_intersect_assoc() but does not do compare of the data. */
    3433                 : PHP_FUNCTION(array_intersect_key)
    3434             161 : {
    3435             161 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_NONE);
    3436             161 : }
    3437                 : /* }}} */
    3438                 : 
    3439                 : /* {{{ proto array array_intersect_ukey(array arr1, array arr2 [, array ...], callback key_compare_func)
    3440                 :    Returns the entries of arr1 that have keys which are present in all the other arguments. Kind of equivalent to array_diff(array_keys($arr1), array_keys($arr2)[,array_keys(...)]). The comparison of the keys is performed by a user supplied function. Equivalent of array_intersect_uassoc() but does not do compare of the data. */
    3441                 : PHP_FUNCTION(array_intersect_ukey)
    3442             231 : {
    3443             231 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_KEY,
    3444                 :                                 INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
    3445             231 : }
    3446                 : /* }}} */
    3447                 : 
    3448                 : /* {{{ proto array array_intersect(array arr1, array arr2 [, array ...])
    3449                 :    Returns the entries of arr1 that have values which are present in all the other arguments */
    3450                 : PHP_FUNCTION(array_intersect)
    3451             284 : {
    3452             284 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL, 
    3453                 :                                 INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_INTERNAL);
    3454             284 : }
    3455                 : /* }}} */
    3456                 : 
    3457                 : /* {{{ proto array array_uintersect(array arr1, array arr2 [, array ...], callback data_compare_func)
    3458                 :    Returns the entries of arr1 that have values which are present in all the other arguments. Data is compared by using an user-supplied callback. */
    3459                 : PHP_FUNCTION(array_uintersect)
    3460             113 : {
    3461             113 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_NORMAL,
    3462                 :                                 INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_INTERNAL);
    3463             113 : }
    3464                 : /* }}} */
    3465                 : 
    3466                 : /* {{{ proto array array_intersect_assoc(array arr1, array arr2 [, array ...])
    3467                 :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check */
    3468                 : PHP_FUNCTION(array_intersect_assoc)
    3469             280 : {
    3470             280 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_INTERNAL);
    3471             280 : }
    3472                 : /* }}} */
    3473                 : 
    3474                 : /* {{{ proto array array_uintersect_assoc(array arr1, array arr2 [, array ...], callback data_compare_func)
    3475                 :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Data is compared by using an user-supplied callback. */
    3476                 : PHP_FUNCTION(array_uintersect_assoc)
    3477             111 : {
    3478             111 :         php_array_intersect_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_COMP_DATA_USER);
    3479             111 : }
    3480                 : /* }}} */
    3481                 : 
    3482                 : /* {{{ proto array array_intersect_uassoc(array arr1, array arr2 [, array ...], callback key_compare_func)
    3483                 :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check and they are compared by using an user-supplied callback. */
    3484                 : PHP_FUNCTION(array_intersect_uassoc)
    3485             193 : {
    3486             193 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC,
    3487                 :                                 INTERSECT_COMP_DATA_INTERNAL, INTERSECT_COMP_KEY_USER);
    3488             193 : }
    3489                 : /* }}} */
    3490                 : 
    3491                 : /* {{{ proto array array_uintersect_uassoc(array arr1, array arr2 [, array ...], callback data_compare_func, callback key_compare_func)
    3492                 :    Returns the entries of arr1 that have values which are present in all the other arguments. Keys are used to do more restrictive check. Both data and keys are compared by using user-supplied callbacks. */
    3493                 : PHP_FUNCTION(array_uintersect_uassoc)
    3494             139 : {
    3495             139 :         php_array_intersect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INTERSECT_ASSOC,
    3496                 :                                 INTERSECT_COMP_DATA_USER, INTERSECT_COMP_KEY_USER);
    3497             139 : }
    3498                 : /* }}} */
    3499                 : 
    3500                 : static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */
    3501             416 : {
    3502                 :         Bucket *p;
    3503                 :         int argc, i;
    3504                 :         zval ***args;
    3505             416 :         int (*diff_data_compare_func)(zval **, zval ** TSRMLS_DC) = NULL;
    3506                 :         zend_bool ok;
    3507                 :         zval **data;
    3508                 : 
    3509                 :         /* Get the argument count */
    3510             416 :         argc = ZEND_NUM_ARGS();
    3511                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    3512             416 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    3513             416 :         if (argc < 2 || zend_get_parameters_array_ex(argc, args) == FAILURE) {
    3514               4 :                 efree(args);
    3515               4 :                 WRONG_PARAM_COUNT;
    3516                 :         }
    3517             412 :         if (data_compare_type == DIFF_COMP_DATA_USER) {
    3518                 :                 char *callback_name;
    3519                 : 
    3520             113 :                 if (argc < 3) {
    3521               1 :                         efree(args);
    3522               1 :                         WRONG_PARAM_COUNT;
    3523                 :                 }
    3524             112 :                 argc--;
    3525             112 :                 if (!zend_is_callable(*args[argc], 0, &callback_name)) {
    3526              29 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3527              29 :                         efree(callback_name);
    3528              29 :                         efree(args);
    3529              29 :                         return;
    3530                 :                 } 
    3531              83 :                 efree(callback_name);
    3532              83 :                 diff_data_compare_func = zval_user_compare;
    3533              83 :                 BG(user_compare_func_name) = args[argc];
    3534              83 :                 BG(user_compare_fci_cache).initialized = 0;
    3535             299 :         } else if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
    3536             137 :                 diff_data_compare_func = zval_compare;
    3537                 :         }
    3538                 : 
    3539             850 :         for (i = 0; i < argc; i++) {
    3540             725 :                 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
    3541             257 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
    3542             257 :                         RETVAL_NULL();
    3543             257 :                         goto out;
    3544                 :                 }
    3545                 :         }
    3546                 :         
    3547             125 :         array_init(return_value);
    3548                 : 
    3549             996 :         for (p = Z_ARRVAL_PP(args[0])->pListHead; p != NULL; p = p->pListNext) {
    3550             871 :                 if (p->nKeyLength == 0) {
    3551             743 :                         ok = 1;
    3552            1367 :                         for (i = 1; i < argc; i++) {
    3553             777 :                                 if (zend_hash_index_find(Z_ARRVAL_PP(args[i]), p->h, (void**)&data) == SUCCESS &&
    3554                 :                                     (!diff_data_compare_func ||
    3555                 :                                      diff_data_compare_func((zval**)p->pData, data TSRMLS_CC) == 0)) {
    3556             153 :                                         ok = 0;
    3557             153 :                                         break;
    3558                 :                                 }
    3559                 :                         }
    3560             743 :                         if (ok) {
    3561             590 :                                 (*((zval**)p->pData))->refcount++;
    3562             590 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), p->h, p->pData, sizeof(zval*), NULL);
    3563                 :                         }
    3564                 :                 } else {
    3565             128 :                         ok = 1;
    3566             218 :                         for (i = 1; i < argc; i++) {
    3567             142 :                                 if (zend_hash_quick_find(Z_ARRVAL_PP(args[i]), p->arKey, p->nKeyLength, p->h, (void**)&data) == SUCCESS &&
    3568                 :                                     (!diff_data_compare_func ||
    3569                 :                                      diff_data_compare_func((zval**)p->pData, data TSRMLS_CC) == 0)) {
    3570              52 :                                         ok = 0;
    3571              52 :                                         break;
    3572                 :                                 }
    3573                 :                         }
    3574             128 :                         if (ok) {
    3575              76 :                                 (*((zval**)p->pData))->refcount++;
    3576              76 :                                 zend_hash_quick_update(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h, p->pData, sizeof(zval*), NULL);
    3577                 :                         }
    3578                 :                 }
    3579                 :         }
    3580             382 : out:
    3581             382 :         efree(args);
    3582                 : }
    3583                 : /* }}} */
    3584                 : 
    3585                 : static void php_array_diff(INTERNAL_FUNCTION_PARAMETERS, int behavior, int data_compare_type, int key_compare_type) /* {{{ */
    3586             739 : {
    3587             739 :         zval ***args = NULL;
    3588                 :         HashTable *hash;
    3589                 :         int argc, arr_argc, i, c;
    3590                 :         Bucket ***lists, **list, ***ptrs, *p;
    3591                 :         char *callback_name;
    3592                 :         
    3593                 :         PHP_ARRAY_CMP_FUNC_VARS;
    3594                 : 
    3595                 :         int (*diff_key_compare_func)(const void *, const void * TSRMLS_DC);
    3596                 :         int (*diff_data_compare_func)(const void *, const void * TSRMLS_DC);
    3597                 :         
    3598                 : 
    3599                 :         /* Get the argument count */
    3600             739 :         argc = ZEND_NUM_ARGS();
    3601                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    3602             739 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    3603             739 :         if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
    3604               0 :                 efree(args);
    3605               0 :                 WRONG_PARAM_COUNT;
    3606                 :         }
    3607                 : 
    3608             739 :         PHP_ARRAY_CMP_FUNC_BACKUP();
    3609                 : 
    3610             739 :         if (behavior == DIFF_NORMAL) {
    3611             249 :                 diff_key_compare_func = array_key_compare;
    3612             249 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL) {
    3613                 :                         /* array_diff */
    3614                 :                         
    3615             138 :                         if (argc < 2) {
    3616               2 :                                 efree(args);
    3617               2 :                                 WRONG_PARAM_COUNT;
    3618                 :                         }
    3619             136 :                         arr_argc = argc;
    3620             136 :                         diff_data_compare_func = array_data_compare;
    3621             111 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER) {
    3622                 :                         /* array_udiff */
    3623             111 :                         if (argc < 3) {
    3624               1 :                                 efree(args);
    3625               1 :                                 WRONG_PARAM_COUNT;
    3626                 :                         }
    3627             110 :                         arr_argc = argc - 1;
    3628             110 :                         diff_data_compare_func = array_user_compare;
    3629             110 :                         if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3630              29 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3631              29 :                                 efree(callback_name);
    3632              29 :                                 efree(args);
    3633              29 :                                 return;
    3634                 :                         }
    3635              81 :                         efree(callback_name);
    3636                 : 
    3637              81 :                         BG(user_compare_func_name) = args[arr_argc];
    3638              81 :                         BG(user_compare_fci_cache).initialized = 0;
    3639                 :                 } else {
    3640               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. This should never happen. Please report as a bug", data_compare_type);
    3641               0 :                         return;         
    3642                 :                 }
    3643             490 :         } else if (behavior & DIFF_ASSOC) { /* triggered also if DIFF_KEY */
    3644                 :                 /*
    3645                 :                         DIFF_KEY is subset of DIFF_ASSOC. When having the former
    3646                 :                         no comparison of the data is done (part of DIFF_ASSOC)
    3647                 :                 */
    3648             490 :                 diff_key_compare_func = array_key_compare;
    3649             490 :                 if (data_compare_type == DIFF_COMP_DATA_INTERNAL 
    3650                 :                                 && 
    3651                 :                         key_compare_type == DIFF_COMP_KEY_INTERNAL) {
    3652                 :                         /* array_diff_assoc() or array_diff_key() */
    3653                 :                         
    3654               0 :                         if (argc < 2) {
    3655               0 :                                 efree(args);
    3656               0 :                                 WRONG_PARAM_COUNT;
    3657                 :                         }
    3658               0 :                         arr_argc = argc;
    3659               0 :                         diff_key_compare_func = array_key_compare;
    3660               0 :                         diff_data_compare_func = array_data_compare;
    3661             490 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER 
    3662                 :                                 && 
    3663                 :                         key_compare_type == DIFF_COMP_KEY_INTERNAL) {
    3664                 :                         /* array_udiff_assoc() */
    3665                 : 
    3666               0 :                         if (argc < 3) {
    3667               0 :                                 efree(args);
    3668               0 :                                 WRONG_PARAM_COUNT;
    3669                 :                         }
    3670               0 :                         arr_argc = argc - 1;
    3671               0 :                         if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3672               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3673               0 :                                 efree(callback_name);
    3674               0 :                                 efree(args);
    3675               0 :                                 return;
    3676                 :                         }
    3677               0 :                         efree(callback_name);
    3678               0 :                         diff_key_compare_func = array_key_compare;
    3679               0 :                         diff_data_compare_func = array_user_compare;
    3680             762 :                 } else if (data_compare_type == DIFF_COMP_DATA_INTERNAL 
    3681                 :                                 && 
    3682                 :                         key_compare_type == DIFF_COMP_KEY_USER) {
    3683                 :                         /* array_diff_uassoc() or array_diff_ukey() */
    3684                 :                         
    3685             352 :                         if (argc < 3) {
    3686               4 :                                 efree(args);
    3687               4 :                                 WRONG_PARAM_COUNT;
    3688                 :                         }
    3689             348 :                         arr_argc = argc - 1;
    3690             348 :                         if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3691              76 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3692              76 :                                 efree(callback_name);
    3693              76 :                                 efree(args);
    3694              76 :                                 return;
    3695                 :                         }
    3696             272 :                         efree(callback_name);
    3697             272 :                         diff_key_compare_func = array_user_key_compare;
    3698             272 :                         diff_data_compare_func = array_data_compare;
    3699             272 :                         BG(user_compare_func_name) = args[arr_argc];
    3700             272 :                         BG(user_compare_fci_cache).initialized = 0;
    3701             218 :                 } else if (data_compare_type == DIFF_COMP_DATA_USER 
    3702                 :                                 && 
    3703                 :                         key_compare_type == DIFF_COMP_KEY_USER) {
    3704                 :                         /* array_udiff_uassoc() */
    3705                 :                         
    3706             138 :                         if (argc < 4) {
    3707               1 :                                 efree(args);
    3708               1 :                                 WRONG_PARAM_COUNT;
    3709                 :                         }
    3710             137 :                         arr_argc = argc - 2;
    3711             137 :                         if (!zend_is_callable(*args[arr_argc], 0, &callback_name)) {
    3712              28 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3713              28 :                                 efree(callback_name);
    3714              28 :                                 efree(args);
    3715              28 :                                 return;
    3716                 :                         }
    3717             109 :                         efree(callback_name);
    3718             109 :                         if (!zend_is_callable(*args[arr_argc + 1], 0, &callback_name)) {
    3719              29 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback %s", callback_name);
    3720              29 :                                 efree(callback_name);
    3721              29 :                                 efree(args);
    3722              29 :                                 return;
    3723                 :                         }
    3724              80 :                         efree(callback_name);
    3725              80 :                         diff_key_compare_func = array_user_key_compare;
    3726              80 :                         diff_data_compare_func = array_user_compare;
    3727              80 :                         BG(user_compare_func_name) = args[arr_argc + 1];/* data - key*/
    3728              80 :                         BG(user_compare_fci_cache).initialized = 0;
    3729                 :                 } else {
    3730               0 :                         efree(args);
    3731               0 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_compare_type is %d. key_compare_type is %d. This should never happen. Please report as a bug", data_compare_type, key_compare_type);
    3732               0 :                         return; 
    3733                 :                 }                       
    3734                 :         } else {
    3735               0 :                 efree(args);
    3736               0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "behavior is %d. This should never happen. Please report as a bug", behavior);
    3737               0 :                 return; 
    3738                 :         }
    3739                 : 
    3740                 :         
    3741                 :         /* for each argument, create and sort list with pointers to the hash buckets */
    3742             569 :         lists = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
    3743             569 :         ptrs = (Bucket ***)safe_emalloc(arr_argc, sizeof(Bucket **), 0);
    3744             569 :         set_compare_func(SORT_STRING TSRMLS_CC);
    3745            1255 :         for (i = 0; i < arr_argc; i++) {
    3746            1096 :                 if (Z_TYPE_PP(args[i]) != IS_ARRAY) {
    3747             410 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is not an array", i + 1);
    3748             410 :                         arr_argc = i; /* only free up to i-1 */
    3749             410 :                         goto out;
    3750                 :                 }
    3751             686 :                 hash = HASH_OF(*args[i]);
    3752             686 :                 list = (Bucket **) pemalloc((hash->nNumOfElements + 1) * sizeof(Bucket *), hash->persistent);
    3753             686 :                 if (!list) {
    3754               0 :                         efree(args);
    3755               0 :                         efree(ptrs);
    3756               0 :                         efree(lists);
    3757               0 :                         RETURN_FALSE;
    3758                 :                 }
    3759             686 :                 lists[i] = list;
    3760             686 :                 ptrs[i] = list;
    3761            6738 :                 for (p = hash->pListHead; p; p = p->pListNext) {
    3762            6052 :                         *list++ = p;
    3763                 :                 }
    3764             686 :                 *list = NULL;
    3765             686 :                 if (behavior == DIFF_NORMAL) {
    3766             284 :                         zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), diff_data_compare_func TSRMLS_CC);
    3767             402 :                 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    3768             402 :                         zend_qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), diff_key_compare_func TSRMLS_CC);
    3769                 :                 }
    3770                 :         }
    3771                 : 
    3772                 :         /* copy the argument array */
    3773             159 :         RETVAL_ZVAL(*args[0], 1, 0);
    3774             159 :         if (return_value->value.ht == &EG(symbol_table)) {
    3775                 :                 HashTable *ht;
    3776                 :                 zval *tmp;
    3777                 : 
    3778               0 :                 ALLOC_HASHTABLE(ht);
    3779               0 :                 zend_hash_init(ht, zend_hash_num_elements(return_value->value.ht), NULL, ZVAL_PTR_DTOR, 0);
    3780               0 :                 zend_hash_copy(ht, return_value->value.ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
    3781               0 :                 return_value->value.ht = ht;         
    3782                 :         }
    3783                 : 
    3784             159 :         if (behavior == DIFF_NORMAL && data_compare_type == DIFF_COMP_DATA_USER) {
    3785                 :                 /* array_udiff() */
    3786               6 :                 BG(user_compare_func_name) = args[arr_argc];
    3787               6 :                 BG(user_compare_fci_cache).initialized = 0;
    3788                 :         }
    3789                 :         
    3790                 :         /* go through the lists and look for values of ptr[0] that are not in the others */
    3791            1215 :         while (*ptrs[0]) {
    3792            1055 :                 if ((behavior & DIFF_ASSOC) /* triggered also when DIFF_KEY */
    3793                 :                                 &&
    3794                 :                         key_compare_type == DIFF_COMP_KEY_USER) {
    3795                 :                         
    3796             212 :                         BG(user_compare_func_name) = args[argc - 1];
    3797             212 :                         BG(user_compare_fci_cache).initialized = 0;
    3798                 :                 }
    3799            1055 :                 c = 1;
    3800            1348 :                 for (i = 1; i < arr_argc; i++) {
    3801            1085 :                         Bucket **ptr = ptrs[i];
    3802            1085 :                         if (behavior == DIFF_NORMAL) {
    3803          437955 :                                 while (*ptr && (0 < (c = diff_data_compare_func(ptrs[0], ptr TSRMLS_CC)))) {
    3804          436245 :                                         ptr++;
    3805                 :                                 }
    3806             230 :                         } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    3807            1084 :                                 while (*ptr && (0 != (c = diff_key_compare_func(ptrs[0], ptr TSRMLS_CC)))) {
    3808             624 :                                         ptr++;
    3809                 :                                 }
    3810                 :                         }
    3811            1085 :                         if (!c) {
    3812             817 :                                 if (behavior == DIFF_NORMAL) {
    3813             693 :                                         if (*ptrs[i]) {
    3814             693 :                                                 ptrs[i]++;
    3815                 :                                         }
    3816             693 :                                         break;
    3817             124 :                                 } else if (behavior == DIFF_ASSOC) {  /* only when DIFF_ASSOC */
    3818                 :                                         /*
    3819                 :                                                 In this branch is execute only when DIFF_ASSOC. If behavior == DIFF_KEY
    3820                 :                                                 data comparison is not needed - skipped.
    3821                 :                                         */
    3822              70 :                                         if (*ptr) {
    3823              70 :                                                 if (data_compare_type == DIFF_COMP_DATA_USER) {
    3824              12 :                                                         BG(user_compare_func_name) = args[arr_argc];
    3825              12 :                                                         BG(user_compare_fci_cache).initialized = 0;
    3826                 :                                                 }
    3827              70 :                                                 if (diff_data_compare_func(ptrs[0], ptr TSRMLS_CC) != 0) {
    3828                 :                                                         /* the data is not the same */
    3829              25 :                                                         c = -1;
    3830              25 :                                                         if (key_compare_type == DIFF_COMP_KEY_USER) {
    3831              25 :                                                                 BG(user_compare_func_name) = args[argc - 1];
    3832              25 :                                                                 BG(user_compare_fci_cache).initialized = 0;
    3833                 :                                                         }
    3834                 :                                                 } else {
    3835              45 :                                                         break;
    3836                 :                                                         /*
    3837                 :                                                                 we have found the element in other arrays thus we don't want it 
    3838                 :                                                                 in the return_value -> delete from there
    3839                 :                                                         */
    3840                 :                                                 }
    3841                 :                                         }
    3842              54 :                                 } else if (behavior == DIFF_KEY) { /* only when DIFF_KEY */
    3843                 :                                         /*
    3844                 :                                                 the behavior here differs from INTERSECT_KEY in php_intersect
    3845                 :                                                 since in the "diff" case we have to remove the entry from
    3846                 :                                                 return_value while when doing intersection the entry must not
    3847                 :                                                 be deleted.
    3848                 :                                         */
    3849              54 :                                         break; /* remove the key */
    3850                 :                                 }
    3851                 :                         }
    3852                 :                 }
    3853            1055 :                 if (!c) {
    3854                 :                         /* ptrs[0] in one of the other arguments */
    3855                 :                         /* delete all entries with value as ptrs[0] */
    3856                 :                         for (;;) {
    3857            2189 :                                 p = *ptrs[0];
    3858            2189 :                                 if (p->nKeyLength) {
    3859            1992 :                                         zend_hash_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength);
    3860                 :                                 } else {
    3861             197 :                                         zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);
    3862                 :                                 }
    3863            2189 :                                 if (!*++ptrs[0]) {
    3864              57 :                                         goto out;
    3865                 :                                 }
    3866            2132 :                                 if (behavior == DIFF_NORMAL) {
    3867            2060 :                                         if (diff_data_compare_func(ptrs[0] - 1, ptrs[0] TSRMLS_CC)) {
    3868             663 :                                                 break;
    3869                 :                                         }
    3870              72 :                                 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    3871                 :                                         /* in this case no array_key_compare is needed */
    3872              72 :                                         break;
    3873                 :                                 }
    3874            1397 :                         }
    3875                 :                 } else {
    3876                 :                         /* ptrs[0] in none of the other arguments */
    3877                 :                         /* skip all entries with value as ptrs[0] */
    3878                 :                         for (;;) {
    3879             277 :                                 if (!*++ptrs[0]) {
    3880             101 :                                         goto out;
    3881                 :                                 }
    3882             176 :                                 if (behavior == DIFF_NORMAL) {
    3883             106 :                                         if (diff_data_compare_func(ptrs[0]-1, ptrs[0] TSRMLS_CC)) {
    3884              92 :                                                 break;
    3885                 :                                         }
    3886              70 :                                 } else if (behavior & DIFF_ASSOC) { /* triggered also when DIFF_KEY */
    3887                 :                                         /* in this case no array_key_compare is needed */
    3888              70 :                                         break;
    3889                 :                                 }
    3890              14 :                         }
    3891                 :                 }
    3892                 :         }
    3893             569 : out:
    3894            1255 :         for (i = 0; i < arr_argc; i++) {
    3895             686 :                 hash = HASH_OF(*args[i]);
    3896             686 :                 pefree(lists[i], hash->persistent);
    3897                 :         }
    3898                 : 
    3899             569 :         PHP_ARRAY_CMP_FUNC_RESTORE();
    3900                 : 
    3901                 :         
    3902             569 :         efree(ptrs);
    3903             569 :         efree(lists);
    3904             569 :         efree(args);
    3905                 : }
    3906                 : /* }}} */
    3907                 : 
    3908                 : /* {{{ proto array array_diff_key(array arr1, array arr2 [, array ...])
    3909                 :    Returns the entries of arr1 that have keys which are not present in any of the others arguments. This function is like array_diff() but works on the keys instead of the values. The associativity is preserved. */
    3910                 : PHP_FUNCTION(array_diff_key)
    3911             164 : {
    3912             164 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_NONE);
    3913             164 : }
    3914                 : /* }}} */
    3915                 : 
    3916                 : /* {{{ proto array array_diff_ukey(array arr1, array arr2 [, array ...], callback key_comp_func)
    3917                 :    Returns the entries of arr1 that have keys which are not present in any of the others arguments. User supplied function is used for comparing the keys. This function is like array_udiff() but works on the keys instead of the values. The associativity is preserved. */
    3918                 : PHP_FUNCTION(array_diff_ukey)
    3919             204 : {
    3920             204 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_KEY,
    3921                 :                          DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
    3922             204 : }
    3923                 : /* }}} */
    3924                 : 
    3925                 : /* {{{ proto array array_diff(array arr1, array arr2 [, array ...])
    3926                 :    Returns the entries of arr1 that have values which are not present in any of the others arguments. */
    3927                 : PHP_FUNCTION(array_diff)
    3928             138 : {
    3929             138 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL,
    3930                 :                          DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_INTERNAL);
    3931             138 : }
    3932                 : /* }}} */
    3933                 : 
    3934                 : /* {{{ proto array array_udiff(array arr1, array arr2 [, array ...], callback data_comp_func)
    3935                 :    Returns the entries of arr1 that have values which are not present in any of the others arguments. Elements are compared by user supplied function. */
    3936                 : PHP_FUNCTION(array_udiff)
    3937             111 : {
    3938             111 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_NORMAL,
    3939                 :                          DIFF_COMP_DATA_USER, DIFF_COMP_KEY_INTERNAL);
    3940             111 : }
    3941                 : /* }}} */
    3942                 : 
    3943                 : /* {{{ proto array array_diff_assoc(array arr1, array arr2 [, array ...])
    3944                 :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal */
    3945                 : PHP_FUNCTION(array_diff_assoc)
    3946             139 : {
    3947             139 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_INTERNAL);
    3948             139 : }
    3949                 : /* }}} */
    3950                 : 
    3951                 : /* {{{ proto array array_diff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func)
    3952                 :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Elements are compared by user supplied function. */
    3953                 : PHP_FUNCTION(array_diff_uassoc)
    3954             148 : {
    3955             148 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC,
    3956                 :                          DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
    3957             148 : }
    3958                 : /* }}} */
    3959                 : 
    3960                 : /* {{{ proto array array_udiff_assoc(array arr1, array arr2 [, array ...], callback key_comp_func)
    3961                 :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys are compared by user supplied function. */
    3962                 : PHP_FUNCTION(array_udiff_assoc)
    3963             113 : {
    3964             113 :         php_array_diff_key(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_COMP_DATA_USER);
    3965             113 : }
    3966                 : /* }}} */
    3967                 : 
    3968                 : /* {{{ proto array array_udiff_uassoc(array arr1, array arr2 [, array ...], callback data_comp_func, callback key_comp_func)
    3969                 :    Returns the entries of arr1 that have values which are not present in any of the others arguments but do additional checks whether the keys are equal. Keys and elements are compared by user supplied functions. */
    3970                 : PHP_FUNCTION(array_udiff_uassoc)
    3971             138 : {
    3972             138 :         php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC,
    3973                 :                          DIFF_COMP_DATA_USER, DIFF_COMP_KEY_USER);
    3974             138 : }
    3975                 : /* }}} */
    3976                 : 
    3977                 : #define MULTISORT_ORDER 0
    3978                 : #define MULTISORT_TYPE  1
    3979                 : #define MULTISORT_LAST  2
    3980                 : 
    3981                 : int multisort_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
    3982             114 : {
    3983             114 :         Bucket **ab = *(Bucket ***)a;
    3984             114 :         Bucket **bb = *(Bucket ***)b;
    3985                 :         int      r;
    3986             114 :         int      result = 0;
    3987                 :         zval     temp;
    3988                 :         
    3989             114 :         r = 0;
    3990                 :         do {
    3991             120 :                 set_compare_func(ARRAYG(multisort_flags)[MULTISORT_TYPE][r] TSRMLS_CC);
    3992                 : 
    3993             120 :                 ARRAYG(compare_func)(&temp, *((zval **)ab[r]->pData), *((zval **)bb[r]->pData) TSRMLS_CC);
    3994             120 :                 result = ARRAYG(multisort_flags)[MULTISORT_ORDER][r] * Z_LVAL(temp);
    3995             120 :                 if (result != 0) {
    3996              90 :                         return result;
    3997                 :                 }
    3998              30 :                 r++;
    3999              30 :         } while (ab[r] != NULL);
    4000                 : 
    4001              24 :         return result;
    4002                 : }
    4003                 : /* }}} */
    4004                 : 
    4005                 : #define MULTISORT_ABORT                                         \
    4006                 :         for (k = 0; k < MULTISORT_LAST; k++) \
    4007                 :                 efree(ARRAYG(multisort_flags)[k]);      \
    4008                 :         efree(arrays);                                                  \
    4009                 :         efree(args);                                                    \
    4010                 :         RETURN_FALSE;
    4011                 : 
    4012                 : /* {{{ 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]], ...])
    4013                 :    Sort multiple arrays at once similar to how ORDER BY clause works in SQL */
    4014                 : PHP_FUNCTION(array_multisort)
    4015              99 : {
    4016                 :         zval***                 args;
    4017                 :         zval***                 arrays;
    4018                 :         Bucket***               indirect;
    4019                 :         Bucket*                 p;
    4020                 :         HashTable*              hash;
    4021                 :         int                             argc;
    4022                 :         int                             array_size;
    4023              99 :         int                             num_arrays = 0;
    4024                 :         int                             parse_state[MULTISORT_LAST];   /* 0 - flag not allowed 1 - flag allowed  */
    4025              99 :         int                             sort_order = SORT_ASC;
    4026              99 :         int                             sort_type  = SORT_REGULAR;
    4027                 :         int                             i, k;
    4028                 :         
    4029                 :         /* Get the argument count and check it */
    4030              99 :         argc = ZEND_NUM_ARGS();
    4031              99 :         if (argc < 1) {
    4032               1 :                 WRONG_PARAM_COUNT;
    4033                 :         }
    4034                 :         
    4035                 :         /* Allocate arguments array and get the arguments, checking for errors. */
    4036              98 :         args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
    4037              98 :         if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
    4038               0 :                 efree(args);
    4039               0 :                 WRONG_PARAM_COUNT;
    4040                 :         }
    4041                 : 
    4042                 :         /* Allocate space for storing pointers to input arrays and sort flags. */
    4043              98 :         arrays = (zval ***)ecalloc(argc, sizeof(zval **)); 
    4044             294 :         for (i = 0; i < MULTISORT_LAST; i++) {
    4045             196 :                 parse_state[i] = 0;
    4046             196 :                 ARRAYG(multisort_flags)[i] = (int *)ecalloc(argc, sizeof(int));
    4047                 :         }
    4048                 : 
    4049                 :         /* Here we go through the input arguments and parse them. Each one can
    4050                 :          * be either an array or a sort flag which follows an array. If not
    4051                 :          * specified, the sort flags defaults to SORT_ASC and SORT_REGULAR
    4052                 :          * accordingly. There can't be two sort flags of the same type after an
    4053                 :          * array, and the very first argument has to be an array.
    4054                 :          */
    4055             231 :         for (i = 0; i < argc; i++) {
    4056             208 :                 if (Z_TYPE_PP(args[i]) == IS_ARRAY) {
    4057                 :                         /* We see the next array, so we update the sort flags of
    4058                 :                            the previous array and reset the sort flags. */
    4059              82 :                         if (i > 0) {
    4060               9 :                                 ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays-1] = sort_order;
    4061               9 :                                 ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays-1] = sort_type;
    4062               9 :                                 sort_order = SORT_ASC;
    4063               9 :                                 sort_type = SORT_REGULAR;
    4064                 :                         }
    4065              82 :                         arrays[num_arrays++] = args[i];
    4066                 : 
    4067                 :                         /* Next one may be an array or a list of sort flags. */
    4068             246 :                         for (k = 0; k < MULTISORT_LAST; k++) {
    4069             164 :                                 parse_state[k] = 1;
    4070                 :                         }
    4071             126 :                 } else if (Z_TYPE_PP(args[i]) == IS_LONG) {
    4072              63 :                         switch (Z_LVAL_PP(args[i])) {
    4073                 :                                 case SORT_ASC:
    4074                 :                                 case SORT_DESC:
    4075                 :                                         /* flag allowed here */
    4076              12 :                                         if (parse_state[MULTISORT_ORDER] == 1) {
    4077                 :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    4078              11 :                                                 sort_order = Z_LVAL_PP(args[i]) == SORT_DESC ? -1 : 1;
    4079              11 :                                                 parse_state[MULTISORT_ORDER] = 0;
    4080                 :                                         } else {
    4081               1 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i+1);
    4082               1 :                                                 MULTISORT_ABORT;
    4083                 :                                         }
    4084              11 :                                         break;
    4085                 : 
    4086                 :                                 case SORT_REGULAR:
    4087                 :                                 case SORT_NUMERIC:
    4088                 :                                 case SORT_STRING:
    4089                 :                                         /* flag allowed here */
    4090              45 :                                         if (parse_state[MULTISORT_TYPE] == 1) {
    4091                 :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    4092              40 :                                                 sort_type = Z_LVAL_PP(args[i]);
    4093              40 :                                                 parse_state[MULTISORT_TYPE] = 0;
    4094                 :                                         } else {
    4095               5 :                                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or sorting flag that has not already been specified", i + 1);
    4096               5 :                                                 MULTISORT_ABORT;
    4097                 :                                         }
    4098              40 :                                         break;
    4099                 : 
    4100                 :                                 default:
    4101               6 :                                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is an unknown sort flag", i + 1);
    4102               6 :                                         MULTISORT_ABORT;
    4103                 :                                         break;
    4104                 : 
    4105                 :                         }
    4106                 :                 } else {
    4107              63 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d is expected to be an array or a sort flag", i + 1);
    4108              63 :                         MULTISORT_ABORT;
    4109                 :                 }
    4110                 :         }
    4111                 :         /* Take care of the last array sort flags. */
    4112              23 :         ARRAYG(multisort_flags)[MULTISORT_ORDER][num_arrays-1] = sort_order;
    4113              23 :         ARRAYG(multisort_flags)[MULTISORT_TYPE][num_arrays-1] = sort_type;
    4114                 :         
    4115                 :         /* Make sure the arrays are of the same size. */
    4116              23 :         array_size = zend_hash_num_elements(Z_ARRVAL_PP(arrays[0]));
    4117              52 :         for (i = 0; i < num_arrays; i++) {
    4118              32 :                 if (zend_hash_num_elements(Z_ARRVAL_PP(arrays[i])) != array_size) {
    4119               3 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array sizes are inconsistent");
    4120               3 :                         MULTISORT_ABORT;
    4121                 :                 }
    4122                 :         }
    4123                 : 
    4124                 :         /* If all arrays are empty or have only one entry, we don't need to do anything. */
    4125              20 :         if (array_size < 1) {
    4126               3 :                 for (k = 0; k < MULTISORT_LAST; k++)
    4127               2 :                         efree(ARRAYG(multisort_flags)[k]);
    4128               1 :                 efree(arrays);
    4129               1 :                 efree(args);
    4130               1 :                 RETURN_TRUE;
    4131                 :         }
    4132                 : 
    4133                 :         /* Create the indirection array. This array is of size MxN, where 
    4134                 :          * M is the number of entries in each input array and N is the number
    4135                 :          * of the input arrays + 1. The last column is NULL to indicate the end
    4136                 :          * of the row.
    4137                 :          */
    4138              19 :         indirect = (Bucket ***)safe_emalloc(array_size, sizeof(Bucket **), 0);
    4139              96 :         for (i = 0; i < array_size; i++)
    4140              77 :                 indirect[i] = (Bucket **)safe_emalloc((num_arrays+1), sizeof(Bucket *), 0);
    4141                 :         
    4142              44 :         for (i = 0; i < num_arrays; i++) {
    4143              25 :                 k = 0;
    4144             123 :                 for (p = Z_ARRVAL_PP(arrays[i])->pListHead; p; p = p->pListNext, k++) {
    4145              98 :                         indirect[k][i] = p;
    4146                 :                 }
    4147                 :         }
    4148              96 :         for (k = 0; k < array_size; k++)
    4149              77 :                 indirect[k][num_arrays] = NULL;
    4150                 : 
    4151                 :         /* Do the actual sort magic - bada-bim, bada-boom. */
    4152              19 :         zend_qsort(indirect, array_size, sizeof(Bucket **), multisort_compare TSRMLS_CC);
    4153                 :         
    4154                 :         /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
    4155              19 :         HANDLE_BLOCK_INTERRUPTIONS();
    4156              44 :         for (i = 0; i < num_arrays; i++) {
    4157              25 :                 hash = Z_ARRVAL_PP(arrays[i]);
    4158              25 :                 hash->pListHead = indirect[0][i];;
    4159              25 :                 hash->pListTail = NULL;
    4160              25 :                 hash->pInternalPointer = hash->pListHead;
    4161                 : 
    4162             123 :                 for (k = 0; k < array_size; k++) {
    4163              98 :                         if (hash->pListTail) {
    4164              73 :                                 hash->pListTail->pListNext = indirect[k][i];
    4165                 :                         }
    4166              98 :                         indirect[k][i]->pListLast = hash->pListTail;
    4167              98 :                         indirect[k][i]->pListNext = NULL;
    4168              98 :                         hash->pListTail = indirect[k][i];
    4169                 :                 }
    4170                 :                 
    4171              25 :                 p = hash->pListHead;
    4172              25 :                 k = 0;
    4173             148 :                 while (p != NULL) {
    4174              98 :                         if (p->nKeyLength == 0)
    4175              59 :                                 p->h = k++;
    4176              98 :                         p = p->pListNext;
    4177                 :                 }
    4178              25 :                 hash->nNextFreeElement = array_size;
    4179              25 :                 zend_hash_rehash(hash);
    4180                 :         }
    4181              19 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    4182                 :                 
    4183                 :         /* Clean up. */ 
    4184              96 :         for (i = 0; i < array_size; i++)
    4185              77 :                 efree(indirect[i]);
    4186              19 :         efree(indirect);
    4187              57 :         for (k = 0; k < MULTISORT_LAST; k++)
    4188              38 :                 efree(ARRAYG(multisort_flags)[k]);
    4189              19 :         efree(arrays);
    4190              19 :         efree(args);
    4191              19 :         RETURN_TRUE;
    4192                 : }
    4193                 : /* }}} */
    4194                 : 
    4195                 : /* {{{ proto mixed array_rand(array input [, int num_req])
    4196                 :    Return key/keys for random entry/entries in the array */
    4197                 : PHP_FUNCTION(array_rand)
    4198             363 : {
    4199                 :         zval **input, **num_req;
    4200                 :         long randval;
    4201                 :         int num_req_val, num_avail, key_type;
    4202                 :         char *string_key;
    4203                 :         uint string_key_len;
    4204                 :         ulong num_key;
    4205                 :         HashPosition pos;
    4206                 : 
    4207             363 :         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
    4208                 :                 zend_get_parameters_ex(ZEND_NUM_ARGS(), &input, &num_req) == FAILURE) {
    4209               3 :                 WRONG_PARAM_COUNT;
    4210                 :         }
    4211                 : 
    4212             360 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    4213              24 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "First argument has to be an array");
    4214              24 :                 return;
    4215                 :         }
    4216                 : 
    4217             336 :         num_avail = zend_hash_num_elements(Z_ARRVAL_PP(input));
    4218                 : 
    4219             336 :         if (ZEND_NUM_ARGS() > 1) {
    4220             318 :                 convert_to_long_ex(num_req);
    4221             318 :                 num_req_val = Z_LVAL_PP(num_req);
    4222             318 :                 if (num_req_val <= 0 || num_req_val > num_avail) {
    4223              25 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be between 1 and the number of elements in the array");
    4224              25 :                         return;
    4225                 :                 }
    4226                 :         } else
    4227              18 :                 num_req_val = 1;
    4228                 : 
    4229                 :         /* Make the return value an array only if we need to pass back more than one result. */
    4230             311 :         if (num_req_val > 1) {
    4231              25 :                 array_init(return_value);
    4232                 :         }
    4233                 : 
    4234                 :         /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
    4235             311 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos);
    4236            1497 :         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) {
    4237                 : 
    4238            1160 :                 randval = php_rand(TSRMLS_C);
    4239                 : 
    4240            1160 :                 if ((double)(randval/(PHP_RAND_MAX+1.0)) < (double)num_req_val/(double)num_avail) {
    4241                 :                         /* If we are returning a single result, just do it. */
    4242             761 :                         if (Z_TYPE_P(return_value) != IS_ARRAY) {
    4243             285 :                                 if (key_type == HASH_KEY_IS_STRING) {
    4244               7 :                                         RETURN_STRINGL(string_key, string_key_len-1, 1);
    4245                 :                                 } else {
    4246             278 :                                         RETURN_LONG(num_key);
    4247                 :                                 }
    4248                 :                         } else {
    4249                 :                                 /* Append the result to the return value. */
    4250             476 :                                 if (key_type == HASH_KEY_IS_STRING)
    4251              19 :                                         add_next_index_stringl(return_value, string_key, string_key_len-1, 1);
    4252                 :                                 else
    4253             457 :                                         add_next_index_long(return_value, num_key);
    4254                 :                         }
    4255             476 :                         num_req_val--;
    4256                 :                 }
    4257             875 :                 num_avail--;
    4258             875 :                 zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos);
    4259                 :         }
    4260                 : }
    4261                 : /* }}} */
    4262                 : 
    4263                 : /* {{{ proto mixed array_sum(array input)
    4264                 :    Returns the sum of the array entries */
    4265                 : PHP_FUNCTION(array_sum)
    4266              58 : {
    4267                 :         zval **input,
    4268                 :                  **entry,
    4269                 :                  entry_n;
    4270              58 :         int argc = ZEND_NUM_ARGS();
    4271                 :         HashPosition pos;
    4272                 :         double dval;
    4273                 :         
    4274              58 :         if (argc != 1 || zend_get_parameters_ex(argc, &input) == FAILURE) {
    4275               2 :                 WRONG_PARAM_COUNT;
    4276                 :         }
    4277                 : 
    4278              56 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    4279              23 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    4280              23 :                 return;
    4281                 :         }
    4282                 : 
    4283              33 :         ZVAL_LONG(return_value, 0);
    4284                 : 
    4285              33 :         for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos);
    4286          202212 :                  zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, &pos) == SUCCESS;
    4287          202146 :                  zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos)) {
    4288                 :                 
    4289          202146 :                 if (Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT)
    4290                 :                         continue;
    4291                 : 
    4292          202138 :                 entry_n = **entry;
    4293          202138 :                 zval_copy_ctor(&entry_n);
    4294          202138 :                 convert_scalar_to_number(&entry_n TSRMLS_CC);
    4295                 : 
    4296          202138 :                 if (Z_TYPE(entry_n) == IS_LONG && Z_TYPE_P(return_value) == IS_LONG) {
    4297          133157 :                         dval = (double)Z_LVAL_P(return_value) + (double)Z_LVAL(entry_n);
    4298          133157 :                         if ( (double)LONG_MIN <= dval && dval <= (double)LONG_MAX ) {
    4299          133155 :                                 Z_LVAL_P(return_value) += Z_LVAL(entry_n);
    4300          133155 :                                 continue;
    4301                 :                         }
    4302                 :                 }
    4303           68983 :                 convert_to_double(return_value);
    4304           68983 :                 convert_to_double(&entry_n);
    4305           68983 :                 Z_DVAL_P(return_value) += Z_DVAL(entry_n);
    4306                 :         }
    4307                 : }
    4308                 : /* }}} */
    4309                 : 
    4310                 : /* {{{ proto mixed array_product(array input)
    4311                 :    Returns the product of the array entries */
    4312                 : PHP_FUNCTION(array_product)
    4313              52 : {
    4314                 :         zval **input,
    4315                 :                  **entry,
    4316                 :                  entry_n;
    4317              52 :         int argc = ZEND_NUM_ARGS();
    4318                 :         HashPosition pos;
    4319                 :         double dval;
    4320                 :         
    4321              52 :         if (argc != 1 || zend_get_parameters_ex(argc, &input) == FAILURE) {
    4322               2 :                 WRONG_PARAM_COUNT;
    4323                 :         }
    4324                 : 
    4325              50 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    4326              27 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
    4327              27 :                 return;
    4328                 :         }
    4329                 :         
    4330              23 :         if (!zend_hash_num_elements(Z_ARRVAL_PP(input))) {
    4331               1 :                 RETURN_LONG(0);
    4332                 :         }
    4333              22 :         ZVAL_LONG(return_value, 1);
    4334                 : 
    4335              22 :         for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(input), &pos);
    4336            1076 :                  zend_hash_get_current_data_ex(Z_ARRVAL_PP(input), (void **)&entry, &pos) == SUCCESS;
    4337            1032 :                  zend_hash_move_forward_ex(Z_ARRVAL_PP(input), &pos)) {
    4338                 :                 
    4339            1032 :                 if (Z_TYPE_PP(entry) == IS_ARRAY || Z_TYPE_PP(entry) == IS_OBJECT)
    4340                 :                         continue;
    4341                 : 
    4342            1030 :                 entry_n = **entry;
    4343            1030 :                 zval_copy_ctor(&entry_n);
    4344            1030 :                 convert_scalar_to_number(&entry_n TSRMLS_CC);
    4345                 : 
    4346            1030 :                 if (Z_TYPE(entry_n) == IS_LONG && Z_TYPE_P(return_value) == IS_LONG) {
    4347              25 :                         dval = (double)Z_LVAL_P(return_value) * (double)Z_LVAL(entry_n);
    4348              25 :                         if ( (double)LONG_MIN <= dval && dval <= (double)LONG_MAX ) {
    4349              23 :                                 Z_LVAL_P(return_value) *= Z_LVAL(entry_n);
    4350              23 :                                 continue;
    4351                 :                         }
    4352                 :                 }
    4353            1007 :                 convert_to_double(return_value);
    4354            1007 :                 convert_to_double(&entry_n);
    4355            1007 :                 Z_DVAL_P(return_value) *= Z_DVAL(entry_n);
    4356                 :         }
    4357                 : }
    4358                 : /* }}} */
    4359                 : 
    4360                 : /* {{{ proto mixed array_reduce(array input, mixed callback [, int initial])
    4361                 :    Iteratively reduce the array to a single value via the callback. */
    4362                 : PHP_FUNCTION(array_reduce)
    4363              24 : {
    4364                 :         zval **input, **callback, **initial;
    4365                 :         zval **args[2];
    4366                 :         zval **operand;
    4367              24 :         zval *result = NULL;
    4368                 :         zval *retval;
    4369              24 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    4370                 :         char *callback_name;
    4371                 :         HashPosition pos;
    4372                 :         HashTable *htbl;
    4373                 :         
    4374              24 :         if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 3 ||
    4375                 :                 zend_get_parameters_ex(ZEND_NUM_ARGS(), &input, &callback, &initial) == FAILURE) {
    4376               2 :                 WRONG_PARAM_COUNT;
    4377                 :         }
    4378                 : 
    4379              22 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    4380               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array");
    4381               2 :                 return;
    4382                 :         }
    4383                 : 
    4384              20 :         if (!zend_is_callable(*callback, 0, &callback_name)) {
    4385               1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument, '%s', should be a valid callback", callback_name);
    4386               1 :                 efree(callback_name);
    4387               1 :                 return;
    4388                 :         }
    4389              19 :         efree(callback_name);
    4390                 : 
    4391              19 :         if (ZEND_NUM_ARGS() > 2) {
    4392              10 :                 ALLOC_ZVAL(result);
    4393              10 :                 *result = **initial;
    4394              10 :                 zval_copy_ctor(result);
    4395              10 :                 convert_to_long(result);
    4396              10 :                 INIT_PZVAL(result);
    4397                 :         } else {
    4398               9 :                 MAKE_STD_ZVAL(result);
    4399               9 :                 ZVAL_NULL(result);
    4400                 :         }
    4401                 : 
    4402                 :         /* (zval **)input points to an element of argument stack
    4403                 :          * the base pointer of which is subject to change.
    4404                 :          * thus we need to keep the pointer to the hashtable for safety */
    4405                 : 
    4406              19 :         htbl = Z_ARRVAL_PP(input);
    4407                 :         
    4408              19 :         if (zend_hash_num_elements(htbl) == 0) {
    4409               1 :                 if (result) {
    4410               1 :                         RETVAL_ZVAL(result, 1, 1);
    4411                 :                 }
    4412               1 :                 return;
    4413                 :         }
    4414                 : 
    4415              18 :         zend_hash_internal_pointer_reset_ex(htbl, &pos);
    4416              75 :         while (zend_hash_get_current_data_ex(htbl, (void **)&operand, &pos) == SUCCESS) {
    4417              39 :                 if (result) {
    4418                 :                         zend_fcall_info fci;
    4419              39 :                         args[0] = &result;
    4420              39 :                         args[1] = operand;
    4421              39 :                         fci.size = sizeof(fci);
    4422              39 :                         fci.function_table = EG(function_table);
    4423              39 :                         fci.function_name = *callback;
    4424              39 :                         fci.symbol_table = NULL;
    4425              39 :                         fci.object_pp = NULL;
    4426              39 :                         fci.retval_ptr_ptr = &retval;
    4427              39 :                         fci.param_count = 2;
    4428              39 :                         fci.params = args;
    4429              39 :                         fci.no_separation = 0;
    4430                 : 
    4431              39 :                         if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && retval) {
    4432              39 :                                 zval_ptr_dtor(&result);
    4433              39 :                                 result = retval;
    4434                 :                         } else {
    4435               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the reduction callback");
    4436               0 :                                 return;
    4437                 :                         }
    4438                 :                 } else {
    4439               0 :                         result = *operand;
    4440               0 :                         zval_add_ref(&result);
    4441                 :                 }
    4442                 : 
    4443              39 :                 zend_hash_move_forward_ex(htbl, &pos);
    4444                 :         }
    4445                 :         
    4446              18 :         RETVAL_ZVAL(result, 1, 1);
    4447                 : }
    4448                 : /* }}} */
    4449                 : 
    4450                 : /* {{{ proto array array_filter(array input [, mixed callback])
    4451                 :    Filters elements from the array via the callback. */
    4452                 : PHP_FUNCTION(array_filter)
    4453             117 : {
    4454             117 :         zval **input, **callback = NULL;
    4455             117 :         zval *array, *func = NULL;
    4456                 :         zval **operand;
    4457                 :         zval **args[1];
    4458             117 :         zval *retval = NULL;
    4459                 :         char *callback_name;
    4460                 :         char *string_key;
    4461             117 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    4462                 :         uint string_key_len;
    4463                 :         ulong num_key;
    4464                 :         HashPosition pos;
    4465                 :         
    4466             117 :         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 ||
    4467                 :                 zend_get_parameters_ex(ZEND_NUM_ARGS(), &input, &callback) == FAILURE) {
    4468               2 :                 WRONG_PARAM_COUNT;
    4469                 :         }
    4470                 : 
    4471             115 :         if (Z_TYPE_PP(input) != IS_ARRAY) {
    4472              24 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument should be an array");
    4473              24 :                 return;
    4474                 :         }
    4475              91 :         array = *input;
    4476                 : 
    4477              91 :         if (ZEND_NUM_ARGS() > 1) {
    4478              78 :                 func = *callback;
    4479              78 :                 if (!zend_is_callable(func, 0, &callback_name)) {
    4480              33 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument, '%s', should be a valid callback", callback_name);
    4481              33 :                         efree(callback_name);
    4482              33 :                         return;
    4483                 :                 }
    4484              45 :                 efree(callback_name);
    4485                 :         }
    4486                 : 
    4487              58 :         array_init(return_value);
    4488              58 :         if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
    4489               1 :                 return;
    4490                 :         }
    4491                 : 
    4492              57 :         for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
    4493            1097 :                  zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&operand, &pos) == SUCCESS;
    4494             983 :                  zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)) {
    4495                 : 
    4496             983 :                 if (func) {
    4497                 :                         zend_fcall_info fci;
    4498                 : 
    4499             922 :                         args[0] = operand;
    4500                 : 
    4501             922 :                         fci.size = sizeof(fci);
    4502             922 :                         fci.function_table = EG(function_table);
    4503             922 :                         fci.function_name = func;
    4504             922 :                         fci.symbol_table = NULL;
    4505             922 :                         fci.object_pp = NULL;
    4506             922 :                         fci.retval_ptr_ptr = &retval;
    4507             922 :                         fci.param_count = 1;
    4508             922 :                         fci.params = args;
    4509             922 :                         fci.no_separation = 0;
    4510                 : 
    4511             922 :                         if (zend_call_function(&fci, &fci_cache TSRMLS_CC) == SUCCESS && retval) {
    4512             922 :                                 if (!zend_is_true(retval)) {
    4513             121 :                                         zval_ptr_dtor(&retval);
    4514             121 :                                         continue;
    4515                 :                                 } else {
    4516             801 :                                         zval_ptr_dtor(&retval);
    4517                 :                                 }
    4518                 :                         } else {
    4519               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "An error occurred while invoking the filter callback");
    4520               0 :                                 return;
    4521                 :                         }
    4522              61 :                 } else if (!zend_is_true(*operand)) {
    4523              26 :                         continue;
    4524                 :                 }
    4525                 : 
    4526             836 :                 zval_add_ref(operand);
    4527             836 :                 switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &string_key_len, &num_key, 0, &pos)) {
    4528                 :                         case HASH_KEY_IS_STRING:
    4529              15 :                                 zend_hash_update(Z_ARRVAL_P(return_value), string_key, string_key_len, operand, sizeof(zval *), NULL);
    4530              15 :                                 break;
    4531                 : 
    4532                 :                         case HASH_KEY_IS_LONG:
    4533             821 :                                 zend_hash_index_update(Z_ARRVAL_P(return_value), num_key, operand, sizeof(zval *), NULL);
    4534                 :                                 break;
    4535                 :                 }
    4536                 :         }
    4537                 : }
    4538                 : /* }}} */
    4539                 : 
    4540                 : /* {{{ proto array array_map(mixed callback, array input1 [, array input2 ,...])
    4541                 :    Applies the callback to the elements in given arrays. */
    4542                 : PHP_FUNCTION(array_map)
    4543             294 : {
    4544             294 :         zval ***pargs = NULL;
    4545                 :         zval ***params;
    4546                 :         zval *callback;
    4547                 :         zval *result, *null;
    4548                 :         HashPosition *array_pos;
    4549                 :         zval **args;
    4550                 :         char *callback_name;
    4551             294 :         zend_fcall_info_cache fci_cache = empty_fcall_info_cache;
    4552             294 :         int i, k, maxlen = 0;
    4553                 :         int *array_len;
    4554                 : 
    4555             294 :         if (ZEND_NUM_ARGS() < 2) {
    4556               2 :                 WRONG_PARAM_COUNT;
    4557                 :         }
    4558                 : 
    4559             292 :         RETVAL_NULL();
    4560                 : 
    4561             292 :         pargs = (zval ***)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval **), 0);
    4562             292 :         if (zend_get_parameters_array_ex(ZEND_NUM_ARGS(), pargs) == FAILURE) {
    4563               0 :                 efree(pargs);
    4564               0 :                 WRONG_PARAM_COUNT;
    4565                 :         }
    4566                 : 
    4567             292 :         callback = *pargs[0];
    4568                 : 
    4569             292 :         if (Z_TYPE_P(callback) != IS_NULL) {
    4570             283 :                 if (!zend_is_callable(callback, 0, &callback_name)) {
    4571              41 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "The first argument, '%s', should be either NULL or a valid callback", callback_name);
    4572              41 :                         efree(callback_name);
    4573              41 :                         efree(pargs);
    4574              41 :                         return;
    4575                 :                 }
    4576             242 :                 efree(callback_name);
    4577                 :         }
    4578                 : 
    4579             251 :         args = (zval **)safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval *), 0);
    4580             251 :         array_len = (int *)safe_emalloc(ZEND_NUM_ARGS(), sizeof(int), 0);
    4581             251 :         array_pos = (HashPosition *)safe_emalloc(ZEND_NUM_ARGS(), sizeof(HashPosition), 0);
    4582                 : 
    4583             505 :         for (i = 1; i < ZEND_NUM_ARGS(); i++) {
    4584             280 :                 if (Z_TYPE_PP(pargs[i]) != IS_ARRAY) {
    4585              26 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument #%d should be an array", i + 1);
    4586              26 :                         efree(pargs);
    4587              26 :                         efree(args);
    4588              26 :                         efree(array_len);
    4589              26 :                         efree(array_pos);
    4590              26 :                         return;
    4591                 :                 }
    4592             254 :                 SEPARATE_ZVAL_IF_NOT_REF(pargs[i]);
    4593             254 :                 args[i] = *pargs[i];
    4594             254 :                 array_len[i] = zend_hash_num_elements(Z_ARRVAL_PP(pargs[i]));
    4595             254 :                 if (array_len[i] > maxlen) {
    4596             201 :                         maxlen = array_len[i];
    4597                 :                 }
    4598             254 :                 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(pargs[i]), &array_pos[i]);
    4599                 :         }
    4600                 : 
    4601             225 :         efree(pargs);
    4602                 : 
    4603                 :         /* Short-circuit: if no callback and only one array, just return it. */
    4604             225 :         if (Z_TYPE_P(callback) == IS_NULL && Z