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

Generated by: LCOV version 1.10

Generated at Wed, 16 Apr 2014 12:47:57 +0000 (3 days ago)

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