Returns the number of times a substring occurs in the string */
PHP_FUNCTION(substr_count)
{
- zval **haystack, **needle, **offset, **length;
+ void *haystack, *needle;
+ int32_t haystack_len, needle_len;
+ zend_uchar haystack_type, needle_type;
+ long offset = 0, length = 0;
int ac = ZEND_NUM_ARGS();
int count = 0;
- char *p, *endp, cmp;
-
- if (ac < 2 || ac > 4 || zend_get_parameters_ex(ac, &haystack, &needle, &offset, &length) == FAILURE) {
- WRONG_PARAM_COUNT;
+ void *p, *endp, *tmp;
+ int32_t i, j;
+ char cmp;
+
+ if (zend_parse_parameters(ac TSRMLS_CC, "TT|ll",
+ &haystack, &haystack_len, &haystack_type,
+ &needle, &needle_len, &needle_type,
+ &offset, &length) == FAILURE) {
+ return;
}
- convert_to_string_ex(haystack);
- convert_to_string_ex(needle);
-
- if (Z_STRLEN_PP(needle) == 0) {
+ if (needle_len == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring.");
RETURN_FALSE;
}
-
- p = Z_STRVAL_PP(haystack);
- endp = p + Z_STRLEN_PP(haystack);
-
+
+ if (haystack_type == IS_UNICODE) {
+ p = (UChar *)haystack;
+ endp = (UChar *)haystack + haystack_len;
+ } else {
+ p = (char *)haystack;
+ endp = (char *)haystack + haystack_len;
+ }
+
if (ac > 2) {
- convert_to_long_ex(offset);
- if (Z_LVAL_PP(offset) < 0) {
+ if (offset < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset should be greater then or equal to 0.");
- RETURN_FALSE;
+ RETURN_FALSE;
+ }
+ if (haystack_type == IS_UNICODE) {
+ i = 0;
+ U16_FWD_N((UChar *)haystack, i, haystack_len, offset);
+ p = (UChar *)haystack + i;
+ } else {
+ p = (char *)haystack + offset;
}
- p += Z_LVAL_PP(offset);
if (p > endp) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length.", Z_LVAL_PP(offset));
- RETURN_FALSE;
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length.", offset);
+ RETURN_FALSE;
}
if (ac == 4) {
- convert_to_long_ex(length);
- if (Z_LVAL_PP(length) <= 0) {
+ if (length < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length should be greater than 0.");
- RETURN_FALSE;
+ RETURN_FALSE;
}
- if ((p + Z_LVAL_PP(length)) > endp) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length value %ld exceeds string length.", Z_LVAL_PP(length));
+ if (haystack_type == IS_UNICODE) {
+ j = i;
+ i = 0;
+ U16_FWD_N((UChar *)p, i, haystack_len-j, length);
+ tmp = (UChar *)p + i;
+ } else {
+ tmp = (char *)p + length;
+ }
+ if (tmp > endp) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length.", offset);
RETURN_FALSE;
+ } else {
+ endp = tmp;
}
- endp = p + Z_LVAL_PP(length);
}
}
-
- if (Z_STRLEN_PP(needle) == 1) {
- cmp = Z_STRVAL_PP(needle)[0];
- while ((p = memchr(p, cmp, endp - p))) {
+ if (haystack_type == IS_UNICODE) {
+ while ((p = zend_u_memnstr((UChar *)p, (UChar *)needle, needle_len, (UChar *)endp)) != NULL) {
+ (UChar *)p += needle_len;
count++;
- p++;
}
} else {
- while ((p = php_memnstr(p, Z_STRVAL_PP(needle), Z_STRLEN_PP(needle), endp))) {
- p += Z_STRLEN_PP(needle);
- count++;
+ if (needle_len == 1) {
+ cmp = ((char *)needle)[0];
+ while ((p = memchr(p, cmp, endp - p))) {
+ count++;
+ (char *)p++;
+ }
+ } else {
+ while ((p = php_memnstr((char *)p, (char *)needle, needle_len, (char *)endp))) {
+ (char *)p += needle_len;
+ count++;
+ }
}
}