PageRenderTime 60ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/ext/standard/array.c

http://github.com/infusion/PHP
C | 4526 lines | 3401 code | 614 blank | 511 comment | 1101 complexity | b5b12aed4606a7491dead72c4b471851 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, BSD-3-Clause

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2011 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. /* $Id: array.c 306939 2011-01-01 02:19:59Z felipe $ */
  24. #include "php.h"
  25. #include "php_ini.h"
  26. #include <stdarg.h>
  27. #include <stdlib.h>
  28. #include <math.h>
  29. #include <time.h>
  30. #include <stdio.h>
  31. #if HAVE_STRING_H
  32. #include <string.h>
  33. #else
  34. #include <strings.h>
  35. #endif
  36. #ifdef PHP_WIN32
  37. #include "win32/unistd.h"
  38. #endif
  39. #include "zend_globals.h"
  40. #include "zend_interfaces.h"
  41. #include "php_globals.h"
  42. #include "php_array.h"
  43. #include "basic_functions.h"
  44. #include "php_string.h"
  45. #include "php_rand.h"
  46. #include "php_smart_str.h"
  47. #ifdef HAVE_SPL
  48. #include "ext/spl/spl_array.h"
  49. #endif
  50. /* {{{ defines */
  51. #define EXTR_OVERWRITE 0
  52. #define EXTR_SKIP 1
  53. #define EXTR_PREFIX_SAME 2
  54. #define EXTR_PREFIX_ALL 3
  55. #define EXTR_PREFIX_INVALID 4
  56. #define EXTR_PREFIX_IF_EXISTS 5
  57. #define EXTR_IF_EXISTS 6
  58. #define EXTR_REFS 0x100
  59. #define CASE_LOWER 0
  60. #define CASE_UPPER 1
  61. #define COUNT_NORMAL 0
  62. #define COUNT_RECURSIVE 1
  63. #define DIFF_NORMAL 1
  64. #define DIFF_KEY 2
  65. #define DIFF_ASSOC 6
  66. #define DIFF_COMP_DATA_NONE -1
  67. #define DIFF_COMP_DATA_INTERNAL 0
  68. #define DIFF_COMP_DATA_USER 1
  69. #define DIFF_COMP_KEY_INTERNAL 0
  70. #define DIFF_COMP_KEY_USER 1
  71. #define INTERSECT_NORMAL 1
  72. #define INTERSECT_KEY 2
  73. #define INTERSECT_ASSOC 6
  74. #define INTERSECT_COMP_DATA_NONE -1
  75. #define INTERSECT_COMP_DATA_INTERNAL 0
  76. #define INTERSECT_COMP_DATA_USER 1
  77. #define INTERSECT_COMP_KEY_INTERNAL 0
  78. #define INTERSECT_COMP_KEY_USER 1
  79. #define DOUBLE_DRIFT_FIX 0.000000000000001
  80. /* }}} */
  81. ZEND_DECLARE_MODULE_GLOBALS(array)
  82. /* {{{ php_array_init_globals
  83. */
  84. static void php_array_init_globals(zend_array_globals *array_globals)
  85. {
  86. memset(array_globals, 0, sizeof(zend_array_globals));
  87. }
  88. /* }}} */
  89. PHP_MINIT_FUNCTION(array) /* {{{ */
  90. {
  91. ZEND_INIT_MODULE_GLOBALS(array, php_array_init_globals, NULL);
  92. REGISTER_LONG_CONSTANT("EXTR_OVERWRITE", EXTR_OVERWRITE, CONST_CS | CONST_PERSISTENT);
  93. REGISTER_LONG_CONSTANT("EXTR_SKIP", EXTR_SKIP, CONST_CS | CONST_PERSISTENT);
  94. REGISTER_LONG_CONSTANT("EXTR_PREFIX_SAME", EXTR_PREFIX_SAME, CONST_CS | CONST_PERSISTENT);
  95. REGISTER_LONG_CONSTANT("EXTR_PREFIX_ALL", EXTR_PREFIX_ALL, CONST_CS | CONST_PERSISTENT);
  96. REGISTER_LONG_CONSTANT("EXTR_PREFIX_INVALID", EXTR_PREFIX_INVALID, CONST_CS | CONST_PERSISTENT);
  97. REGISTER_LONG_CONSTANT("EXTR_PREFIX_IF_EXISTS", EXTR_PREFIX_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
  98. REGISTER_LONG_CONSTANT("EXTR_IF_EXISTS", EXTR_IF_EXISTS, CONST_CS | CONST_PERSISTENT);
  99. REGISTER_LONG_CONSTANT("EXTR_REFS", EXTR_REFS, CONST_CS | CONST_PERSISTENT);
  100. REGISTER_LONG_CONSTANT("SORT_ASC", PHP_SORT_ASC, CONST_CS | CONST_PERSISTENT);
  101. REGISTER_LONG_CONSTANT("SORT_DESC", PHP_SORT_DESC, CONST_CS | CONST_PERSISTENT);
  102. REGISTER_LONG_CONSTANT("SORT_REGULAR", PHP_SORT_REGULAR, CONST_CS | CONST_PERSISTENT);
  103. REGISTER_LONG_CONSTANT("SORT_NUMERIC", PHP_SORT_NUMERIC, CONST_CS | CONST_PERSISTENT);
  104. REGISTER_LONG_CONSTANT("SORT_STRING", PHP_SORT_STRING, CONST_CS | CONST_PERSISTENT);
  105. REGISTER_LONG_CONSTANT("SORT_LOCALE_STRING", PHP_SORT_LOCALE_STRING, CONST_CS | CONST_PERSISTENT);
  106. REGISTER_LONG_CONSTANT("CASE_LOWER", CASE_LOWER, CONST_CS | CONST_PERSISTENT);
  107. REGISTER_LONG_CONSTANT("CASE_UPPER", CASE_UPPER, CONST_CS | CONST_PERSISTENT);
  108. REGISTER_LONG_CONSTANT("COUNT_NORMAL", COUNT_NORMAL, CONST_CS | CONST_PERSISTENT);
  109. REGISTER_LONG_CONSTANT("COUNT_RECURSIVE", COUNT_RECURSIVE, CONST_CS | CONST_PERSISTENT);
  110. return SUCCESS;
  111. }
  112. /* }}} */
  113. PHP_MSHUTDOWN_FUNCTION(array) /* {{{ */
  114. {
  115. #ifdef ZTS
  116. ts_free_id(array_globals_id);
  117. #endif
  118. return SUCCESS;
  119. }
  120. /* }}} */
  121. static void php_set_compare_func(int sort_type TSRMLS_DC) /* {{{ */
  122. {
  123. switch (sort_type) {
  124. case PHP_SORT_NUMERIC:
  125. ARRAYG(compare_func) = numeric_compare_function;
  126. break;
  127. case PHP_SORT_STRING:
  128. ARRAYG(compare_func) = string_compare_function;
  129. break;
  130. #if HAVE_STRCOLL
  131. case PHP_SORT_LOCALE_STRING:
  132. ARRAYG(compare_func) = string_locale_compare_function;
  133. break;
  134. #endif
  135. case PHP_SORT_REGULAR:
  136. default:
  137. ARRAYG(compare_func) = compare_function;
  138. break;
  139. }
  140. }
  141. /* }}} */
  142. static int php_array_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  143. {
  144. Bucket *f;
  145. Bucket *s;
  146. zval result;
  147. zval first;
  148. zval second;
  149. f = *((Bucket **) a);
  150. s = *((Bucket **) b);
  151. if (f->nKeyLength == 0) {
  152. Z_TYPE(first) = IS_LONG;
  153. Z_LVAL(first) = f->h;
  154. } else {
  155. Z_TYPE(first) = IS_STRING;
  156. Z_STRVAL(first) = f->arKey;
  157. Z_STRLEN(first) = f->nKeyLength - 1;
  158. }
  159. if (s->nKeyLength == 0) {
  160. Z_TYPE(second) = IS_LONG;
  161. Z_LVAL(second) = s->h;
  162. } else {
  163. Z_TYPE(second) = IS_STRING;
  164. Z_STRVAL(second) = s->arKey;
  165. Z_STRLEN(second) = s->nKeyLength - 1;
  166. }
  167. if (ARRAYG(compare_func)(&result, &first, &second TSRMLS_CC) == FAILURE) {
  168. return 0;
  169. }
  170. if (Z_TYPE(result) == IS_DOUBLE) {
  171. if (Z_DVAL(result) < 0) {
  172. return -1;
  173. } else if (Z_DVAL(result) > 0) {
  174. return 1;
  175. } else {
  176. return 0;
  177. }
  178. }
  179. convert_to_long(&result);
  180. if (Z_LVAL(result) < 0) {
  181. return -1;
  182. } else if (Z_LVAL(result) > 0) {
  183. return 1;
  184. }
  185. return 0;
  186. }
  187. /* }}} */
  188. static int php_array_reverse_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  189. {
  190. return php_array_key_compare(a, b TSRMLS_CC) * -1;
  191. }
  192. /* }}} */
  193. /* {{{ proto bool krsort(array &array_arg [, int sort_flags])
  194. Sort an array by key value in reverse order */
  195. PHP_FUNCTION(krsort)
  196. {
  197. zval *array;
  198. long sort_type = PHP_SORT_REGULAR;
  199. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
  200. RETURN_FALSE;
  201. }
  202. php_set_compare_func(sort_type TSRMLS_CC);
  203. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_key_compare, 0 TSRMLS_CC) == FAILURE) {
  204. RETURN_FALSE;
  205. }
  206. RETURN_TRUE;
  207. }
  208. /* }}} */
  209. /* {{{ proto bool ksort(array &array_arg [, int sort_flags])
  210. Sort an array by key */
  211. PHP_FUNCTION(ksort)
  212. {
  213. zval *array;
  214. long sort_type = PHP_SORT_REGULAR;
  215. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
  216. RETURN_FALSE;
  217. }
  218. php_set_compare_func(sort_type TSRMLS_CC);
  219. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_key_compare, 0 TSRMLS_CC) == FAILURE) {
  220. RETURN_FALSE;
  221. }
  222. RETURN_TRUE;
  223. }
  224. /* }}} */
  225. static int php_count_recursive(zval *array, long mode TSRMLS_DC) /* {{{ */
  226. {
  227. long cnt = 0;
  228. zval **element;
  229. if (Z_TYPE_P(array) == IS_ARRAY) {
  230. if (Z_ARRVAL_P(array)->nApplyCount > 1) {
  231. php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
  232. return 0;
  233. }
  234. cnt = zend_hash_num_elements(Z_ARRVAL_P(array));
  235. if (mode == COUNT_RECURSIVE) {
  236. HashPosition pos;
  237. for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
  238. zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **) &element, &pos) == SUCCESS;
  239. zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos)
  240. ) {
  241. Z_ARRVAL_P(array)->nApplyCount++;
  242. cnt += php_count_recursive(*element, COUNT_RECURSIVE TSRMLS_CC);
  243. Z_ARRVAL_P(array)->nApplyCount--;
  244. }
  245. }
  246. }
  247. return cnt;
  248. }
  249. /* }}} */
  250. /* {{{ proto int sizeof(mixed var [, int mode])
  251. Count the number of elements in a variable (usually an array) */
  252. PHP_FUNCTION(sizeof)
  253. {
  254. zval *array;
  255. long mode = COUNT_NORMAL;
  256. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {
  257. return;
  258. }
  259. switch (Z_TYPE_P(array)) {
  260. case IS_NULL:
  261. RETURN_LONG(0);
  262. break;
  263. case IS_ARRAY:
  264. RETURN_LONG (php_count_recursive (array, mode TSRMLS_CC));
  265. break;
  266. case IS_OBJECT: {
  267. #ifdef HAVE_SPL
  268. zval *retval;
  269. #endif
  270. /* first, we check if the handler is defined */
  271. if (Z_OBJ_HT_P(array)->count_elements) {
  272. RETVAL_LONG(1);
  273. if (SUCCESS == Z_OBJ_HT(*array)->count_elements(array, &Z_LVAL_P(return_value) TSRMLS_CC)) {
  274. return;
  275. }
  276. }
  277. #ifdef HAVE_SPL
  278. /* if not and the object implements Countable we call its count() method */
  279. if (Z_OBJ_HT_P(array)->get_class_entry && instanceof_function(Z_OBJCE_P(array), spl_ce_Countable TSRMLS_CC)) {
  280. zend_call_method_with_0_params(&array, NULL, NULL, "count", &retval);
  281. if (retval) {
  282. convert_to_long_ex(&retval);
  283. RETVAL_LONG(Z_LVAL_P(retval));
  284. zval_ptr_dtor(&retval);
  285. }
  286. return;
  287. }
  288. #endif
  289. }
  290. default:
  291. RETURN_LONG(1);
  292. break;
  293. }
  294. }
  295. /* }}} */
  296. /* Numbers are always smaller than strings int this function as it
  297. * anyway doesn't make much sense to compare two different data types.
  298. * This keeps it consistant and simple.
  299. *
  300. * This is not correct any more, depends on what compare_func is set to.
  301. */
  302. static int php_array_data_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  303. {
  304. Bucket *f;
  305. Bucket *s;
  306. zval result;
  307. zval *first;
  308. zval *second;
  309. f = *((Bucket **) a);
  310. s = *((Bucket **) b);
  311. first = *((zval **) f->pData);
  312. second = *((zval **) s->pData);
  313. if (ARRAYG(compare_func)(&result, first, second TSRMLS_CC) == FAILURE) {
  314. return 0;
  315. }
  316. if (Z_TYPE(result) == IS_DOUBLE) {
  317. if (Z_DVAL(result) < 0) {
  318. return -1;
  319. } else if (Z_DVAL(result) > 0) {
  320. return 1;
  321. } else {
  322. return 0;
  323. }
  324. }
  325. convert_to_long(&result);
  326. if (Z_LVAL(result) < 0) {
  327. return -1;
  328. } else if (Z_LVAL(result) > 0) {
  329. return 1;
  330. }
  331. return 0;
  332. }
  333. /* }}} */
  334. static int php_array_reverse_data_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  335. {
  336. return php_array_data_compare(a, b TSRMLS_CC) * -1;
  337. }
  338. /* }}} */
  339. static int php_array_natural_general_compare(const void *a, const void *b, int fold_case) /* {{{ */
  340. {
  341. Bucket *f, *s;
  342. zval *fval, *sval;
  343. zval first, second;
  344. int result;
  345. f = *((Bucket **) a);
  346. s = *((Bucket **) b);
  347. fval = *((zval **) f->pData);
  348. sval = *((zval **) s->pData);
  349. first = *fval;
  350. second = *sval;
  351. if (Z_TYPE_P(fval) != IS_STRING) {
  352. zval_copy_ctor(&first);
  353. convert_to_string(&first);
  354. }
  355. if (Z_TYPE_P(sval) != IS_STRING) {
  356. zval_copy_ctor(&second);
  357. convert_to_string(&second);
  358. }
  359. result = strnatcmp_ex(Z_STRVAL(first), Z_STRLEN(first), Z_STRVAL(second), Z_STRLEN(second), fold_case);
  360. if (Z_TYPE_P(fval) != IS_STRING) {
  361. zval_dtor(&first);
  362. }
  363. if (Z_TYPE_P(sval) != IS_STRING) {
  364. zval_dtor(&second);
  365. }
  366. return result;
  367. }
  368. /* }}} */
  369. static int php_array_natural_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  370. {
  371. return php_array_natural_general_compare(a, b, 0);
  372. }
  373. /* }}} */
  374. static int php_array_natural_case_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  375. {
  376. return php_array_natural_general_compare(a, b, 1);
  377. }
  378. /* }}} */
  379. static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) /* {{{ */
  380. {
  381. zval *array;
  382. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
  383. return;
  384. }
  385. if (fold_case) {
  386. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_case_compare, 0 TSRMLS_CC) == FAILURE) {
  387. return;
  388. }
  389. } else {
  390. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_natural_compare, 0 TSRMLS_CC) == FAILURE) {
  391. return;
  392. }
  393. }
  394. RETURN_TRUE;
  395. }
  396. /* }}} */
  397. /* {{{ proto void natsort(array &array_arg)
  398. Sort an array using natural sort */
  399. PHP_FUNCTION(natsort)
  400. {
  401. php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  402. }
  403. /* }}} */
  404. /* {{{ proto void natcasesort(array &array_arg)
  405. Sort an array using case-insensitive natural sort */
  406. PHP_FUNCTION(natcasesort)
  407. {
  408. php_natsort(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  409. }
  410. /* }}} */
  411. /* {{{ proto bool asort(array &array_arg [, int sort_flags])
  412. Sort an array and maintain index association */
  413. PHP_FUNCTION(asort)
  414. {
  415. zval *array;
  416. long sort_type = PHP_SORT_REGULAR;
  417. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
  418. RETURN_FALSE;
  419. }
  420. php_set_compare_func(sort_type TSRMLS_CC);
  421. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 0 TSRMLS_CC) == FAILURE) {
  422. RETURN_FALSE;
  423. }
  424. RETURN_TRUE;
  425. }
  426. /* }}} */
  427. /* {{{ proto bool arsort(array &array_arg [, int sort_flags])
  428. Sort an array in reverse order and maintain index association */
  429. PHP_FUNCTION(arsort)
  430. {
  431. zval *array;
  432. long sort_type = PHP_SORT_REGULAR;
  433. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
  434. RETURN_FALSE;
  435. }
  436. php_set_compare_func(sort_type TSRMLS_CC);
  437. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 0 TSRMLS_CC) == FAILURE) {
  438. RETURN_FALSE;
  439. }
  440. RETURN_TRUE;
  441. }
  442. /* }}} */
  443. /* {{{ proto bool sort(array &array_arg [, int sort_flags])
  444. Sort an array */
  445. PHP_FUNCTION(sort)
  446. {
  447. zval *array;
  448. long sort_type = PHP_SORT_REGULAR;
  449. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
  450. RETURN_FALSE;
  451. }
  452. php_set_compare_func(sort_type TSRMLS_CC);
  453. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_data_compare, 1 TSRMLS_CC) == FAILURE) {
  454. RETURN_FALSE;
  455. }
  456. RETURN_TRUE;
  457. }
  458. /* }}} */
  459. /* {{{ proto bool rsort(array &array_arg [, int sort_flags])
  460. Sort an array in reverse order */
  461. PHP_FUNCTION(rsort)
  462. {
  463. zval *array;
  464. long sort_type = PHP_SORT_REGULAR;
  465. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {
  466. RETURN_FALSE;
  467. }
  468. php_set_compare_func(sort_type TSRMLS_CC);
  469. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_reverse_data_compare, 1 TSRMLS_CC) == FAILURE) {
  470. RETURN_FALSE;
  471. }
  472. RETURN_TRUE;
  473. }
  474. /* }}} */
  475. static int php_array_user_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  476. {
  477. Bucket *f;
  478. Bucket *s;
  479. zval **args[2];
  480. zval *retval_ptr = NULL;
  481. f = *((Bucket **) a);
  482. s = *((Bucket **) b);
  483. args[0] = (zval **) f->pData;
  484. args[1] = (zval **) s->pData;
  485. BG(user_compare_fci).param_count = 2;
  486. BG(user_compare_fci).params = args;
  487. BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
  488. BG(user_compare_fci).no_separation = 0;
  489. if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
  490. long retval;
  491. convert_to_long_ex(&retval_ptr);
  492. retval = Z_LVAL_P(retval_ptr);
  493. zval_ptr_dtor(&retval_ptr);
  494. return retval < 0 ? -1 : retval > 0 ? 1 : 0;
  495. } else {
  496. return 0;
  497. }
  498. }
  499. /* }}} */
  500. /* check if comparison function is valid */
  501. #define PHP_ARRAY_CMP_FUNC_CHECK(func_name) \
  502. if (!zend_is_callable(*func_name, 0, NULL TSRMLS_CC)) { \
  503. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid comparison function"); \
  504. BG(user_compare_fci) = old_user_compare_fci; \
  505. BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
  506. RETURN_FALSE; \
  507. } \
  508. /* Clear FCI cache otherwise : for example the same or other array with
  509. * (partly) the same key values has been sorted with uasort() or
  510. * other sorting function the comparison is cached, however the the name
  511. * of the function for comparison is not respected. see bug #28739 AND #33295
  512. *
  513. * Following defines will assist in backup / restore values. */
  514. #define PHP_ARRAY_CMP_FUNC_VARS \
  515. zend_fcall_info old_user_compare_fci; \
  516. zend_fcall_info_cache old_user_compare_fci_cache \
  517. #define PHP_ARRAY_CMP_FUNC_BACKUP() \
  518. old_user_compare_fci = BG(user_compare_fci); \
  519. old_user_compare_fci_cache = BG(user_compare_fci_cache); \
  520. BG(user_compare_fci_cache) = empty_fcall_info_cache; \
  521. #define PHP_ARRAY_CMP_FUNC_RESTORE() \
  522. BG(user_compare_fci) = old_user_compare_fci; \
  523. BG(user_compare_fci_cache) = old_user_compare_fci_cache; \
  524. /* {{{ proto bool usort(array array_arg, string cmp_function)
  525. Sort an array by values using a user-defined comparison function */
  526. PHP_FUNCTION(usort)
  527. {
  528. zval *array;
  529. int refcount;
  530. PHP_ARRAY_CMP_FUNC_VARS;
  531. PHP_ARRAY_CMP_FUNC_BACKUP();
  532. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
  533. PHP_ARRAY_CMP_FUNC_RESTORE();
  534. return;
  535. }
  536. /* Clear the is_ref flag, so the attemts to modify the array in user
  537. * comparison function will create a copy of array and won't affect the
  538. * original array. The fact of modification is detected using refcount
  539. * comparison. The result of sorting in such case is undefined and the
  540. * function returns FALSE.
  541. */
  542. Z_UNSET_ISREF_P(array);
  543. refcount = Z_REFCOUNT_P(array);
  544. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 1 TSRMLS_CC) == FAILURE) {
  545. RETVAL_FALSE;
  546. } else {
  547. if (refcount > Z_REFCOUNT_P(array)) {
  548. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
  549. RETVAL_FALSE;
  550. } else {
  551. RETVAL_TRUE;
  552. }
  553. }
  554. if (Z_REFCOUNT_P(array) > 1) {
  555. Z_SET_ISREF_P(array);
  556. }
  557. PHP_ARRAY_CMP_FUNC_RESTORE();
  558. }
  559. /* }}} */
  560. /* {{{ proto bool uasort(array array_arg, string cmp_function)
  561. Sort an array with a user-defined comparison function and maintain index association */
  562. PHP_FUNCTION(uasort)
  563. {
  564. zval *array;
  565. int refcount;
  566. PHP_ARRAY_CMP_FUNC_VARS;
  567. PHP_ARRAY_CMP_FUNC_BACKUP();
  568. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
  569. PHP_ARRAY_CMP_FUNC_RESTORE();
  570. return;
  571. }
  572. /* Clear the is_ref flag, so the attemts to modify the array in user
  573. * comaprison function will create a copy of array and won't affect the
  574. * original array. The fact of modification is detected using refcount
  575. * comparison. The result of sorting in such case is undefined and the
  576. * function returns FALSE.
  577. */
  578. Z_UNSET_ISREF_P(array);
  579. refcount = Z_REFCOUNT_P(array);
  580. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_compare, 0 TSRMLS_CC) == FAILURE) {
  581. RETVAL_FALSE;
  582. } else {
  583. if (refcount > Z_REFCOUNT_P(array)) {
  584. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
  585. RETVAL_FALSE;
  586. } else {
  587. RETVAL_TRUE;
  588. }
  589. }
  590. if (Z_REFCOUNT_P(array) > 1) {
  591. Z_SET_ISREF_P(array);
  592. }
  593. PHP_ARRAY_CMP_FUNC_RESTORE();
  594. }
  595. /* }}} */
  596. static int php_array_user_key_compare(const void *a, const void *b TSRMLS_DC) /* {{{ */
  597. {
  598. Bucket *f;
  599. Bucket *s;
  600. zval *key1, *key2;
  601. zval **args[2];
  602. zval *retval_ptr = NULL;
  603. long result;
  604. ALLOC_INIT_ZVAL(key1);
  605. ALLOC_INIT_ZVAL(key2);
  606. args[0] = &key1;
  607. args[1] = &key2;
  608. f = *((Bucket **) a);
  609. s = *((Bucket **) b);
  610. if (f->nKeyLength == 0) {
  611. Z_LVAL_P(key1) = f->h;
  612. Z_TYPE_P(key1) = IS_LONG;
  613. } else {
  614. Z_STRVAL_P(key1) = estrndup(f->arKey, f->nKeyLength - 1);
  615. Z_STRLEN_P(key1) = f->nKeyLength - 1;
  616. Z_TYPE_P(key1) = IS_STRING;
  617. }
  618. if (s->nKeyLength == 0) {
  619. Z_LVAL_P(key2) = s->h;
  620. Z_TYPE_P(key2) = IS_LONG;
  621. } else {
  622. Z_STRVAL_P(key2) = estrndup(s->arKey, s->nKeyLength - 1);
  623. Z_STRLEN_P(key2) = s->nKeyLength - 1;
  624. Z_TYPE_P(key2) = IS_STRING;
  625. }
  626. BG(user_compare_fci).param_count = 2;
  627. BG(user_compare_fci).params = args;
  628. BG(user_compare_fci).retval_ptr_ptr = &retval_ptr;
  629. BG(user_compare_fci).no_separation = 0;
  630. if (zend_call_function(&BG(user_compare_fci), &BG(user_compare_fci_cache) TSRMLS_CC) == SUCCESS && retval_ptr) {
  631. convert_to_long_ex(&retval_ptr);
  632. result = Z_LVAL_P(retval_ptr);
  633. zval_ptr_dtor(&retval_ptr);
  634. } else {
  635. result = 0;
  636. }
  637. zval_ptr_dtor(&key1);
  638. zval_ptr_dtor(&key2);
  639. return result;
  640. }
  641. /* }}} */
  642. /* {{{ proto bool uksort(array array_arg, string cmp_function)
  643. Sort an array by keys using a user-defined comparison function */
  644. PHP_FUNCTION(uksort)
  645. {
  646. zval *array;
  647. int refcount;
  648. PHP_ARRAY_CMP_FUNC_VARS;
  649. PHP_ARRAY_CMP_FUNC_BACKUP();
  650. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "af", &array, &BG(user_compare_fci), &BG(user_compare_fci_cache)) == FAILURE) {
  651. PHP_ARRAY_CMP_FUNC_RESTORE();
  652. return;
  653. }
  654. /* Clear the is_ref flag, so the attemts to modify the array in user
  655. * comaprison function will create a copy of array and won't affect the
  656. * original array. The fact of modification is detected using refcount
  657. * comparison. The result of sorting in such case is undefined and the
  658. * function returns FALSE.
  659. */
  660. Z_UNSET_ISREF_P(array);
  661. refcount = Z_REFCOUNT_P(array);
  662. if (zend_hash_sort(Z_ARRVAL_P(array), zend_qsort, php_array_user_key_compare, 0 TSRMLS_CC) == FAILURE) {
  663. RETVAL_FALSE;
  664. } else {
  665. if (refcount > Z_REFCOUNT_P(array)) {
  666. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array was modified by the user comparison function");
  667. RETVAL_FALSE;
  668. } else {
  669. RETVAL_TRUE;
  670. }
  671. }
  672. if (Z_REFCOUNT_P(array) > 1) {
  673. Z_SET_ISREF_P(array);
  674. }
  675. PHP_ARRAY_CMP_FUNC_RESTORE();
  676. }
  677. /* }}} */
  678. /* {{{ proto mixed end(array array_arg)
  679. Advances array argument's internal pointer to the last element and return it */
  680. PHP_FUNCTION(end)
  681. {
  682. HashTable *array;
  683. zval **entry;
  684. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
  685. return;
  686. }
  687. zend_hash_internal_pointer_end(array);
  688. if (return_value_used) {
  689. if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
  690. RETURN_FALSE;
  691. }
  692. RETURN_ZVAL(*entry, 1, 0);
  693. }
  694. }
  695. /* }}} */
  696. /* {{{ proto mixed prev(array array_arg)
  697. Move array argument's internal pointer to the previous element and return it */
  698. PHP_FUNCTION(prev)
  699. {
  700. HashTable *array;
  701. zval **entry;
  702. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
  703. return;
  704. }
  705. zend_hash_move_backwards(array);
  706. if (return_value_used) {
  707. if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
  708. RETURN_FALSE;
  709. }
  710. RETURN_ZVAL(*entry, 1, 0);
  711. }
  712. }
  713. /* }}} */
  714. /* {{{ proto mixed next(array array_arg)
  715. Move array argument's internal pointer to the next element and return it */
  716. PHP_FUNCTION(next)
  717. {
  718. HashTable *array;
  719. zval **entry;
  720. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
  721. return;
  722. }
  723. zend_hash_move_forward(array);
  724. if (return_value_used) {
  725. if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
  726. RETURN_FALSE;
  727. }
  728. RETURN_ZVAL(*entry, 1, 0);
  729. }
  730. }
  731. /* }}} */
  732. /* {{{ proto mixed reset(array array_arg)
  733. Set array argument's internal pointer to the first element and return it */
  734. PHP_FUNCTION(reset)
  735. {
  736. HashTable *array;
  737. zval **entry;
  738. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
  739. return;
  740. }
  741. zend_hash_internal_pointer_reset(array);
  742. if (return_value_used) {
  743. if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
  744. RETURN_FALSE;
  745. }
  746. RETURN_ZVAL(*entry, 1, 0);
  747. }
  748. }
  749. /* }}} */
  750. /* {{{ proto mixed current(array array_arg)
  751. Return the element currently pointed to by the internal array pointer */
  752. PHP_FUNCTION(current)
  753. {
  754. HashTable *array;
  755. zval **entry;
  756. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
  757. return;
  758. }
  759. if (zend_hash_get_current_data(array, (void **) &entry) == FAILURE) {
  760. RETURN_FALSE;
  761. }
  762. RETURN_ZVAL(*entry, 1, 0);
  763. }
  764. /* }}} */
  765. /* {{{ proto mixed key(array array_arg)
  766. Return the key of the element currently pointed to by the internal array pointer */
  767. PHP_FUNCTION(key)
  768. {
  769. HashTable *array;
  770. char *string_key;
  771. uint string_length;
  772. ulong num_key;
  773. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H", &array) == FAILURE) {
  774. return;
  775. }
  776. switch (zend_hash_get_current_key_ex(array, &string_key, &string_length, &num_key, 0, NULL)) {
  777. case HASH_KEY_IS_STRING:
  778. RETVAL_STRINGL(string_key, string_length - 1, 1);
  779. break;
  780. case HASH_KEY_IS_LONG:
  781. RETVAL_LONG(num_key);
  782. break;
  783. case HASH_KEY_NON_EXISTANT:
  784. return;
  785. }
  786. }
  787. /* }}} */
  788. /* {{{ proto mixed min(mixed arg1 [, mixed arg2 [, mixed ...]])
  789. Return the lowest value in an array or a series of arguments */
  790. PHP_FUNCTION(min)
  791. {
  792. int argc;
  793. zval ***args = NULL;
  794. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
  795. return;
  796. }
  797. php_set_compare_func(PHP_SORT_REGULAR TSRMLS_CC);
  798. /* mixed min ( array $values ) */
  799. if (argc == 1) {
  800. zval **result;
  801. if (Z_TYPE_PP(args[0]) != IS_ARRAY) {
  802. php_error_docref(NULL TSRMLS_CC, E_WARNING, "When only one parameter is given, it must be an array");
  803. RETVAL_NULL();
  804. } else {
  805. if (zend_hash_minmax(Z_ARRVAL_PP(args[0]), php_array_data_compare, 0, (void **) &result TSRMLS_CC) == SUCCESS) {
  806. RETVAL_ZVAL(*result, 1, 0);
  807. } else {
  808. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
  809. RETVAL_FALSE;
  810. }
  811. }
  812. } else {
  813. /* mixed min ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
  814. zval **min, result;
  815. int i;
  816. min = args[0];
  817. for (i = 1; i < argc; i++) {
  818. is_smaller_function(&result, *args[i], *min TSRMLS_CC);
  819. if (Z_LVAL(result) == 1) {
  820. min = args[i];
  821. }
  822. }
  823. RETVAL_ZVAL(*min, 1, 0);
  824. }
  825. if (args) {
  826. efree(args);
  827. }
  828. }
  829. /* }}} */
  830. /* {{{ proto mixed max(mixed arg1 [, mixed arg2 [, mixed ...]])
  831. Return the highest value in an array or a series of arguments */
  832. PHP_FUNCTION(max)
  833. {
  834. zval ***args = NULL;
  835. int argc;
  836. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) {
  837. return;
  838. }
  839. php_set_compare_func(PHP_SORT_REGULAR TSRMLS_CC);
  840. /* mixed max ( array $values ) */
  841. if (argc == 1) {
  842. zval **result;
  843. if (Z_TYPE_PP(args[0]) != IS_ARRAY) {
  844. php_error_docref(NULL TSRMLS_CC, E_WARNING, "When only one parameter is given, it must be an array");
  845. RETVAL_NULL();
  846. } else {
  847. if (zend_hash_minmax(Z_ARRVAL_PP(args[0]), php_array_data_compare, 1, (void **) &result TSRMLS_CC) == SUCCESS) {
  848. RETVAL_ZVAL(*result, 1, 0);
  849. } else {
  850. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Array must contain at least one element");
  851. RETVAL_FALSE;
  852. }
  853. }
  854. } else {
  855. /* mixed max ( mixed $value1 , mixed $value2 [, mixed $value3... ] ) */
  856. zval **max, result;
  857. int i;
  858. max = args[0];
  859. for (i = 1; i < argc; i++) {
  860. is_smaller_or_equal_function(&result, *args[i], *max TSRMLS_CC);
  861. if (Z_LVAL(result) == 0) {
  862. max = args[i];
  863. }
  864. }
  865. RETVAL_ZVAL(*max, 1, 0);
  866. }
  867. if (args) {
  868. efree(args);
  869. }
  870. }
  871. /* }}} */
  872. static int php_array_walk(HashTable *target_hash, zval **userdata, int recursive TSRMLS_DC) /* {{{ */
  873. {
  874. zval **args[3], /* Arguments to userland function */
  875. *retval_ptr, /* Return value - unused */
  876. *key=NULL; /* Entry key */
  877. char *string_key;
  878. uint string_key_len;
  879. ulong num_key;
  880. HashPosition pos;
  881. /* Set up known arguments */
  882. args[1] = &key;
  883. args[2] = userdata;
  884. if (userdata) {
  885. Z_ADDREF_PP(userdata);
  886. }
  887. zend_hash_internal_pointer_reset_ex(target_hash, &pos);
  888. BG(array_walk_fci).retval_ptr_ptr = &retval_ptr;
  889. BG(array_walk_fci).param_count = userdata ? 3 : 2;
  890. BG(array_walk_fci).params = args;
  891. BG(array_walk_fci).no_separation = 0;
  892. /* Iterate through hash */
  893. while (!EG(exception) && zend_hash_get_current_data_ex(target_hash, (void **)&args[0], &pos) == SUCCESS) {
  894. if (recursive && Z_TYPE_PP(args[0]) == IS_ARRAY) {
  895. HashTable *thash;
  896. zend_fcall_info orig_array_walk_fci;
  897. zend_fcall_info_cache orig_array_walk_fci_cache;
  898. SEPARATE_ZVAL_IF_NOT_REF(args[0]);
  899. thash = Z_ARRVAL_PP(args[0]);
  900. if (thash->nApplyCount > 1) {
  901. php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
  902. if (userdata) {
  903. zval_ptr_dtor(userdata);
  904. }
  905. return 0;
  906. }
  907. /* backup the fcall info and cache */
  908. orig_array_walk_fci = BG(array_walk_fci);
  909. orig_array_walk_fci_cache = BG(array_walk_fci_cache);
  910. thash->nApplyCount++;
  911. php_array_walk(thash, userdata, recursive TSRMLS_CC);
  912. thash->nApplyCount--;
  913. /* restore the fcall info and cache */
  914. BG(array_walk_fci) = orig_array_walk_fci;
  915. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  916. } else {
  917. /* Allocate space for key */
  918. MAKE_STD_ZVAL(key);
  919. /* Set up the key */
  920. switch (zend_hash_get_current_key_ex(target_hash, &string_key, &string_key_len, &num_key, 0, &pos)) {
  921. case HASH_KEY_IS_LONG:
  922. Z_TYPE_P(key) = IS_LONG;
  923. Z_LVAL_P(key) = num_key;
  924. break;
  925. case HASH_KEY_IS_STRING:
  926. ZVAL_STRINGL(key, string_key, string_key_len - 1, 1);
  927. break;
  928. }
  929. /* Call the userland function */
  930. if (zend_call_function(&BG(array_walk_fci), &BG(array_walk_fci_cache) TSRMLS_CC) == SUCCESS) {
  931. if (retval_ptr) {
  932. zval_ptr_dtor(&retval_ptr);
  933. }
  934. } else {
  935. if (key) {
  936. zval_ptr_dtor(&key);
  937. key = NULL;
  938. }
  939. break;
  940. }
  941. }
  942. if (key) {
  943. zval_ptr_dtor(&key);
  944. key = NULL;
  945. }
  946. zend_hash_move_forward_ex(target_hash, &pos);
  947. }
  948. if (userdata) {
  949. zval_ptr_dtor(userdata);
  950. }
  951. return 0;
  952. }
  953. /* }}} */
  954. /* {{{ proto bool array_walk(array input, string funcname [, mixed userdata])
  955. Apply a user function to every member of an array */
  956. PHP_FUNCTION(array_walk)
  957. {
  958. HashTable *array;
  959. zval *userdata = NULL;
  960. zend_fcall_info orig_array_walk_fci;
  961. zend_fcall_info_cache orig_array_walk_fci_cache;
  962. orig_array_walk_fci = BG(array_walk_fci);
  963. orig_array_walk_fci_cache = BG(array_walk_fci_cache);
  964. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Hf|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
  965. BG(array_walk_fci) = orig_array_walk_fci;
  966. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  967. return;
  968. }
  969. php_array_walk(array, userdata ? &userdata : NULL, 0 TSRMLS_CC);
  970. BG(array_walk_fci) = orig_array_walk_fci;
  971. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  972. RETURN_TRUE;
  973. }
  974. /* }}} */
  975. /* {{{ proto bool array_walk_recursive(array input, string funcname [, mixed userdata])
  976. Apply a user function recursively to every member of an array */
  977. PHP_FUNCTION(array_walk_recursive)
  978. {
  979. HashTable *array;
  980. zval *userdata = NULL;
  981. zend_fcall_info orig_array_walk_fci;
  982. zend_fcall_info_cache orig_array_walk_fci_cache;
  983. orig_array_walk_fci = BG(array_walk_fci);
  984. orig_array_walk_fci_cache = BG(array_walk_fci_cache);
  985. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Hf|z/", &array, &BG(array_walk_fci), &BG(array_walk_fci_cache), &userdata) == FAILURE) {
  986. BG(array_walk_fci) = orig_array_walk_fci;
  987. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  988. return;
  989. }
  990. php_array_walk(array, userdata ? &userdata : NULL, 1 TSRMLS_CC);
  991. BG(array_walk_fci) = orig_array_walk_fci;
  992. BG(array_walk_fci_cache) = orig_array_walk_fci_cache;
  993. RETURN_TRUE;
  994. }
  995. /* }}} */
  996. /* void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
  997. * 0 = return boolean
  998. * 1 = return key
  999. */
  1000. static void php_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
  1001. {
  1002. zval *value, /* value to check for */
  1003. *array, /* array to check in */
  1004. **entry, /* pointer to array entry */
  1005. res; /* comparison result */
  1006. HashPosition pos; /* hash iterator */
  1007. zend_bool strict = 0; /* strict comparison or not */
  1008. ulong num_key;
  1009. uint str_key_len;
  1010. char *string_key;
  1011. int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;
  1012. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "za|b", &value, &array, &strict) == FAILURE) {
  1013. return;
  1014. }
  1015. if (strict) {
  1016. is_equal_func = is_identical_function;
  1017. }
  1018. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);
  1019. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {
  1020. is_equal_func(&res, value, *entry TSRMLS_CC);
  1021. if (Z_LVAL(res)) {
  1022. if (behavior == 0) {
  1023. RETURN_TRUE;
  1024. } else {
  1025. /* Return current key */
  1026. switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 0, &pos)) {
  1027. case HASH_KEY_IS_STRING:
  1028. RETURN_STRINGL(string_key, str_key_len - 1, 1);
  1029. break;
  1030. case HASH_KEY_IS_LONG:
  1031. RETURN_LONG(num_key);
  1032. break;
  1033. }
  1034. }
  1035. }
  1036. zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);
  1037. }
  1038. RETURN_FALSE;
  1039. }
  1040. /* }}} */
  1041. /* {{{ proto bool in_array(mixed needle, array haystack [, bool strict])
  1042. Checks if the given value exists in the array */
  1043. PHP_FUNCTION(in_array)
  1044. {
  1045. php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  1046. }
  1047. /* }}} */
  1048. /* {{{ proto mixed array_search(mixed needle, array haystack [, bool strict])
  1049. Searches the array for a given value and returns the corresponding key if successful */
  1050. PHP_FUNCTION(array_search)
  1051. {
  1052. php_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  1053. }
  1054. /* }}} */
  1055. static int php_valid_var_name(char *var_name, int var_name_len) /* {{{ */
  1056. {
  1057. int i, ch;
  1058. if (!var_name || !var_name_len) {
  1059. return 0;
  1060. }
  1061. /* These are allowed as first char: [a-zA-Z_\x7f-\xff] */
  1062. ch = (int)((unsigned char *)var_name)[0];
  1063. if (var_name[0] != '_' &&
  1064. (ch < 65 /* A */ || /* Z */ ch > 90) &&
  1065. (ch < 97 /* a */ || /* z */ ch > 122) &&
  1066. (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
  1067. ) {
  1068. return 0;
  1069. }
  1070. /* And these as the rest: [a-zA-Z0-9_\x7f-\xff] */
  1071. if (var_name_len > 1) {
  1072. for (i = 1; i < var_name_len; i++) {
  1073. ch = (int)((unsigned char *)var_name)[i];
  1074. if (var_name[i] != '_' &&
  1075. (ch < 48 /* 0 */ || /* 9 */ ch > 57) &&
  1076. (ch < 65 /* A */ || /* Z */ ch > 90) &&
  1077. (ch < 97 /* a */ || /* z */ ch > 122) &&
  1078. (ch < 127 /* 0x7f */ || /* 0xff */ ch > 255)
  1079. ) {
  1080. return 0;
  1081. }
  1082. }
  1083. }
  1084. return 1;
  1085. }
  1086. /* }}} */
  1087. PHPAPI int php_prefix_varname(zval *result, zval *prefix, char *var_name, int var_name_len, zend_bool add_underscore TSRMLS_DC) /* {{{ */
  1088. {
  1089. Z_STRLEN_P(result) = Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0) + var_name_len;
  1090. Z_TYPE_P(result) = IS_STRING;
  1091. Z_STRVAL_P(result) = emalloc(Z_STRLEN_P(result) + 1);
  1092. memcpy(Z_STRVAL_P(result), Z_STRVAL_P(prefix), Z_STRLEN_P(prefix));
  1093. if (add_underscore) {
  1094. Z_STRVAL_P(result)[Z_STRLEN_P(prefix)] = '_';
  1095. }
  1096. memcpy(Z_STRVAL_P(result) + Z_STRLEN_P(prefix) + (add_underscore ? 1 : 0), var_name, var_name_len + 1);
  1097. return SUCCESS;
  1098. }
  1099. /* }}} */
  1100. /* {{{ proto int extract(array var_array [, int extract_type [, string prefix]])
  1101. Imports variables into symbol table from an array */
  1102. PHP_FUNCTION(extract)
  1103. {
  1104. zval *var_array, *prefix = NULL;
  1105. long extract_type = EXTR_OVERWRITE;
  1106. zval **entry, *data;
  1107. char *var_name;
  1108. ulong num_key;
  1109. uint var_name_len;
  1110. int var_exists, key_type, count = 0;
  1111. int extract_refs = 0;
  1112. HashPosition pos;
  1113. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|lz/", &var_array, &extract_type, &prefix) == FAILURE) {
  1114. return;
  1115. }
  1116. extract_refs = (extract_type & EXTR_REFS);
  1117. extract_type &= 0xff;
  1118. if (extract_type < EXTR_OVERWRITE || extract_type > EXTR_IF_EXISTS) {
  1119. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid extract type");
  1120. return;
  1121. }
  1122. if (extract_type > EXTR_SKIP && extract_type <= EXTR_PREFIX_IF_EXISTS && ZEND_NUM_ARGS() < 3) {
  1123. php_error_docref(NULL TSRMLS_CC, E_WARNING, "specified extract type requires the prefix parameter");
  1124. return;
  1125. }
  1126. if (prefix) {
  1127. convert_to_string(prefix);
  1128. if (Z_STRLEN_P(prefix) && !php_valid_var_name(Z_STRVAL_P(prefix), Z_STRLEN_P(prefix))) {
  1129. php_error_docref(NULL TSRMLS_CC, E_WARNING, "prefix is not a valid identifier");
  1130. return;
  1131. }
  1132. }
  1133. if (!EG(active_symbol_table)) {
  1134. zend_rebuild_symbol_table(TSRMLS_C);
  1135. }
  1136. /* var_array is passed by ref for the needs of EXTR_REFS (needs to
  1137. * work on the original array to create refs to its members)
  1138. * simulate pass_by_value if EXTR_REFS is not used */
  1139. if (!extract_refs) {
  1140. SEPARATE_ARG_IF_REF(var_array);
  1141. }
  1142. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(var_array), &pos);
  1143. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(var_array), (void **)&entry, &pos) == SUCCESS) {
  1144. zval final_name;
  1145. ZVAL_NULL(&final_name);
  1146. key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(var_array), &var_name, &var_name_len, &num_key, 0, &pos);
  1147. var_exists = 0;
  1148. if (key_type == HASH_KEY_IS_STRING) {
  1149. var_name_len--;
  1150. var_exists = zend_hash_exists(EG(active_symbol_table), var_name, var_name_len + 1);
  1151. } else if (key_type == HASH_KEY_IS_LONG && (extract_type == EXTR_PREFIX_ALL || extract_type == EXTR_PREFIX_INVALID)) {
  1152. zval num;
  1153. ZVAL_LONG(&num, num_key);
  1154. convert_to_string(&num);
  1155. php_prefix_varname(&final_name, prefix, Z_STRVAL(num), Z_STRLEN(num), 1 TSRMLS_CC);
  1156. zval_dtor(&num);
  1157. } else {
  1158. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
  1159. continue;
  1160. }
  1161. switch (extract_type) {
  1162. case EXTR_IF_EXISTS:
  1163. if (!var_exists) break;
  1164. /* break omitted intentionally */
  1165. case EXTR_OVERWRITE:
  1166. /* GLOBALS protection */
  1167. if (var_exists && var_name_len == sizeof("GLOBALS")-1 && !strcmp(var_name, "GLOBALS")) {
  1168. break;
  1169. }
  1170. if (var_exists && var_name_len == sizeof("this")-1 && !strcmp(var_name, "this") && EG(scope) && EG(scope)->name_length != 0) {
  1171. break;
  1172. }
  1173. ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
  1174. break;
  1175. case EXTR_PREFIX_IF_EXISTS:
  1176. if (var_exists) {
  1177. php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
  1178. }
  1179. break;
  1180. case EXTR_PREFIX_SAME:
  1181. if (!var_exists && var_name_len != 0) {
  1182. ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
  1183. }
  1184. /* break omitted intentionally */
  1185. case EXTR_PREFIX_ALL:
  1186. if (Z_TYPE(final_name) == IS_NULL && var_name_len != 0) {
  1187. php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
  1188. }
  1189. break;
  1190. case EXTR_PREFIX_INVALID:
  1191. if (Z_TYPE(final_name) == IS_NULL) {
  1192. if (!php_valid_var_name(var_name, var_name_len)) {
  1193. php_prefix_varname(&final_name, prefix, var_name, var_name_len, 1 TSRMLS_CC);
  1194. } else {
  1195. ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
  1196. }
  1197. }
  1198. break;
  1199. default:
  1200. if (!var_exists) {
  1201. ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);
  1202. }
  1203. break;
  1204. }
  1205. if (Z_TYPE(final_name) != IS_NULL && php_valid_var_name(Z_STRVAL(final_name), Z_STRLEN(final_name))) {
  1206. if (extract_refs) {
  1207. zval **orig_var;
  1208. SEPARATE_ZVAL_TO_MAKE_IS_REF(entry);
  1209. zval_add_ref(entry);
  1210. if (zend_hash_find(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, (void **) &orig_var) == SUCCESS) {
  1211. zval_ptr_dtor(orig_var);
  1212. *orig_var = *entry;
  1213. } else {
  1214. zend_hash_update(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, (void **) entry, sizeof(zval *), NULL);
  1215. }
  1216. } else {
  1217. MAKE_STD_ZVAL(data);
  1218. *data = **entry;
  1219. zval_copy_ctor(data);
  1220. ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table), Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, data, 1, 0);
  1221. }
  1222. count++;
  1223. }
  1224. zval_dtor(&final_name);
  1225. zend_hash_move_forward_ex(Z_ARRVAL_P(var_array), &pos);
  1226. }
  1227. if (!extract_refs) {
  1228. zval_ptr_dtor(&var_array);
  1229. }
  1230. RETURN_LONG(count);
  1231. }
  1232. /* }}} */
  1233. static void php_compact_var(HashTable *eg_active_symbol_table, zval *return_value, zval *entry TSRMLS_DC) /* {{{ */
  1234. {
  1235. zval **value_ptr, *value, *data;
  1236. if (Z_TYPE_P(entry) == IS_STRING) {
  1237. if (zend_hash_find(eg_active_symbol_table, Z_STRVAL_P(entry), Z_STRLEN_P(entry) + 1, (void **)&value_ptr) != FAILURE) {
  1238. value = *value_ptr;
  1239. ALLOC_ZVAL(data);
  1240. MAKE_COPY_ZVAL(&value, data);
  1241. zend_hash_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(entry), Z_STRLEN_P(entry) + 1, &data, sizeof(zval *), NULL);
  1242. }
  1243. }
  1244. else if (Z_TYPE_P(entry) == IS_ARRAY) {
  1245. HashPosition pos;
  1246. if ((Z_ARRVAL_P(entry)->nApplyCount > 1)) {
  1247. php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected");
  1248. return;
  1249. }
  1250. Z_ARRVAL_P(entry)->nApplyCount++;
  1251. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(entry), &pos);
  1252. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(entry), (void**)&value_ptr, &pos) == SUCCESS) {
  1253. value = *value_ptr;
  1254. php_compact_var(eg_active_symbol_table, return_value, value TSRMLS_CC);
  1255. zend_hash_move_forward_ex(Z_ARRVAL_P(entry), &pos);
  1256. }
  1257. Z_ARRVAL_P(entry)->nApplyCount--;
  1258. }
  1259. }
  1260. /* }}} */
  1261. /* {{{ proto array compact(mixed var_names [, mixed ...])
  1262. Creates a hash containing variables and their values */
  1263. PHP_FUNCTION(compact)
  1264. {
  1265. zval ***args = NULL; /* function arguments array */
  1266. int num_args, i;
  1267. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &num_args) == FAILURE) {
  1268. return;
  1269. }
  1270. if (!EG(active_symbol_table)) {
  1271. zend_rebuild_symbol_table(TSRMLS_C);
  1272. }
  1273. /* compact() is probably most used with a single array of var_names
  1274. or multiple string names, rather than a combination of both.
  1275. So quickly guess a minimum result size based on that */
  1276. if (ZEND_NUM_ARGS() == 1 && Z_TYPE_PP(args[0]) == IS_ARRAY) {
  1277. array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_PP(args[0])));
  1278. } else {
  1279. array_init_size(return_value, ZEND_NUM_ARGS());
  1280. }
  1281. for (i=0; i<ZEND_NUM_ARGS(); i++) {
  1282. php_compact_var(EG(active_symbol_table), return_value, *args[i] TSRMLS_CC);
  1283. }
  1284. if (args) {
  1285. efree(args);
  1286. }
  1287. }
  1288. /* }}} */
  1289. /* {{{ proto array array_fill(int start_key, int num, mixed val)
  1290. Create an array containing num elements starting with index start_key each initialized to val */
  1291. PHP_FUNCTION(array_fill)
  1292. {
  1293. zval *val;
  1294. long start_key, num;
  1295. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "llz", &start_key, &num, &val) == FAILURE) {
  1296. return;
  1297. }
  1298. if (num < 1) {
  1299. php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements must be positive");
  1300. RETURN_FALSE;
  1301. }
  1302. /* allocate an array for return */
  1303. array_init_size(return_value, num);
  1304. num--;
  1305. zval_add_ref(&val);
  1306. zend_hash_index_update(Z_ARRVAL_P(return_value), start_key, &val, sizeof(zval *), NULL);
  1307. while (num--) {
  1308. zval_add_ref(&val);
  1309. zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &val, sizeof(zval *), NULL);
  1310. }
  1311. }
  1312. /* }}} */
  1313. /* {{{ proto array array_fill_keys(array keys, mixed val)
  1314. Create an array using the elements of the first parameter as keys each initialized to val */
  1315. PHP_FUNCTION(array_fill_keys)
  1316. {
  1317. zval *keys, *val, **entry;
  1318. HashPosition pos;
  1319. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "az", &keys, &val) == FAILURE) {
  1320. return;
  1321. }
  1322. /* Initialize return array */
  1323. array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(keys)));
  1324. zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(keys), &pos);
  1325. while (zend_hash_get_current_data_ex(Z_ARRVAL_P(keys), (void **)&entry, &pos) == SUCCESS) {
  1326. if (Z_TYPE_PP(entry) == IS_LONG) {
  1327. zval_add_ref(&val);
  1328. zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &val, sizeof(zval *), NULL);
  1329. } else {
  1330. zval key, *key_ptr = *entry;
  1331. if (Z_TYPE_PP(entry) != IS_STRING) {
  1332. key = **entry;
  1333. zval_copy_ctor(&key);
  1334. convert_to_string(&key);
  1335. key_ptr = &key;
  1336. }
  1337. zval_add_ref(&val);
  1338. zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_P(key_ptr), Z_STRLEN_P(key_ptr) + 1, &val, sizeof(zval *), NULL);
  1339. if (key_ptr != *entry) {
  1340. zval_dtor(&key);
  1341. }
  1342. }
  1343. zend_hash_move_forward_ex(Z_ARRVAL_P(keys), &pos);
  1344. }
  1345. }
  1346. /* }}} */
  1347. /* {{{ proto array range(mixed low, mixed high[, int step])
  1348. Create an array containing the range of integers or characters from low to high (inclusive) */
  1349. PHP_FUNCTION(range)
  1350. {
  1351. zval *zlow, *zhigh, *zstep = NULL;
  1352. int err = 0, is_step_double = 0;
  1353. double step = 1.0;
  1354. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/z/|z/", &zlow, &zhigh, &zstep) == FAILURE) {
  1355. RETURN_FALSE;
  1356. }
  1357. if (zstep) {
  1358. if (Z_TYPE_P(zstep) == IS_DOUBLE ||
  1359. (Z_TYPE_P(zstep) == IS_STRING && is_numeric_string(Z_STRVAL_P(zstep), Z_STRLEN_P(zstep), NULL, NULL, 0) == IS_DOUBLE)
  1360. ) {
  1361. is_step_double = 1;
  1362. }
  1363. convert_to_double_ex(&zstep);
  1364. step = Z_DVAL_P(zstep);
  1365. /* We only want positive step values. */
  1366. if (step < 0.0) {
  1367. step *= -1;
  1368. }
  1369. }
  1370. /* Initialize the return_value as an array. */
  1371. array_init(return_value);
  1372. /* If the range is given as strings, generate an array of characters. */
  1373. if (Z_TYPE_P(zlow) == IS_STRING && Z_TYPE_P(zhigh) == IS_STRING && Z_STRLEN_P(zlow) >= 1 && Z_STRLEN_P(zhigh) >= 1) {
  1374. int type1, type2;
  1375. unsigned char *low, *high;
  1376. long lstep = (long) step;
  1377. type1 = is_numeric_string(Z_STRVAL_P(zlow), Z_STRLEN_P(zlow), NULL, NULL, 0);
  1378. type2 = is_numeric_string(Z_STRVAL_P(zhigh), Z_STRLEN_P(zhigh), NULL, NULL, 0);
  1379. if (type1 == IS_DOUBLE || type2 == IS_DOUBLE || is_step_double) {
  1380. goto double_str;
  1381. } else if (type1 == IS_LONG || type2 == IS_LONG) {
  1382. goto long_str;
  1383. }
  1384. convert_to_string(zlow);
  1385. convert_to_string(zhigh);
  1386. low = (unsigned char *)Z_STRVAL_P(zlow);
  1387. high = (unsigned char *)Z_STRVAL_P(zhigh);
  1388. if (*low > *high) { /* Negative Steps */
  1389. if (lstep <= 0) {
  1390. err = 1;
  1391. goto err;
  1392. }
  1393. for (; *low >= *high; (*low) -= (unsigned int)lstep) {
  1394. add_next_index_stringl(return_value, (const char *)low, 1, 1);
  1395. if (((signed int)*low - lstep) < 0) {
  1396. break;
  1397. }
  1398. }
  1399. } else if (*high > *low) { /* Positive Steps */
  1400. if (lstep <= 0) {
  1401. err = 1;
  1402. goto err;
  1403. }
  1404. for (; *low <= *high; (*low) += (unsigned int)lstep) {
  1405. add_next_index_stringl(return_value, (const char *)low, 1, 1);
  1406. if (((signed int)*low + lstep) > 255) {
  1407. break;
  1408. }
  1409. }
  1410. } else {
  1411. add_next_index_stringl(return_value, (const char *)low, 1, 1);
  1412. }
  1413. } else if (Z_TYPE_P(zlow) == IS_DOUBLE || Z_TYPE_P(zhigh) == IS_DOUBLE || is_step_double) {
  1414. double low, high;
  1415. double_str:
  1416. convert_to_double(zlow);
  1417. convert_to_double(zhigh);
  1418. low = Z_DVAL_P(zlow);
  1419. high = Z_DVAL_P(zhigh);
  1420. if (low > high) { /* Negative steps */
  1421. if (low - high < step || step <= 0) {
  1422. err = 1;
  1423. goto err;
  1424. }
  1425. for (; low >= (high - DOUBLE_DRIFT_FIX); low -= step) {
  1426. add_next_index_double(return_value, low);
  1427. }
  1428. } else if (high > low) { /* Positive steps */
  1429. if (high - low < step || step <= 0) {
  1430. err = 1;
  1431. goto err;
  1432. }
  1433. for (; low <= (high + DOUBLE_DRIFT_FIX); low += step) {
  1434. add_next_index_double(return_value, low);
  1435. }
  1436. } else {
  1437. add_next_index_double(return_value, low);
  1438. }
  1439. } else {
  1440. double low, high;
  1441. long lstep;
  1442. long_str:
  1443. convert_to_double(zlow);
  1444. convert_to_double(zhigh);
  1445. low = Z_DVAL_P(zlow);
  1446. high = Z_DVAL_P(zhigh);
  1447. lstep = (long) step;
  1448. if (low > high) { /* Negative steps */
  1449. if (low - high < lstep || lstep <= 0) {
  1450. err = 1;
  1451. goto err;
  1452. }
  1453. for (; low >= high; low -= lstep) {
  1454. add_next_index_long(return_value, (long)low);
  1455. }
  1456. } else if (high > low) { /* Positive steps */
  1457. if (high - low < lstep || lstep <= 0) {
  1458. err = 1;
  1459. goto err;
  1460. }
  1461. for (; low <= high; low += lstep) {
  1462. add_next_index_long(return_value, (long)low);
  1463. }
  1464. } else {
  1465. add_next_index_long(return_value, (long)low);
  1466. }
  1467. }
  1468. err:
  1469. if (err) {
  1470. php_error_docref(NULL TSRMLS_CC, E_WARNING, "step exceeds the specified range");
  1471. zval_dtor(return_value);
  1472. RETURN_FALSE;
  1473. }
  1474. }
  1475. /* }}} */
  1476. static void php_array_data_shuffle(zval *array TSRMLS_DC) /* {{{ */
  1477. {
  1478. Bucket **elems, *temp;
  1479. HashTable *hash;
  1480. int j, n_elems, rnd_idx, n_left;
  1481. n_elems = zend_hash_num_elements(Z_ARRVAL_P(array));
  1482. if (n_elems < 1) {
  1483. return;
  1484. }
  1485. elems = (Bucket **)safe_emalloc(n_elems, sizeof(Bucket *), 0);
  1486. hash = Z_ARRVAL_P(array);
  1487. n_left = n_elems;
  1488. for (j = 0, temp = hash->pListHead; temp; temp = temp->pListNext)
  1489. elems[j++] = temp;
  1490. while (--n_left) {
  1491. rnd_idx = php_rand(TSRMLS_C);
  1492. RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
  1493. if (rnd_idx != n_left) {
  1494. temp = elems[n_left];
  1495. elems[n_left] = elems[rnd_idx];
  1496. elems[rnd_idx] = temp;
  1497. }
  1498. }
  1499. HANDLE_BLOCK_INTERRUPTIONS();
  1500. hash->pListHead = elems[0];
  1501. hash->pListTail = NULL;
  1502. hash->pInternalPointer = hash->pListHead;
  1503. for (j = 0; j < n_elems; j++) {
  1504. if (hash->pListTail) {
  1505. hash->pListTail->pListNext = elems[j];
  1506. }
  1507. elems[j]->pListLast = hash->pListTail;
  1508. elems[j]->pListNext = NULL;
  1509. hash->pListTail = elems[j];
  1510. }
  1511. temp = hash->pListHead;
  1512. j = 0;
  1513. while (temp != NULL) {
  1514. temp->nKeyLength = 0;
  1515. temp->h = j++;
  1516. temp = temp->pListNext;
  1517. }
  1518. hash->nNextFreeElement = n_elems;
  1519. zend_hash_rehash(hash);
  1520. HANDLE_UNBLOCK_INTERRUPTIONS();
  1521. efree(elems);
  1522. }
  1523. /* }}} */
  1524. /* {{{ proto bool shuffle(array array_arg)
  1525. Randomly shuffle the contents of an array */
  1526. PHP_FUNCTION(shuffle)
  1527. {
  1528. zval *array;
  1529. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {
  1530. RETURN_FALSE;
  1531. }
  1532. php_array_data_shuffle(array TSRMLS_CC);
  1533. RETURN_TRUE;
  1534. }
  1535. /* }}} */
  1536. PHPAPI HashTable* php_splice(HashTable *in_hash, int offset, int length, zval ***list, int list_count, HashTable **removed) /* {{{ */
  1537. {
  1538. HashTable *out_hash = NULL; /* Output hashtable */
  1539. int num_in, /* Number of entries in the input hashtable */
  1540. pos, /* Current position in the hashtable */
  1541. i; /* Loop counter */
  1542. Bucket *p; /* Pointer to hash bucket */
  1543. zval *entry; /* Hash entry */
  1544. /* If input hash doesn't exist, we have nothing to do */
  1545. if (!in_hash) {
  1546. return NULL;
  1547. }
  1548. /* Get number of entries in the input hash */
  1549. num_in = zend_hash_num_elements(in_hash);
  1550. /* Clamp the offset.. */
  1551. if (offset > num_in) {
  1552. offset = num_in;
  1553. } else if (offset < 0 && (offset = (num_in + offset)) < 0) {
  1554. offset = 0;
  1555. }
  1556. /* ..and the length */
  1557. if (length < 0) {
  1558. length = num_in - offset + length;
  1559. } else if (((unsigned)offset + (unsigned)length) > (unsigned)num_in) {
  1560. length = num_in - offset;
  1561. }
  1562. /* Create and initialize output hash */
  1563. ALLOC_HASHTABLE(out_hash);
  1564. zend_hash_init(out_hash, (length > 0 ? num_in - length : 0) + list_count, NULL, ZVAL_PTR_DTOR, 0);
  1565. /* Start at the beginning of the input hash and copy entries to output hash untiā€¦

Large files files are truncated, but you can click here to view the full file