zval *fval, *sval;
zval first, second;
int result;
+ zend_uchar type;
f = *((Bucket **) a);
s = *((Bucket **) b);
sval = *((zval **) s->pData);
first = *fval;
second = *sval;
- if (Z_TYPE_P(fval) != IS_STRING) {
+
+ type = zend_get_unified_string_type(2 TSRMLS_CC, Z_TYPE_P(fval), Z_TYPE_P(sval));
+ if (Z_TYPE_P(fval) != type) {
zval_copy_ctor(&first);
- convert_to_string(&first);
+ convert_to_explicit_type(&first, type);
}
- if (Z_TYPE_P(sval) != IS_STRING) {
+ if (Z_TYPE_P(sval) != type) {
zval_copy_ctor(&second);
- convert_to_string(&second);
+ convert_to_explicit_type(&second, type);
}
- result = strnatcmp_ex(Z_STRVAL(first), Z_STRLEN(first), Z_STRVAL(second), Z_STRLEN(second), fold_case);
+ if (type == IS_UNICODE) {
+ result = u_strnatcmp_ex(Z_USTRVAL(first), Z_USTRLEN(first), Z_USTRVAL(second), Z_USTRLEN(second), fold_case);
+ } else {
+ result = strnatcmp_ex(Z_STRVAL(first), Z_STRLEN(first), Z_STRVAL(second), Z_STRLEN(second), fold_case);
+ }
- if (Z_TYPE_P(fval) != IS_STRING)
+ if (Z_TYPE_P(fval) != type)
zval_dtor(&first);
- if (Z_TYPE_P(sval) != IS_STRING)
+ if (Z_TYPE_P(sval) != type)
zval_dtor(&second);
return result;
static void php_natsort(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
{
- zval **array;
+ zval *array;
HashTable *target_hash;
- if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &array) == FAILURE) {
- WRONG_PARAM_COUNT;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &array) == FAILURE) {
+ return;
}
- target_hash = HASH_OF(*array);
+ target_hash = HASH_OF(array);
if (!target_hash) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The argument should be an array");
return;
}
-/* {{{ proto void natsort(array &array_arg)
+/* {{{ proto void natsort(array &array_arg) U
Sort an array using natural sort */
PHP_FUNCTION(natsort)
{
/* }}} */
-/* {{{ proto void natcasesort(array &array_arg)
+/* {{{ proto void natcasesort(array &array_arg) U
Sort an array using case-insensitive natural sort */
PHP_FUNCTION(natcasesort)
{
*/
static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
{
- zval **s1, **s2;
+ zstr s1, s2;
+ int s1_len, s2_len;
+ zend_uchar type;
- if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
- WRONG_PARAM_COUNT;
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "TT", &s1, &s1_len,
+ &type, &s2, &s2_len, &type) == FAILURE) {
+ return;
}
- convert_to_string_ex(s1);
- convert_to_string_ex(s2);
-
- RETURN_LONG(strnatcmp_ex(Z_STRVAL_PP(s1), Z_STRLEN_PP(s1),
- Z_STRVAL_PP(s2), Z_STRLEN_PP(s2),
- fold_case));
+ if (type == IS_UNICODE) {
+ RETURN_LONG(u_strnatcmp_ex(s1.u, s1_len, s2.u, s2_len, fold_case));
+ } else {
+ RETURN_LONG(strnatcmp_ex(s1.s, s1_len, s2.s, s2_len, fold_case));
+ }
}
/* }}} */
-/* {{{ proto int strnatcmp(string s1, string s2)
+/* {{{ proto int strnatcmp(string s1, string s2) U
Returns the result of string comparison using 'natural' algorithm */
PHP_FUNCTION(strnatcmp)
{
}
/* }}} */
-/* {{{ proto int strnatcasecmp(string s1, string s2)
+/* {{{ proto int strnatcasecmp(string s1, string s2) U
Returns the result of case-insensitive string comparison using 'natural' algorithm */
PHP_FUNCTION(strnatcasecmp)
{
/* -*- mode: c; c-file-style: "k&r" -*-
- Modified for PHP by Andrei Zmievski <andrei@ispi.net>
+ Modified for PHP by Andrei Zmievski <andrei@php.net>
strnatcmp.c -- Perform 'natural order' comparisons of strings in C.
- Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
+ Copyright (C) 2000, 2004 by Martin Pool <mbp sourcefrog net>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
/* {{{ compare_right
*/
static int
-compare_right(char const **a, char const *aend, char const **b, char const *bend)
+compare_right(char const *a, char const *b)
{
int bias = 0;
value wins, but we can't know that it will until we've scanned
both numbers to know that they have the same magnitude, so we
remember it in BIAS. */
- for(;; (*a)++, (*b)++) {
- if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
- (*b == bend || !isdigit((int)(unsigned char)**b)))
+ for(;; a++, b++) {
+ if (!isdigit((int)(unsigned char)*a) &&
+ !isdigit((int)(unsigned char)*b))
return bias;
- else if (*a == aend || !isdigit((int)(unsigned char)**a))
+ else if (!isdigit((int)(unsigned char)*a))
return -1;
- else if (*b == bend || !isdigit((int)(unsigned char)**b))
+ else if (!isdigit((int)(unsigned char)*b))
return +1;
- else if (**a < **b) {
+ else if (*a < *b) {
if (!bias)
bias = -1;
- } else if (**a > **b) {
+ } else if (*a > *b) {
if (!bias)
bias = +1;
+ } else if (!*a && !*b) {
+ return bias;
}
}
/* {{{ compare_left
*/
static int
-compare_left(char const **a, char const *aend, char const **b, char const *bend)
+compare_left(char const *a, char const *b)
{
/* Compare two left-aligned numbers: the first to have a
different value wins. */
- for(;; (*a)++, (*b)++) {
- if ((*a == aend || !isdigit((int)(unsigned char)**a)) &&
- (*b == bend || !isdigit((int)(unsigned char)**b)))
+ for(;; a++, b++) {
+ if (!isdigit((int)(unsigned char)*a) &&
+ !isdigit((int)(unsigned char)*b))
return 0;
- else if (*a == aend || !isdigit((int)(unsigned char)**a))
+ else if (!isdigit((int)(unsigned char)*a))
return -1;
- else if (*b == bend || !isdigit((int)(unsigned char)**b))
+ else if (!isdigit((int)(unsigned char)*b))
return +1;
- else if (**a < **b)
+ else if (*a < *b)
return -1;
- else if (**a > **b)
+ else if (*a > *b)
return +1;
}
PHPAPI int strnatcmp_ex(char const *a, size_t a_len, char const *b, size_t b_len, int fold_case)
{
char ca, cb;
- char const *ap, *bp;
- char const *aend = a + a_len,
- *bend = b + b_len;
+ int ai, bi;
int fractional, result;
- if (a_len == 0 || b_len == 0)
- return a_len - b_len;
-
- ap = a;
- bp = b;
+ ai = bi = 0;
while (1) {
- ca = *ap; cb = *bp;
+ ca = a[ai]; cb = b[bi];
/* skip over leading spaces or zeros */
while (isspace((int)(unsigned char)ca))
- ca = *++ap;
+ ca = a[++ai];
while (isspace((int)(unsigned char)cb))
- cb = *++bp;
+ cb = b[++bi];
/* process run of digits */
if (isdigit((int)(unsigned char)ca) && isdigit((int)(unsigned char)cb)) {
fractional = (ca == '0' || cb == '0');
- if (fractional)
- result = compare_left(&ap, aend, &bp, bend);
- else
- result = compare_right(&ap, aend, &bp, bend);
-
- if (result != 0)
- return result;
- else if (ap == aend && bp == bend)
- /* End of the strings. Let caller sort them out. */
- return 0;
- else {
- /* Keep on comparing from the current point. */
- ca = *ap; cb = *bp;
+ if (fractional) {
+ if ((result = compare_left(a+ai, b+bi)) != 0) {
+ return result;
+ }
+ } else {
+ if ((result = compare_right(a+ai, b+bi)) != 0)
+ return result;
}
}
+ if (!ca && !cb) {
+ /* The strings compare the same. Perhaps the caller
+ will want to call strcmp to break the tie. */
+ return 0;
+ }
+
if (fold_case) {
ca = toupper((int)(unsigned char)ca);
cb = toupper((int)(unsigned char)cb);
else if (ca > cb)
return +1;
- ++ap; ++bp;
- if (ap >= aend && bp >= bend)
+ ++ai; ++bi;
+ }
+}
+/* }}} */
+
+/* {{{ u_compare_right
+ */
+static int
+u_compare_right(UChar const *a, int a_len, int *a_curr, UChar const *b, int b_len, int *b_curr)
+{
+ UChar32 ca, cb;
+ int a_off, b_off;
+ int bias = 0;
+
+ /* The longest run of digits wins. That aside, the greatest
+ value wins, but we can't know that it will until we've scanned
+ both numbers to know that they have the same magnitude, so we
+ remember it in BIAS. */
+
+ for (;;) {
+ a_off = *a_curr;
+ b_off = *b_curr;
+ U16_NEXT(a, a_off, a_len, ca);
+ U16_NEXT(b, b_off, b_len, cb);
+
+ if (!u_isdigit(ca) && !u_isdigit(cb)) {
+ return bias;
+ } else if (!u_isdigit(ca)) {
+ return -1;
+ } else if (!u_isdigit(cb)) {
+ return +1;
+ } else if (ca < cb) {
+ if (!bias)
+ bias = -1;
+ } else if (ca > cb) {
+ if (!bias)
+ bias = +1;
+ } else if (ca == 0 && cb == 0) {
+ return bias;
+ }
+ *a_curr = a_off;
+ *b_curr = b_off;
+ }
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ u_compare_left
+ */
+static int
+u_compare_left(UChar const *a, int a_len, int *a_curr, UChar const *b, int b_len, int *b_curr)
+{
+ int a_off, b_off;
+ UChar32 ca, cb;
+
+ /* Compare two left-aligned numbers: the first to have a
+ different value wins. */
+ for (;;) {
+ a_off = *a_curr;
+ b_off = *b_curr;
+ U16_NEXT(a, a_off, a_len, ca);
+ U16_NEXT(b, b_off, b_len, cb);
+
+ if (!u_isdigit(ca) && !u_isdigit(cb)) {
+ return 0;
+ } else if (!u_isdigit(ca)) {
+ return -1;
+ } else if (!u_isdigit(cb)) {
+ return +1;
+ } else if (ca < cb) {
+ return -1;
+ } else if (ca > cb) {
+ return +1;
+ }
+ *a_curr = a_off;
+ *b_curr = b_off;
+ }
+
+ return 0;
+}
+/* }}} */
+
+/* {{{ u_strnatcmp_ex
+ */
+PHPAPI int u_strnatcmp_ex(UChar const *a, size_t a_len, UChar const *b, size_t b_len, int fold_case)
+{
+ UChar ca, cb;
+ UChar const *ap, *bp;
+ int fractional, result;
+ int a_off, b_off;
+ int a_curr, b_curr;
+
+ if (a_len == 0 || b_len == 0)
+ return a_len - b_len;
+
+ ap = a;
+ bp = b;
+ a_curr = b_curr = 0;
+
+ while (1) {
+ a_off = a_curr;
+ b_off = b_curr;
+ U16_NEXT(a, a_curr, a_len, ca);
+ U16_NEXT(b, b_curr, b_len, cb);
+
+ /* skip over leading spaces */
+ for ( ; u_isspace(ca) && a_curr < a_len; ) {
+ a_off = a_curr;
+ U16_NEXT(a, a_curr, a_len, ca);
+ }
+
+ for ( ; u_isspace(cb) && b_curr < b_len; ) {
+ b_off = b_curr;
+ U16_NEXT(b, b_curr, b_len, cb);
+ }
+
+ /* process run of digits */
+ if (u_isdigit(ca) && u_isdigit(cb)) {
+ fractional = (ca == 0x30 /*'0'*/ || cb == 0x30 /*'0'*/);
+
+ if (fractional) {
+ if ((result = u_compare_left(a, a_len, &a_off, b, b_len, &b_off)) != 0) {
+ return result;
+ }
+ } else {
+ if ((result = u_compare_right(a, a_len, &a_off, b, b_len, &b_off)) != 0) {
+ return result;
+ }
+ }
+
+ a_curr = a_off;
+ b_curr = b_off;
+ }
+
+ if (ca == 0 && cb == 0) {
/* The strings compare the same. Perhaps the caller
will want to call strcmp to break the tie. */
return 0;
- else if (ap >= aend)
+ }
+
+ if (fold_case) {
+ ca = u_toupper(ca);
+ cb = u_toupper(cb);
+ }
+
+ if (ca < cb)
return -1;
- else if (bp >= bend)
- return 1;
+ else if (ca > cb)
+ return +1;
}
}
/* }}} */
-
/*
* Local variables:
* tab-width: 4