]> granicus.if.org Git - php/commitdiff
Unicode support in substr_compare().
authorAndrei Zmievski <andrei@php.net>
Wed, 4 Oct 2006 17:25:12 +0000 (17:25 +0000)
committerAndrei Zmievski <andrei@php.net>
Wed, 4 Oct 2006 17:25:12 +0000 (17:25 +0000)
ext/standard/string.c

index 9d148c7e893ca3de1b8fcb37c9aaf478b95c81e3..04cf7bf5a2de64982cd6223918056bc82400d71a 100644 (file)
@@ -7316,17 +7316,19 @@ PHP_FUNCTION(strpbrk)
 }
 /* }}} */
 
-/* {{{ proto int substr_compare(string main_str, string str, int offset [, int length [, bool case_sensitivity]])
+/* {{{ proto int substr_compare(string main_str, string str, int offset [, int length [, bool case_sensitivity]]) U
    Binary safe optionally case insensitive comparison of 2 strings from an offset, up to length characters */
 PHP_FUNCTION(substr_compare)
 {
-       char *s1, *s2;
+       zstr s1, s2;
        int s1_len, s2_len;
-       long offset, len=0;
+       zend_uchar str_type;
+       long offset, start_offset, end_offset, len=0;
        zend_bool cs=0;
        uint cmp_len;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssl|lb", &s1, &s1_len, &s2, &s2_len, &offset, &len, &cs) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "TTl|lb", &s1, &s1_len,
+                                                         &str_type, &s2, &s2_len, &str_type, &offset, &len, &cs) == FAILURE) {
                RETURN_FALSE;
        }
 
@@ -7335,22 +7337,61 @@ PHP_FUNCTION(substr_compare)
                RETURN_FALSE;
        }
 
-       if (offset < 0) {
-               offset = s1_len + offset;
-               offset = (offset < 0) ? 0 : offset;
-       }
+       if (str_type == IS_UNICODE) {
+               /* calculate starting offset of the segment */
+               if (offset < 0) {
+                       if (-offset > s1_len) {
+                               start_offset = 0;
+                       } else {
+                               start_offset = s1_len;
+                               U16_BACK_N(s1.u, 0, start_offset, -offset);
+                       }
+               } else {
+                       start_offset = 0;
+                       U16_FWD_N(s1.u, start_offset, s1_len, offset);
+               }
 
-       if ((offset + len) > s1_len) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "The start position cannot exceed initial string length");
-               RETURN_FALSE;
-       }
+               /* calculate ending offset of the segment */
+               if (len) {
+                       end_offset = start_offset;
+                       while (len > 0 && end_offset < s1_len) {
+                               U16_FWD_1_UNSAFE(s1.u, end_offset);
+                               --len;
+                       }
+
+                       if (len > 0) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "The specified segment exceeds string length");
+                               RETURN_FALSE;
+                       }
+               } else {
+                       end_offset = s1_len;
+               }
 
-       cmp_len = (uint) (len ? len : MAX(s2_len, (s1_len - offset)));
+               cmp_len = MAX(s2_len, (end_offset - start_offset));
 
-       if (!cs) {
-               RETURN_LONG(zend_binary_strncmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len));
+               if (!cs) {
+                       RETURN_LONG(zend_u_binary_strncmp(s1.u + start_offset, (s1_len - start_offset), s2.u, s2_len, cmp_len));
+               } else {
+                       RETURN_LONG(zend_u_binary_strncasecmp(s1.u + start_offset, (s1_len - start_offset), s2.u, s2_len, cmp_len));
+               }
        } else {
-               RETURN_LONG(zend_binary_strncasecmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len));
+               if (offset < 0) {
+                       offset = s1_len + offset;
+                       offset = (offset < 0) ? 0 : offset;
+               }
+
+               if ((offset + len) > s1_len) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "The specified segment exceeds string length");
+                       RETURN_FALSE;
+               }
+
+               cmp_len = (uint) (len ? len : MAX(s2_len, (s1_len - offset)));
+
+               if (!cs) {
+                       RETURN_LONG(zend_binary_strncmp(s1.s + offset, (s1_len - offset), s2.s, s2_len, cmp_len));
+               } else {
+                       RETURN_LONG(zend_binary_strncasecmp(s1.s + offset, (s1_len - offset), s2.s, s2_len, cmp_len));
+               }
        }
 }
 /* }}} */