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