diff options
author | Stig Venaas <venaas@php.net> | 2000-12-28 23:50:42 +0000 |
---|---|---|
committer | Stig Venaas <venaas@php.net> | 2000-12-28 23:50:42 +0000 |
commit | c5b11042b0094a6db72a96850c6eec3d52065191 (patch) | |
tree | b8f39d0067f8dad3b627ab971682ddb2b9c7202b /ext | |
parent | fbbaf5b5b5e8f33214a5f380ef7dba65266241be (diff) | |
download | php-git-c5b11042b0094a6db72a96850c6eec3d52065191.tar.gz |
Hopefully solves some bad behavior in array_unique(), array_intersect()
and array_diff(). Now using SORT_STRING instead of SORT_REGULAR
@- Fixed misbehavior of array_unique(), array_intersect() and array_diff();
@ could in certain cases give wrong result or segfault (Stig Venaas)
Diffstat (limited to 'ext')
-rw-r--r-- | ext/standard/array.c | 90 |
1 files changed, 21 insertions, 69 deletions
diff --git a/ext/standard/array.c b/ext/standard/array.c index f3ad659843..dad26ba590 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -257,8 +257,7 @@ PHP_FUNCTION(count) * anyway doesn't make much sense to compare two different data types. * This keeps it consistant and simple. * - * This is not correct any more, if you want this behavior, use - * array_type_data_compare(). + * This is not correct any more, depends on what compare_func is set to. */ static int array_data_compare(const void *a, const void *b) { @@ -349,53 +348,6 @@ static int array_natural_case_compare(const void *a, const void *b) return array_natural_general_compare(a, b, 1); } -/* Compare types first, if exactly one argument is a string, return the - * type difference, thus numbers are always smaller than strings */ -static int array_type_data_compare(const void *a, const void *b) -{ - Bucket *f; - Bucket *s; - pval result; - pval *first; - pval *second; - int diff; - ARRAYLS_FETCH(); - - f = *((Bucket **) a); - s = *((Bucket **) b); - - first = *((pval **) f->pData); - second = *((pval **) s->pData); - - diff = Z_TYPE_P(first) - Z_TYPE_P(second); - if (diff && ((Z_TYPE_P(first) == IS_STRING) || (Z_TYPE_P(second) == IS_STRING))) - return diff; - - if (ARRAYG(compare_func)(&result, first, second) == FAILURE) { - return 0; - } - - if (Z_TYPE(result) == IS_DOUBLE) { - if (Z_DVAL(result) < 0) { - return -1; - } else if (Z_DVAL(result) > 0) { - return 1; - } else { - return 0; - } - } - - convert_to_long(&result); - - if (Z_LVAL(result) < 0) { - return -1; - } else if (Z_LVAL(result) > 0) { - return 1; - } - - return 0; -} - static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case) { zval **array; @@ -2240,13 +2192,13 @@ PHP_FUNCTION(array_unique) for (i = 0, p = target_hash->pListHead; p; i++, p = p->pListNext) arTmp[i] = p; arTmp[i] = NULL; - set_compare_func(SORT_REGULAR); - qsort((void *) arTmp, i, sizeof(Bucket *), array_type_data_compare); + set_compare_func(SORT_STRING); + qsort((void *) arTmp, i, sizeof(Bucket *), array_data_compare); /* go through the sorted array and delete duplicates from the copy */ lastkept = arTmp; for (cmpdata = arTmp + 1; *cmpdata; cmpdata++) { - if (array_type_data_compare(lastkept, cmpdata)) { + if (array_data_compare(lastkept, cmpdata)) { lastkept = cmpdata; } else { p = *cmpdata; @@ -2283,7 +2235,7 @@ PHP_FUNCTION(array_intersect) /* for each argument, create and sort list with pointers to the hash buckets */ lists = (Bucket ***)emalloc(argc * sizeof(Bucket **)); ptrs = (Bucket ***)emalloc(argc * sizeof(Bucket **)); - set_compare_func(SORT_REGULAR); + set_compare_func(SORT_STRING); for (i=0; i<argc; i++) { if (Z_TYPE_PP(args[i]) != IS_ARRAY) { php_error(E_WARNING, "Argument #%d to array_intersect() is not an array", i+1); @@ -2299,7 +2251,7 @@ PHP_FUNCTION(array_intersect) for (p = hash->pListHead; p; p = p->pListNext) *list++ = p; *list = NULL; - qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_type_data_compare); + qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_data_compare); } /* copy the argument array */ @@ -2309,7 +2261,7 @@ PHP_FUNCTION(array_intersect) /* go through the lists and look for common values */ while (*ptrs[0]) { for (i=1; i<argc; i++) { - while (*ptrs[i] && (0 < (c = array_type_data_compare(ptrs[0], ptrs[i])))) + while (*ptrs[i] && (0 < (c = array_data_compare(ptrs[0], ptrs[i])))) ptrs[i]++; if (!*ptrs[i]) { /* delete any values corresponding to remains of ptrs[0] */ @@ -2339,7 +2291,7 @@ PHP_FUNCTION(array_intersect) zend_hash_index_del(Z_ARRVAL_P(return_value), p->h); if (!*++ptrs[0]) goto out; - if (0 <= array_type_data_compare(ptrs[0], ptrs[i])) + if (0 <= array_data_compare(ptrs[0], ptrs[i])) break; } } else { @@ -2348,7 +2300,7 @@ PHP_FUNCTION(array_intersect) for (;;) { if (!*++ptrs[0]) goto out; - if (array_type_data_compare(ptrs[0]-1, ptrs[0])) + if (array_data_compare(ptrs[0]-1, ptrs[0])) break; } } @@ -2356,7 +2308,7 @@ PHP_FUNCTION(array_intersect) out: for (i=0; i<argc; i++) { - hash = HASH_OF(*args[i]); + hash = HASH_OF(*args[i]); pefree(lists[i], hash->persistent); } efree(ptrs); @@ -2369,7 +2321,7 @@ out: Returns the entries of arr1 that have values which are not present in any of the others arguments */ PHP_FUNCTION(array_diff) { - zval ***args = NULL; + zval ***args = NULL; HashTable *hash; int argc, i, c; Bucket ***lists, **list, ***ptrs, *p; @@ -2388,7 +2340,7 @@ PHP_FUNCTION(array_diff) /* for each argument, create and sort list with pointers to the hash buckets */ lists = (Bucket ***)emalloc(argc * sizeof(Bucket **)); ptrs = (Bucket ***)emalloc(argc * sizeof(Bucket **)); - set_compare_func(SORT_REGULAR); + set_compare_func(SORT_STRING); for (i=0; i<argc; i++) { if (Z_TYPE_PP(args[i]) != IS_ARRAY) { php_error(E_WARNING, "Argument #%d to array_diff() is not an array", i+1); @@ -2404,7 +2356,7 @@ PHP_FUNCTION(array_diff) for (p = hash->pListHead; p; p = p->pListNext) *list++ = p; *list = NULL; - qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_type_data_compare); + qsort((void *) lists[i], hash->nNumOfElements, sizeof(Bucket *), array_data_compare); } /* copy the argument array */ @@ -2414,14 +2366,14 @@ PHP_FUNCTION(array_diff) /* go through the lists and look for values of ptr[0] that are not in the others */ while (*ptrs[0]) { - c = 1; + c = 1; for (i=1; i<argc; i++) { - while (*ptrs[i] && (0 < (c = array_type_data_compare(ptrs[0], ptrs[i])))) - ptrs[i]++; + while (*ptrs[i] && (0 < (c = array_data_compare(ptrs[0], ptrs[i])))) + ptrs[i]++; if (!c) { - if (*ptrs[i]) - ptrs[i]++; - break; + if (*ptrs[i]) + ptrs[i]++; + break; } } if (!c) { @@ -2435,7 +2387,7 @@ PHP_FUNCTION(array_diff) zend_hash_index_del(Z_ARRVAL_P(return_value), p->h); if (!*++ptrs[0]) goto out; - if (array_type_data_compare(ptrs[0]-1, ptrs[0])) + if (array_data_compare(ptrs[0]-1, ptrs[0])) break; } } else { @@ -2444,7 +2396,7 @@ PHP_FUNCTION(array_diff) for (;;) { if (!*++ptrs[0]) goto out; - if (array_type_data_compare(ptrs[0]-1, ptrs[0])) + if (array_data_compare(ptrs[0]-1, ptrs[0])) break; } } |