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

LTP GCOV extension - code coverage report
Current view: directory - standard - array.c
Test: PHP Code Coverage
Date: 2009-11-23 Instrumented lines: 2212
Code covered: 91.2 % Executed lines: 2017
Legend: not executed executed

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