和stripos实现不相同,除开查找方式不一样即返回的地址不一样外,个人感觉strripos比stripos的实现在条件判断上更好(看strripos函数的判断,绿色字体的地方)。
/* {{{ proto int strripos(string haystack, string needle [, int offset])
Finds position of last occurrence of a string within another string */
PHP_FUNCTION(strripos)
{
zval *zneedle;
char *needle, *haystack;
int needle_len, haystack_len;
long offset = 0;
char *p, *e, ord_needle[2];
char *needle_dup, *haystack_dup;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
RETURN_FALSE;
}
if (Z_TYPE_P(zneedle) == IS_STRING) {
needle = Z_STRVAL_P(zneedle);
needle_len = Z_STRLEN_P(zneedle);
} else {
if (php_needle_char(zneedle, ord_needle TSRMLS_CC) != SUCCESS) {
RETURN_FALSE;
}
ord_needle[1] = '\0';
needle = ord_needle;
needle_len = 1;
}
if ((haystack_len == 0) || (needle_len == 0)) {
RETURN_FALSE;
}
if (needle_len == 1) {
/* Single character search can shortcut memcmps
Can also avoid tolower emallocs */
if (offset >= 0) {
if (offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack + offset;
e = haystack + haystack_len - 1;
} else {
p = haystack;
if (offset < -INT_MAX || -offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
e = haystack + haystack_len + offset;
}
/* Borrow that ord_needle buffer to avoid repeatedly tolower()ing needle */
*ord_needle = tolower(*needle);
while (e >= p) {
if (tolower(*e) == *ord_needle) {
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
RETURN_FALSE;
}
needle_dup = estrndup(needle, needle_len);
php_strtolower(needle_dup, needle_len);
haystack_dup = estrndup(haystack, haystack_len);
php_strtolower(haystack_dup, haystack_len);
if (offset >= 0) {
if (offset > haystack_len) {
efree(needle_dup);
efree(haystack_dup);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack_dup + offset;
e = haystack_dup + haystack_len - needle_len;
} else {
if (offset < -INT_MAX || -offset > haystack_len) {
efree(needle_dup);
efree(haystack_dup);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack_dup;
if (needle_len > -offset) {
e = haystack_dup + haystack_len - needle_len;
} else {
e = haystack_dup + haystack_len + offset;
}
}
while (e >= p) {
if (memcmp(e, needle_dup, needle_len) == 0) {
efree(haystack_dup);
efree(needle_dup);
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
efree(haystack_dup);
efree(needle_dup);
RETURN_FALSE;
}
/* }}} */