From 1297c0508a1dc88310e0f0c8297de3de732a7f67 Mon Sep 17 00:00:00 2001 From: Rui Hirokawa Date: Sun, 25 Sep 2011 08:01:54 +0000 Subject: [PATCH] added mb_ereg_replace_callback(). --- ext/mbstring/mbstring.c | 7 ++++ ext/mbstring/php_mbregex.c | 83 +++++++++++++++++++++++++++++++++----- ext/mbstring/php_mbregex.h | 2 + 3 files changed, 83 insertions(+), 9 deletions(-) diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index f2d10e05485..62c10a8f1f1 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -467,6 +467,13 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_eregi_replace, 0, 0, 3) ZEND_ARG_INFO(0, string) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_ereg_replace_callback, 0, 0, 3) + ZEND_ARG_INFO(0, pattern) + ZEND_ARG_INFO(0, callback) + ZEND_ARG_INFO(0, string) + ZEND_ARG_INFO(0, option) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_split, 0, 0, 2) ZEND_ARG_INFO(0, pattern) ZEND_ARG_INFO(0, string) diff --git a/ext/mbstring/php_mbregex.c b/ext/mbstring/php_mbregex.c index ba718354787..dcd739937a2 100644 --- a/ext/mbstring/php_mbregex.c +++ b/ext/mbstring/php_mbregex.c @@ -784,7 +784,7 @@ PHP_FUNCTION(mb_eregi) /* }}} */ /* {{{ _php_mb_regex_ereg_replace_exec */ -static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOptionType options) +static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOptionType options, int is_callable) { zval **arg_pattern_zval; @@ -793,9 +793,11 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp char *replace; int replace_len; + zval **arg_replace_zval; char *string; int string_len; + zval **arg_string_zval; char *p; php_mb_regex_t *re; @@ -826,14 +828,20 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp char *option_str = NULL; int option_str_len = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zss|s", - &arg_pattern_zval, - &replace, &replace_len, - &string, &string_len, - &option_str, &option_str_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|s", + &arg_pattern_zval, + &arg_replace_zval, + &arg_string_zval, + &option_str, &option_str_len) == FAILURE) { RETURN_FALSE; } + replace = Z_STRVAL_PP(arg_replace_zval); + replace_len = Z_STRLEN_PP(arg_replace_zval); + + string = Z_STRVAL_PP(arg_string_zval); + string_len = Z_STRLEN_PP(arg_string_zval); + if (option_str != NULL) { _php_mb_regex_init_options(option_str, option_str_len, &options, &syntax, &eval); } else { @@ -859,7 +867,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp RETURN_FALSE; } - if (eval) { + if (eval || is_callable) { pbuf = &eval_buf; description = zend_make_compiled_string_description("mbregex replace" TSRMLS_CC); } else { @@ -867,6 +875,22 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp description = NULL; } + if (is_callable) { + char *callback_name; + if (!zend_is_callable(*arg_replace_zval, 0, &callback_name TSRMLS_CC)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires argument 2, '%s', to be a valid callback", callback_name); + efree(callback_name); + MAKE_COPY_ZVAL(arg_string_zval, return_value); + RETURN_FALSE; + } + efree(callback_name); + + if (eval) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Option 'e' cannot be used with replacement callback"); + RETURN_FALSE; + } + } + /* do the actual work */ err = 0; pos = (OnigUChar *)string; @@ -911,6 +935,8 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp i += fwd; } } + + if (eval) { zval v; /* null terminate buffer */ @@ -928,7 +954,38 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp /* Clean up */ eval_buf.len = 0; zval_dtor(&v); + } else if (is_callable) { + zval *retval_ptr; + zval **args[1]; + zval *subpats; + int i; + + MAKE_STD_ZVAL(subpats); + array_init(subpats); + + for (i = 0; i < regs->num_regs; i++) { + add_next_index_stringl(subpats, string + regs->beg[i], regs->end[i] - regs->beg[i], 1); + } + + args[0] = &subpats; + /* null terminate buffer */ + smart_str_0(&eval_buf); + + if (call_user_function_ex(EG(function_table), NULL, *arg_replace_zval, &retval_ptr, 1, args, 0, + NULL TSRMLS_CC) == SUCCESS && retval_ptr) { + convert_to_string_ex(&retval_ptr); + smart_str_appendl(&out_buf, Z_STRVAL_P(retval_ptr), Z_STRLEN_P(retval_ptr)); + eval_buf.len = 0; + zval_ptr_dtor(&retval_ptr); + } else { + efree(description); + if (!EG(exception)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to call custom replacement function"); + } + } + zval_ptr_dtor(&subpats); } + n = regs->end[0]; if ((pos - (OnigUChar *)string) < n) { pos = (OnigUChar *)string + n; @@ -969,7 +1026,7 @@ static void _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAMETERS, OnigOp Replace regular expression for multibyte string */ PHP_FUNCTION(mb_ereg_replace) { - _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); + _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0); } /* }}} */ @@ -977,7 +1034,15 @@ PHP_FUNCTION(mb_ereg_replace) Case insensitive replace regular expression for multibyte string */ PHP_FUNCTION(mb_eregi_replace) { - _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, ONIG_OPTION_IGNORECASE); + _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, ONIG_OPTION_IGNORECASE, 0); +} +/* }}} */ + +/* {{{ proto string mb_ereg_replace_callback(string pattern, string callback, string string [, string option]) + regular expression for multibyte string using replacement callback */ +PHP_FUNCTION(mb_ereg_replace_callback) +{ + _php_mb_regex_ereg_replace_exec(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1); } /* }}} */ diff --git a/ext/mbstring/php_mbregex.h b/ext/mbstring/php_mbregex.h index f7751ff5a4f..8384fb722e9 100644 --- a/ext/mbstring/php_mbregex.h +++ b/ext/mbstring/php_mbregex.h @@ -34,6 +34,7 @@ PHP_FE(mb_eregi, arginfo_mb_eregi) \ PHP_FE(mb_ereg_replace, arginfo_mb_ereg_replace) \ PHP_FE(mb_eregi_replace, arginfo_mb_eregi_replace) \ + PHP_FE(mb_ereg_replace_callback, arginfo_mb_ereg_replace_callback) \ PHP_FE(mb_split, arginfo_mb_split) \ PHP_FE(mb_ereg_match, arginfo_mb_ereg_match) \ PHP_FE(mb_ereg_search, arginfo_mb_ereg_search) \ @@ -81,6 +82,7 @@ PHP_FUNCTION(mb_ereg); PHP_FUNCTION(mb_eregi); PHP_FUNCTION(mb_ereg_replace); PHP_FUNCTION(mb_eregi_replace); +PHP_FUNCTION(mb_ereg_replace_callback); PHP_FUNCTION(mb_split); PHP_FUNCTION(mb_ereg_match); PHP_FUNCTION(mb_ereg_search);