- Unicode impl of strrpos()

This commit is contained in:
Rolland Santimano 2005-10-17 17:07:44 +00:00
parent b154fa6e7c
commit b277b1d1c0

View File

@ -2292,61 +2292,118 @@ PHP_FUNCTION(stripos)
Finds position of last occurrence of a string within another string */
PHP_FUNCTION(strrpos)
{
zval *zneedle;
char *needle, *haystack;
int needle_len, haystack_len;
zval *zhaystack, *zneedle;
void *haystack, *needle;
int32_t haystack_len, needle_len = 0;
zend_uchar str_type;
long offset = 0;
char *p, *e, ord_needle[2];
UChar *pos, *u_p, *u_e, u_ord_needle[3];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l",
&zhaystack, &zneedle, &offset) == FAILURE) {
RETURN_FALSE;
}
if (Z_TYPE_P(zneedle) == IS_STRING) {
needle = Z_STRVAL_P(zneedle);
needle_len = Z_STRLEN_P(zneedle);
} else {
convert_to_long(zneedle);
ord_needle[0] = (char)(Z_LVAL_P(zneedle) & 0xFF);
ord_needle[1] = '\0';
needle = ord_needle;
needle_len = 1;
if (Z_TYPE_P(zhaystack) != IS_UNICODE && Z_TYPE_P(zhaystack) != IS_BINARY && Z_TYPE_P(zhaystack) != IS_STRING) {
convert_to_text(zhaystack);
}
if (Z_TYPE_P(zneedle) == IS_UNICODE || Z_TYPE_P(zneedle) == IS_BINARY || Z_TYPE_P(zneedle) == IS_STRING) {
if (Z_TYPE_P(zneedle) != Z_TYPE_P(zhaystack)) {
str_type = zend_get_unified_string_type(2 TSRMLS_CC, Z_TYPE_P(zhaystack), Z_TYPE_P(zneedle));
if (str_type == (zend_uchar)-1) {
convert_to_explicit_type(zhaystack, IS_BINARY);
convert_to_explicit_type(zneedle, IS_BINARY);
} else {
convert_to_explicit_type(zhaystack, str_type);
convert_to_explicit_type(zneedle, str_type);
}
}
needle = Z_UNIVAL_P(zneedle);
needle_len = Z_UNILEN_P(zneedle);
} else {
if (Z_TYPE_P(zhaystack) == IS_UNICODE) {
if (Z_LVAL_P(zneedle) < 0 || Z_LVAL_P(zneedle) > 0x10FFFF) {
php_error(E_WARNING, "Needle argument codepoint value out of range (0 - 0x10FFFF)");
RETURN_FALSE;
}
if (U_IS_BMP(Z_LVAL_P(zneedle))) {
u_ord_needle[needle_len++] = (UChar)Z_LVAL_P(zneedle);
u_ord_needle[needle_len] = 0;
} else {
u_ord_needle[needle_len++] = (UChar)U16_LEAD(Z_LVAL_P(zneedle));
u_ord_needle[needle_len++] = (UChar)U16_TRAIL(Z_LVAL_P(zneedle));
u_ord_needle[needle_len] = 0;
}
needle = u_ord_needle;
} else {
convert_to_long(zneedle);
ord_needle[0] = (char)(Z_LVAL_P(zneedle) & 0xFF);
ord_needle[1] = '\0';
needle = ord_needle;
needle_len = 1;
}
}
haystack = Z_UNIVAL_P(zhaystack);
haystack_len = Z_UNILEN_P(zhaystack);
if ((haystack_len == 0) || (needle_len == 0)) {
RETURN_FALSE;
}
if (offset >= 0) {
p = haystack + offset;
e = haystack + haystack_len - needle_len;
} else {
p = haystack;
if (-offset > haystack_len) {
e = haystack - needle_len;
} else if (needle_len > -offset) {
e = haystack + haystack_len - needle_len;
if (Z_TYPE_P(zhaystack) == IS_UNICODE) {
if (offset >= 0) {
u_p = (UChar *)haystack + offset;
u_e = (UChar *)haystack + haystack_len - needle_len;
} else {
e = haystack + haystack_len + offset;
u_p = haystack;
if (-offset > haystack_len) {
u_e = (UChar *)haystack - needle_len;
} else if (needle_len > -offset) {
u_e = (UChar *)haystack + haystack_len - needle_len;
} else {
u_e = (UChar *)haystack + haystack_len + offset;
}
}
pos = u_strFindLast(u_p, u_e-u_p+needle_len, (UChar *)needle, needle_len);
if (pos) {
RETURN_LONG(pos - (UChar *)haystack);
} else {
RETURN_FALSE;
}
} else {
if (offset >= 0) {
p = (char *)haystack + offset;
e = (char *)haystack + haystack_len - needle_len;
} else {
p = haystack;
if (-offset > haystack_len) {
e = (char *)haystack - needle_len;
} else if (needle_len > -offset) {
e = (char *)haystack + haystack_len - needle_len;
} else {
e = (char *)haystack + haystack_len + offset;
}
}
if (needle_len == 1) {
/* Single character search can shortcut memcmps */
while (e >= p) {
if (*e == *(char *)needle) {
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
RETURN_FALSE;
}
}
if (needle_len == 1) {
/* Single character search can shortcut memcmps */
while (e >= p) {
if (*e == *needle) {
if (memcmp(e, needle, needle_len) == 0) {
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
RETURN_FALSE;
}
while (e >= p) {
if (memcmp(e, needle, needle_len) == 0) {
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
RETURN_FALSE;