/* }}} */
/* {{{ php_pcre_replace_array */
-static zend_string *php_pcre_replace_array(HashTable *regex, zval *replace, zend_string *subject_str, size_t limit, size_t *replace_count)
+static zend_string *php_pcre_replace_array(HashTable *regex,
+ zend_string *replace_str, HashTable *replace_ht,
+ zend_string *subject_str, size_t limit, size_t *replace_count)
{
zval *regex_entry;
zend_string *result;
- zend_string *replace_str, *tmp_replace_str;
- if (Z_TYPE_P(replace) == IS_ARRAY) {
+ zend_string_addref(subject_str);
+
+ if (replace_ht) {
uint32_t replace_idx = 0;
- HashTable *replace_ht = Z_ARRVAL_P(replace);
/* For each entry in the regex array, get the entry */
ZEND_HASH_FOREACH_VAL(regex, regex_entry) {
/* Make sure we're dealing with strings. */
zend_string *tmp_regex_str;
zend_string *regex_str = zval_get_tmp_string(regex_entry, &tmp_regex_str);
+ zend_string *replace_entry_str, *tmp_replace_entry_str;
zval *zv;
/* Get current entry */
while (1) {
if (replace_idx == replace_ht->nNumUsed) {
- replace_str = ZSTR_EMPTY_ALLOC();
- tmp_replace_str = NULL;
+ replace_entry_str = ZSTR_EMPTY_ALLOC();
+ tmp_replace_entry_str = NULL;
break;
}
zv = &replace_ht->arData[replace_idx].val;
replace_idx++;
if (Z_TYPE_P(zv) != IS_UNDEF) {
- replace_str = zval_get_tmp_string(zv, &tmp_replace_str);
+ replace_entry_str = zval_get_tmp_string(zv, &tmp_replace_entry_str);
break;
}
}
/* Do the actual replacement and put the result back into subject_str
for further replacements. */
- result = php_pcre_replace(regex_str,
- subject_str,
- ZSTR_VAL(subject_str),
- ZSTR_LEN(subject_str),
- replace_str,
- limit,
- replace_count);
- zend_tmp_string_release(tmp_replace_str);
+ result = php_pcre_replace(regex_str, subject_str, ZSTR_VAL(subject_str),
+ ZSTR_LEN(subject_str), replace_entry_str, limit, replace_count);
+ zend_tmp_string_release(tmp_replace_entry_str);
zend_tmp_string_release(tmp_regex_str);
zend_string_release_ex(subject_str, 0);
subject_str = result;
} ZEND_HASH_FOREACH_END();
} else {
- replace_str = Z_STR_P(replace);
+ ZEND_ASSERT(replace_str != NULL);
/* For each entry in the regex array, get the entry */
ZEND_HASH_FOREACH_VAL(regex, regex_entry) {
/* Do the actual replacement and put the result back into subject_str
for further replacements. */
- result = php_pcre_replace(regex_str,
- subject_str,
- ZSTR_VAL(subject_str),
- ZSTR_LEN(subject_str),
- replace_str,
- limit,
- replace_count);
+ result = php_pcre_replace(regex_str, subject_str, ZSTR_VAL(subject_str),
+ ZSTR_LEN(subject_str), replace_str, limit, replace_count);
zend_tmp_string_release(tmp_regex_str);
zend_string_release_ex(subject_str, 0);
subject_str = result;
/* }}} */
/* {{{ php_replace_in_subject */
-static zend_always_inline zend_string *php_replace_in_subject(zval *regex, zval *replace, zval *subject, size_t limit, size_t *replace_count)
+static zend_always_inline zend_string *php_replace_in_subject(
+ zend_string *regex_str, HashTable *regex_ht,
+ zend_string *replace_str, HashTable *replace_ht,
+ zend_string *subject, size_t limit, size_t *replace_count)
{
zend_string *result;
- zend_string *subject_str = zval_get_string(subject);
-
- if (Z_TYPE_P(regex) != IS_ARRAY) {
- result = php_pcre_replace(Z_STR_P(regex),
- subject_str,
- ZSTR_VAL(subject_str),
- ZSTR_LEN(subject_str),
- Z_STR_P(replace),
- limit,
- replace_count);
- zend_string_release_ex(subject_str, 0);
+
+ if (regex_str) {
+ ZEND_ASSERT(replace_str != NULL);
+ result = php_pcre_replace(regex_str, subject, ZSTR_VAL(subject), ZSTR_LEN(subject),
+ replace_str, limit, replace_count);
} else {
- result = php_pcre_replace_array(Z_ARRVAL_P(regex),
- replace,
- subject_str,
- limit,
- replace_count);
+ ZEND_ASSERT(regex_ht != NULL);
+ result = php_pcre_replace_array(regex_ht, replace_str, replace_ht, subject,
+ limit, replace_count);
}
return result;
}
/* }}} */
/* {{{ php_replace_in_subject_func */
-static zend_string *php_replace_in_subject_func(zval *regex, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *subject, size_t limit, size_t *replace_count, zend_long flags)
+static zend_string *php_replace_in_subject_func(zend_string *regex_str, HashTable *regex_ht,
+ zend_fcall_info *fci, zend_fcall_info_cache *fcc,
+ zend_string *subject, size_t limit, size_t *replace_count, zend_long flags)
{
zend_string *result;
- zend_string *subject_str = zval_get_string(subject);
- if (Z_TYPE_P(regex) != IS_ARRAY) {
+ if (regex_str) {
result = php_pcre_replace_func(
- Z_STR_P(regex), subject_str, fci, fcc, limit, replace_count, flags);
- zend_string_release_ex(subject_str, 0);
+ regex_str, subject, fci, fcc, limit, replace_count, flags);
return result;
} else {
+ /* If regex is an array */
zval *regex_entry;
- /* If regex is an array */
+ ZEND_ASSERT(regex_ht != NULL);
+
+ zend_string_addref(subject);
/* For each entry in the regex array, get the entry */
- ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(regex), regex_entry) {
+ ZEND_HASH_FOREACH_VAL(regex_ht, regex_entry) {
/* Make sure we're dealing with strings. */
- zend_string *tmp_regex_str;
- zend_string *regex_str = zval_get_tmp_string(regex_entry, &tmp_regex_str);
+ zend_string *tmp_regex_entry_str;
+ zend_string *regex_entry_str = zval_get_tmp_string(regex_entry, &tmp_regex_entry_str);
- /* Do the actual replacement and put the result back into subject_str
+ /* Do the actual replacement and put the result back into subject
for further replacements. */
result = php_pcre_replace_func(
- regex_str, subject_str, fci, fcc, limit, replace_count, flags);
- zend_tmp_string_release(tmp_regex_str);
- zend_string_release_ex(subject_str, 0);
- subject_str = result;
+ regex_entry_str, subject, fci, fcc, limit, replace_count, flags);
+ zend_tmp_string_release(tmp_regex_entry_str);
+ zend_string_release(subject);
+ subject = result;
if (UNEXPECTED(result == NULL)) {
break;
}
} ZEND_HASH_FOREACH_END();
- return subject_str;
+ return subject;
}
}
/* }}} */
/* {{{ preg_replace_func_impl */
-static size_t preg_replace_func_impl(zval *return_value, zval *regex, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *subject, zend_long limit_val, zend_long flags)
+static size_t preg_replace_func_impl(zval *return_value,
+ zend_string *regex_str, HashTable *regex_ht,
+ zend_fcall_info *fci, zend_fcall_info_cache *fcc,
+ zend_string *subject_str, HashTable *subject_ht, zend_long limit_val, zend_long flags)
{
zend_string *result;
size_t replace_count = 0;
- if (Z_TYPE_P(regex) != IS_ARRAY) {
- convert_to_string_ex(regex);
- }
-
- if (Z_TYPE_P(subject) != IS_ARRAY) {
+ if (subject_str) {
result = php_replace_in_subject_func(
- regex, fci, fcc, subject, limit_val, &replace_count, flags);
+ regex_str, regex_ht, fci, fcc, subject_str, limit_val, &replace_count, flags);
if (result != NULL) {
RETVAL_STR(result);
} else {
zend_string *string_key;
zend_ulong num_key;
- array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(subject)));
+ ZEND_ASSERT(subject_ht != NULL);
+
+ array_init_size(return_value, zend_hash_num_elements(subject_ht));
/* For each subject entry, convert it to string, then perform replacement
and add the result to the return_value array. */
- ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(subject), num_key, string_key, subject_entry) {
+ ZEND_HASH_FOREACH_KEY_VAL(subject_ht, num_key, string_key, subject_entry) {
+ zend_string *tmp_subject_entry_str;
+ zend_string *subject_entry_str = zval_get_tmp_string(subject_entry, &tmp_subject_entry_str);
+
result = php_replace_in_subject_func(
- regex, fci, fcc, subject_entry, limit_val, &replace_count, flags);
+ regex_str, regex_ht, fci, fcc, subject_entry_str, limit_val, &replace_count, flags);
if (result != NULL) {
/* Add to return array */
ZVAL_STR(&zv, result);
zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &zv);
}
}
+ zend_tmp_string_release(tmp_subject_entry_str);
} ZEND_HASH_FOREACH_END();
}
/* }}} */
/* {{{ preg_replace_common */
-static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, int is_filter)
+static void preg_replace_common(INTERNAL_FUNCTION_PARAMETERS, bool is_filter)
{
- zval *regex, *replace, *subject, *zcount = NULL;
+ zval *zcount = NULL;
+ zend_string *regex_str;
+ HashTable *regex_ht;
+ zend_string *replace_str;
+ HashTable *replace_ht;
+ zend_string *subject_str;
+ HashTable *subject_ht;
zend_long limit = -1;
size_t replace_count = 0;
zend_string *result;
/* Get function parameters and do error-checking. */
ZEND_PARSE_PARAMETERS_START(3, 5)
- Z_PARAM_ZVAL(regex)
- Z_PARAM_ZVAL(replace)
- Z_PARAM_ZVAL(subject)
+ Z_PARAM_STR_OR_ARRAY_HT(regex_str, regex_ht)
+ Z_PARAM_STR_OR_ARRAY_HT(replace_str, replace_ht)
+ Z_PARAM_STR_OR_ARRAY_HT(subject_str, subject_ht)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(limit)
Z_PARAM_ZVAL(zcount)
ZEND_PARSE_PARAMETERS_END();
- if (Z_TYPE_P(replace) != IS_ARRAY) {
- convert_to_string_ex(replace);
- if (Z_TYPE_P(regex) != IS_ARRAY) {
- convert_to_string_ex(regex);
- }
- } else {
- if (Z_TYPE_P(regex) != IS_ARRAY) {
- zend_argument_type_error(1, "must be of type array when argument #2 ($replace) is an array, %s given", zend_zval_type_name(regex));
- RETURN_THROWS();
- }
+ /* If replace is an array then the regex argument needs to also be an array */
+ if (replace_ht && !regex_ht) {
+ zend_argument_type_error(1, "must be of type array when argument #2 ($replace) is an array, string given");
+ RETURN_THROWS();
}
- if (Z_TYPE_P(subject) != IS_ARRAY) {
+ if (subject_str) {
old_replace_count = replace_count;
- result = php_replace_in_subject(regex,
- replace,
- subject,
- limit,
- &replace_count);
+ result = php_replace_in_subject(regex_str, regex_ht, replace_str, replace_ht,
+ subject_str, limit, &replace_count);
if (result != NULL) {
if (!is_filter || replace_count > old_replace_count) {
RETVAL_STR(result);
zend_string *string_key;
zend_ulong num_key;
- array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(subject)));
+ ZEND_ASSERT(subject_ht != NULL);
+
+ array_init_size(return_value, zend_hash_num_elements(subject_ht));
/* For each subject entry, convert it to string, then perform replacement
and add the result to the return_value array. */
- ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(subject), num_key, string_key, subject_entry) {
+ ZEND_HASH_FOREACH_KEY_VAL(subject_ht, num_key, string_key, subject_entry) {
old_replace_count = replace_count;
- result = php_replace_in_subject(regex,
- replace,
- subject_entry,
- limit,
- &replace_count);
+ zend_string *tmp_subject_entry_str;
+ zend_string *subject_entry_str = zval_get_tmp_string(subject_entry, &tmp_subject_entry_str);
+ result = php_replace_in_subject(regex_str, regex_ht, replace_str, replace_ht,
+ subject_entry_str, limit, &replace_count);
+
if (result != NULL) {
if (!is_filter || replace_count > old_replace_count) {
/* Add to return array */
zend_string_release_ex(result, 0);
}
}
+ zend_tmp_string_release(tmp_subject_entry_str);
} ZEND_HASH_FOREACH_END();
}
/* {{{ Perform Perl-style regular expression replacement. */
PHP_FUNCTION(preg_replace)
{
- preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+ preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
}
/* }}} */
/* {{{ Perform Perl-style regular expression replacement using replacement callback. */
PHP_FUNCTION(preg_replace_callback)
{
- zval *regex, *subject, *zcount = NULL;
+ zval *zcount = NULL;
+ zend_string *regex_str;
+ HashTable *regex_ht;
+ zend_string *subject_str;
+ HashTable *subject_ht;
zend_long limit = -1, flags = 0;
size_t replace_count;
zend_fcall_info fci;
/* Get function parameters and do error-checking. */
ZEND_PARSE_PARAMETERS_START(3, 6)
- Z_PARAM_ZVAL(regex)
+ Z_PARAM_STR_OR_ARRAY_HT(regex_str, regex_ht)
Z_PARAM_FUNC(fci, fcc)
- Z_PARAM_ZVAL(subject)
+ Z_PARAM_STR_OR_ARRAY_HT(subject_str, subject_ht)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(limit)
Z_PARAM_ZVAL(zcount)
Z_PARAM_LONG(flags)
ZEND_PARSE_PARAMETERS_END();
- replace_count = preg_replace_func_impl(return_value, regex, &fci, &fcc, subject, limit, flags);
+ replace_count = preg_replace_func_impl(return_value, regex_str, regex_ht,
+ &fci, &fcc,
+ subject_str, subject_ht, limit, flags);
if (zcount) {
ZEND_TRY_ASSIGN_REF_LONG(zcount, replace_count);
}
/* {{{ Perform Perl-style regular expression replacement using replacement callback. */
PHP_FUNCTION(preg_replace_callback_array)
{
- zval regex, zv, *replace, *subject, *pattern, *zcount = NULL;
+ zval zv, *replace, *subject, *zcount = NULL;
+ HashTable *pattern;
+ zend_string *str_idx_regex;
zend_long limit = -1, flags = 0;
- zend_string *str_idx;
size_t replace_count = 0;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
/* Get function parameters and do error-checking. */
ZEND_PARSE_PARAMETERS_START(2, 5)
- Z_PARAM_ARRAY(pattern)
+ Z_PARAM_ARRAY_HT(pattern)
Z_PARAM_ZVAL(subject)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(limit)
fci.size = sizeof(fci);
fci.object = NULL;
- ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pattern), str_idx, replace) {
- if (str_idx) {
- ZVAL_STR_COPY(®ex, str_idx);
- } else {
+ ZEND_HASH_FOREACH_STR_KEY_VAL(pattern, str_idx_regex, replace) {
+ if (!str_idx_regex) {
php_error_docref(NULL, E_WARNING, "Delimiter must not be alphanumeric or backslash");
zval_ptr_dtor(return_value);
RETURN_NULL();
if (!zend_is_callable_ex(replace, NULL, 0, NULL, &fcc, NULL)) {
zend_string *callback_name = zend_get_callable_name(replace);
- php_error_docref(NULL, E_WARNING, "'%s' is not a valid callback", ZSTR_VAL(callback_name));
+ zend_type_error("'%s' is not a valid callback", ZSTR_VAL(callback_name));
zend_string_release_ex(callback_name, 0);
- zval_ptr_dtor(®ex);
- zval_ptr_dtor(return_value);
- ZVAL_COPY(return_value, subject);
- return;
+ RETURN_THROWS();
}
ZVAL_COPY_VALUE(&fci.function_name, replace);
- replace_count += preg_replace_func_impl(&zv, ®ex, &fci, &fcc, subject, limit, flags);
+ replace_count += preg_replace_func_impl(&zv, str_idx_regex, /* regex_ht */ NULL, &fci, &fcc,
+ Z_STR_P(subject), Z_ARRVAL_P(subject),
+ limit, flags);
+
if (subject != return_value) {
subject = return_value;
} else {
zval_ptr_dtor(return_value);
}
- zval_ptr_dtor(®ex);
-
ZVAL_COPY_VALUE(return_value, &zv);
if (UNEXPECTED(EG(exception))) {
/* {{{ Perform Perl-style regular expression replacement and only return matches. */
PHP_FUNCTION(preg_filter)
{
- preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+ preg_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
}
/* }}} */