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

LCOV - code coverage report
Current view: top level - ext/standard - array.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 1980 2098 94.4 %
Date: 2014-10-16 Functions: 107 107 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Thu, 16 Oct 2014 05:27:11 +0000 (5 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.