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: 1954 2073 94.3 %
Date: 2014-08-04 Functions: 109 109 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 04 Aug 2014 15:49:14 +0000 (43 days ago)

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