]> granicus.if.org Git - php/commitdiff
Refactor php_pcre_replace to return zend_string
authorXinchen Hui <laruence@gmail.com>
Sun, 16 Mar 2014 00:44:07 +0000 (08:44 +0800)
committerXinchen Hui <laruence@gmail.com>
Sun, 16 Mar 2014 00:44:07 +0000 (08:44 +0800)
ext/pcre/php_pcre.c
ext/pcre/php_pcre.h
ext/spl/spl_iterators.c

index 1ae46de022cdce47fe8f005f7c7a5f45f043a87a..3c60a6a3e4bf478a28a9c74700efcdcdb52d523a 100644 (file)
@@ -963,10 +963,10 @@ static int preg_do_eval(char *eval_str, int eval_str_len, char *subject,
 
 /* {{{ php_pcre_replace
  */
-PHPAPI char *php_pcre_replace(zend_string *regex,
+PHPAPI zend_string *php_pcre_replace(zend_string *regex,
                                                          char *subject, int subject_len,
                                                          zval *replace_val, int is_callable_replace,
-                                                         int *result_len, int limit, int *replace_count TSRMLS_DC)
+                                                         int limit, int *replace_count TSRMLS_DC)
 {
        pcre_cache_entry        *pce;                       /* Compiled regular expression */
 
@@ -976,13 +976,13 @@ PHPAPI char *php_pcre_replace(zend_string *regex,
        }
 
        return php_pcre_replace_impl(pce, subject, subject_len, replace_val, 
-               is_callable_replace, result_len, limit, replace_count TSRMLS_CC);
+               is_callable_replace, limit, replace_count TSRMLS_CC);
 }
 /* }}} */
 
 /* {{{ php_pcre_replace_impl() */
-PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *replace_val, 
-       int is_callable_replace, int *result_len, int limit, int *replace_count TSRMLS_DC)
+PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *replace_val, 
+       int is_callable_replace, int limit, int *replace_count TSRMLS_DC)
 {
        pcre_extra              *extra = pce->extra;/* Holds results of studying */
        pcre_extra               extra_data;            /* Used locally for exec options */
@@ -1002,9 +1002,7 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
        int                              start_offset;          /* Where the new search starts */
        int                              g_notempty=0;          /* If the match should not be empty */
        int                              replace_len=0;         /* Length of replacement string */
-       char                    *result,                        /* Result of replacement */
-                                       *replace=NULL,          /* Replacement string */
-                                       *new_buf,                       /* Temporary buffer for re-allocation */
+       char                    *replace=NULL,          /* Replacement string */
                                        *walkbuf,                       /* Location of current replacement in the result */
                                        *walk,                          /* Used to walk the replacement string */
                                        *match,                         /* The current match */
@@ -1012,7 +1010,9 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
                                        *replace_end=NULL,      /* End of replacement string */
                                        *eval_result,           /* Result of eval or custom function */
                                         walk_last;                     /* Last walked character */
-       int                              rc;
+       int                              rc,
+                                        result_len;            /* Length of result */
+       zend_string             *result;                        /* Result of replacement */
 
        if (extra == NULL) {
                extra_data.flags = PCRE_EXTRA_MATCH_LIMIT | PCRE_EXTRA_MATCH_LIMIT_RECURSION;
@@ -1058,13 +1058,13 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 
        offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
        
-       alloc_len = 2 * subject_len + 1;
-       result = safe_emalloc(alloc_len, sizeof(char), 0);
+       alloc_len = 2 * subject_len;
+       result = STR_ALLOC(alloc_len * sizeof(char), 0);
 
        /* Initialize */
        match = NULL;
-       *result_len = 0;
        start_offset = 0;
+       result_len = 0;
        PCRE_G(error_code) = PHP_PCRE_NO_ERROR;
        
        while (1) {
@@ -1090,7 +1090,7 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
                        /* Set the match location in subject */
                        match = subject + offsets[0];
 
-                       new_len = *result_len + offsets[0] - start_offset; /* part before the match */
+                       new_len = result_len + offsets[0] - start_offset; /* part before the match */
                        
                        /* If evaluating, do it and add the return string's length */
                        if (eval) {
@@ -1123,25 +1123,22 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
                                }
                        }
 
-                       if (new_len + 1 > alloc_len) {
-                               alloc_len = 1 + alloc_len + 2 * new_len;
-                               new_buf = emalloc(alloc_len);
-                               memcpy(new_buf, result, *result_len);
-                               efree(result);
-                               result = new_buf;
+                       if (new_len > alloc_len) {
+                               alloc_len = alloc_len + 2 * new_len;
+                               result = STR_REALLOC(result, alloc_len, 0);
                        }
                        /* copy the part of the string before the match */
-                       memcpy(&result[*result_len], piece, match-piece);
-                       *result_len += match-piece;
+                       memcpy(&result->val[result_len], piece, match-piece);
+                       result_len += match-piece;
 
                        /* copy replacement and backrefs */
-                       walkbuf = result + *result_len;
+                       walkbuf = result->val + result_len;
                        
                        /* If evaluating or using custom function, copy result to the buffer
                         * and clean up. */
                        if (eval || is_callable_replace) {
                                memcpy(walkbuf, eval_result, eval_result_len);
-                               *result_len += eval_result_len;
+                               result_len += eval_result_len;
                                if (eval_result) efree(eval_result);
                        } else { /* do regular backreference copying */
                                walk = replace;
@@ -1167,7 +1164,7 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
                                }
                                *walkbuf = '\0';
                                /* increment the result length by how much we've added to the string */
-                               *result_len += walkbuf - (result + *result_len);
+                               result_len += walkbuf - (result->val + result_len);
                        }
 
                        if (limit != -1)
@@ -1181,26 +1178,23 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
                        if (g_notempty != 0 && start_offset < subject_len) {
                                offsets[0] = start_offset;
                                offsets[1] = start_offset + 1;
-                               memcpy(&result[*result_len], piece, 1);
-                               (*result_len)++;
+                               memcpy(&result->val[result_len], piece, 1);
+                               result_len++;
                        } else {
-                               new_len = *result_len + subject_len - start_offset;
-                               if (new_len + 1 > alloc_len) {
-                                       alloc_len = new_len + 1; /* now we know exactly how long it is */
-                                       new_buf = safe_emalloc(alloc_len, sizeof(char), 0);
-                                       memcpy(new_buf, result, *result_len);
-                                       efree(result);
-                                       result = new_buf;
+                               new_len = result_len + subject_len - start_offset;
+                               if (new_len > alloc_len) {
+                                       alloc_len = new_len; /* now we know exactly how long it is */
+                                       result = STR_REALLOC(result, alloc_len, 0);
                                }
                                /* stick that last bit of string on our output */
-                               memcpy(&result[*result_len], piece, subject_len - start_offset);
-                               *result_len += subject_len - start_offset;
-                               result[*result_len] = '\0';
+                               memcpy(&result->val[result_len], piece, subject_len - start_offset);
+                               result_len += subject_len - start_offset;
+                               result->val[result_len] = '\0';
                                break;
                        }
                } else {
                        pcre_handle_exec_error(count TSRMLS_CC);
-                       efree(result);
+                       STR_FREE(result);
                        result = NULL;
                        break;
                }
@@ -1215,6 +1209,9 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
                start_offset = offsets[1];
        }
 
+       if (result) {
+               result->len = result_len;
+       }
        efree(offsets);
        efree(subpat_names);
 
@@ -1224,15 +1221,14 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 
 /* {{{ php_replace_in_subject
  */
-static char *php_replace_in_subject(zval *regex, zval *replace, zval *subject, int *result_len, int limit, int is_callable_replace, int *replace_count TSRMLS_DC)
+static zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *subject, int limit, int is_callable_replace, int *replace_count TSRMLS_DC)
 {
        zval            *regex_entry,
                                *replace_entry = NULL,
                                *replace_value,
                                 empty_replace;
-       char            *subject_value,
-                               *result;
-       int                      subject_len;
+       zend_string     *subject_value;
+       zend_string *result;
 
        /* Make sure we're dealing with strings. */     
        convert_to_string_ex(subject);
@@ -1243,9 +1239,7 @@ static char *php_replace_in_subject(zval *regex, zval *replace, zval *subject, i
        /* If regex is an array */
        if (Z_TYPE_P(regex) == IS_ARRAY) {
                /* Duplicate subject string for repeated replacement */
-               subject_value = estrndup(Z_STRVAL_P(subject), Z_STRLEN_P(subject));
-               subject_len = Z_STRLEN_P(subject);
-               *result_len = subject_len;
+               subject_value = STR_INIT(Z_STRVAL_P(subject), Z_STRLEN_P(subject), 0);
                
                zend_hash_internal_pointer_reset(Z_ARRVAL_P(regex));
 
@@ -1276,18 +1270,16 @@ static char *php_replace_in_subject(zval *regex, zval *replace, zval *subject, i
                        /* Do the actual replacement and put the result back into subject_value
                           for further replacements. */
                        if ((result = php_pcre_replace(Z_STR_P(regex_entry),
-                                                                                  subject_value,
-                                                                                  subject_len,
+                                                                                  subject_value->val,
+                                                                                  subject_value->len,
                                                                                   replace_value,
                                                                                   is_callable_replace,
-                                                                                  result_len,
                                                                                   limit,
                                                                                   replace_count TSRMLS_CC)) != NULL) {
-                               efree(subject_value);
+                               STR_RELEASE(subject_value);
                                subject_value = result;
-                               subject_len = *result_len;
                        } else {
-                               efree(subject_value);
+                               STR_RELEASE(subject_value);
                                return NULL;
                        }
 
@@ -1301,7 +1293,6 @@ static char *php_replace_in_subject(zval *regex, zval *replace, zval *subject, i
                                                                  Z_STRLEN_P(subject),
                                                                  replace,
                                                                  is_callable_replace,
-                                                                 result_len,
                                                                  limit,
                                                                  replace_count TSRMLS_CC);
                return result;
@@ -1318,10 +1309,9 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, int is_callable_repl
                                    *subject,
                                    *subject_entry,
                                    *zcount = NULL;
-       char                    *result;
-       int                              result_len;
        int                              limit_val = -1;
-       long                    limit = -1;
+       long                     limit = -1;
+       zend_string             *result;
        zend_string             *string_key;
        ulong                    num_key;
        zend_string             *callback_name;
@@ -1371,24 +1361,21 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, int is_callable_repl
                while ((subject_entry = zend_hash_get_current_data(Z_ARRVAL_P(subject))) != NULL) {
                        SEPARATE_ZVAL(subject_entry);
                        old_replace_count = replace_count;
-                       if ((result = php_replace_in_subject(regex, replace, subject_entry, &result_len, limit_val, is_callable_replace, &replace_count TSRMLS_CC)) != NULL) {
+                       if ((result = php_replace_in_subject(regex, replace, subject_entry, limit_val, is_callable_replace, &replace_count TSRMLS_CC)) != NULL) {
                                if (!is_filter || replace_count > old_replace_count) {
                                        /* Add to return array */
                                        switch(zend_hash_get_current_key_ex(Z_ARRVAL_P(subject), &string_key, &num_key, 0, NULL))
                                        {
                                        case HASH_KEY_IS_STRING:
-//???
-                                               add_assoc_stringl_ex(return_value, string_key->val, string_key->len, result, result_len, 0);
-                                               efree(result);
+                                               add_assoc_str_ex(return_value, string_key->val, string_key->len, result);
                                                break;
 
                                        case HASH_KEY_IS_LONG:
-                                               add_index_stringl(return_value, num_key, result, result_len, 0);
-                                               efree(result);
+                                               add_index_str(return_value, num_key, result);
                                                break;
                                        }
                                } else {
-                                       efree(result);
+                                       STR_FREE(result);
                                }
                        }
                
@@ -1396,14 +1383,11 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, int is_callable_repl
                }
        } else {        /* if subject is not an array */
                old_replace_count = replace_count;
-               if ((result = php_replace_in_subject(regex, replace, subject, &result_len, limit_val, is_callable_replace, &replace_count TSRMLS_CC)) != NULL) {
+               if ((result = php_replace_in_subject(regex, replace, subject, limit_val, is_callable_replace, &replace_count TSRMLS_CC)) != NULL) {
                        if (!is_filter || replace_count > old_replace_count) {
-//??? TODO: reimpplement to avoid double reallocation
-//???                          RETVAL_STRINGL(result, result_len, 0);
-                               RETVAL_STRINGL(result, result_len);
-                               efree(result);
+                               RETVAL_STR(result);
                        } else {
-                               efree(result);
+                               STR_FREE(result);
                        }
                }
        }
@@ -1791,7 +1775,11 @@ PHPAPI void  php_pcre_grep_impl(pcre_cache_entry *pce, zval *input, zval *return
        while ((entry = zend_hash_get_current_data(Z_ARRVAL_P(input))) != NULL) {
                zval subject;
                
-                ZVAL_COPY_VALUE(&subject, entry);
+               if (Z_TYPE_P(entry) == IS_REFERENCE) {
+                       entry = Z_REFVAL_P(entry);
+               }
+
+               ZVAL_COPY_VALUE(&subject, entry);
 
                if (Z_TYPE_P(entry) != IS_STRING) {
                        zval_copy_ctor(&subject);
index 9e6fa6c32fe8fb40d7f5f63b5a765daf260c9823..f352059e62e31f3db50f0b723e01b6b34e5ae86e 100644 (file)
@@ -33,7 +33,7 @@
 #include <locale.h>
 #endif
 
-PHPAPI char *php_pcre_replace(zend_string *regex, char *subject, int subject_len, zval *replace_val, int is_callable_replace, int *result_len, int limit, int *replace_count TSRMLS_DC);
+PHPAPI zend_string *php_pcre_replace(zend_string *regex, char *subject, int subject_len, zval *replace_val, int is_callable_replace, int limit, int *replace_count TSRMLS_DC);
 PHPAPI pcre* pcre_get_compiled_regex(zend_string *regex, pcre_extra **extra, int *options TSRMLS_DC);
 PHPAPI pcre* pcre_get_compiled_regex_ex(zend_string *regex, pcre_extra **extra, int *preg_options, int *coptions TSRMLS_DC);
 
@@ -57,8 +57,8 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(zend_string *regex TSRMLS
 PHPAPI void  php_pcre_match_impl(  pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value,
        zval *subpats, int global, int use_flags, long flags, long start_offset TSRMLS_DC);
 
-PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value, 
-       int is_callable_replace, int *result_len, int limit, int *replace_count TSRMLS_DC);
+PHPAPI zend_string *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value, 
+       int is_callable_replace, int limit, int *replace_count TSRMLS_DC);
 
 PHPAPI void  php_pcre_split_impl(  pcre_cache_entry *pce, char *subject, int subject_len, zval *return_value,
        long limit_val, long flags TSRMLS_DC);
index cff5221a0dbeb0afb0d9c87792b729e01f562186..4128f0761c8c28f2b6ec3407342e41dd3e9c8dd7 100644 (file)
@@ -1960,9 +1960,10 @@ SPL_METHOD(CallbackFilterIterator, accept)
 SPL_METHOD(RegexIterator, accept)
 {
        spl_dual_it_object *intern;
-       char       *subject, *result;
-       int        subject_len, use_copy, count = 0, result_len;
-       zval       *subject_ptr, subject_copy, zcount, *replacement, tmp_replacement;
+       char *subject;
+       zend_string *result;
+       int subject_len, use_copy, count = 0;
+       zval *subject_ptr, subject_copy, zcount, *replacement, tmp_replacement;
        
        if (zend_parse_parameters_none() == FAILURE) {
                return;
@@ -2033,16 +2034,14 @@ SPL_METHOD(RegexIterator, accept)
                                convert_to_string(&tmp_replacement);
                                replacement = &tmp_replacement;
                        }
-                       result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, &result_len, -1, &count TSRMLS_CC);
+                       result = php_pcre_replace_impl(intern->u.regex.pce, subject, subject_len, replacement, 0, -1, &count TSRMLS_CC);
                        
                        if (intern->u.regex.flags & REGIT_USE_KEY) {
                                zval_ptr_dtor(&intern->current.key);
-       //???                   ZVAL_STRINGL(intern->current.key, result, result_len, 0);
-                               ZVAL_STRINGL(&intern->current.key, result, result_len);
+                               ZVAL_STR(&intern->current.key, result);
                        } else {
                                zval_ptr_dtor(&intern->current.data);
-       //???                   ZVAL_STRINGL(intern->current.data, result, result_len, 0);
-                               ZVAL_STRINGL(&intern->current.data, result, result_len);
+                               ZVAL_STR(&intern->current.data, result);
                        }
 
                        if (replacement == &tmp_replacement) {