⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 php_pcre.c

📁 php-4.4.7学习linux时下载的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
 */PHPAPI char *php_pcre_replace(char *regex,   int regex_len,							  char *subject, int subject_len,							  zval *replace_val, int is_callable_replace,							  int *result_len, int limit TSRMLS_DC){	pcre			*re = NULL;			/* Compiled regular expression */	pcre_extra		*extra = NULL;		/* Holds results of studying */	int			 	 exoptions = 0;		/* Execution options */	int			 	 preg_options = 0;	/* Custom preg options */	int			 	 count = 0;			/* Count of matched subpatterns */	int			 	*offsets;			/* Array of subpattern offsets */	int			 	 size_offsets;		/* Size of the offsets array */	int				 new_len;			/* Length of needed storage */	int				 alloc_len;			/* Actual allocated length */	int				 eval_result_len=0;	/* Length of the eval'ed or										   function-returned string */	int				 match_len;			/* Length of the current match */	int				 backref;			/* Backreference number */	int				 eval;				/* If the replacement string should be eval'ed */	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 */					*walkbuf,			/* Location of current replacement in the result */					*walk,				/* Used to walk the replacement string */					*match,				/* The current match */					*piece,				/* The current piece of subject */					*replace_end=NULL,	/* End of replacement string */					*eval_result,		/* Result of eval or custom function */					 walk_last;			/* Last walked character */	int				 rc;	/* Compile regex or get it from cache. */	if ((re = pcre_get_compiled_regex(regex, &extra, &preg_options)) == NULL) {		return NULL;	}	eval = preg_options & PREG_REPLACE_EVAL;	if (is_callable_replace) {		if (eval) {			php_error(E_WARNING, "/e modifier cannot be used with replacement callback");			return NULL;		}	} else {		replace = Z_STRVAL_P(replace_val);		replace_len = Z_STRLEN_P(replace_val);		replace_end = replace + replace_len;	}	/* Calculate the size of the offsets array, and allocate memory for it. */	rc = pcre_fullinfo(re, extra, PCRE_INFO_CAPTURECOUNT, &size_offsets);	if (rc < 0) {		php_error(E_WARNING, "%s: internal pcre_fullinfo() error %d",				  get_active_function_name(TSRMLS_C), rc);		return NULL;	}	size_offsets = (size_offsets + 1) * 3;	offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);		alloc_len = 2 * subject_len + 1;	result = safe_emalloc(alloc_len, sizeof(char), 0);	/* Initialize */	match = NULL;	*result_len = 0;	start_offset = 0;		while (1) {		/* Execute the regular expression. */		count = pcre_exec(re, extra, subject, subject_len, start_offset,						  exoptions|g_notempty, offsets, size_offsets);				/* Check for too many substrings condition. */		if (count == 0) {			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Matched, but too many substrings");			count = size_offsets/3;		}		piece = subject + start_offset;		if (count > 0 && (limit == -1 || limit > 0)) {			/* Set the match location in subject */			match = subject + offsets[0];			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) {				eval_result_len = preg_do_eval(replace, replace_len, subject,											   offsets, count, &eval_result TSRMLS_CC);				new_len += eval_result_len;			} else if (is_callable_replace) {				/* Use custom function to get replacement string and its length. */				eval_result_len = preg_do_repl_func(replace_val, subject, offsets,													count, &eval_result);				new_len += eval_result_len;			} else { /* do regular substitution */				walk = replace;				walk_last = 0;				while (walk < replace_end) {					if ('\\' == *walk || '$' == *walk) {						if (walk_last == '\\') {							walk++;							walk_last = 0;							continue;						}						if (preg_get_backref(&walk, &backref)) {							if (backref < count)								new_len += offsets[(backref<<1)+1] - offsets[backref<<1];							continue;						}					}					new_len++;					walk++;					walk_last = walk[-1];				}			}			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;			}			/* copy the part of the string before the match */			memcpy(&result[*result_len], piece, match-piece);			*result_len += match-piece;			/* copy replacement and backrefs */			walkbuf = result + *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;				STR_FREE(eval_result);			} else { /* do regular backreference copying */				walk = replace;				walk_last = 0;				while (walk < replace_end) {					if ('\\' == *walk || '$' == *walk) {						if (walk_last == '\\') {							*(walkbuf-1) = *walk++;							walk_last = 0;							continue;						}						if (preg_get_backref(&walk, &backref)) {							if (backref < count) {								match_len = offsets[(backref<<1)+1] - offsets[backref<<1];								memcpy(walkbuf, subject + offsets[backref<<1], match_len);								walkbuf += match_len;							}							continue;						}					}					*walkbuf++ = *walk++;					walk_last = walk[-1];				}				*walkbuf = '\0';				/* increment the result length by how much we've added to the string */				*result_len += walkbuf - (result + *result_len);			}			if (limit != -1)				limit--;		} else { /* Failed to match */			/* If we previously set PCRE_NOTEMPTY after a null match,			   this is not necessarily the end. We need to advance			   the start offset, and continue. Fudge the offset values			   to achieve this, unless we're already at the end of the string. */			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)++;			} 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;				}				/* 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';				break;			}		}					/* If we have matched an empty string, mimic what Perl's /g options does.		   This turns out to be rather cunning. First we set PCRE_NOTEMPTY and try		   the match again at the same point. If this fails (picked up above) we		   advance to the next character. */		g_notempty = (offsets[1] == offsets[0])? PCRE_NOTEMPTY | PCRE_ANCHORED : 0;				/* Advance to the next piece. */		start_offset = offsets[1];	}		efree(offsets);	return result;}/* }}} *//* {{{ php_replace_in_subject */static char *php_replace_in_subject(zval *regex, zval *replace, zval **subject, int *result_len, int limit, zend_bool is_callable_replace TSRMLS_DC){	zval		**regex_entry,				**replace_entry = NULL,				 *replace_value,				  empty_replace;	char		*subject_value,				*result;	int			 subject_len;	/* Make sure we're dealing with strings. */		convert_to_string_ex(subject);	ZVAL_STRINGL(&empty_replace, empty_string, 0, 0);		/* If regex is an array */	if (Z_TYPE_P(regex) == IS_ARRAY) {		/* Duplicate subject string for repeated replacement */		subject_value = estrndup(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject));		subject_len = Z_STRLEN_PP(subject);		*result_len = subject_len;				zend_hash_internal_pointer_reset(Z_ARRVAL_P(regex));		replace_value = replace;		if (Z_TYPE_P(replace) == IS_ARRAY && !is_callable_replace)			zend_hash_internal_pointer_reset(Z_ARRVAL_P(replace));		/* For each entry in the regex array, get the entry */		while (zend_hash_get_current_data(Z_ARRVAL_P(regex), (void **)&regex_entry) == SUCCESS) {			/* Make sure we're dealing with strings. */				convert_to_string_ex(regex_entry);					/* If replace is an array and not a callable construct */			if (Z_TYPE_P(replace) == IS_ARRAY && !is_callable_replace) {				/* Get current entry */				if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) {					if (!is_callable_replace) {						convert_to_string_ex(replace_entry);					}					replace_value = *replace_entry;					zend_hash_move_forward(Z_ARRVAL_P(replace));				} else {					/* We've run out of replacement strings, so use an empty one */					replace_value = &empty_replace;				}			}						/* Do the actual replacement and put the result back into subject_value			   for further replacements. */			if ((result = php_pcre_replace(Z_STRVAL_PP(regex_entry),										   Z_STRLEN_PP(regex_entry),										   subject_value,										   subject_len,										   replace_value,										   is_callable_replace,										   result_len,										   limit TSRMLS_CC)) != NULL) {				efree(subject_value);				subject_value = result;				subject_len = *result_len;			}						zend_hash_move_forward(Z_ARRVAL_P(regex));		}		return subject_value;	} else {		result = php_pcre_replace(Z_STRVAL_P(regex),								  Z_STRLEN_P(regex),							      Z_STRVAL_PP(subject),								  Z_STRLEN_PP(subject),								  replace,								  is_callable_replace,								  result_len,								  limit TSRMLS_CC);		return result;	}}/* }}} *//* {{{ preg_replace_impl */static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callable_replace){	zval		   **regex,				   **replace,				   **subject,				   **limit,				   **subject_entry;	char			*result;	int				 result_len;	int				 limit_val = -1;	char			*string_key;	ulong			 num_key;	char			*callback_name = NULL;		/* Get function parameters and do error-checking. */	if (ZEND_NUM_ARGS() < 3 || ZEND_NUM_ARGS() > 4 ||		zend_get_parameters_ex(ZEND_NUM_ARGS(), &regex, &replace, &subject, &limit) == FAILURE) {		WRONG_PARAM_COUNT;	}	if (!is_callable_replace && Z_TYPE_PP(replace) == IS_ARRAY && Z_TYPE_PP(regex) != IS_ARRAY) {		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Parameter mismatch, pattern is a string while replacement in an array.");		RETURN_FALSE;	}	SEPARATE_ZVAL(replace);	if (Z_TYPE_PP(replace) != IS_ARRAY)		convert_to_string_ex(replace);	if (is_callable_replace) {		if (!zend_is_callable(*replace, 0, &callback_name)) {			php_error(E_WARNING, "%s() requires argument 2, '%s', to be a valid callback",					  get_active_function_name(TSRMLS_C), callback_name);			efree(callback_name);			*return_value = **subject;			zval_copy_ctor(return_value);			return;		}		efree(callback_name);	}	SEPARATE_ZVAL(regex);	SEPARATE_ZVAL(subject);	if (ZEND_NUM_ARGS() > 3) {		convert_to_long_ex(limit);		limit_val = Z_LVAL_PP(limit);	}			if (Z_TYPE_PP(regex) != IS_ARRAY)		convert_to_string_ex(regex);		/* if subject is an array */	if (Z_TYPE_PP(subject) == IS_ARRAY) {		array_init(return_value);		zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject));		/* For each subject entry, convert it to string, then perform replacement		   and add the result to the return_value array. */		while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) {			SEPARATE_ZVAL(subject_entry);			if ((result = php_replace_in_subject(*regex, *replace, subject_entry, &result_len, limit_val, is_callable_replace TSRMLS_CC)) != NULL) {				/* Add to return array */				switch(zend_hash_get_current_key(Z_ARRVAL_PP(subject), &string_key, &num_key, 0))				{					case HASH_KEY_IS_STRING:						add_assoc_stringl(return_value, string_key, result, result_len, 0);						break;					case HASH_KEY_IS_LONG:						add_index_stringl(return_value, num_key, result, result_len, 0);						break;				}			}					zend_hash_move_forward(Z_ARRVAL_PP(subject));		}	}	else {	/* if subject is not an array */		if ((result = php_replace_in_subject(*regex, *replace, subject, &result_len, limit_val, is_callable_replace TSRMLS_CC)) != NULL) {			RETVAL_STRINGL(result, result_len, 0);		}	}	}/* }}} *//* {{{ proto string preg_replace(mixed regex, mixed replace, mixed subject [, int limit])   Perform Perl-style regular expression replacement. */PHP_FUNCTION(preg_replace){	preg_replace_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);}/* }}} *//* {{{ proto string preg_replace_callback(mixed regex, mixed callback, mixed subject [, int limit])   Perform Perl-style regular expression replacement using replacement callback. */PHP_FUNCTION(preg_replace_callback){	preg_replace_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);}/* }}} *//* {{{ proto array preg_split(string pattern, string subject [, int limit [, int flags]])    Split string into an array using a perl-style regular expression as a delimiter */PHP_FUNCTION(preg_split){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -