Line data Source code
1 : /*
2 : +----------------------------------------------------------------------+
3 : | COLOPL PHP Backwards Compatibility Extension. |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) COLOPL, Inc. |
6 : | Copyright (c) The PHP Group |
7 : +----------------------------------------------------------------------+
8 : | This source file is subject to version 3.01 of the PHP license, |
9 : | that is bundled with this package in the file LICENSE, and is |
10 : | available through the world-wide-web at the following url: |
11 : | http://www.php.net/license/3_01.txt |
12 : | If you did not receive a copy of the PHP license and are unable to |
13 : | obtain it through the world-wide-web, please send a note to |
14 : | license@php.net so we can mail you a copy immediately. |
15 : +----------------------------------------------------------------------+
16 : | Author: Go Kudo <g-kudo@colopl.co.jp> |
17 : +----------------------------------------------------------------------+
18 : */
19 :
20 : #ifdef HAVE_CONFIG_H
21 : # include "config.h"
22 : #endif
23 :
24 : #include "php_colopl_bc.h"
25 :
26 : #include "ext/standard/php_array.h"
27 : #include "ext/standard/php_string.h"
28 : #include "zend_operators.h"
29 :
30 : /* zend_operators.c */
31 :
32 : #define COLOPL_BC_TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
33 :
34 : #define php_colopl_bc_convert_object_to_type(op, dst, ctype) \
35 : ZVAL_UNDEF(dst); \
36 : if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), dst, ctype) == FAILURE) { \
37 : zend_error(E_WARNING, \
38 : "Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name), \
39 : zend_get_type_by_const(ctype)); \
40 : } \
41 :
42 7704 : static zend_never_inline zval* ZEND_FASTCALL _php_colopl_bc_zendi_convert_scalar_to_number_silent(zval *op, zval *holder)
43 : {
44 7704 : switch (Z_TYPE_P(op)) {
45 0 : case IS_NULL:
46 : case IS_FALSE:
47 0 : ZVAL_LONG(holder, 0);
48 0 : return holder;
49 0 : case IS_TRUE:
50 0 : ZVAL_LONG(holder, 1);
51 0 : return holder;
52 3532 : case IS_STRING:
53 3532 : if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), 1)) == 0) {
54 1096 : ZVAL_LONG(holder, 0);
55 : }
56 3532 : return holder;
57 0 : case IS_RESOURCE:
58 0 : ZVAL_LONG(holder, Z_RES_HANDLE_P(op));
59 0 : return holder;
60 0 : case IS_OBJECT:
61 0 : php_colopl_bc_convert_object_to_type(op, holder, _IS_NUMBER);
62 0 : if (UNEXPECTED(EG(exception)) ||
63 0 : UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) {
64 0 : ZVAL_LONG(holder, 1);
65 : }
66 0 : return holder;
67 4172 : case IS_LONG:
68 : case IS_DOUBLE:
69 : default:
70 4172 : return op;
71 : }
72 : }
73 :
74 15084 : static int legacy_compare_fast(zval *op1, zval *op2)
75 : {
76 15084 : int converted = 0;
77 : zval op1_copy, op2_copy;
78 :
79 : while (1) {
80 18936 : switch (COLOPL_BC_TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
81 8880 : case COLOPL_BC_TYPE_PAIR(IS_LONG, IS_LONG):
82 8880 : return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
83 :
84 200 : case COLOPL_BC_TYPE_PAIR(IS_DOUBLE, IS_LONG):
85 200 : return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - (double)Z_LVAL_P(op2));
86 :
87 200 : case COLOPL_BC_TYPE_PAIR(IS_LONG, IS_DOUBLE):
88 200 : return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2));
89 :
90 60 : case COLOPL_BC_TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
91 60 : if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
92 60 : return 0;
93 : } else {
94 0 : return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - Z_DVAL_P(op2));
95 : }
96 :
97 80 : case COLOPL_BC_TYPE_PAIR(IS_ARRAY, IS_ARRAY):
98 80 : return zend_compare_arrays(op1, op2);
99 :
100 100 : case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_NULL):
101 : case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_FALSE):
102 : case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_NULL):
103 : case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_FALSE):
104 : case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_TRUE):
105 100 : return 0;
106 :
107 20 : case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_TRUE):
108 20 : return -1;
109 :
110 20 : case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_NULL):
111 20 : return 1;
112 :
113 60 : case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_OBJECT):
114 60 : return zval_is_true(op2) ? 0 : 1;
115 :
116 60 : case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_OBJECT):
117 60 : return zval_is_true(op2) ? -1 : 0;
118 :
119 60 : case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_TRUE):
120 60 : return zval_is_true(op1) ? 0 : -1;
121 :
122 60 : case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_FALSE):
123 60 : return zval_is_true(op1) ? 1 : 0;
124 :
125 1584 : case COLOPL_BC_TYPE_PAIR(IS_STRING, IS_STRING):
126 1584 : if (Z_STR_P(op1) == Z_STR_P(op2)) {
127 772 : return 0;
128 : }
129 812 : return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
130 :
131 100 : case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_STRING):
132 100 : return Z_STRLEN_P(op2) == 0 ? 0 : -1;
133 :
134 100 : case COLOPL_BC_TYPE_PAIR(IS_STRING, IS_NULL):
135 100 : return Z_STRLEN_P(op1) == 0 ? 0 : 1;
136 :
137 60 : case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_NULL):
138 60 : return 1;
139 :
140 60 : case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_OBJECT):
141 60 : return -1;
142 :
143 7232 : default:
144 7232 : if (Z_ISREF_P(op1)) {
145 0 : op1 = Z_REFVAL_P(op1);
146 0 : continue;
147 7232 : } else if (Z_ISREF_P(op2)) {
148 0 : op2 = Z_REFVAL_P(op2);
149 0 : continue;
150 : }
151 :
152 7232 : if (Z_TYPE_P(op1) == IS_OBJECT
153 840 : && Z_TYPE_P(op2) == IS_OBJECT
154 180 : && Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
155 60 : return 0;
156 7172 : } else if (Z_TYPE_P(op1) == IS_OBJECT) {
157 780 : return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
158 6392 : } else if (Z_TYPE_P(op2) == IS_OBJECT) {
159 660 : return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
160 : }
161 :
162 5732 : if (!converted) {
163 5012 : if (Z_TYPE_P(op1) < IS_TRUE) {
164 360 : return zval_is_true(op2) ? -1 : 0;
165 4652 : } else if (Z_TYPE_P(op1) == IS_TRUE) {
166 240 : return zval_is_true(op2) ? 0 : 1;
167 4412 : } else if (Z_TYPE_P(op2) < IS_TRUE) {
168 340 : return zval_is_true(op1) ? 1 : 0;
169 4072 : } else if (Z_TYPE_P(op2) == IS_TRUE) {
170 220 : return zval_is_true(op1) ? 0 : -1;
171 : } else {
172 3852 : op1 = _php_colopl_bc_zendi_convert_scalar_to_number_silent(op1, &op1_copy);
173 3852 : op2 = _php_colopl_bc_zendi_convert_scalar_to_number_silent(op2, &op2_copy);
174 3852 : if (EG(exception)) {
175 0 : return 1; /* to stop comparison of arrays */
176 : }
177 3852 : converted = 1;
178 : }
179 720 : } else if (Z_TYPE_P(op1)==IS_ARRAY) {
180 360 : return 1;
181 360 : } else if (Z_TYPE_P(op2)==IS_ARRAY) {
182 360 : return -1;
183 : } else {
184 0 : ZEND_UNREACHABLE();
185 : zend_throw_error(NULL, "Unsupported operand types");
186 : return 1;
187 : }
188 : }
189 : }
190 : }
191 :
192 11880 : static int legacy_compare_slow(zval *op1, zval *op2)
193 : {
194 11880 : int bc = legacy_compare_fast(op1, op2);
195 11880 : int native = zend_compare(op1, op2);
196 :
197 11880 : if (native != bc) {
198 812 : if (COLOPL_BC_G(php74_compare_mode) & COLOPL_BC_PHP74_COMPARE_MODE_LOG) {
199 808 : php_log_err_with_severity("Incompatible compare detected", LOG_NOTICE);
200 : }
201 812 : if (COLOPL_BC_G(php74_compare_mode) & COLOPL_BC_PHP74_COMPARE_MODE_DEPRECATED) {
202 808 : php_error_docref(NULL, E_DEPRECATED, "Incompatible compare detected");
203 : }
204 : }
205 :
206 11880 : return bc;
207 : }
208 :
209 222 : PHP_INI_MH(OnUpdateCompareMode)
210 : {
211 222 : if (OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
212 0 : return FAILURE;
213 : }
214 :
215 222 : if (COLOPL_BC_G(php74_compare_mode) <= COLOPL_BC_PHP74_COMPARE_MODE_SILENT) {
216 134 : COLOPL_BC_G(php74_compare_func) = legacy_compare_fast;
217 : } else {
218 88 : COLOPL_BC_G(php74_compare_func) = legacy_compare_slow;
219 : }
220 :
221 222 : return SUCCESS;
222 : }
223 :
224 15084 : int php_colopl_bc_compare(zval *op1, zval *op2)
225 : {
226 15084 : return COLOPL_BC_G(php74_compare_func)(op1, op2);
227 : }
228 :
229 0 : static zend_always_inline bool php_colopl_bc_fast_equal_check_long(zval *op1, zval *op2)
230 : {
231 0 : if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
232 0 : return Z_LVAL_P(op1) == Z_LVAL_P(op2);
233 : }
234 0 : return php_colopl_bc_compare(op1, op2) == 0;
235 : }
236 :
237 8 : static zend_always_inline bool php_colopl_bc_fast_equal_check_string(zval *op1, zval *op2)
238 : {
239 8 : if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
240 0 : return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
241 : }
242 8 : return php_colopl_bc_compare(op1, op2) == 0;
243 : }
244 :
245 8 : static zend_always_inline bool php_colopl_bc_fast_equal_check_function(zval *op1, zval *op2)
246 : {
247 8 : if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
248 0 : if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
249 0 : return Z_LVAL_P(op1) == Z_LVAL_P(op2);
250 0 : } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
251 0 : return ((double)Z_LVAL_P(op1)) == Z_DVAL_P(op2);
252 : }
253 8 : } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
254 0 : if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
255 0 : return Z_DVAL_P(op1) == Z_DVAL_P(op2);
256 0 : } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
257 0 : return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2));
258 : }
259 8 : } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
260 8 : if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
261 4 : return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
262 : }
263 : }
264 4 : return php_colopl_bc_compare(op1, op2) == 0;
265 : }
266 :
267 : /* array.c */
268 :
269 2792 : static int php_colopl_bc_array_key_compare(Bucket *f, Bucket *s)
270 : {
271 : zend_uchar t;
272 : zend_long l1, l2;
273 : double d;
274 :
275 2792 : if (f->key == NULL) {
276 40 : if (s->key == NULL) {
277 0 : return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
278 : } else {
279 40 : l1 = (zend_long)f->h;
280 40 : t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
281 40 : if (t == IS_LONG) {
282 : /* pass */
283 40 : } else if (t == IS_DOUBLE) {
284 0 : return ZEND_NORMALIZE_BOOL((double)l1 - d);
285 : } else {
286 40 : l2 = 0;
287 : }
288 : }
289 : } else {
290 2752 : if (s->key) {
291 2704 : return zendi_smart_strcmp(f->key, s->key);
292 : } else {
293 48 : l2 = (zend_long)s->h;
294 48 : t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
295 48 : if (t == IS_LONG) {
296 : /* pass */
297 48 : } else if (t == IS_DOUBLE) {
298 0 : return ZEND_NORMALIZE_BOOL(d - (double)l2);
299 : } else {
300 48 : l1 = 0;
301 : }
302 : }
303 : }
304 88 : return ZEND_NORMALIZE_BOOL(l1 - l2);
305 : }
306 :
307 1412 : static int php_colopl_bc_array_reverse_key_compare(Bucket *a, Bucket *b)
308 : {
309 1412 : return php_colopl_bc_array_key_compare(b, a);
310 : }
311 :
312 0 : static int php_colopl_bc_array_key_compare_numeric(Bucket *f, Bucket *s)
313 : {
314 0 : if (f->key == NULL && s->key == NULL) {
315 0 : return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
316 : } else {
317 : double d1, d2;
318 0 : if (f->key) {
319 0 : d1 = zend_strtod(f->key->val, NULL);
320 : } else {
321 0 : d1 = (double)(zend_long)f->h;
322 : }
323 0 : if (s->key) {
324 0 : d2 = zend_strtod(s->key->val, NULL);
325 : } else {
326 0 : d2 = (double)(zend_long)s->h;
327 : }
328 0 : return ZEND_NORMALIZE_BOOL(d1 - d2);
329 : }
330 : }
331 :
332 0 : static int php_colopl_bc_array_reverse_key_compare_numeric(Bucket *a, Bucket *b)
333 : {
334 0 : return php_colopl_bc_array_key_compare_numeric(b, a);
335 : }
336 :
337 0 : static int php_colopl_bc_array_key_compare_string_case(Bucket *f, Bucket *s)
338 : {
339 : const char *s1, *s2;
340 : size_t l1, l2;
341 : char buf1[MAX_LENGTH_OF_LONG + 1];
342 : char buf2[MAX_LENGTH_OF_LONG + 1];
343 :
344 0 : if (f->key) {
345 0 : s1 = f->key->val;
346 0 : l1 = f->key->len;
347 : } else {
348 0 : s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
349 0 : l1 = buf1 + sizeof(buf1) - 1 - s1;
350 : }
351 0 : if (s->key) {
352 0 : s2 = s->key->val;
353 0 : l2 = s->key->len;
354 : } else {
355 0 : s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
356 0 : l2 = buf2 + sizeof(buf2) - 1 - s1;
357 : }
358 0 : return zend_binary_strcasecmp_l(s1, l1, s2, l2);
359 : }
360 :
361 0 : static int php_colopl_bc_array_reverse_key_compare_string_case(Bucket *a, Bucket *b)
362 : {
363 0 : return php_colopl_bc_array_key_compare_string_case(b, a);
364 : }
365 :
366 0 : static int php_colopl_bc_array_key_compare_string(Bucket *f, Bucket *s)
367 : {
368 : const char *s1, *s2;
369 : size_t l1, l2;
370 : char buf1[MAX_LENGTH_OF_LONG + 1];
371 : char buf2[MAX_LENGTH_OF_LONG + 1];
372 :
373 0 : if (f->key) {
374 0 : s1 = f->key->val;
375 0 : l1 = f->key->len;
376 : } else {
377 0 : s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
378 0 : l1 = buf1 + sizeof(buf1) - 1 - s1;
379 : }
380 0 : if (s->key) {
381 0 : s2 = s->key->val;
382 0 : l2 = s->key->len;
383 : } else {
384 0 : s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
385 0 : l2 = buf2 + sizeof(buf2) - 1 - s2;
386 : }
387 0 : return zend_binary_strcmp(s1, l1, s2, l2);
388 : }
389 :
390 0 : static int php_colopl_bc_array_reverse_key_compare_string(Bucket *a, Bucket *b)
391 : {
392 0 : return php_colopl_bc_array_key_compare_string(b, a);
393 : }
394 :
395 0 : static int php_colopl_bc_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case)
396 : {
397 : const char *s1, *s2;
398 : size_t l1, l2;
399 : char buf1[MAX_LENGTH_OF_LONG + 1];
400 : char buf2[MAX_LENGTH_OF_LONG + 1];
401 :
402 0 : if (f->key) {
403 0 : s1 = f->key->val;
404 0 : l1 = f->key->len;
405 : } else {
406 0 : s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
407 0 : l1 = buf1 + sizeof(buf1) - 1 - s1;
408 : }
409 0 : if (s->key) {
410 0 : s2 = s->key->val;
411 0 : l2 = s->key->len;
412 : } else {
413 0 : s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
414 0 : l2 = buf2 + sizeof(buf2) - 1 - s1;
415 : }
416 0 : return strnatcmp_ex(s1, l1, s2, l2, fold_case);
417 : }
418 :
419 0 : static int php_colopl_bc_array_key_compare_string_natural_case(Bucket *a, Bucket *b)
420 : {
421 0 : return php_colopl_bc_array_key_compare_string_natural_general(a, b, 1);
422 : }
423 :
424 0 : static int php_colopl_bc_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b)
425 : {
426 0 : return php_colopl_bc_array_key_compare_string_natural_general(b, a, 1);
427 : }
428 :
429 0 : static int php_colopl_bc_array_key_compare_string_natural(Bucket *a, Bucket *b)
430 : {
431 0 : return php_colopl_bc_array_key_compare_string_natural_general(a, b, 0);
432 : }
433 :
434 0 : static int php_colopl_bc_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b)
435 : {
436 0 : return php_colopl_bc_array_key_compare_string_natural_general(b, a, 0);
437 : }
438 :
439 0 : static int php_colopl_bc_array_key_compare_string_locale(Bucket *f, Bucket *s)
440 : {
441 : const char *s1, *s2;
442 : char buf1[MAX_LENGTH_OF_LONG + 1];
443 : char buf2[MAX_LENGTH_OF_LONG + 1];
444 :
445 0 : if (f->key) {
446 0 : s1 = f->key->val;
447 : } else {
448 0 : s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
449 : }
450 0 : if (s->key) {
451 0 : s2 = s->key->val;
452 : } else {
453 0 : s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
454 : }
455 0 : return strcoll(s1, s2);
456 : }
457 :
458 0 : static int php_colopl_bc_array_reverse_key_compare_string_locale(Bucket *a, Bucket *b)
459 : {
460 0 : return php_colopl_bc_array_key_compare_string_locale(b, a);
461 : }
462 :
463 9276 : static int php_colopl_bc_array_data_compare(Bucket *f, Bucket *s)
464 : {
465 9276 : zval *first = &f->val;
466 9276 : zval *second = &s->val;
467 :
468 9276 : if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
469 0 : first = Z_INDIRECT_P(first);
470 : }
471 9276 : if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
472 0 : second = Z_INDIRECT_P(second);
473 : }
474 :
475 9276 : return php_colopl_bc_compare(first, second);
476 : }
477 :
478 3120 : static int php_colopl_bc_array_reverse_data_compare(Bucket *a, Bucket *b)
479 : {
480 3120 : return php_colopl_bc_array_data_compare(a, b) * -1;
481 : }
482 :
483 0 : static int php_colopl_bc_array_data_compare_numeric(Bucket *f, Bucket *s)
484 : {
485 0 : zval *first = &f->val;
486 0 : zval *second = &s->val;
487 :
488 0 : if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
489 0 : first = Z_INDIRECT_P(first);
490 : }
491 0 : if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
492 0 : second = Z_INDIRECT_P(second);
493 : }
494 :
495 0 : return numeric_compare_function(first, second);
496 : }
497 :
498 0 : static int php_colopl_bc_array_reverse_data_compare_numeric(Bucket *a, Bucket *b)
499 : {
500 0 : return php_colopl_bc_array_data_compare_numeric(b, a);
501 : }
502 :
503 0 : static int php_colopl_bc_array_data_compare_string_case(Bucket *f, Bucket *s)
504 : {
505 0 : zval *first = &f->val;
506 0 : zval *second = &s->val;
507 :
508 0 : if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
509 0 : first = Z_INDIRECT_P(first);
510 : }
511 0 : if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
512 0 : second = Z_INDIRECT_P(second);
513 : }
514 :
515 0 : return string_case_compare_function(first, second);
516 : }
517 :
518 0 : static int php_colopl_bc_array_reverse_data_compare_string_case(Bucket *a, Bucket *b)
519 : {
520 0 : return php_colopl_bc_array_data_compare_string_case(b, a);
521 : }
522 :
523 0 : static int php_colopl_bc_array_data_compare_string(Bucket *f, Bucket *s)
524 : {
525 0 : zval *first = &f->val;
526 0 : zval *second = &s->val;
527 :
528 0 : if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
529 0 : first = Z_INDIRECT_P(first);
530 : }
531 0 : if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
532 0 : second = Z_INDIRECT_P(second);
533 : }
534 :
535 0 : return string_compare_function(first, second);
536 : }
537 :
538 0 : static int php_colopl_bc_array_reverse_data_compare_string(Bucket *a, Bucket *b)
539 : {
540 0 : return php_colopl_bc_array_data_compare_string(b, a);
541 : }
542 :
543 0 : static int php_colopl_bc_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case)
544 : {
545 : zend_string *tmp_str1, *tmp_str2;
546 0 : zend_string *str1 = zval_get_tmp_string(&f->val, &tmp_str1);
547 0 : zend_string *str2 = zval_get_tmp_string(&s->val, &tmp_str2);
548 :
549 0 : int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
550 :
551 0 : zend_tmp_string_release(tmp_str1);
552 0 : zend_tmp_string_release(tmp_str2);
553 0 : return result;
554 : }
555 :
556 0 : static int php_colopl_bc_array_natural_compare(Bucket *a, Bucket *b)
557 : {
558 0 : return php_colopl_bc_array_natural_general_compare(a, b, 0);
559 : }
560 :
561 0 : static int php_colopl_bc_array_reverse_natural_compare(Bucket *a, Bucket *b)
562 : {
563 0 : return php_colopl_bc_array_natural_general_compare(b, a, 0);
564 : }
565 :
566 0 : static int php_colopl_bc_array_natural_case_compare(Bucket *a, Bucket *b)
567 : {
568 0 : return php_colopl_bc_array_natural_general_compare(a, b, 1);
569 : }
570 :
571 0 : static int php_colopl_bc_array_reverse_natural_case_compare(Bucket *a, Bucket *b)
572 : {
573 0 : return php_colopl_bc_array_natural_general_compare(b, a, 1);
574 : }
575 :
576 0 : static int php_colopl_bc_array_data_compare_string_locale(Bucket *f, Bucket *s)
577 : {
578 0 : zval *first = &f->val;
579 0 : zval *second = &s->val;
580 :
581 0 : if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
582 0 : first = Z_INDIRECT_P(first);
583 : }
584 0 : if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
585 0 : second = Z_INDIRECT_P(second);
586 : }
587 :
588 0 : return string_locale_compare_function(first, second);
589 : }
590 :
591 0 : static int php_colopl_bc_array_reverse_data_compare_string_locale(Bucket *a, Bucket *b)
592 : {
593 0 : return php_colopl_bc_array_data_compare_string_locale(b, a);
594 : }
595 :
596 3048 : static int php_colopl_bc_array_user_compare(Bucket *f, Bucket *s)
597 : {
598 : zval args[2];
599 : zval retval;
600 :
601 3048 : ZVAL_COPY(&args[0], &f->val);
602 3048 : ZVAL_COPY(&args[1], &s->val);
603 :
604 3048 : COLOPL_BC_G(user_compare_fci).param_count = 2;
605 3048 : COLOPL_BC_G(user_compare_fci).params = args;
606 3048 : COLOPL_BC_G(user_compare_fci).retval = &retval;
607 3048 : if (zend_call_function(&COLOPL_BC_G(user_compare_fci), &COLOPL_BC_G(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
608 3048 : zend_long ret = zval_get_long(&retval);
609 3048 : zval_ptr_dtor(&retval);
610 3048 : zval_ptr_dtor(&args[1]);
611 3048 : zval_ptr_dtor(&args[0]);
612 3048 : return ZEND_NORMALIZE_BOOL(ret);
613 : } else {
614 0 : zval_ptr_dtor(&args[1]);
615 0 : zval_ptr_dtor(&args[0]);
616 0 : return 0;
617 : }
618 : }
619 :
620 1524 : static int php_colopl_bc_array_user_key_compare(Bucket *f, Bucket *s)
621 : {
622 : zval args[2];
623 : zval retval;
624 : zend_long result;
625 :
626 1524 : if (f->key == NULL) {
627 740 : ZVAL_LONG(&args[0], f->h);
628 : } else {
629 784 : ZVAL_STR_COPY(&args[0], f->key);
630 : }
631 1524 : if (s->key == NULL) {
632 740 : ZVAL_LONG(&args[1], s->h);
633 : } else {
634 784 : ZVAL_STR_COPY(&args[1], s->key);
635 : }
636 :
637 1524 : COLOPL_BC_G(user_compare_fci).param_count = 2;
638 1524 : COLOPL_BC_G(user_compare_fci).params = args;
639 1524 : COLOPL_BC_G(user_compare_fci).retval = &retval;;
640 1524 : if (zend_call_function(&COLOPL_BC_G(user_compare_fci), &COLOPL_BC_G(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
641 1524 : result = zval_get_long(&retval);
642 1524 : zval_ptr_dtor(&retval);
643 : } else {
644 0 : result = 0;
645 : }
646 :
647 1524 : zval_ptr_dtor(&args[0]);
648 1524 : zval_ptr_dtor(&args[1]);
649 :
650 1524 : return ZEND_NORMALIZE_BOOL(result);
651 : }
652 :
653 44 : static bucket_compare_func_t php_colopl_bc_get_key_compare_func(zend_long sort_type, int reverse)
654 : {
655 44 : switch (sort_type & ~PHP_SORT_FLAG_CASE) {
656 0 : case PHP_SORT_NUMERIC:
657 0 : if (reverse) {
658 0 : return php_colopl_bc_array_reverse_key_compare_numeric;
659 : } else {
660 0 : return php_colopl_bc_array_key_compare_numeric;
661 : }
662 : break;
663 :
664 0 : case PHP_SORT_STRING:
665 0 : if (sort_type & PHP_SORT_FLAG_CASE) {
666 0 : if (reverse) {
667 0 : return php_colopl_bc_array_reverse_key_compare_string_case;
668 : } else {
669 0 : return php_colopl_bc_array_key_compare_string_case;
670 : }
671 : } else {
672 0 : if (reverse) {
673 0 : return php_colopl_bc_array_reverse_key_compare_string;
674 : } else {
675 0 : return php_colopl_bc_array_key_compare_string;
676 : }
677 : }
678 : break;
679 :
680 0 : case PHP_SORT_NATURAL:
681 0 : if (sort_type & PHP_SORT_FLAG_CASE) {
682 0 : if (reverse) {
683 0 : return php_colopl_bc_array_reverse_key_compare_string_natural_case;
684 : } else {
685 0 : return php_colopl_bc_array_key_compare_string_natural_case;
686 : }
687 : } else {
688 0 : if (reverse) {
689 0 : return php_colopl_bc_array_reverse_key_compare_string_natural;
690 : } else {
691 0 : return php_colopl_bc_array_key_compare_string_natural;
692 : }
693 : }
694 : break;
695 :
696 0 : case PHP_SORT_LOCALE_STRING:
697 0 : if (reverse) {
698 0 : return php_colopl_bc_array_reverse_key_compare_string_locale;
699 : } else {
700 0 : return php_colopl_bc_array_key_compare_string_locale;
701 : }
702 : break;
703 :
704 44 : case PHP_SORT_REGULAR:
705 : default:
706 44 : if (reverse) {
707 24 : return php_colopl_bc_array_reverse_key_compare;
708 : } else {
709 20 : return php_colopl_bc_array_key_compare;
710 : }
711 : break;
712 : }
713 : return NULL;
714 : }
715 :
716 88 : static bucket_compare_func_t php_colopl_bc_get_data_compare_func(zend_long sort_type, int reverse)
717 : {
718 88 : switch (sort_type & ~PHP_SORT_FLAG_CASE) {
719 0 : case PHP_SORT_NUMERIC:
720 0 : if (reverse) {
721 0 : return php_colopl_bc_array_reverse_data_compare_numeric;
722 : } else {
723 0 : return php_colopl_bc_array_data_compare_numeric;
724 : }
725 : break;
726 :
727 0 : case PHP_SORT_STRING:
728 0 : if (sort_type & PHP_SORT_FLAG_CASE) {
729 0 : if (reverse) {
730 0 : return php_colopl_bc_array_reverse_data_compare_string_case;
731 : } else {
732 0 : return php_colopl_bc_array_data_compare_string_case;
733 : }
734 : } else {
735 0 : if (reverse) {
736 0 : return php_colopl_bc_array_reverse_data_compare_string;
737 : } else {
738 0 : return php_colopl_bc_array_data_compare_string;
739 : }
740 : }
741 : break;
742 :
743 0 : case PHP_SORT_NATURAL:
744 0 : if (sort_type & PHP_SORT_FLAG_CASE) {
745 0 : if (reverse) {
746 0 : return php_colopl_bc_array_reverse_natural_case_compare;
747 : } else {
748 0 : return php_colopl_bc_array_natural_case_compare;
749 : }
750 : } else {
751 0 : if (reverse) {
752 0 : return php_colopl_bc_array_reverse_natural_compare;
753 : } else {
754 0 : return php_colopl_bc_array_natural_compare;
755 : }
756 : }
757 : break;
758 :
759 0 : case PHP_SORT_LOCALE_STRING:
760 0 : if (reverse) {
761 0 : return php_colopl_bc_array_reverse_data_compare_string_locale;
762 : } else {
763 0 : return php_colopl_bc_array_data_compare_string_locale;
764 : }
765 : break;
766 :
767 88 : case PHP_SORT_REGULAR:
768 : default:
769 88 : if (reverse) {
770 40 : return php_colopl_bc_array_reverse_data_compare;
771 : } else {
772 48 : return php_colopl_bc_array_data_compare;
773 : }
774 : break;
775 : }
776 : return NULL;
777 : }
778 :
779 : #define COLOPL_BC_MULTISORT_ORDER 0
780 : #define COLOPL_BC_MULTISORT_TYPE 1
781 : #define COLOPL_BC_MULTISORT_LAST 2
782 :
783 1496 : int php_colopl_bc_multisort_compare(const void *a, const void *b)
784 : {
785 1496 : Bucket *ab = *(Bucket **)a;
786 1496 : Bucket *bb = *(Bucket **)b;
787 : int r;
788 : zend_long result;
789 :
790 1496 : r = 0;
791 : do {
792 2992 : result = COLOPL_BC_G(multisort_func)[r](&ab[r], &bb[r]);
793 2992 : if (result != 0) {
794 0 : return result > 0 ? 1 : -1;
795 : }
796 2992 : r++;
797 2992 : } while (Z_TYPE(ab[r].val) != IS_UNDEF);
798 :
799 1496 : return 0;
800 : }
801 :
802 : #define COLOPL_BC_MULTISORT_ABORT \
803 : efree(func); \
804 : efree(arrays); \
805 : return;
806 :
807 596 : static void colopl_bc_array_bucket_p_swap(void *p, void *q)
808 : {
809 : Bucket *t;
810 596 : Bucket **f = (Bucket **)p;
811 596 : Bucket **g = (Bucket **)q;
812 :
813 596 : t = *f;
814 596 : *f = *g;
815 596 : *g = t;
816 596 : }
817 :
818 8 : static inline void php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
819 : {
820 : zval *value, /* value to check for */
821 : *array, /* array to check in */
822 : *entry; /* pointer to array entry */
823 : zend_ulong num_idx;
824 : zend_string *str_idx;
825 8 : bool strict = 0; /* strict comparison or not */
826 :
827 8 : ZEND_PARSE_PARAMETERS_START(2, 3)
828 8 : Z_PARAM_ZVAL(value)
829 8 : Z_PARAM_ARRAY(array)
830 8 : Z_PARAM_OPTIONAL
831 8 : Z_PARAM_BOOL(strict)
832 8 : ZEND_PARSE_PARAMETERS_END();
833 :
834 8 : if (strict) {
835 0 : if (Z_TYPE_P(value) == IS_LONG) {
836 0 : ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
837 0 : ZVAL_DEREF(entry);
838 0 : if (Z_TYPE_P(entry) == IS_LONG && Z_LVAL_P(entry) == Z_LVAL_P(value)) {
839 0 : if (behavior == 0) {
840 0 : RETURN_TRUE;
841 : } else {
842 0 : if (str_idx) {
843 0 : RETURN_STR_COPY(str_idx);
844 : } else {
845 0 : RETURN_LONG(num_idx);
846 : }
847 : }
848 : }
849 : } ZEND_HASH_FOREACH_END();
850 : } else {
851 0 : ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
852 0 : ZVAL_DEREF(entry);
853 0 : if (fast_is_identical_function(value, entry)) {
854 0 : if (behavior == 0) {
855 0 : RETURN_TRUE;
856 : } else {
857 0 : if (str_idx) {
858 0 : RETURN_STR_COPY(str_idx);
859 : } else {
860 0 : RETURN_LONG(num_idx);
861 : }
862 : }
863 : }
864 : } ZEND_HASH_FOREACH_END();
865 : }
866 : } else {
867 8 : if (Z_TYPE_P(value) == IS_LONG) {
868 0 : ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
869 0 : if (php_colopl_bc_fast_equal_check_long(value, entry)) {
870 0 : if (behavior == 0) {
871 0 : RETURN_TRUE;
872 : } else {
873 0 : if (str_idx) {
874 0 : RETURN_STR_COPY(str_idx);
875 : } else {
876 0 : RETURN_LONG(num_idx);
877 : }
878 : }
879 : }
880 : } ZEND_HASH_FOREACH_END();
881 8 : } else if (Z_TYPE_P(value) == IS_STRING) {
882 8 : ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
883 8 : if (php_colopl_bc_fast_equal_check_string(value, entry)) {
884 8 : if (behavior == 0) {
885 4 : RETURN_TRUE;
886 : } else {
887 4 : if (str_idx) {
888 4 : RETURN_STR_COPY(str_idx);
889 : } else {
890 0 : RETURN_LONG(num_idx);
891 : }
892 : }
893 : }
894 : } ZEND_HASH_FOREACH_END();
895 : } else {
896 0 : ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
897 0 : if (php_colopl_bc_fast_equal_check_function(value, entry)) {
898 0 : if (behavior == 0) {
899 0 : RETURN_TRUE;
900 : } else {
901 0 : if (str_idx) {
902 0 : RETURN_STR_COPY(str_idx);
903 : } else {
904 0 : RETURN_LONG(num_idx);
905 : }
906 : }
907 : }
908 : } ZEND_HASH_FOREACH_END();
909 : }
910 : }
911 :
912 0 : RETURN_FALSE;
913 : }
914 :
915 : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_VARS \
916 : zend_fcall_info old_user_compare_fci; \
917 : zend_fcall_info_cache old_user_compare_fci_cache \
918 :
919 : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_BACKUP() \
920 : old_user_compare_fci = COLOPL_BC_G(user_compare_fci); \
921 : old_user_compare_fci_cache = COLOPL_BC_G(user_compare_fci_cache); \
922 : COLOPL_BC_G(user_compare_fci_cache) = empty_fcall_info_cache; \
923 :
924 : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE() \
925 : zend_release_fcall_info_cache(&COLOPL_BC_G(user_compare_fci_cache)); \
926 : COLOPL_BC_G(user_compare_fci) = old_user_compare_fci; \
927 : COLOPL_BC_G(user_compare_fci_cache) = old_user_compare_fci_cache; \
928 :
929 184 : static void legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAMETERS, zval *array, bucket_compare_func_t comapre_func, bool renumber)
930 : {
931 184 : zend_hash_sort(Z_ARRVAL_P(array), comapre_func, renumber);
932 184 : }
933 :
934 148 : static void legacy_hash_sort_slow(INTERNAL_FUNCTION_PARAMETERS, zval *array, bucket_compare_func_t compare_func, bool renumber)
935 : {
936 : zval legacy;
937 : zend_internal_function *fn;
938 : char *fnname_ptr;
939 :
940 148 : ZVAL_DUP(&legacy, array);
941 :
942 148 : legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAM_PASSTHRU, &legacy, compare_func, renumber);
943 :
944 : /* Get native PHP bundled (internal) function ptr */
945 148 : fnname_ptr = execute_data->func->internal_function.function_name->val;
946 : /*
947 : * Extracting last piece of namespaces, they're always identical a native function name
948 : *
949 : * e.g.)
950 : * Colopl\ColoplBc\Php74\*****
951 : * ^^^^^
952 : */
953 3404 : while (strchr(fnname_ptr, '\\')) {
954 3256 : ++fnname_ptr;
955 : }
956 148 : fn = zend_hash_str_find_ptr(EG(function_table), fnname_ptr, strlen(fnname_ptr));
957 148 : if (EXPECTED(fn != NULL)) {
958 : /* Passthrough PHP bundled (internal) function */
959 148 : fn->handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
960 :
961 148 : if (!zend_is_identical(&legacy, array)) {
962 120 : if (COLOPL_BC_G(php74_sort_mode) & COLOPL_BC_PHP74_SORT_MODE_LOG) {
963 92 : php_log_err_with_severity("Incompatible sort detected", LOG_NOTICE);
964 : }
965 120 : if (COLOPL_BC_G(php74_sort_mode) & COLOPL_BC_PHP74_SORT_MODE_DEPRECATED) {
966 92 : php_error_docref(NULL, E_DEPRECATED, "Incompatible sort detected");
967 : }
968 : }
969 : }
970 :
971 148 : zval_ptr_dtor(array);
972 148 : ZVAL_ARR(array, Z_ARRVAL(legacy));
973 148 : }
974 :
975 222 : PHP_INI_MH(OnUpdateSortMode)
976 : {
977 222 : if (OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
978 0 : return FAILURE;
979 : }
980 :
981 222 : if (COLOPL_BC_G(php74_sort_mode) <= 0) {
982 134 : COLOPL_BC_G(php74_hash_sort_func) = legacy_hash_sort_fast;
983 : } else {
984 88 : COLOPL_BC_G(php74_hash_sort_func) = legacy_hash_sort_slow;
985 : }
986 :
987 222 : return SUCCESS;
988 : }
989 :
990 60 : static void php_colopl_bc_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compare_func, zend_bool renumber)
991 : {
992 : zval *array, arr;
993 : PHP_COLOPL_BC_ARRAY_CMP_FUNC_VARS;
994 :
995 60 : PHP_COLOPL_BC_ARRAY_CMP_FUNC_BACKUP();
996 :
997 60 : ZEND_PARSE_PARAMETERS_START(2, 2)
998 60 : Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
999 60 : Z_PARAM_FUNC(COLOPL_BC_G(user_compare_fci), COLOPL_BC_G(user_compare_fci_cache))
1000 60 : ZEND_PARSE_PARAMETERS_END_EX( PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE(); return );
1001 :
1002 : /* Copy array, so the in-place modifications will not be visible to the callback function */
1003 60 : ZVAL_DUP(&arr, array);
1004 60 : if (zend_hash_num_elements(Z_ARRVAL(arr)) == 0) {
1005 0 : PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
1006 0 : RETURN_TRUE;
1007 : }
1008 :
1009 60 : COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, &arr, compare_func, renumber);
1010 :
1011 60 : zval_ptr_dtor(array);
1012 60 : ZVAL_ARR(array, Z_ARRVAL(arr));
1013 :
1014 60 : PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
1015 60 : RETURN_TRUE;
1016 : }
1017 :
1018 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_ksort)
1019 : {
1020 : zval *array;
1021 20 : zend_long sort_type = PHP_SORT_REGULAR;
1022 : bucket_compare_func_t cmp;
1023 :
1024 20 : ZEND_PARSE_PARAMETERS_START(1, 2)
1025 20 : Z_PARAM_ARRAY_EX(array, 0, 1)
1026 20 : Z_PARAM_OPTIONAL
1027 20 : Z_PARAM_LONG(sort_type)
1028 20 : ZEND_PARSE_PARAMETERS_END();
1029 :
1030 20 : cmp = php_colopl_bc_get_key_compare_func(sort_type, 0);
1031 :
1032 20 : COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0);
1033 :
1034 20 : RETURN_TRUE;
1035 : }
1036 :
1037 24 : PHP_FUNCTION(Colopl_ColoplBc_Php74_krsort)
1038 : {
1039 : zval *array;
1040 24 : zend_long sort_type = PHP_SORT_REGULAR;
1041 : bucket_compare_func_t cmp;
1042 :
1043 24 : ZEND_PARSE_PARAMETERS_START(1, 2)
1044 24 : Z_PARAM_ARRAY_EX(array, 0, 1)
1045 24 : Z_PARAM_OPTIONAL
1046 24 : Z_PARAM_LONG(sort_type)
1047 24 : ZEND_PARSE_PARAMETERS_END();
1048 :
1049 24 : cmp = php_colopl_bc_get_key_compare_func(sort_type, 1);
1050 :
1051 24 : COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0);
1052 :
1053 24 : RETURN_TRUE;
1054 : }
1055 :
1056 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_asort)
1057 : {
1058 : zval *array;
1059 20 : zend_long sort_type = PHP_SORT_REGULAR;
1060 : bucket_compare_func_t cmp;
1061 :
1062 20 : ZEND_PARSE_PARAMETERS_START(1, 2)
1063 20 : Z_PARAM_ARRAY_EX(array, 0, 1)
1064 20 : Z_PARAM_OPTIONAL
1065 20 : Z_PARAM_LONG(sort_type)
1066 20 : ZEND_PARSE_PARAMETERS_END();
1067 :
1068 20 : cmp = php_colopl_bc_get_data_compare_func(sort_type, 0);
1069 :
1070 20 : COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0);
1071 :
1072 20 : RETURN_TRUE;
1073 : }
1074 :
1075 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_arsort)
1076 : {
1077 : zval *array;
1078 20 : zend_long sort_type = PHP_SORT_REGULAR;
1079 : bucket_compare_func_t cmp;
1080 :
1081 20 : ZEND_PARSE_PARAMETERS_START(1, 2)
1082 20 : Z_PARAM_ARRAY_EX(array, 0, 1)
1083 20 : Z_PARAM_OPTIONAL
1084 20 : Z_PARAM_LONG(sort_type)
1085 20 : ZEND_PARSE_PARAMETERS_END();
1086 :
1087 20 : cmp = php_colopl_bc_get_data_compare_func(sort_type, 1);
1088 :
1089 20 : COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0);
1090 :
1091 20 : RETURN_TRUE;
1092 : }
1093 :
1094 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_sort)
1095 : {
1096 : zval *array;
1097 20 : zend_long sort_type = PHP_SORT_REGULAR;
1098 : bucket_compare_func_t cmp;
1099 :
1100 20 : ZEND_PARSE_PARAMETERS_START(1, 2)
1101 20 : Z_PARAM_ARRAY_EX(array, 0, 1)
1102 20 : Z_PARAM_OPTIONAL
1103 20 : Z_PARAM_LONG(sort_type)
1104 20 : ZEND_PARSE_PARAMETERS_END();
1105 :
1106 20 : cmp = php_colopl_bc_get_data_compare_func(sort_type, 0);
1107 :
1108 20 : COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 1);
1109 :
1110 20 : RETURN_TRUE;
1111 : }
1112 :
1113 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_rsort)
1114 : {
1115 : zval *array;
1116 20 : zend_long sort_type = PHP_SORT_REGULAR;
1117 : bucket_compare_func_t cmp;
1118 :
1119 20 : ZEND_PARSE_PARAMETERS_START(1, 2)
1120 20 : Z_PARAM_ARRAY_EX(array, 0, 1)
1121 20 : Z_PARAM_OPTIONAL
1122 20 : Z_PARAM_LONG(sort_type)
1123 20 : ZEND_PARSE_PARAMETERS_END();
1124 :
1125 20 : cmp = php_colopl_bc_get_data_compare_func(sort_type, 1);
1126 :
1127 20 : COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 1);
1128 :
1129 20 : RETURN_TRUE;
1130 : }
1131 :
1132 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_usort)
1133 : {
1134 20 : php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_compare, 1);
1135 20 : }
1136 :
1137 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_uasort)
1138 : {
1139 20 : php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_compare, 0);
1140 20 : }
1141 :
1142 20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_uksort)
1143 : {
1144 20 : php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_key_compare, 0);
1145 20 : }
1146 :
1147 4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_in_array)
1148 : {
1149 4 : php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1150 4 : }
1151 :
1152 4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_search)
1153 : {
1154 4 : php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1155 4 : }
1156 :
1157 4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_keys)
1158 : {
1159 : zval *input, /* Input array */
1160 4 : *search_value = NULL, /* Value to search for */
1161 : *entry, /* An entry in the input array */
1162 : new_val; /* New value */
1163 4 : bool strict = 0; /* do strict comparison */
1164 : zend_ulong num_idx;
1165 : zend_string *str_idx;
1166 : zend_array *arrval;
1167 : zend_ulong elem_count;
1168 :
1169 4 : ZEND_PARSE_PARAMETERS_START(1, 3)
1170 4 : Z_PARAM_ARRAY(input)
1171 4 : Z_PARAM_OPTIONAL
1172 4 : Z_PARAM_ZVAL(search_value)
1173 4 : Z_PARAM_BOOL(strict)
1174 4 : ZEND_PARSE_PARAMETERS_END();
1175 4 : arrval = Z_ARRVAL_P(input);
1176 4 : elem_count = zend_hash_num_elements(arrval);
1177 :
1178 : /* Base case: empty input */
1179 4 : if (!elem_count) {
1180 0 : RETURN_COPY(input);
1181 : }
1182 :
1183 : /* Initialize return array */
1184 4 : if (search_value != NULL) {
1185 4 : array_init(return_value);
1186 :
1187 4 : if (strict) {
1188 0 : ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
1189 0 : ZVAL_DEREF(entry);
1190 0 : if (fast_is_identical_function(search_value, entry)) {
1191 0 : if (str_idx) {
1192 0 : ZVAL_STR_COPY(&new_val, str_idx);
1193 : } else {
1194 0 : ZVAL_LONG(&new_val, num_idx);
1195 : }
1196 0 : zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
1197 : }
1198 : } ZEND_HASH_FOREACH_END();
1199 : } else {
1200 12 : ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
1201 8 : if (php_colopl_bc_fast_equal_check_function(search_value, entry)) {
1202 8 : if (str_idx) {
1203 8 : ZVAL_STR_COPY(&new_val, str_idx);
1204 : } else {
1205 0 : ZVAL_LONG(&new_val, num_idx);
1206 : }
1207 8 : zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
1208 : }
1209 : } ZEND_HASH_FOREACH_END();
1210 : }
1211 : } else {
1212 0 : array_init_size(return_value, elem_count);
1213 0 : zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
1214 0 : ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
1215 0 : if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) {
1216 : /* Optimistic case: range(0..n-1) for vector-like packed array */
1217 0 : zend_ulong lval = 0;
1218 :
1219 0 : for (; lval < elem_count; ++lval) {
1220 0 : ZEND_HASH_FILL_SET_LONG(lval);
1221 0 : ZEND_HASH_FILL_NEXT();
1222 : }
1223 : } else {
1224 : /* Go through input array and add keys to the return array */
1225 0 : ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
1226 0 : if (str_idx) {
1227 0 : ZEND_HASH_FILL_SET_STR_COPY(str_idx);
1228 : } else {
1229 0 : ZEND_HASH_FILL_SET_LONG(num_idx);
1230 : }
1231 0 : ZEND_HASH_FILL_NEXT();
1232 : } ZEND_HASH_FOREACH_END();
1233 : }
1234 0 : } ZEND_HASH_FILL_END();
1235 : }
1236 : }
1237 :
1238 : #if PHP_VERSION_ID < 80200
1239 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_multisort)
1240 : {
1241 : zval* args;
1242 : zval** arrays;
1243 : Bucket** indirect;
1244 : uint32_t idx;
1245 : Bucket* p;
1246 : HashTable* hash;
1247 : int argc;
1248 : int array_size;
1249 : int num_arrays = 0;
1250 : int parse_state[COLOPL_BC_MULTISORT_LAST]; /* 0 - flag not allowed 1 - flag allowed */
1251 : int sort_order = PHP_SORT_ASC;
1252 : int sort_type = PHP_SORT_REGULAR;
1253 : int i, k, n;
1254 : bucket_compare_func_t *func;
1255 :
1256 : ZEND_PARSE_PARAMETERS_START(1, -1)
1257 : Z_PARAM_VARIADIC('+', args, argc)
1258 : ZEND_PARSE_PARAMETERS_END();
1259 :
1260 : /* Allocate space for storing pointers to input arrays and sort flags. */
1261 : arrays = (zval **)ecalloc(argc, sizeof(zval *));
1262 : for (i = 0; i < COLOPL_BC_MULTISORT_LAST; i++) {
1263 : parse_state[i] = 0;
1264 : }
1265 : func = COLOPL_BC_G(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
1266 :
1267 : /* Here we go through the input arguments and parse them. Each one can
1268 : * be either an array or a sort flag which follows an array. If not
1269 : * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
1270 : * accordingly. There can't be two sort flags of the same type after an
1271 : * array, and the very first argument has to be an array. */
1272 : for (i = 0; i < argc; i++) {
1273 : zval *arg = &args[i];
1274 :
1275 : ZVAL_DEREF(arg);
1276 : if (Z_TYPE_P(arg) == IS_ARRAY) {
1277 : SEPARATE_ARRAY(arg);
1278 : /* We see the next array, so we update the sort flags of
1279 : * the previous array and reset the sort flags. */
1280 : if (i > 0) {
1281 : COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
1282 : sort_order = PHP_SORT_ASC;
1283 : sort_type = PHP_SORT_REGULAR;
1284 : }
1285 : arrays[num_arrays++] = arg;
1286 :
1287 : /* Next one may be an array or a list of sort flags. */
1288 : for (k = 0; k < COLOPL_BC_MULTISORT_LAST; k++) {
1289 : parse_state[k] = 1;
1290 : }
1291 : } else if (Z_TYPE_P(arg) == IS_LONG) {
1292 : switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
1293 : case PHP_SORT_ASC:
1294 : case PHP_SORT_DESC:
1295 : /* flag allowed here */
1296 : if (parse_state[COLOPL_BC_MULTISORT_ORDER] == 1) {
1297 : /* Save the flag and make sure then next arg is not the current flag. */
1298 : sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
1299 : parse_state[COLOPL_BC_MULTISORT_ORDER] = 0;
1300 : } else {
1301 : zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
1302 : COLOPL_BC_MULTISORT_ABORT;
1303 : }
1304 : break;
1305 :
1306 : case PHP_SORT_REGULAR:
1307 : case PHP_SORT_NUMERIC:
1308 : case PHP_SORT_STRING:
1309 : case PHP_SORT_NATURAL:
1310 : case PHP_SORT_LOCALE_STRING:
1311 : /* flag allowed here */
1312 : if (parse_state[COLOPL_BC_MULTISORT_TYPE] == 1) {
1313 : /* Save the flag and make sure then next arg is not the current flag. */
1314 : sort_type = (int)Z_LVAL_P(arg);
1315 : parse_state[COLOPL_BC_MULTISORT_TYPE] = 0;
1316 : } else {
1317 : zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
1318 : COLOPL_BC_MULTISORT_ABORT;
1319 : }
1320 : break;
1321 :
1322 : default:
1323 : zend_argument_value_error(i + 1, "must be a valid sort flag");
1324 : COLOPL_BC_MULTISORT_ABORT;
1325 : break;
1326 :
1327 : }
1328 : } else {
1329 : zend_argument_type_error(i + 1, "must be an array or a sort flag");
1330 : COLOPL_BC_MULTISORT_ABORT;
1331 : }
1332 : }
1333 : /* Take care of the last array sort flags. */
1334 : COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
1335 :
1336 : /* Make sure the arrays are of the same size. */
1337 : array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
1338 : for (i = 0; i < num_arrays; i++) {
1339 : if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != (uint32_t)array_size) {
1340 : zend_value_error("Array sizes are inconsistent");
1341 : COLOPL_BC_MULTISORT_ABORT;
1342 : }
1343 : }
1344 :
1345 : /* If all arrays are empty we don't need to do anything. */
1346 : if (array_size < 1) {
1347 : efree(func);
1348 : efree(arrays);
1349 : RETURN_TRUE;
1350 : }
1351 :
1352 : /* Create the indirection array. This array is of size MxN, where
1353 : * M is the number of entries in each input array and N is the number
1354 : * of the input arrays + 1. The last column is NULL to indicate the end
1355 : * of the row. */
1356 : indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
1357 : for (i = 0; i < array_size; i++) {
1358 : indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
1359 : }
1360 : for (i = 0; i < num_arrays; i++) {
1361 : k = 0;
1362 : for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++) {
1363 : p = Z_ARRVAL_P(arrays[i])->arData + idx;
1364 : if (Z_TYPE(p->val) == IS_UNDEF) continue;
1365 : indirect[k][i] = *p;
1366 : k++;
1367 : }
1368 : }
1369 : for (k = 0; k < array_size; k++) {
1370 : ZVAL_UNDEF(&indirect[k][num_arrays].val);
1371 : }
1372 :
1373 : /* Do the actual sort magic - bada-bim, bada-boom. */
1374 : zend_sort(indirect, array_size, sizeof(Bucket *), php_colopl_bc_multisort_compare, (swap_func_t)colopl_bc_array_bucket_p_swap);
1375 :
1376 : /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
1377 : for (i = 0; i < num_arrays; i++) {
1378 : int repack;
1379 :
1380 : hash = Z_ARRVAL_P(arrays[i]);
1381 : hash->nNumUsed = array_size;
1382 : hash->nInternalPointer = 0;
1383 : repack = !(HT_FLAGS(hash) & HASH_FLAG_PACKED);
1384 :
1385 : for (n = 0, k = 0; k < array_size; k++) {
1386 : hash->arData[k] = indirect[k][i];
1387 : if (hash->arData[k].key == NULL) {
1388 : hash->arData[k].h = n++;
1389 : } else {
1390 : repack = 0;
1391 : }
1392 : }
1393 : hash->nNextFreeElement = array_size;
1394 : if (repack) {
1395 : zend_hash_to_packed(hash);
1396 : } else if (!(HT_FLAGS(hash) & HASH_FLAG_PACKED)) {
1397 : zend_hash_rehash(hash);
1398 : }
1399 : }
1400 :
1401 : /* Clean up. */
1402 : for (i = 0; i < array_size; i++) {
1403 : efree(indirect[i]);
1404 : }
1405 : efree(indirect);
1406 : efree(func);
1407 : efree(arrays);
1408 : RETURN_TRUE;
1409 : }
1410 : #else
1411 4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_multisort)
1412 : {
1413 : zval* args;
1414 : zval** arrays;
1415 : Bucket** indirect;
1416 : uint32_t idx;
1417 : HashTable* hash;
1418 : int argc;
1419 : int array_size;
1420 4 : int num_arrays = 0;
1421 : int parse_state[COLOPL_BC_MULTISORT_LAST]; /* 0 - flag not allowed 1 - flag allowed */
1422 4 : int sort_order = PHP_SORT_ASC;
1423 4 : int sort_type = PHP_SORT_REGULAR;
1424 : int i, k, n;
1425 : bucket_compare_func_t *func;
1426 :
1427 4 : ZEND_PARSE_PARAMETERS_START(1, -1)
1428 4 : Z_PARAM_VARIADIC('+', args, argc)
1429 4 : ZEND_PARSE_PARAMETERS_END();
1430 :
1431 : /* Allocate space for storing pointers to input arrays and sort flags. */
1432 4 : arrays = (zval **)ecalloc(argc, sizeof(zval *));
1433 12 : for (i = 0; i < COLOPL_BC_MULTISORT_LAST; i++) {
1434 8 : parse_state[i] = 0;
1435 : }
1436 4 : func = COLOPL_BC_G(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
1437 :
1438 : /* Here we go through the input arguments and parse them. Each one can
1439 : * be either an array or a sort flag which follows an array. If not
1440 : * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
1441 : * accordingly. There can't be two sort flags of the same type after an
1442 : * array, and the very first argument has to be an array. */
1443 12 : for (i = 0; i < argc; i++) {
1444 8 : zval *arg = &args[i];
1445 :
1446 8 : ZVAL_DEREF(arg);
1447 8 : if (Z_TYPE_P(arg) == IS_ARRAY) {
1448 8 : SEPARATE_ARRAY(arg);
1449 : /* We see the next array, so we update the sort flags of
1450 : * the previous array and reset the sort flags. */
1451 8 : if (i > 0) {
1452 4 : COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
1453 4 : sort_order = PHP_SORT_ASC;
1454 4 : sort_type = PHP_SORT_REGULAR;
1455 : }
1456 8 : arrays[num_arrays++] = arg;
1457 :
1458 : /* Next one may be an array or a list of sort flags. */
1459 24 : for (k = 0; k < COLOPL_BC_MULTISORT_LAST; k++) {
1460 16 : parse_state[k] = 1;
1461 : }
1462 0 : } else if (Z_TYPE_P(arg) == IS_LONG) {
1463 0 : switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
1464 0 : case PHP_SORT_ASC:
1465 : case PHP_SORT_DESC:
1466 : /* flag allowed here */
1467 0 : if (parse_state[COLOPL_BC_MULTISORT_ORDER] == 1) {
1468 : /* Save the flag and make sure then next arg is not the current flag. */
1469 0 : sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
1470 0 : parse_state[COLOPL_BC_MULTISORT_ORDER] = 0;
1471 : } else {
1472 0 : zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
1473 0 : COLOPL_BC_MULTISORT_ABORT;
1474 : }
1475 0 : break;
1476 :
1477 0 : case PHP_SORT_REGULAR:
1478 : case PHP_SORT_NUMERIC:
1479 : case PHP_SORT_STRING:
1480 : case PHP_SORT_NATURAL:
1481 : case PHP_SORT_LOCALE_STRING:
1482 : /* flag allowed here */
1483 0 : if (parse_state[COLOPL_BC_MULTISORT_TYPE] == 1) {
1484 : /* Save the flag and make sure then next arg is not the current flag. */
1485 0 : sort_type = (int)Z_LVAL_P(arg);
1486 0 : parse_state[COLOPL_BC_MULTISORT_TYPE] = 0;
1487 : } else {
1488 0 : zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
1489 0 : COLOPL_BC_MULTISORT_ABORT;
1490 : }
1491 0 : break;
1492 :
1493 0 : default:
1494 0 : zend_argument_value_error(i + 1, "must be a valid sort flag");
1495 0 : COLOPL_BC_MULTISORT_ABORT;
1496 : break;
1497 :
1498 : }
1499 : } else {
1500 0 : zend_argument_type_error(i + 1, "must be an array or a sort flag");
1501 0 : COLOPL_BC_MULTISORT_ABORT;
1502 : }
1503 : }
1504 : /* Take care of the last array sort flags. */
1505 4 : COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
1506 :
1507 : /* Make sure the arrays are of the same size. */
1508 4 : array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
1509 12 : for (i = 0; i < num_arrays; i++) {
1510 8 : if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != (uint32_t)array_size) {
1511 0 : zend_value_error("Array sizes are inconsistent");
1512 0 : COLOPL_BC_MULTISORT_ABORT;
1513 : }
1514 : }
1515 :
1516 : /* If all arrays are empty we don't need to do anything. */
1517 4 : if (array_size < 1) {
1518 0 : efree(func);
1519 0 : efree(arrays);
1520 0 : RETURN_TRUE;
1521 : }
1522 :
1523 : /* Create the indirection array. This array is of size MxN, where
1524 : * M is the number of entries in each input array and N is the number
1525 : * of the input arrays + 1. The last column is UNDEF to indicate the end
1526 : * of the row. It also stores the original position for stable sorting. */
1527 4 : indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
1528 404 : for (i = 0; i < array_size; i++) {
1529 400 : indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
1530 : }
1531 12 : for (i = 0; i < num_arrays; i++) {
1532 8 : k = 0;
1533 8 : if (HT_IS_PACKED(Z_ARRVAL_P(arrays[i]))) {
1534 8 : zval *zv = Z_ARRVAL_P(arrays[i])->arPacked;
1535 808 : for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, zv++) {
1536 800 : if (Z_TYPE_P(zv) == IS_UNDEF) continue;
1537 800 : ZVAL_COPY_VALUE(&indirect[k][i].val, zv);
1538 800 : indirect[k][i].h = idx;
1539 800 : indirect[k][i].key = NULL;
1540 800 : k++;
1541 : }
1542 : } else {
1543 0 : Bucket *p = Z_ARRVAL_P(arrays[i])->arData;
1544 0 : for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, p++) {
1545 0 : if (Z_TYPE(p->val) == IS_UNDEF) continue;
1546 0 : indirect[k][i] = *p;
1547 0 : k++;
1548 : }
1549 : }
1550 : }
1551 404 : for (k = 0; k < array_size; k++) {
1552 400 : ZVAL_UNDEF(&indirect[k][num_arrays].val);
1553 400 : Z_EXTRA_P(&indirect[k][num_arrays].val) = k;
1554 : }
1555 :
1556 : /* Do the actual sort magic - bada-bim, bada-boom. */
1557 4 : zend_sort(indirect, array_size, sizeof(Bucket *), php_colopl_bc_multisort_compare, (swap_func_t)colopl_bc_array_bucket_p_swap);
1558 :
1559 : /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
1560 12 : for (i = 0; i < num_arrays; i++) {
1561 8 : hash = Z_ARRVAL_P(arrays[i]);
1562 8 : hash->nNumUsed = array_size;
1563 8 : hash->nNextFreeElement = array_size;
1564 8 : hash->nInternalPointer = 0;
1565 8 : if (HT_IS_PACKED(hash)) {
1566 808 : for (k = 0; k < array_size; k++) {
1567 800 : ZVAL_COPY_VALUE(&hash->arPacked[k], &indirect[k][i].val);
1568 : }
1569 : } else {
1570 0 : int repack = 1;
1571 :
1572 0 : for (n = 0, k = 0; k < array_size; k++) {
1573 0 : hash->arData[k] = indirect[k][i];
1574 0 : if (hash->arData[k].key == NULL) {
1575 0 : hash->arData[k].h = n++;
1576 : } else {
1577 0 : repack = 0;
1578 : }
1579 : }
1580 0 : if (repack) {
1581 0 : zend_hash_to_packed(hash);
1582 : }
1583 : }
1584 : }
1585 :
1586 : /* Clean up. */
1587 404 : for (i = 0; i < array_size; i++) {
1588 400 : efree(indirect[i]);
1589 : }
1590 4 : efree(indirect);
1591 4 : efree(func);
1592 4 : efree(arrays);
1593 4 : RETURN_TRUE;
1594 : }
1595 : #endif
1596 :
1597 : /* BinaryOps */
1598 :
1599 1172 : PHP_FUNCTION(Colopl_ColoplBc_Php74_eq)
1600 : {
1601 : zval *op1, *op2;
1602 :
1603 1172 : ZEND_PARSE_PARAMETERS_START(2, 2)
1604 1172 : Z_PARAM_ZVAL(op1)
1605 1172 : Z_PARAM_ZVAL(op2)
1606 1172 : ZEND_PARSE_PARAMETERS_END();
1607 :
1608 1172 : RETURN_BOOL(php_colopl_bc_compare(op1, op2) == 0);
1609 : }
1610 :
1611 0 : PHP_FUNCTION(Colopl_ColoplBc_Php74_neq)
1612 : {
1613 : zval *op1, *op2;
1614 :
1615 0 : ZEND_PARSE_PARAMETERS_START(2, 2)
1616 0 : Z_PARAM_ZVAL(op1)
1617 0 : Z_PARAM_ZVAL(op2)
1618 0 : ZEND_PARSE_PARAMETERS_END();
1619 :
1620 0 : RETURN_BOOL(php_colopl_bc_compare(op1, op2) != 0);
1621 : }
1622 :
1623 1156 : PHP_FUNCTION(Colopl_ColoplBc_Php74_lt)
1624 : {
1625 : zval *op1, *op2;
1626 :
1627 1156 : ZEND_PARSE_PARAMETERS_START(2, 2)
1628 1156 : Z_PARAM_ZVAL(op1)
1629 1156 : Z_PARAM_ZVAL(op2)
1630 1156 : ZEND_PARSE_PARAMETERS_END();
1631 :
1632 1156 : RETURN_BOOL(php_colopl_bc_compare(op1, op2) < 0);
1633 : }
1634 :
1635 1156 : PHP_FUNCTION(Colopl_ColoplBc_Php74_lte)
1636 : {
1637 : zval *op1, *op2;
1638 :
1639 1156 : ZEND_PARSE_PARAMETERS_START(2, 2)
1640 1156 : Z_PARAM_ZVAL(op1)
1641 1156 : Z_PARAM_ZVAL(op2)
1642 1156 : ZEND_PARSE_PARAMETERS_END();
1643 :
1644 1156 : RETURN_BOOL(php_colopl_bc_compare(op1, op2) <= 0);
1645 : }
1646 :
1647 1156 : PHP_FUNCTION(Colopl_ColoplBc_Php74_gt)
1648 : {
1649 : zval *op1, *op2;
1650 :
1651 1156 : ZEND_PARSE_PARAMETERS_START(2, 2)
1652 1156 : Z_PARAM_ZVAL(op1)
1653 1156 : Z_PARAM_ZVAL(op2)
1654 1156 : ZEND_PARSE_PARAMETERS_END();
1655 :
1656 1156 : RETURN_BOOL(php_colopl_bc_compare(op2, op1) < 0);
1657 : }
1658 :
1659 1156 : PHP_FUNCTION(Colopl_ColoplBc_Php74_gte)
1660 : {
1661 : zval *op1, *op2;
1662 :
1663 1156 : ZEND_PARSE_PARAMETERS_START(2, 2)
1664 1156 : Z_PARAM_ZVAL(op1)
1665 1156 : Z_PARAM_ZVAL(op2)
1666 1156 : ZEND_PARSE_PARAMETERS_END();
1667 :
1668 1156 : RETURN_BOOL(php_colopl_bc_compare(op2, op1) <= 0);
1669 : }
1670 :
1671 0 : PHP_FUNCTION(Colopl_ColoplBc_Php74_spaceship)
1672 : {
1673 : zval *op1, *op2;
1674 :
1675 0 : ZEND_PARSE_PARAMETERS_START(2, 2)
1676 0 : Z_PARAM_ZVAL(op1)
1677 0 : Z_PARAM_ZVAL(op2)
1678 0 : ZEND_PARSE_PARAMETERS_END();
1679 :
1680 0 : RETURN_LONG(php_colopl_bc_compare(op1, op2));
1681 : }
|