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

Generated by: LCOV version 1.10

Generated at Wed, 23 Jul 2014 19:58:41 +0000 (25 hours ago)

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