Commit:    2111ee3df54e890c9e2f14b09c01d68445389540
Author:    Gustavo Lopes <glo...@nebm.ist.utl.pt>         Wed, 9 Jan 2013 
00:33:14 +0100
Committer: Gustavo Lopes <gust...@icemobile.com>      Mon, 14 Jan 2013 12:22:41 
+0100
Parents:   ccf15cf2dc92d11f92ee30c97e2d86b07f81e030
Branches:  PHP-5.4 PHP-5.5 master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=2111ee3df54e890c9e2f14b09c01d68445389540

Log:
Refactoring, bugs & leaks

Changed paths:
  M  ext/standard/string.c


Diff:
diff --git a/ext/standard/string.c b/ext/standard/string.c
index dc92e8e..827f9de 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -2863,7 +2863,91 @@ static int php_strtr_compare_hash_suffix(const void *a, 
const void *b, void *ctx
                                        hash_b = 
php_strtr_hash(&S(&pnr_b->pat)[res->m - res->B], res->B)
                                                                & 
res->hash->table_mask;
        /* TODO: don't recalculate the hashes all the time */
-       return hash_a - hash_b;
+       if (hash_a > hash_b) {
+               return 1;
+       } else if (hash_a < hash_b) {
+               return -1;
+       } else {
+               /* longer patterns must be sorted first */
+               if (L(&pnr_a->pat) > L(&pnr_b->pat)) {
+                       return -1;
+               } else if (L(&pnr_a->pat) < L(&pnr_b->pat)) {
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+}
+/* }}} */
+/* {{{ php_strtr_free_strp */
+static void php_strtr_free_strp(void *strp)
+{
+       STR_FREE(*(char**)strp);
+}
+/* }}} */
+/* {{{ php_strtr_array_prepare_repls */
+static PATNREPL *php_strtr_array_prepare_repls(int slen, HashTable *pats, 
zend_llist **allocs, int *outsize)
+{
+       PATNREPL                *patterns;
+       HashPosition    hpos;
+       zval                    **entry;
+       int                             num_pats = zend_hash_num_elements(pats),
+                                       i;
+
+       patterns = safe_emalloc(num_pats, sizeof(*patterns), 0);
+       *allocs = emalloc(sizeof **allocs);
+       zend_llist_init(*allocs, sizeof(void*), &php_strtr_free_strp, 0);
+
+       for (i = 0, zend_hash_internal_pointer_reset_ex(pats, &hpos);
+                       zend_hash_get_current_data_ex(pats, (void **)&entry, 
&hpos) == SUCCESS;
+                       zend_hash_move_forward_ex(pats, &hpos)) {
+               char    *string_key;
+               uint    string_key_len;
+               ulong   num_key;
+               zval    *tzv = NULL;
+
+               switch (zend_hash_get_current_key_ex(pats, &string_key, 
&string_key_len, &num_key, 0, &hpos)) {
+               case HASH_KEY_IS_LONG:
+                       string_key_len = 1 + zend_spprintf(&string_key, 0, 
"%ld", (long)num_key);
+                       zend_llist_add_element(*allocs, &string_key);
+                       /* break missing intentionally */
+
+               case HASH_KEY_IS_STRING:
+                       string_key_len--; /* exclude final '\0' */
+                       if (string_key_len == 0) { /* empty string given as 
pattern */
+                               efree(patterns);
+                               zend_llist_destroy(*allocs);
+                               efree(*allocs);
+                               *allocs = NULL;
+                               return NULL;
+                       }
+                       if (string_key_len > slen) { /* this pattern can never 
match */
+                               continue;
+                       }
+
+                       if (Z_TYPE_PP(entry) != IS_STRING) {
+                               tzv = *entry;
+                               zval_addref_p(tzv);
+                               SEPARATE_ZVAL(&tzv);
+                               convert_to_string(tzv);
+                               entry = &tzv;
+                               zend_llist_add_element(*allocs, 
&Z_STRVAL_PP(entry));
+                       }
+
+                       S(&patterns[i].pat) = string_key;
+                       L(&patterns[i].pat) = string_key_len;
+                       S(&patterns[i].repl) = Z_STRVAL_PP(entry);
+                       L(&patterns[i].repl) = Z_STRLEN_PP(entry);
+                       i++;
+
+                       if (tzv) {
+                               efree(tzv);
+                       }
+               }
+       }
+
+       *outsize = i;
+       return patterns;
 }
 /* }}} */
 
@@ -2952,7 +3036,7 @@ static void php_strtr_array_do_repl(STR *text, PPRES *d, 
zval *return_value)
                STRLEN  shift   = d->shift->entries[h];
 
                if (shift > 0) {
-                       smart_str_appendl(&result, &S(text)[pos], shift);
+                       smart_str_appendl(&result, &S(text)[pos], MIN(shift, 
L(text) - pos));
                        pos += shift;
                } else {
                        HASH    h2                              = h & 
d->hash->table_mask,
@@ -2999,64 +3083,25 @@ end_outer_loop: ;
 /* {{{ php_strtr_array */
 static void php_strtr_array(zval *return_value, char *str, int slen, HashTable 
*pats)
 {      
-       PPRES                   *data;
-       STR                             text;
-       PATNREPL                *patterns;
-       HashPosition    hpos;
-       zval                    **entry;
-       int                             num_pats = zend_hash_num_elements(pats),
-                                       i;
+       PPRES           *data;
+       STR                     text;
+       PATNREPL        *patterns;
+       int                     patterns_len;
+       zend_llist      *allocs;
 
        S(&text) = str;
        L(&text) = slen;
-       patterns = safe_emalloc(num_pats, sizeof(*patterns), 0);
-
-       for (i = 0, zend_hash_internal_pointer_reset_ex(pats, &hpos);
-                       zend_hash_get_current_data_ex(pats, (void **)&entry, 
&hpos) == SUCCESS;
-                       i++, zend_hash_move_forward_ex(pats, &hpos)) {
-               char    *string_key;
-               uint    string_key_len;
-               ulong   num_key;
-               int             free_str = 0,
-                               free_repl = 0;
-               zval    *tzv;
-
-               switch (zend_hash_get_current_key_ex(pats, &string_key, 
&string_key_len, &num_key, 0, &hpos)) {
-               case HASH_KEY_IS_LONG:
-                       string_key_len = 1 + zend_spprintf(&string_key, 0, 
"%ld", (long)num_key);
-                       free_str = 1;
-                       /* break missing intentionally */
 
-               case HASH_KEY_IS_STRING:
-                       string_key_len--; /* exclude final '\0' */
-                       if (string_key_len == 0) { /* empty string given as 
pattern */
-                               efree(patterns);
-                               RETURN_FALSE;   
-                       }
-                       if (string_key_len > slen) { /* this pattern can never 
match */
-                               continue;
-                       }
-
-                       if (Z_TYPE_PP(entry) != IS_STRING) {
-                               tzv = *entry;
-                               zval_addref_p(tzv);
-                               SEPARATE_ZVAL(&tzv);
-                               convert_to_string(tzv);
-                               entry = &tzv;
-                               free_repl = 1;
-                       }
-
-                       S(&patterns[i].pat) = string_key;
-                       L(&patterns[i].pat) = string_key_len;
-                       S(&patterns[i].repl) = Z_STRVAL_PP(entry);
-                       L(&patterns[i].repl) = Z_STRLEN_PP(entry);
-               }
+       patterns = php_strtr_array_prepare_repls(slen, pats, &allocs, 
&patterns_len);
+       if (patterns == NULL) {
+               RETURN_FALSE;
        }
-
-       data = php_strtr_array_prepare(&text, patterns, i, 2, 2);
+       data = php_strtr_array_prepare(&text, patterns, patterns_len, 2, 2);
        efree(patterns);
        php_strtr_array_do_repl(&text, data, return_value);
        php_strtr_array_destroy_ppres(data);
+       zend_llist_destroy(allocs);
+       efree(allocs);
 }
 /* }}} */


--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to