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

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:19 +0000 (8 days ago)

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