static char **make_subpats_table(int num_subpats, pcre_cache_entry *pce TSRMLS_DC)
{
pcre_extra *extra = pce->extra;
- int name_cnt = 0, name_size, ni = 0;
+ int name_cnt = pce->name_count, name_size, ni = 0;
int rc;
char *name_table;
unsigned short name_idx;
- char **subpat_names = (char **)ecalloc(num_subpats, sizeof(char *));
+ char **subpat_names;
+ int rc1, rc2;
- rc = pcre_fullinfo(pce->re, extra, PCRE_INFO_NAMECOUNT, &name_cnt);
+ rc1 = pcre_fullinfo(pce->re, extra, PCRE_INFO_NAMETABLE, &name_table);
+ rc2 = pcre_fullinfo(pce->re, extra, PCRE_INFO_NAMEENTRYSIZE, &name_size);
+ rc = rc2 ? rc2 : rc1;
if (rc < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
- efree(subpat_names);
return NULL;
}
- if (name_cnt > 0) {
- int rc1, rc2;
- rc1 = pcre_fullinfo(pce->re, extra, PCRE_INFO_NAMETABLE, &name_table);
- rc2 = pcre_fullinfo(pce->re, extra, PCRE_INFO_NAMEENTRYSIZE, &name_size);
- rc = rc2 ? rc2 : rc1;
- if (rc < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
+ subpat_names = (char **)ecalloc(num_subpats, sizeof(char *));
+ while (ni++ < name_cnt) {
+ name_idx = 0xff * (unsigned char)name_table[0] + (unsigned char)name_table[1];
+ subpat_names[name_idx] = name_table + 2;
+ if (is_numeric_string(subpat_names[name_idx], strlen(subpat_names[name_idx]), NULL, NULL, 0) > 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Numeric named subpatterns are not allowed");
efree(subpat_names);
return NULL;
}
-
- while (ni++ < name_cnt) {
- name_idx = 0xff * (unsigned char)name_table[0] + (unsigned char)name_table[1];
- subpat_names[name_idx] = name_table + 2;
- if (is_numeric_string(subpat_names[name_idx], strlen(subpat_names[name_idx]), NULL, NULL, 0) > 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Numeric named subpatterns are not allowed");
- efree(subpat_names);
- return NULL;
- }
- name_table += name_size;
- }
+ name_table += name_size;
}
-
return subpat_names;
}
/* }}} */
#endif
pcre_cache_entry *pce;
pcre_cache_entry new_entry;
+ int rc;
#if HAVE_SETLOCALE
# if defined(PHP_WIN32) && defined(ZTS)
* We use a quick pcre_fullinfo() check to see whether cache is corrupted, and if it
* is, we flush it and compile the pattern from scratch.
*/
- if (pcre_fullinfo(pce->re, NULL, PCRE_INFO_CAPTURECOUNT, &count) == PCRE_ERROR_BADMAGIC) {
- zend_hash_clean(&PCRE_G(pcre_cache));
- } else {
+//??? if (pcre_fullinfo(pce->re, NULL, PCRE_INFO_CAPTURECOUNT, &count) == PCRE_ERROR_BADMAGIC) {
+//??? zend_hash_clean(&PCRE_G(pcre_cache));
+//??? } else {
#if HAVE_SETLOCALE
if (!strcmp(pce->locale, locale)) {
#endif
#if HAVE_SETLOCALE
}
#endif
- }
+//??? }
}
p = regex->val;
new_entry.tables = tables;
#endif
+ rc = pcre_fullinfo(re, extra, PCRE_INFO_CAPTURECOUNT, &new_entry.capture_count);
+ if (rc < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
+ return NULL;
+ }
+
+ rc = pcre_fullinfo(re, extra, PCRE_INFO_NAMECOUNT, &new_entry.name_count);
+ if (rc < 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
+ return NULL;
+ }
+
/*
* Interned strings are not duplicated when stored in HashTable,
* but all the interned strings created during HTTP request are removed
{
zval match_pair;
- array_init(&match_pair);
+ array_init_size(&match_pair, 2);
/* Add (match, offset) to the return value */
add_next_index_stringl(&match_pair, str, len);
int offset_capture; /* Capture match offsets: yes/no */
unsigned char *mark = NULL; /* Target for MARK name */
zval marks; /* Array of marks for PREG_PATTERN_ORDER */
+ ALLOCA_FLAG(use_heap);
ZVAL_UNDEF(&marks);
#endif
/* Calculate the size of the offsets array, and allocate memory for it. */
- rc = pcre_fullinfo(pce->re, extra, PCRE_INFO_CAPTURECOUNT, &num_subpats);
- if (rc < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
- RETURN_FALSE;
- }
- num_subpats++;
+ num_subpats = pce->capture_count + 1;
size_offsets = num_subpats * 3;
/*
- * Build a mapping from subpattern numbers to their names. We will always
- * allocate the table, even though there may be no named subpatterns. This
- * avoids somewhat more complicated logic in the inner loops.
+ * Build a mapping from subpattern numbers to their names. We will
+ * allocate the table only if there are any named subpatterns.
*/
- subpat_names = make_subpats_table(num_subpats, pce TSRMLS_CC);
- if (!subpat_names) {
- RETURN_FALSE;
+ subpat_names = NULL;
+ if (pce->name_count > 0) {
+ subpat_names = make_subpats_table(num_subpats, pce TSRMLS_CC);
+ if (!subpat_names) {
+ RETURN_FALSE;
+ }
}
- offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
+ if (size_offsets <= 32) {
+ offsets = (int *)do_alloca(size_offsets * sizeof(int), use_heap);
+ } else {
+ offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
+ }
/* Allocate match sets array and initialize the values. */
if (global && subpats && subpats_order == PREG_PATTERN_ORDER) {
if (subpats != NULL) {
/* Try to get the list of substrings and display a warning if failed. */
if (pcre_get_substring_list(subject, offsets, count, &stringlist) < 0) {
- efree(subpat_names);
- efree(offsets);
+ if (subpat_names) {
+ efree(subpat_names);
+ }
+ if (size_offsets <= 32) {
+ free_alloca(offsets, use_heap);
+ } else {
+ efree(offsets);
+ }
if (match_sets) efree(match_sets);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Get subpatterns list failed");
RETURN_FALSE;
if (global) { /* global pattern matching */
if (subpats && subpats_order == PREG_PATTERN_ORDER) {
/* For each subpattern, insert it into the appropriate array. */
- for (i = 0; i < count; i++) {
- if (offset_capture) {
+ if (offset_capture) {
+ for (i = 0; i < count; i++) {
add_offset_pair(&match_sets[i], (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], NULL);
- } else {
+ }
+ } else {
+ for (i = 0; i < count; i++) {
add_next_index_stringl(&match_sets[i], (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1]);
}
}
} else {
/* Allocate the result set array */
- array_init(&result_set);
+ array_init_size(&result_set, count + (mark ? 1 : 0));
/* Add all the subpatterns to it */
- for (i = 0; i < count; i++) {
+ if (subpat_names) {
if (offset_capture) {
- add_offset_pair(&result_set, (char *)stringlist[i],
- offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], subpat_names[i]);
+ for (i = 0; i < count; i++) {
+ add_offset_pair(&result_set, (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], subpat_names[i]);
+ }
} else {
- if (subpat_names[i]) {
- add_assoc_stringl(&result_set, subpat_names[i], (char *)stringlist[i],
+ for (i = 0; i < count; i++) {
+ if (subpat_names[i]) {
+ add_assoc_stringl(&result_set, subpat_names[i], (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1]);
+ }
+ add_next_index_stringl(&result_set, (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1]);
+ }
+ }
+ } else {
+ if (offset_capture) {
+ for (i = 0; i < count; i++) {
+ add_offset_pair(&result_set, (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1], offsets[i<<1], NULL);
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ add_next_index_stringl(&result_set, (char *)stringlist[i],
offsets[(i<<1)+1] - offsets[i<<1]);
}
- add_next_index_stringl(&result_set, (char *)stringlist[i],
- offsets[(i<<1)+1] - offsets[i<<1]);
}
}
/* Add MARK, if available */
}
} else { /* single pattern matching */
/* For each subpattern, insert it into the subpatterns array. */
- for (i = 0; i < count; i++) {
+ if (subpat_names) {
+ if (offset_capture) {
+ for (i = 0; i < count; i++) {
+ add_offset_pair(subpats, (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1],
+ offsets[i<<1], subpat_names[i]);
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ if (subpat_names[i]) {
+ add_assoc_stringl(subpats, subpat_names[i], (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1]);
+ }
+ add_next_index_stringl(subpats, (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1]);
+ }
+ }
+ } else {
if (offset_capture) {
- add_offset_pair(subpats, (char *)stringlist[i],
- offsets[(i<<1)+1] - offsets[i<<1],
- offsets[i<<1], subpat_names[i]);
+ for (i = 0; i < count; i++) {
+ add_offset_pair(subpats, (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1],
+ offsets[i<<1], NULL);
+ }
} else {
- if (subpat_names[i]) {
- add_assoc_stringl(subpats, subpat_names[i], (char *)stringlist[i],
- offsets[(i<<1)+1] - offsets[i<<1]);
+ for (i = 0; i < count; i++) {
+ add_next_index_stringl(subpats, (char *)stringlist[i],
+ offsets[(i<<1)+1] - offsets[i<<1]);
}
- add_next_index_stringl(subpats, (char *)stringlist[i],
- offsets[(i<<1)+1] - offsets[i<<1]);
}
}
/* Add MARK, if available */
/* Add the match sets to the output array and clean up */
if (global && subpats && subpats_order == PREG_PATTERN_ORDER) {
- for (i = 0; i < num_subpats; i++) {
- if (subpat_names[i]) {
- zend_hash_str_update(Z_ARRVAL_P(subpats), subpat_names[i],
- strlen(subpat_names[i]), &match_sets[i]);
- Z_ADDREF(match_sets[i]);
+ if (subpat_names) {
+ for (i = 0; i < num_subpats; i++) {
+ if (subpat_names[i]) {
+ zend_hash_str_update(Z_ARRVAL_P(subpats), subpat_names[i],
+ strlen(subpat_names[i]), &match_sets[i]);
+ Z_ADDREF(match_sets[i]);
+ }
+ zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &match_sets[i]);
+ }
+ } else {
+ for (i = 0; i < num_subpats; i++) {
+ zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &match_sets[i]);
}
- zend_hash_next_index_insert(Z_ARRVAL_P(subpats), &match_sets[i]);
}
efree(match_sets);
}
}
- efree(offsets);
- efree(subpat_names);
+ if (size_offsets <= 32) {
+ free_alloca(offsets, use_heap);
+ } else {
+ efree(offsets);
+ }
+ if (subpat_names) {
+ efree(subpat_names);
+ }
/* Did we encounter an error? */
if (PCRE_G(error_code) == PHP_PCRE_NO_ERROR) {
zval args[1]; /* Argument to pass to function */
int i;
- array_init(&args[0]);
- for (i = 0; i < count; i++) {
- if (subpat_names[i]) {
- add_assoc_stringl(&args[0], subpat_names[i], &subject[offsets[i<<1]] , offsets[(i<<1)+1] - offsets[i<<1]);
+ array_init_size(&args[0], count + (mark ? 1 : 0));
+ if (subpat_names) {
+ for (i = 0; i < count; i++) {
+ if (subpat_names[i]) {
+ add_assoc_stringl(&args[0], subpat_names[i], &subject[offsets[i<<1]] , offsets[(i<<1)+1] - offsets[i<<1]);
+ }
+ add_next_index_stringl(&args[0], &subject[offsets[i<<1]], offsets[(i<<1)+1] - offsets[i<<1]);
+ }
+ } else {
+ for (i = 0; i < count; i++) {
+ add_next_index_stringl(&args[0], &subject[offsets[i<<1]], offsets[(i<<1)+1] - offsets[i<<1]);
}
- add_next_index_stringl(&args[0], &subject[offsets[i<<1]], offsets[(i<<1)+1] - offsets[i<<1]);
}
if (mark) {
add_assoc_string(&args[0], "MARK", (char *) mark);
unsigned char *mark = NULL; /* Target for MARK name */
zend_string *result; /* Result of replacement */
zend_string *eval_result=NULL; /* Result of eval or custom function */
+ ALLOCA_FLAG(use_heap);
if (extra == NULL) {
extra_data.flags = PCRE_EXTRA_MATCH_LIMIT | PCRE_EXTRA_MATCH_LIMIT_RECURSION;
}
/* Calculate the size of the offsets array, and allocate memory for it. */
- rc = pcre_fullinfo(pce->re, extra, PCRE_INFO_CAPTURECOUNT, &num_subpats);
- if (rc < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
- return NULL;
- }
- num_subpats++;
+ num_subpats = pce->capture_count + 1;
size_offsets = num_subpats * 3;
+ if (size_offsets <= 32) {
+ offsets = (int *)do_alloca(size_offsets * sizeof(int), use_heap);
+ } else {
+ offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
+ }
/*
- * Build a mapping from subpattern numbers to their names. We will always
- * allocate the table, even though there may be no named subpatterns. This
- * avoids somewhat more complicated logic in the inner loops.
+ * Build a mapping from subpattern numbers to their names. We will
+ * allocate the table only if there are any named subpatterns.
*/
- subpat_names = make_subpats_table(num_subpats, pce TSRMLS_CC);
- if (!subpat_names) {
- return NULL;
+ subpat_names = NULL;
+ if (pce->name_count > 0) {
+ subpat_names = make_subpats_table(num_subpats, pce TSRMLS_CC);
+ if (!subpat_names) {
+ return NULL;
+ }
}
- offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
-
alloc_len = 2 * subject_len;
result = STR_ALLOC(alloc_len * sizeof(char), 0);
if (result) {
result->len = result_len;
}
- efree(offsets);
- efree(subpat_names);
+ if (size_offsets <= 32) {
+ free_alloca(offsets, use_heap);
+ } else {
+ efree(offsets);
+ }
+ if (subpat_names) {
+ efree(subpat_names);
+ }
return result;
}
empty_replace;
zend_string *result;
zend_string *subject_str = zval_get_string(subject);
- HashPosition pos;
+ zend_uint replace_idx;
/* FIXME: This might need to be changed to STR_EMPTY_ALLOC(). Check if this zval could be dtor()'ed somehow */
ZVAL_EMPTY_STRING(&empty_replace);
/* If regex is an array */
if (Z_TYPE_P(regex) == IS_ARRAY) {
replace_value = replace;
- if (Z_TYPE_P(replace) == IS_ARRAY && !is_callable_replace)
- zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(replace), &pos);
+ replace_idx = 0;
/* For each entry in the regex array, get the entry */
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(regex), 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 ((replace_entry = zend_hash_get_current_data_ex(Z_ARRVAL_P(replace), &pos)) != NULL) {
+ replace_entry = NULL;
+ while (replace_idx < Z_ARRVAL_P(replace)->nNumUsed) {
+ if (Z_TYPE(Z_ARRVAL_P(replace)->arData[replace_idx].val) != IS_UNUSED) {
+ replace_entry = &Z_ARRVAL_P(replace)->arData[replace_idx].val;
+ break;
+ }
+ replace_idx++;
+ }
+ if (replace_entry != NULL) {
if (!is_callable_replace) {
convert_to_string_ex(replace_entry);
}
replace_value = replace_entry;
- zend_hash_move_forward_ex(Z_ARRVAL_P(replace), &pos);
+ replace_idx++;
} else {
/* We've run out of replacement strings, so use an empty one */
replace_value = &empty_replace;
/* if subject is an array */
if (Z_TYPE_P(subject) == IS_ARRAY) {
- array_init(return_value);
+ array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(subject)));
/* For each subject entry, convert it to string, then perform replacement
and add the result to the return_value array. */
int no_empty; /* If NO_EMPTY flag is set */
int delim_capture; /* If delimiters should be captured */
int offset_capture; /* If offsets should be captured */
+ ALLOCA_FLAG(use_heap);
no_empty = flags & PREG_SPLIT_NO_EMPTY;
delim_capture = flags & PREG_SPLIT_DELIM_CAPTURE;
array_init(return_value);
/* Calculate the size of the offsets array, and allocate memory for it. */
- rc = pcre_fullinfo(pce->re, extra, PCRE_INFO_CAPTURECOUNT, &size_offsets);
- if (rc < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
- RETURN_FALSE;
+ size_offsets = (pce->capture_count + 1) * 3;
+ if (size_offsets <= 32) {
+ offsets = (int *)do_alloca(size_offsets * sizeof(int), use_heap);
+ } else {
+ offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
}
- size_offsets = (size_offsets + 1) * 3;
- offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
/* Start at the beginning of the string */
start_offset = 0;
/* Clean up */
- efree(offsets);
+ if (size_offsets <= 32) {
+ free_alloca(offsets, use_heap);
+ } else {
+ efree(offsets);
+ }
}
/* }}} */
zend_bool invert; /* Whether to return non-matching
entries */
int rc;
+ ALLOCA_FLAG(use_heap);
invert = flags & PREG_GREP_INVERT ? 1 : 0;
#endif
/* Calculate the size of the offsets array, and allocate memory for it. */
- rc = pcre_fullinfo(pce->re, extra, PCRE_INFO_CAPTURECOUNT, &size_offsets);
- if (rc < 0) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal pcre_fullinfo() error %d", rc);
- RETURN_FALSE;
+ size_offsets = (pce->capture_count + 1) * 3;
+ if (size_offsets <= 32) {
+ offsets = (int *)do_alloca(size_offsets * sizeof(int), use_heap);
+ } else {
+ offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
}
- size_offsets = (size_offsets + 1) * 3;
- offsets = (int *)safe_emalloc(size_offsets, sizeof(int), 0);
/* Initialize return array */
array_init(return_value);
} ZEND_HASH_FOREACH_END();
/* Clean up */
- efree(offsets);
+ if (size_offsets <= 32) {
+ free_alloca(offsets, use_heap);
+ } else {
+ efree(offsets);
+ }
}
/* }}} */