PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/standard - string.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 2461 2570 95.8 %
Date: 2015-09-02 Functions: 114 114 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2015 The PHP Group                                |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 3.01 of the PHP license,      |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.php.net/license/3_01.txt                                  |
      11             :    | If you did not receive a copy of the PHP license and are unable to   |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@php.net so we can mail you a copy immediately.               |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
      16             :    |          Stig S�ther Bakken <ssb@php.net>                          |
      17             :    |          Zeev Suraski <zeev@zend.com>                                |
      18             :    +----------------------------------------------------------------------+
      19             :  */
      20             : 
      21             : /* $Id$ */
      22             : 
      23             : /* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */
      24             : 
      25             : #include <stdio.h>
      26             : #include "php.h"
      27             : #include "php_rand.h"
      28             : #include "php_string.h"
      29             : #include "php_variables.h"
      30             : #ifdef HAVE_LOCALE_H
      31             : # include <locale.h>
      32             : #endif
      33             : #ifdef HAVE_LANGINFO_H
      34             : # include <langinfo.h>
      35             : #endif
      36             : #ifdef HAVE_MONETARY_H
      37             : # include <monetary.h>
      38             : #endif
      39             : /*
      40             :  * This define is here because some versions of libintl redefine setlocale
      41             :  * to point to libintl_setlocale.  That's a ridiculous thing to do as far
      42             :  * as I am concerned, but with this define and the subsequent undef we
      43             :  * limit the damage to just the actual setlocale() call in this file
      44             :  * without turning zif_setlocale into zif_libintl_setlocale.  -Rasmus
      45             :  */
      46             : #define php_my_setlocale setlocale
      47             : #ifdef HAVE_LIBINTL
      48             : # include <libintl.h> /* For LC_MESSAGES */
      49             :  #ifdef setlocale
      50             :  # undef setlocale
      51             :  #endif
      52             : #endif
      53             : 
      54             : #include "scanf.h"
      55             : #include "zend_API.h"
      56             : #include "zend_execute.h"
      57             : #include "php_globals.h"
      58             : #include "basic_functions.h"
      59             : #include "zend_smart_str.h"
      60             : #include <Zend/zend_exceptions.h>
      61             : #ifdef ZTS
      62             : #include "TSRM.h"
      63             : #endif
      64             : 
      65             : /* For str_getcsv() support */
      66             : #include "ext/standard/file.h"
      67             : 
      68             : #define STR_PAD_LEFT                    0
      69             : #define STR_PAD_RIGHT                   1
      70             : #define STR_PAD_BOTH                    2
      71             : #define PHP_PATHINFO_DIRNAME    1
      72             : #define PHP_PATHINFO_BASENAME   2
      73             : #define PHP_PATHINFO_EXTENSION  4
      74             : #define PHP_PATHINFO_FILENAME   8
      75             : #define PHP_PATHINFO_ALL        (PHP_PATHINFO_DIRNAME | PHP_PATHINFO_BASENAME | PHP_PATHINFO_EXTENSION | PHP_PATHINFO_FILENAME)
      76             : 
      77             : #define STR_STRSPN                              0
      78             : #define STR_STRCSPN                             1
      79             : 
      80             : /* {{{ register_string_constants
      81             :  */
      82       21297 : void register_string_constants(INIT_FUNC_ARGS)
      83             : {
      84       21297 :         REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
      85       21297 :         REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
      86       21297 :         REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
      87       21297 :         REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
      88       21297 :         REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
      89       21297 :         REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
      90       21297 :         REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT);
      91             : 
      92             : #ifdef HAVE_LOCALECONV
      93             :         /* If last members of struct lconv equal CHAR_MAX, no grouping is done */
      94             : 
      95             : /* This is bad, but since we are going to be hardcoding in the POSIX stuff anyway... */
      96             : # ifndef HAVE_LIMITS_H
      97             : # define CHAR_MAX 127
      98             : # endif
      99             : 
     100       21297 :         REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
     101             : #endif
     102             : 
     103             : #ifdef HAVE_LOCALE_H
     104       21297 :         REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT);
     105       21297 :         REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT);
     106       21297 :         REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT);
     107       21297 :         REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT);
     108       21297 :         REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT);
     109       21297 :         REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT);
     110             : # ifdef LC_MESSAGES
     111       21297 :         REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
     112             : # endif
     113             : #endif
     114             : 
     115       21297 : }
     116             : /* }}} */
     117             : 
     118             : int php_tag_find(char *tag, size_t len, const char *set);
     119             : 
     120             : #ifdef PHP_WIN32
     121             : # define SET_ALIGNED(alignment, decl) __declspec(align(alignment)) decl
     122             : #elif HAVE_ATTRIBUTE_ALIGNED
     123             : # define SET_ALIGNED(alignment, decl) decl __attribute__ ((__aligned__ (alignment)))
     124             : #else
     125             : # define SET_ALIGNED(alignment, decl) decl
     126             : #endif
     127             : 
     128             : /* this is read-only, so it's ok */
     129             : SET_ALIGNED(16, static char hexconvtab[]) = "0123456789abcdef";
     130             : 
     131             : /* localeconv mutex */
     132             : #ifdef ZTS
     133             : static MUTEX_T locale_mutex = NULL;
     134             : #endif
     135             : 
     136             : /* {{{ php_bin2hex
     137             :  */
     138       22615 : static zend_string *php_bin2hex(const unsigned char *old, const size_t oldlen)
     139             : {
     140             :         zend_string *result;
     141             :         size_t i, j;
     142             : 
     143       22615 :         result = zend_string_safe_alloc(oldlen, 2 * sizeof(char), 0, 0);
     144             : 
     145      142129 :         for (i = j = 0; i < oldlen; i++) {
     146      119514 :                 ZSTR_VAL(result)[j++] = hexconvtab[old[i] >> 4];
     147      119514 :                 ZSTR_VAL(result)[j++] = hexconvtab[old[i] & 15];
     148             :         }
     149       22615 :         ZSTR_VAL(result)[j] = '\0';
     150             : 
     151       22615 :         return result;
     152             : }
     153             : /* }}} */
     154             : 
     155             : /* {{{ php_hex2bin
     156             :  */
     157          95 : static zend_string *php_hex2bin(const unsigned char *old, const size_t oldlen)
     158             : {
     159          95 :         size_t target_length = oldlen >> 1;
     160          95 :         zend_string *str = zend_string_alloc(target_length, 0);
     161          95 :         unsigned char *ret = (unsigned char *)ZSTR_VAL(str);
     162             :         size_t i, j;
     163             : 
     164        2016 :         for (i = j = 0; i < target_length; i++) {
     165         915 :                 unsigned char c = old[j++];
     166         915 :                 unsigned char l = c & ~0x20;
     167         915 :                 int is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
     168             :                 unsigned char d;
     169             : 
     170             :                 /* basically (c >= '0' && c <= '9') || (l >= 'A' && l <= 'F') */ 
     171         915 :                 if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
     172         914 :                         d = (l - 0x10 - 0x27 * is_letter) << 4;
     173             :                 } else {
     174             :                         zend_string_free(str);
     175           1 :                         return NULL;
     176             :                 }
     177         914 :                 c = old[j++];
     178         914 :                 l = c & ~0x20;
     179         914 :                 is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
     180         914 :                 if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
     181         913 :                         d |= l - 0x10 - 0x27 * is_letter;
     182             :                 } else {
     183             :                         zend_string_free(str);
     184           1 :                         return NULL;
     185             :                 }
     186         913 :                 ret[i] = d;
     187             :         }
     188          93 :         ret[i] = '\0';
     189             : 
     190          93 :         return str;
     191             : }
     192             : /* }}} */
     193             : 
     194             : #ifdef HAVE_LOCALECONV
     195             : /* {{{ localeconv_r
     196             :  * glibc's localeconv is not reentrant, so lets make it so ... sorta */
     197          11 : PHPAPI struct lconv *localeconv_r(struct lconv *out)
     198             : {
     199             :         struct lconv *res;
     200             : 
     201             : # ifdef ZTS
     202             :         tsrm_mutex_lock( locale_mutex );
     203             : # endif
     204             : 
     205             : /*  cur->locinfo is struct __crt_locale_info which implementation is
     206             :         hidden in vc14. TODO revisit this and check if a workaround available
     207             :         and needed. */
     208             : #if defined(PHP_WIN32) && _MSC_VER < 1900 && defined(ZTS)
     209             :         {
     210             :                 /* Even with the enabled per thread locale, localeconv
     211             :                         won't check any locale change in the master thread. */
     212             :                 _locale_t cur = _get_current_locale();
     213             : 
     214             :                 res = cur->locinfo->lconv;
     215             :         }
     216             : #else
     217             :         /* localeconv doesn't return an error condition */
     218          11 :         res = localeconv();
     219             : #endif
     220             : 
     221          11 :         *out = *res;
     222             : 
     223             : # ifdef ZTS
     224             :         tsrm_mutex_unlock( locale_mutex );
     225             : # endif
     226             : 
     227          11 :         return out;
     228             : }
     229             : /* }}} */
     230             : 
     231             : # ifdef ZTS
     232             : /* {{{ PHP_MINIT_FUNCTION
     233             :  */
     234             : PHP_MINIT_FUNCTION(localeconv)
     235             : {
     236             :         locale_mutex = tsrm_mutex_alloc();
     237             :         return SUCCESS;
     238             : }
     239             : /* }}} */
     240             : 
     241             : /* {{{ PHP_MSHUTDOWN_FUNCTION
     242             :  */
     243             : PHP_MSHUTDOWN_FUNCTION(localeconv)
     244             : {
     245             :         tsrm_mutex_free( locale_mutex );
     246             :         locale_mutex = NULL;
     247             :         return SUCCESS;
     248             : }
     249             : /* }}} */
     250             : # endif
     251             : #endif
     252             : 
     253             : /* {{{ proto string bin2hex(string data)
     254             :    Converts the binary representation of data to hex */
     255       22621 : PHP_FUNCTION(bin2hex)
     256             : {
     257             :         zend_string *result;
     258             :         zend_string *data;
     259             : 
     260       22621 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &data) == FAILURE) {
     261           6 :                 return;
     262             :         }
     263             : 
     264       22615 :         result = php_bin2hex((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data));
     265             : 
     266       22615 :         if (!result) {
     267           0 :                 RETURN_FALSE;
     268             :         }
     269             : 
     270       22615 :         RETURN_STR(result);
     271             : }
     272             : /* }}} */
     273             : 
     274             : /* {{{ proto string hex2bin(string data)
     275             :    Converts the hex representation of data to binary */
     276          96 : PHP_FUNCTION(hex2bin)
     277             : {
     278             :         zend_string *result, *data;
     279             : 
     280          96 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &data) == FAILURE) {
     281           0 :                 return;
     282             :         }
     283             : 
     284          96 :         if (ZSTR_LEN(data) % 2 != 0) {
     285           1 :                 php_error_docref(NULL, E_WARNING, "Hexadecimal input string must have an even length");
     286           1 :                 RETURN_FALSE;
     287             :         }
     288             : 
     289          95 :         result = php_hex2bin((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data));
     290             : 
     291          95 :         if (!result) {
     292           2 :                 php_error_docref(NULL, E_WARNING, "Input string must be hexadecimal string");
     293           2 :                 RETURN_FALSE;
     294             :         }
     295             : 
     296          93 :         RETVAL_STR(result);
     297             : }
     298             : /* }}} */
     299             : 
     300       13045 : static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
     301             : {
     302             :         zend_string *s11, *s22;
     303       13045 :         zend_long start = 0, len = 0;
     304             : 
     305       13045 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|ll", &s11,
     306             :                                 &s22, &start, &len) == FAILURE) {
     307         144 :                 return;
     308             :         }
     309             : 
     310       12901 :         if (ZEND_NUM_ARGS() < 4) {
     311        4086 :                 len = ZSTR_LEN(s11);
     312             :         }
     313             : 
     314             :         /* look at substr() function for more information */
     315             : 
     316       12901 :         if (start < 0) {
     317        4336 :                 start += (zend_long)ZSTR_LEN(s11);
     318        4336 :                 if (start < 0) {
     319        2306 :                         start = 0;
     320             :                 }
     321        8565 :         } else if ((size_t)start > ZSTR_LEN(s11)) {
     322        2662 :                 RETURN_FALSE;
     323             :         }
     324             : 
     325       10239 :         if (len < 0) {
     326        2226 :                 len += (ZSTR_LEN(s11) - start);
     327        2226 :                 if (len < 0) {
     328        1285 :                         len = 0;
     329             :                 }
     330             :         }
     331             : 
     332       10239 :         if (len > (zend_long)ZSTR_LEN(s11) - start) {
     333        3430 :                 len = ZSTR_LEN(s11) - start;
     334             :         }
     335             : 
     336       10239 :         if(len == 0) {
     337        3624 :                 RETURN_LONG(0);
     338             :         }
     339             : 
     340        6615 :         if (behavior == STR_STRSPN) {
     341        3381 :                 RETURN_LONG(php_strspn(ZSTR_VAL(s11) + start /*str1_start*/,
     342             :                                                 ZSTR_VAL(s22) /*str2_start*/,
     343             :                                                 ZSTR_VAL(s11) + start + len /*str1_end*/,
     344             :                                                 ZSTR_VAL(s22) + ZSTR_LEN(s22) /*str2_end*/));
     345        3234 :         } else if (behavior == STR_STRCSPN) {
     346        3234 :                 RETURN_LONG(php_strcspn(ZSTR_VAL(s11) + start /*str1_start*/,
     347             :                                                 ZSTR_VAL(s22) /*str2_start*/,
     348             :                                                 ZSTR_VAL(s11) + start + len /*str1_end*/,
     349             :                                                 ZSTR_VAL(s22) + ZSTR_LEN(s22) /*str2_end*/));
     350             :         }
     351             : 
     352             : }
     353             : /* }}} */
     354             : 
     355             : /* {{{ proto int strspn(string str, string mask [, int start [, int len]])
     356             :    Finds length of initial segment consisting entirely of characters found in mask. If start or/and length is provided works like strspn(substr($s,$start,$len),$good_chars) */
     357        6718 : PHP_FUNCTION(strspn)
     358             : {
     359        6718 :         php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN);
     360        6718 : }
     361             : /* }}} */
     362             : 
     363             : /* {{{ proto int strcspn(string str, string mask [, int start [, int len]])
     364             :    Finds length of initial segment consisting entirely of characters not found in mask. If start or/and length is provide works like strcspn(substr($s,$start,$len),$bad_chars) */
     365        6327 : PHP_FUNCTION(strcspn)
     366             : {
     367        6327 :         php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN);
     368        6327 : }
     369             : /* }}} */
     370             : 
     371             : /* {{{ PHP_MINIT_FUNCTION(nl_langinfo) */
     372             : #if HAVE_NL_LANGINFO
     373       21297 : PHP_MINIT_FUNCTION(nl_langinfo)
     374             : {
     375             : #define REGISTER_NL_LANGINFO_CONSTANT(x)        REGISTER_LONG_CONSTANT(#x, x, CONST_CS | CONST_PERSISTENT)
     376             : #ifdef ABDAY_1
     377       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
     378       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
     379       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
     380       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
     381       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
     382       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
     383       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
     384             : #endif
     385             : #ifdef DAY_1
     386       21297 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
     387       21297 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
     388       21297 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
     389       21297 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
     390       21297 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
     391       21297 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
     392       21297 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
     393             : #endif
     394             : #ifdef ABMON_1
     395       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
     396       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
     397       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
     398       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
     399       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
     400       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
     401       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
     402       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
     403       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
     404       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
     405       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
     406       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
     407             : #endif
     408             : #ifdef MON_1
     409       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_1);
     410       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_2);
     411       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_3);
     412       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_4);
     413       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_5);
     414       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_6);
     415       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_7);
     416       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_8);
     417       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_9);
     418       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_10);
     419       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_11);
     420       21297 :         REGISTER_NL_LANGINFO_CONSTANT(MON_12);
     421             : #endif
     422             : #ifdef AM_STR
     423       21297 :         REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
     424             : #endif
     425             : #ifdef PM_STR
     426       21297 :         REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
     427             : #endif
     428             : #ifdef D_T_FMT
     429       21297 :         REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
     430             : #endif
     431             : #ifdef D_FMT
     432       21297 :         REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
     433             : #endif
     434             : #ifdef T_FMT
     435       21297 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
     436             : #endif
     437             : #ifdef T_FMT_AMPM
     438       21297 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
     439             : #endif
     440             : #ifdef ERA
     441       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ERA);
     442             : #endif
     443             : #ifdef ERA_YEAR
     444             :         REGISTER_NL_LANGINFO_CONSTANT(ERA_YEAR);
     445             : #endif
     446             : #ifdef ERA_D_T_FMT
     447       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
     448             : #endif
     449             : #ifdef ERA_D_FMT
     450       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
     451             : #endif
     452             : #ifdef ERA_T_FMT
     453       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
     454             : #endif
     455             : #ifdef ALT_DIGITS
     456       21297 :         REGISTER_NL_LANGINFO_CONSTANT(ALT_DIGITS);
     457             : #endif
     458             : #ifdef INT_CURR_SYMBOL
     459             :         REGISTER_NL_LANGINFO_CONSTANT(INT_CURR_SYMBOL);
     460             : #endif
     461             : #ifdef CURRENCY_SYMBOL
     462             :         REGISTER_NL_LANGINFO_CONSTANT(CURRENCY_SYMBOL);
     463             : #endif
     464             : #ifdef CRNCYSTR
     465       21297 :         REGISTER_NL_LANGINFO_CONSTANT(CRNCYSTR);
     466             : #endif
     467             : #ifdef MON_DECIMAL_POINT
     468             :         REGISTER_NL_LANGINFO_CONSTANT(MON_DECIMAL_POINT);
     469             : #endif
     470             : #ifdef MON_THOUSANDS_SEP
     471             :         REGISTER_NL_LANGINFO_CONSTANT(MON_THOUSANDS_SEP);
     472             : #endif
     473             : #ifdef MON_GROUPING
     474             :         REGISTER_NL_LANGINFO_CONSTANT(MON_GROUPING);
     475             : #endif
     476             : #ifdef POSITIVE_SIGN
     477             :         REGISTER_NL_LANGINFO_CONSTANT(POSITIVE_SIGN);
     478             : #endif
     479             : #ifdef NEGATIVE_SIGN
     480             :         REGISTER_NL_LANGINFO_CONSTANT(NEGATIVE_SIGN);
     481             : #endif
     482             : #ifdef INT_FRAC_DIGITS
     483             :         REGISTER_NL_LANGINFO_CONSTANT(INT_FRAC_DIGITS);
     484             : #endif
     485             : #ifdef FRAC_DIGITS
     486             :         REGISTER_NL_LANGINFO_CONSTANT(FRAC_DIGITS);
     487             : #endif
     488             : #ifdef P_CS_PRECEDES
     489             :         REGISTER_NL_LANGINFO_CONSTANT(P_CS_PRECEDES);
     490             : #endif
     491             : #ifdef P_SEP_BY_SPACE
     492             :         REGISTER_NL_LANGINFO_CONSTANT(P_SEP_BY_SPACE);
     493             : #endif
     494             : #ifdef N_CS_PRECEDES
     495             :         REGISTER_NL_LANGINFO_CONSTANT(N_CS_PRECEDES);
     496             : #endif
     497             : #ifdef N_SEP_BY_SPACE
     498             :         REGISTER_NL_LANGINFO_CONSTANT(N_SEP_BY_SPACE);
     499             : #endif
     500             : #ifdef P_SIGN_POSN
     501             :         REGISTER_NL_LANGINFO_CONSTANT(P_SIGN_POSN);
     502             : #endif
     503             : #ifdef N_SIGN_POSN
     504             :         REGISTER_NL_LANGINFO_CONSTANT(N_SIGN_POSN);
     505             : #endif
     506             : #ifdef DECIMAL_POINT
     507             :         REGISTER_NL_LANGINFO_CONSTANT(DECIMAL_POINT);
     508             : #endif
     509             : #ifdef RADIXCHAR
     510       21297 :         REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
     511             : #endif
     512             : #ifdef THOUSANDS_SEP
     513             :         REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
     514             : #endif
     515             : #ifdef THOUSEP
     516       21297 :         REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
     517             : #endif
     518             : #ifdef GROUPING
     519             :         REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
     520             : #endif
     521             : #ifdef YESEXPR
     522       21297 :         REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
     523             : #endif
     524             : #ifdef NOEXPR
     525       21297 :         REGISTER_NL_LANGINFO_CONSTANT(NOEXPR);
     526             : #endif
     527             : #ifdef YESSTR
     528             :         REGISTER_NL_LANGINFO_CONSTANT(YESSTR);
     529             : #endif
     530             : #ifdef NOSTR
     531             :         REGISTER_NL_LANGINFO_CONSTANT(NOSTR);
     532             : #endif
     533             : #ifdef CODESET
     534       21297 :         REGISTER_NL_LANGINFO_CONSTANT(CODESET);
     535             : #endif
     536             : #undef REGISTER_NL_LANGINFO_CONSTANT
     537       21297 :         return SUCCESS;
     538             : }
     539             : /* }}} */
     540             : 
     541             : /* {{{ proto string nl_langinfo(int item)
     542             :    Query language and locale information */
     543          15 : PHP_FUNCTION(nl_langinfo)
     544             : {
     545             :         zend_long item;
     546             :         char *value;
     547             : 
     548          15 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &item) == FAILURE) {
     549           7 :                 return;
     550             :         }
     551             : 
     552           8 :         switch(item) { /* {{{ */
     553             : #ifdef ABDAY_1
     554             :                 case ABDAY_1:
     555             :                 case ABDAY_2:
     556             :                 case ABDAY_3:
     557             :                 case ABDAY_4:
     558             :                 case ABDAY_5:
     559             :                 case ABDAY_6:
     560             :                 case ABDAY_7:
     561             : #endif
     562             : #ifdef DAY_1
     563             :                 case DAY_1:
     564             :                 case DAY_2:
     565             :                 case DAY_3:
     566             :                 case DAY_4:
     567             :                 case DAY_5:
     568             :                 case DAY_6:
     569             :                 case DAY_7:
     570             : #endif
     571             : #ifdef ABMON_1
     572             :                 case ABMON_1:
     573             :                 case ABMON_2:
     574             :                 case ABMON_3:
     575             :                 case ABMON_4:
     576             :                 case ABMON_5:
     577             :                 case ABMON_6:
     578             :                 case ABMON_7:
     579             :                 case ABMON_8:
     580             :                 case ABMON_9:
     581             :                 case ABMON_10:
     582             :                 case ABMON_11:
     583             :                 case ABMON_12:
     584             : #endif
     585             : #ifdef MON_1
     586             :                 case MON_1:
     587             :                 case MON_2:
     588             :                 case MON_3:
     589             :                 case MON_4:
     590             :                 case MON_5:
     591             :                 case MON_6:
     592             :                 case MON_7:
     593             :                 case MON_8:
     594             :                 case MON_9:
     595             :                 case MON_10:
     596             :                 case MON_11:
     597             :                 case MON_12:
     598             : #endif
     599             : #ifdef AM_STR
     600             :                 case AM_STR:
     601             : #endif
     602             : #ifdef PM_STR
     603             :                 case PM_STR:
     604             : #endif
     605             : #ifdef D_T_FMT
     606             :                 case D_T_FMT:
     607             : #endif
     608             : #ifdef D_FMT
     609             :                 case D_FMT:
     610             : #endif
     611             : #ifdef T_FMT
     612             :                 case T_FMT:
     613             : #endif
     614             : #ifdef T_FMT_AMPM
     615             :                 case T_FMT_AMPM:
     616             : #endif
     617             : #ifdef ERA
     618             :                 case ERA:
     619             : #endif
     620             : #ifdef ERA_YEAR
     621             :                 case ERA_YEAR:
     622             : #endif
     623             : #ifdef ERA_D_T_FMT
     624             :                 case ERA_D_T_FMT:
     625             : #endif
     626             : #ifdef ERA_D_FMT
     627             :                 case ERA_D_FMT:
     628             : #endif
     629             : #ifdef ERA_T_FMT
     630             :                 case ERA_T_FMT:
     631             : #endif
     632             : #ifdef ALT_DIGITS
     633             :                 case ALT_DIGITS:
     634             : #endif
     635             : #ifdef INT_CURR_SYMBOL
     636             :                 case INT_CURR_SYMBOL:
     637             : #endif
     638             : #ifdef CURRENCY_SYMBOL
     639             :                 case CURRENCY_SYMBOL:
     640             : #endif
     641             : #ifdef CRNCYSTR
     642             :                 case CRNCYSTR:
     643             : #endif
     644             : #ifdef MON_DECIMAL_POINT
     645             :                 case MON_DECIMAL_POINT:
     646             : #endif
     647             : #ifdef MON_THOUSANDS_SEP
     648             :                 case MON_THOUSANDS_SEP:
     649             : #endif
     650             : #ifdef MON_GROUPING
     651             :                 case MON_GROUPING:
     652             : #endif
     653             : #ifdef POSITIVE_SIGN
     654             :                 case POSITIVE_SIGN:
     655             : #endif
     656             : #ifdef NEGATIVE_SIGN
     657             :                 case NEGATIVE_SIGN:
     658             : #endif
     659             : #ifdef INT_FRAC_DIGITS
     660             :                 case INT_FRAC_DIGITS:
     661             : #endif
     662             : #ifdef FRAC_DIGITS
     663             :                 case FRAC_DIGITS:
     664             : #endif
     665             : #ifdef P_CS_PRECEDES
     666             :                 case P_CS_PRECEDES:
     667             : #endif
     668             : #ifdef P_SEP_BY_SPACE
     669             :                 case P_SEP_BY_SPACE:
     670             : #endif
     671             : #ifdef N_CS_PRECEDES
     672             :                 case N_CS_PRECEDES:
     673             : #endif
     674             : #ifdef N_SEP_BY_SPACE
     675             :                 case N_SEP_BY_SPACE:
     676             : #endif
     677             : #ifdef P_SIGN_POSN
     678             :                 case P_SIGN_POSN:
     679             : #endif
     680             : #ifdef N_SIGN_POSN
     681             :                 case N_SIGN_POSN:
     682             : #endif
     683             : #ifdef DECIMAL_POINT
     684             :                 case DECIMAL_POINT:
     685             : #elif defined(RADIXCHAR)
     686             :                 case RADIXCHAR:
     687             : #endif
     688             : #ifdef THOUSANDS_SEP
     689             :                 case THOUSANDS_SEP:
     690             : #elif defined(THOUSEP)
     691             :                 case THOUSEP:
     692             : #endif
     693             : #ifdef GROUPING
     694             :                 case GROUPING:
     695             : #endif
     696             : #ifdef YESEXPR
     697             :                 case YESEXPR:
     698             : #endif
     699             : #ifdef NOEXPR
     700             :                 case NOEXPR:
     701             : #endif
     702             : #ifdef YESSTR
     703             :                 case YESSTR:
     704             : #endif
     705             : #ifdef NOSTR
     706             :                 case NOSTR:
     707             : #endif
     708             : #ifdef CODESET
     709             :                 case CODESET:
     710             : #endif
     711           5 :                         break;
     712             :                 default:
     713           3 :                         php_error_docref(NULL, E_WARNING, "Item '" ZEND_LONG_FMT "' is not valid", item);
     714           3 :                         RETURN_FALSE;
     715             :         }
     716             :         /* }}} */
     717             : 
     718           5 :         value = nl_langinfo(item);
     719           5 :         if (value == NULL) {
     720           0 :                 RETURN_FALSE;
     721             :         } else {
     722          10 :                 RETURN_STRING(value);
     723             :         }
     724             : }
     725             : #endif
     726             : /* }}} */
     727             : 
     728             : #ifdef HAVE_STRCOLL
     729             : /* {{{ proto int strcoll(string str1, string str2)
     730             :    Compares two strings using the current locale */
     731           5 : PHP_FUNCTION(strcoll)
     732             : {
     733             :         zend_string *s1, *s2;
     734             : 
     735           5 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &s1, &s2) == FAILURE) {
     736           4 :                 return;
     737             :         }
     738             : 
     739           1 :         RETURN_LONG(strcoll((const char *) ZSTR_VAL(s1),
     740             :                             (const char *) ZSTR_VAL(s2)));
     741             : }
     742             : /* }}} */
     743             : #endif
     744             : 
     745             : /* {{{ php_charmask
     746             :  * Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
     747             :  * it needs to be incrementing.
     748             :  * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
     749             :  */
     750        2181 : static inline int php_charmask(unsigned char *input, size_t len, char *mask)
     751             : {
     752             :         unsigned char *end;
     753             :         unsigned char c;
     754        2181 :         int result = SUCCESS;
     755             : 
     756        2181 :         memset(mask, 0, 256);
     757        7401 :         for (end = input+len; input < end; input++) {
     758        5220 :                 c=*input;
     759        5278 :                 if ((input+3 < end) && input[1] == '.' && input[2] == '.'
     760          32 :                                 && input[3] >= c) {
     761          26 :                         memset(mask+c, 1, input[3] - c + 1);
     762          26 :                         input+=3;
     763        5194 :                 } else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
     764             :                         /* Error, try to be as helpful as possible:
     765             :                            (a range ending/starting with '.' won't be captured here) */
     766          15 :                         if (end-len >= input) { /* there was no 'left' char */
     767           3 :                                 php_error_docref(NULL, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
     768           3 :                                 result = FAILURE;
     769           3 :                                 continue;
     770             :                         }
     771          12 :                         if (input+2 >= end) { /* there is no 'right' char */
     772           3 :                                 php_error_docref(NULL, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
     773           3 :                                 result = FAILURE;
     774           3 :                                 continue;
     775             :                         }
     776           9 :                         if (input[-1] > input[2]) { /* wrong order */
     777           6 :                                 php_error_docref(NULL, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
     778           6 :                                 result = FAILURE;
     779           6 :                                 continue;
     780             :                         }
     781             :                         /* FIXME: better error (a..b..c is the only left possibility?) */
     782           3 :                         php_error_docref(NULL, E_WARNING, "Invalid '..'-range");
     783           3 :                         result = FAILURE;
     784           3 :                         continue;
     785             :                 } else {
     786        5179 :                         mask[c]=1;
     787             :                 }
     788             :         }
     789        2181 :         return result;
     790             : }
     791             : /* }}} */
     792             : 
     793             : /* {{{ php_trim()
     794             :  * mode 1 : trim left
     795             :  * mode 2 : trim right
     796             :  * mode 3 : trim left and right
     797             :  * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
     798             :  */
     799     1028465 : PHPAPI zend_string *php_trim(zend_string *str, char *what, size_t what_len, int mode)
     800             : {
     801     1028465 :         const char *c = ZSTR_VAL(str);
     802     1028465 :         size_t len = ZSTR_LEN(str);
     803             :         register size_t i;
     804     1028465 :         size_t trimmed = 0;
     805             :         char mask[256];
     806             : 
     807     1028465 :         if (what) {
     808         242 :                 if (what_len == 1) {
     809          34 :                         char p = *what;
     810          34 :                         if (mode & 1) {
     811          38 :                                 for (i = 0; i < len; i++) {
     812          19 :                                         if (c[i] == p) {
     813           8 :                                                 trimmed++;
     814             :                                         } else {
     815          11 :                                                 break;
     816             :                                         }
     817             :                                 }
     818          11 :                                 len -= trimmed;
     819          11 :                                 c += trimmed;
     820             :                         }
     821          34 :                         if (mode & 2) {
     822          28 :                                 if (len > 0) {
     823          28 :                                         i = len - 1;
     824             :                                         do {
     825          49 :                                                 if (c[i] == p) {
     826          23 :                                                         len--;
     827             :                                                 } else {
     828          26 :                                                         break;
     829             :                                                 }
     830          23 :                                         } while (i-- != 0);
     831             :                                 }
     832             :                         }
     833             :                 } else {
     834         208 :                         php_charmask((unsigned char*)what, what_len, mask);
     835             : 
     836         208 :                         if (mode & 1) {
     837         392 :                                 for (i = 0; i < len; i++) {
     838         184 :                                         if (mask[(unsigned char)c[i]]) {
     839          97 :                                                 trimmed++;
     840             :                                         } else {
     841          87 :                                                 break;
     842             :                                         }
     843             :                                 }
     844          99 :                                 len -= trimmed;
     845          99 :                                 c += trimmed;
     846             :                         }
     847         208 :                         if (mode & 2) {
     848         160 :                                 if (len > 0) {
     849         139 :                                         i = len - 1;
     850             :                                         do {
     851         331 :                                                 if (mask[(unsigned char)c[i]]) {
     852         199 :                                                         len--;
     853             :                                                 } else {
     854         132 :                                                         break;
     855             :                                                 }
     856         199 :                                         } while (i-- != 0);
     857             :                                 }
     858             :                         }
     859             :                 }
     860             :         } else {
     861     1028223 :                 if (mode & 1) {
     862     1034899 :                         for (i = 0; i < len; i++) {
     863      906969 :                                 if ((unsigned char)c[i] <= ' ' &&
     864       10463 :                                     (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v' || c[i] == '\0')) {
     865        6868 :                                         trimmed++;
     866             :                                 } else {
     867             :                                         break;
     868             :                                 }
     869             :                         }
     870     1028031 :                         len -= trimmed;
     871     1028031 :                         c += trimmed;
     872             :                 }
     873     1028223 :                 if (mode & 2) {
     874     1008816 :                         if (len > 0) {
     875      888783 :                                 i = len - 1;
     876             :                                 do {
     877     1041385 :                                         if ((unsigned char)c[i] <= ' ' &&
     878      101456 :                                             (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v' || c[i] == '\0')) {
     879       51149 :                                                 len--;
     880             :                                         } else {
     881             :                                                 break;
     882             :                                         }
     883       51149 :                                 } while (i-- != 0);
     884             :                         }
     885             :                 }
     886             :         }
     887             : 
     888     1028465 :         if (ZSTR_LEN(str) == len) {
     889      979210 :                 return zend_string_copy(str);
     890             :         } else {
     891       49255 :                 return zend_string_init(c, len, 0);
     892             :         }
     893             : }
     894             : /* }}} */
     895             : 
     896             : /* {{{ php_do_trim
     897             :  * Base for trim(), rtrim() and ltrim() functions.
     898             :  */
     899     1007176 : static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
     900             : {
     901             :         zend_string *str;
     902     1007176 :         zend_string *what = NULL;
     903             : 
     904             : #ifndef FAST_ZPP
     905             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S", &str, &what) == FAILURE) {
     906             :                 return;
     907             :         }
     908             : #else
     909     1007176 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     910     3021483 :                 Z_PARAM_STR(str)
     911     1007137 :                 Z_PARAM_OPTIONAL
     912     1007657 :                 Z_PARAM_STR(what)
     913     1007176 :         ZEND_PARSE_PARAMETERS_END();
     914             : #endif
     915             : 
     916     1007119 :         ZVAL_STR(return_value, php_trim(str, (what ? ZSTR_VAL(what) : NULL), (what ? ZSTR_LEN(what) : 0), mode));
     917             : }
     918             : /* }}} */
     919             : 
     920             : /* {{{ proto string trim(string str [, string character_mask])
     921             :    Strips whitespace from the beginning and end of a string */
     922      987371 : PHP_FUNCTION(trim)
     923             : {
     924      987371 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
     925      987371 : }
     926             : /* }}} */
     927             : 
     928             : /* {{{ proto string rtrim(string str [, string character_mask])
     929             :    Removes trailing whitespace */
     930         332 : PHP_FUNCTION(rtrim)
     931             : {
     932         332 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
     933         332 : }
     934             : /* }}} */
     935             : 
     936             : /* {{{ proto string ltrim(string str [, string character_mask])
     937             :    Strips whitespace from the beginning of a string */
     938       19473 : PHP_FUNCTION(ltrim)
     939             : {
     940       19473 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     941       19473 : }
     942             : /* }}} */
     943             : 
     944             : /* {{{ proto string wordwrap(string str [, int width [, string break [, boolean cut]]])
     945             :    Wraps buffer to selected number of characters using string break char */
     946         357 : PHP_FUNCTION(wordwrap)
     947             : {
     948             :         zend_string *text;
     949         357 :         char *breakchar = "\n";
     950         357 :         size_t newtextlen, chk, breakchar_len = 1;
     951             :         size_t alloced;
     952         357 :         zend_long current = 0, laststart = 0, lastspace = 0;
     953         357 :         zend_long linelength = 75;
     954         357 :         zend_bool docut = 0;
     955             :         zend_string *newtext;
     956             : 
     957         357 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|lsb", &text, &linelength, &breakchar, &breakchar_len, &docut) == FAILURE) {
     958         108 :                 return;
     959             :         }
     960             : 
     961         249 :         if (ZSTR_LEN(text) == 0) {
     962          40 :                 RETURN_EMPTY_STRING();
     963             :         }
     964             : 
     965         209 :         if (breakchar_len == 0) {
     966          25 :                 php_error_docref(NULL, E_WARNING, "Break string cannot be empty");
     967          25 :                 RETURN_FALSE;
     968             :         }
     969             : 
     970         184 :         if (linelength == 0 && docut) {
     971           8 :                 php_error_docref(NULL, E_WARNING, "Can't force cut when width is zero");
     972           8 :                 RETURN_FALSE;
     973             :         }
     974             : 
     975             :         /* Special case for a single-character break as it needs no
     976             :            additional storage space */
     977         176 :         if (breakchar_len == 1 && !docut) {
     978         100 :                 newtext = zend_string_init(ZSTR_VAL(text), ZSTR_LEN(text), 0);
     979             : 
     980          50 :                 laststart = lastspace = 0;
     981        1009 :                 for (current = 0; current < ZSTR_LEN(text); current++) {
     982         959 :                         if (ZSTR_VAL(text)[current] == breakchar[0]) {
     983           4 :                                 laststart = lastspace = current + 1;
     984         955 :                         } else if (ZSTR_VAL(text)[current] == ' ') {
     985          72 :                                 if (current - laststart >= linelength) {
     986          30 :                                         ZSTR_VAL(newtext)[current] = breakchar[0];
     987          30 :                                         laststart = current + 1;
     988             :                                 }
     989          72 :                                 lastspace = current;
     990         883 :                         } else if (current - laststart >= linelength && laststart != lastspace) {
     991         220 :                                 ZSTR_VAL(newtext)[lastspace] = breakchar[0];
     992         220 :                                 laststart = lastspace + 1;
     993             :                         }
     994             :                 }
     995             : 
     996          50 :                 RETURN_NEW_STR(newtext);
     997             :         } else {
     998             :                 /* Multiple character line break or forced cut */
     999         126 :                 if (linelength > 0) {
    1000         102 :                         chk = (size_t)(ZSTR_LEN(text)/linelength + 1);
    1001         204 :                         newtext = zend_string_alloc(chk * breakchar_len + ZSTR_LEN(text), 0);
    1002         102 :                         alloced = ZSTR_LEN(text) + chk * breakchar_len + 1;
    1003             :                 } else {
    1004          24 :                         chk = ZSTR_LEN(text);
    1005          24 :                         alloced = ZSTR_LEN(text) * (breakchar_len + 1) + 1;
    1006          48 :                         newtext = zend_string_alloc(ZSTR_LEN(text) * (breakchar_len + 1), 0);
    1007             :                 }
    1008             : 
    1009             :                 /* now keep track of the actual new text length */
    1010         126 :                 newtextlen = 0;
    1011             : 
    1012         126 :                 laststart = lastspace = 0;
    1013        2742 :                 for (current = 0; current < ZSTR_LEN(text); current++) {
    1014        2616 :                         if (chk <= 0) {
    1015           6 :                                 alloced += (size_t) (((ZSTR_LEN(text) - current + 1)/linelength + 1) * breakchar_len) + 1;
    1016           6 :                                 newtext = zend_string_extend(newtext, alloced, 0);
    1017           6 :                                 chk = (size_t) ((ZSTR_LEN(text) - current)/linelength) + 1;
    1018             :                         }
    1019             :                         /* when we hit an existing break, copy to new buffer, and
    1020             :                          * fix up laststart and lastspace */
    1021        7902 :                         if (ZSTR_VAL(text)[current] == breakchar[0]
    1022        5252 :                                 && current + breakchar_len < ZSTR_LEN(text)
    1023          40 :                                 && !strncmp(ZSTR_VAL(text) + current, breakchar, breakchar_len)) {
    1024          14 :                                 memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart + breakchar_len);
    1025          14 :                                 newtextlen += current - laststart + breakchar_len;
    1026          14 :                                 current += breakchar_len - 1;
    1027          14 :                                 laststart = lastspace = current + 1;
    1028          14 :                                 chk--;
    1029             :                         }
    1030             :                         /* if it is a space, check if it is at the line boundary,
    1031             :                          * copy and insert a break, or just keep track of it */
    1032        2602 :                         else if (ZSTR_VAL(text)[current] == ' ') {
    1033         214 :                                 if (current - laststart >= linelength) {
    1034          85 :                                         memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
    1035          85 :                                         newtextlen += current - laststart;
    1036          85 :                                         memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
    1037          85 :                                         newtextlen += breakchar_len;
    1038          85 :                                         laststart = current + 1;
    1039          85 :                                         chk--;
    1040             :                                 }
    1041         214 :                                 lastspace = current;
    1042             :                         }
    1043             :                         /* if we are cutting, and we've accumulated enough
    1044             :                          * characters, and we haven't see a space for this line,
    1045             :                          * copy and insert a break. */
    1046        5898 :                         else if (current - laststart >= linelength
    1047        3342 :                                         && docut && laststart >= lastspace) {
    1048         168 :                                 memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
    1049         168 :                                 newtextlen += current - laststart;
    1050         168 :                                 memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
    1051         168 :                                 newtextlen += breakchar_len;
    1052         168 :                                 laststart = lastspace = current;
    1053         168 :                                 chk--;
    1054             :                         }
    1055             :                         /* if the current word puts us over the linelength, copy
    1056             :                          * back up until the last space, insert a break, and move
    1057             :                          * up the laststart */
    1058        4440 :                         else if (current - laststart >= linelength
    1059        2220 :                                         && laststart < lastspace) {
    1060         107 :                                 memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, lastspace - laststart);
    1061         107 :                                 newtextlen += lastspace - laststart;
    1062         107 :                                 memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
    1063         107 :                                 newtextlen += breakchar_len;
    1064         107 :                                 laststart = lastspace = lastspace + 1;
    1065         107 :                                 chk--;
    1066             :                         }
    1067             :                 }
    1068             : 
    1069             :                 /* copy over any stragglers */
    1070         126 :                 if (laststart != current) {
    1071         126 :                         memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
    1072         126 :                         newtextlen += current - laststart;
    1073             :                 }
    1074             : 
    1075         126 :                 ZSTR_VAL(newtext)[newtextlen] = '\0';
    1076             :                 /* free unused memory */
    1077         126 :                 newtext = zend_string_truncate(newtext, newtextlen, 0);
    1078             : 
    1079         126 :                 RETURN_NEW_STR(newtext);
    1080             :         }
    1081             : }
    1082             : /* }}} */
    1083             : 
    1084             : /* {{{ php_explode
    1085             :  */
    1086      569151 : PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
    1087             : {
    1088      569151 :         char *p1 = ZSTR_VAL(str);
    1089      569151 :         char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
    1090     1138302 :         char *p2 = (char *) php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
    1091             :         zval  tmp;
    1092             : 
    1093      569151 :         if (p2 == NULL) {
    1094         113 :                 ZVAL_STR_COPY(&tmp, str);
    1095         113 :                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1096             :         } else {
    1097             :                 do {
    1098     1157590 :                         ZVAL_STRINGL(&tmp, p1, p2 - p1);
    1099      578795 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1100      578795 :                         p1 = p2 + ZSTR_LEN(delim);
    1101     1157590 :                         p2 = (char *) php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
    1102      578795 :                 } while (p2 != NULL && --limit > 1);
    1103             : 
    1104      569038 :                 if (p1 <= endp) {
    1105     1138076 :                         ZVAL_STRINGL(&tmp, p1, endp - p1);
    1106      569038 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1107             :                 }
    1108             :         }
    1109      569151 : }
    1110             : /* }}} */
    1111             : 
    1112             : /* {{{ php_explode_negative_limit
    1113             :  */
    1114          23 : PHPAPI void php_explode_negative_limit(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
    1115             : {
    1116             : #define EXPLODE_ALLOC_STEP 64
    1117          23 :         char *p1 = ZSTR_VAL(str);
    1118          23 :         char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
    1119          46 :         char *p2 = (char *) php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
    1120             :         zval  tmp;
    1121             : 
    1122          23 :         if (p2 == NULL) {
    1123             :                 /*
    1124             :                 do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0
    1125             :                 by doing nothing we return empty array
    1126             :                 */
    1127             :         } else {
    1128          22 :                 size_t allocated = EXPLODE_ALLOC_STEP, found = 0;
    1129             :                 zend_long i, to_return;
    1130          22 :                 char **positions = emalloc(allocated * sizeof(char *));
    1131             : 
    1132          22 :                 positions[found++] = p1;
    1133             :                 do {
    1134         178 :                         if (found >= allocated) {
    1135           1 :                                 allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */
    1136           1 :                                 positions = erealloc(positions, allocated*sizeof(char *));
    1137             :                         }
    1138         178 :                         positions[found++] = p1 = p2 + ZSTR_LEN(delim);
    1139         356 :                         p2 = (char *) php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
    1140         178 :                 } while (p2 != NULL);
    1141             : 
    1142          22 :                 to_return = limit + found;
    1143             :                 /* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
    1144         181 :                 for (i = 0; i < to_return; i++) { /* this checks also for to_return > 0 */
    1145         318 :                         ZVAL_STRINGL(&tmp, positions[i], (positions[i+1] - ZSTR_LEN(delim)) - positions[i]);
    1146         159 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1147             :                 }
    1148          22 :                 efree(positions);
    1149             :         }
    1150             : #undef EXPLODE_ALLOC_STEP
    1151          23 : }
    1152             : /* }}} */
    1153             : 
    1154             : /* {{{ proto array explode(string separator, string str [, int limit])
    1155             :    Splits a string on string separator and return array of components. If limit is positive only limit number of components is returned. If limit is negative all components except the last abs(limit) are returned. */
    1156      569267 : PHP_FUNCTION(explode)
    1157             : {
    1158             :         zend_string *str, *delim;
    1159      569267 :         zend_long limit = ZEND_LONG_MAX; /* No limit */
    1160             :         zval tmp;
    1161             : 
    1162             : #ifndef FAST_ZPP
    1163             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|l", &delim, &str, &limit) == FAILURE) {
    1164             :                 return;
    1165             :         }
    1166             : #else
    1167      569267 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1168     1707786 :                 Z_PARAM_STR(delim)
    1169     1707759 :                 Z_PARAM_STR(str)
    1170      569249 :                 Z_PARAM_OPTIONAL
    1171     1505677 :                 Z_PARAM_LONG(limit)
    1172      569267 :         ZEND_PARSE_PARAMETERS_END();
    1173             : #endif
    1174             : 
    1175      569244 :         if (ZSTR_LEN(delim) == 0) {
    1176          28 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    1177          28 :                 RETURN_FALSE;
    1178             :         }
    1179             : 
    1180      569216 :         array_init(return_value);
    1181             : 
    1182      569216 :         if (ZSTR_LEN(str) == 0) {
    1183          12 :                 if (limit >= 0) {
    1184          11 :                         ZVAL_EMPTY_STRING(&tmp);
    1185          11 :                         zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
    1186             :                 }
    1187          12 :                 return;
    1188             :         }
    1189             : 
    1190      569204 :         if (limit > 1) {
    1191      569151 :                 php_explode(delim, str, return_value, limit);
    1192          53 :         } else if (limit < 0) {
    1193          23 :                 php_explode_negative_limit(delim, str, return_value, limit);
    1194             :         } else {
    1195          30 :                 ZVAL_STR_COPY(&tmp, str);
    1196          30 :                 zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
    1197             :         }
    1198             : }
    1199             : /* }}} */
    1200             : 
    1201             : /* {{{ proto string join(array src, string glue)
    1202             :    An alias for implode */
    1203             : /* }}} */
    1204             : 
    1205             : /* {{{ php_implode
    1206             :  */
    1207       91027 : PHPAPI void php_implode(const zend_string *delim, zval *arr, zval *return_value)
    1208             : {
    1209             :         zval         *tmp;
    1210             :         int           numelems;
    1211             :         zend_string  *str;
    1212             :         char         *cptr;
    1213       91027 :         size_t        len = 0;
    1214             :         zend_string **strings, **strptr;
    1215             : 
    1216       91027 :         numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
    1217             : 
    1218       91027 :         if (numelems == 0) {
    1219          49 :                 RETURN_EMPTY_STRING();
    1220       90978 :         } else if (numelems == 1) {
    1221             :                 /* loop to search the first not undefined element... */
    1222        1221 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
    1223         814 :                         RETURN_STR(zval_get_string(tmp));
    1224             :                 } ZEND_HASH_FOREACH_END();
    1225             :         }
    1226             : 
    1227       90571 :         strings = emalloc((sizeof(zend_long) + sizeof(zend_string *)) * numelems);
    1228       90571 :         strptr = strings - 1;
    1229             : 
    1230      819889 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
    1231      364637 :                 if (Z_TYPE_P(tmp) == IS_LONG) {
    1232      360727 :                         double val = Z_LVAL_P(tmp);
    1233      360727 :                         *++strptr = NULL;
    1234      360727 :                         ((zend_long *) (strings + numelems))[strptr - strings] = Z_LVAL_P(tmp);
    1235      360727 :                         if (val < 0) {
    1236          24 :                                 val = -10 * val;
    1237             :                         }
    1238      360727 :                         if (val < 10) {
    1239      360622 :                                 len++;
    1240             :                         } else {
    1241         105 :                                 len += (int) log10(10 * (double) val);
    1242             :                         }
    1243             :                 } else {
    1244        7820 :                         *++strptr = zval_get_string(tmp);
    1245        3910 :                         len += ZSTR_LEN(*strptr);
    1246             :                 }
    1247             :         } ZEND_HASH_FOREACH_END();
    1248             : 
    1249      181142 :         str = zend_string_alloc(len + (numelems - 1) * ZSTR_LEN(delim), 0);
    1250       90571 :         cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
    1251       90571 :         *cptr = 0;
    1252             : 
    1253             :         do {
    1254      274066 :                 if (*strptr) {
    1255        3393 :                         cptr -= ZSTR_LEN(*strptr);
    1256        3393 :                         memcpy(cptr, ZSTR_VAL(*strptr), ZSTR_LEN(*strptr));
    1257        3393 :                         zend_string_release(*strptr);
    1258             :                 } else {
    1259      270673 :                         char *oldPtr = cptr;
    1260      270673 :                         char oldVal = *cptr;
    1261      270673 :                         zend_long val = ((zend_long *) (strings + numelems))[strptr - strings];
    1262      270673 :                         cptr = zend_print_long_to_buf(cptr, val);
    1263      270673 :                         *oldPtr = oldVal;
    1264             :                 }
    1265             : 
    1266      274066 :                 cptr -= ZSTR_LEN(delim);
    1267      274066 :                 memcpy(cptr, ZSTR_VAL(delim), ZSTR_LEN(delim));
    1268      274066 :         } while (--strptr > strings);
    1269             : 
    1270       90571 :         if (*strptr) {
    1271         517 :                 memcpy(ZSTR_VAL(str), ZSTR_VAL(*strptr), ZSTR_LEN(*strptr));
    1272         517 :                 zend_string_release(*strptr);
    1273             :         } else {
    1274       90054 :                 char *oldPtr = cptr;
    1275       90054 :                 char oldVal = *cptr;
    1276       90054 :                 zend_print_long_to_buf(cptr, ((zend_long *) (strings + numelems))[strptr - strings]);
    1277       90054 :                 *oldPtr = oldVal;
    1278             :         }
    1279             : 
    1280       90571 :         efree(strings);
    1281       90571 :         RETURN_NEW_STR(str);
    1282             : }
    1283             : /* }}} */
    1284             : 
    1285             : /* {{{ proto string implode([string glue,] array pieces)
    1286             :    Joins array elements placing glue string between items and return one string */
    1287       91061 : PHP_FUNCTION(implode)
    1288             : {
    1289       91061 :         zval *arg1, *arg2 = NULL, *arr;
    1290             :         zend_string *delim;
    1291             : 
    1292             : #ifndef FAST_ZPP
    1293             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|z", &arg1, &arg2) == FAILURE) {
    1294             :                 return;
    1295             :         }
    1296             : #else
    1297       91061 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1298       91057 :                 Z_PARAM_ZVAL(arg1)
    1299       91057 :                 Z_PARAM_OPTIONAL
    1300       91057 :                 Z_PARAM_ZVAL(arg2)
    1301       91061 :         ZEND_PARSE_PARAMETERS_END();
    1302             : #endif
    1303             : 
    1304       91057 :         if (arg2 == NULL) {
    1305          18 :                 if (Z_TYPE_P(arg1) != IS_ARRAY) {
    1306           3 :                         php_error_docref(NULL, E_WARNING, "Argument must be an array");
    1307           3 :                         return;
    1308             :                 }
    1309             : 
    1310           6 :                 delim = ZSTR_EMPTY_ALLOC();
    1311           6 :                 arr = arg1;
    1312             :         } else {
    1313      182096 :                 if (Z_TYPE_P(arg1) == IS_ARRAY) {
    1314          74 :                         delim = zval_get_string(arg2);
    1315          37 :                         arr = arg1;
    1316      182022 :                 } else if (Z_TYPE_P(arg2) == IS_ARRAY) {
    1317      181968 :                         delim = zval_get_string(arg1);
    1318       90984 :                         arr = arg2;
    1319             :                 } else {
    1320          27 :                         php_error_docref(NULL, E_WARNING, "Invalid arguments passed");
    1321          27 :                         return;
    1322             :                 }
    1323             :         }
    1324             : 
    1325       91027 :         php_implode(delim, arr, return_value);
    1326             :         zend_string_release(delim);
    1327             : }
    1328             : /* }}} */
    1329             : 
    1330             : #define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
    1331             : 
    1332             : /* {{{ proto string strtok([string str,] string token)
    1333             :    Tokenize a string */
    1334         344 : PHP_FUNCTION(strtok)
    1335             : {
    1336         344 :         zend_string *str, *tok = NULL;
    1337             :         char *token;
    1338             :         char *token_end;
    1339             :         char *p;
    1340             :         char *pe;
    1341         344 :         size_t skipped = 0;
    1342             : 
    1343             : #ifndef FAST_ZPP
    1344             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|S", &str, &tok) == FAILURE) {
    1345             :                 return;
    1346             :         }
    1347             : #else
    1348         344 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1349        1026 :                 Z_PARAM_STR(str)
    1350         336 :                 Z_PARAM_OPTIONAL
    1351         526 :                 Z_PARAM_STR(tok)
    1352         344 :         ZEND_PARSE_PARAMETERS_END();
    1353             : #endif
    1354             : 
    1355         330 :         if (ZEND_NUM_ARGS() == 1) {
    1356         241 :                 tok = str;
    1357             :         } else {
    1358          89 :                 zval_ptr_dtor(&BG(strtok_zval));
    1359         178 :                 ZVAL_STRINGL(&BG(strtok_zval), ZSTR_VAL(str), ZSTR_LEN(str));
    1360          89 :                 BG(strtok_last) = BG(strtok_string) = Z_STRVAL(BG(strtok_zval));
    1361          89 :                 BG(strtok_len) = ZSTR_LEN(str);
    1362             :         }
    1363             : 
    1364         330 :         p = BG(strtok_last); /* Where we start to search */
    1365         330 :         pe = BG(strtok_string) + BG(strtok_len);
    1366             : 
    1367         330 :         if (!p || p >= pe) {
    1368         160 :                 RETURN_FALSE;
    1369             :         }
    1370             : 
    1371         170 :         token = ZSTR_VAL(tok);
    1372         170 :         token_end = token + ZSTR_LEN(tok);
    1373             : 
    1374         987 :         while (token < token_end) {
    1375         647 :                 STRTOK_TABLE(token++) = 1;
    1376             :         }
    1377             : 
    1378             :         /* Skip leading delimiters */
    1379         427 :         while (STRTOK_TABLE(p)) {
    1380          99 :                 if (++p >= pe) {
    1381             :                         /* no other chars left */
    1382          12 :                         BG(strtok_last) = NULL;
    1383          12 :                         RETVAL_FALSE;
    1384          12 :                         goto restore;
    1385             :                 }
    1386          87 :                 skipped++;
    1387             :         }
    1388             : 
    1389             :         /* We know at this place that *p is no delimiter, so skip it */
    1390        1487 :         while (++p < pe) {
    1391        1278 :                 if (STRTOK_TABLE(p)) {
    1392         107 :                         goto return_token;
    1393             :                 }
    1394             :         }
    1395             : 
    1396          51 :         if (p - BG(strtok_last)) {
    1397             : return_token:
    1398         316 :                 RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped);
    1399         158 :                 BG(strtok_last) = p + 1;
    1400             :         } else {
    1401           0 :                 RETVAL_FALSE;
    1402           0 :                 BG(strtok_last) = NULL;
    1403             :         }
    1404             : 
    1405             :         /* Restore table -- usually faster then memset'ing the table on every invocation */
    1406             : restore:
    1407         170 :         token = ZSTR_VAL(tok);
    1408             : 
    1409         987 :         while (token < token_end) {
    1410         647 :                 STRTOK_TABLE(token++) = 0;
    1411             :         }
    1412             : }
    1413             : /* }}} */
    1414             : 
    1415             : /* {{{ php_strtoupper
    1416             :  */
    1417        1053 : PHPAPI char *php_strtoupper(char *s, size_t len)
    1418             : {
    1419             :         unsigned char *c, *e;
    1420             : 
    1421        1053 :         c = (unsigned char *)s;
    1422        1053 :         e = (unsigned char *)c+len;
    1423             : 
    1424        6424 :         while (c < e) {
    1425        4318 :                 *c = toupper(*c);
    1426        4318 :                 c++;
    1427             :         }
    1428        1053 :         return s;
    1429             : }
    1430             : /* }}} */
    1431             : 
    1432             : /* {{{ php_string_toupper
    1433             :  */
    1434         617 : PHPAPI zend_string *php_string_toupper(zend_string *s)
    1435             : {
    1436             :         unsigned char *c, *e;
    1437             : 
    1438         617 :         c = (unsigned char *)ZSTR_VAL(s);
    1439         617 :         e = c + ZSTR_LEN(s);
    1440             : 
    1441        2178 :         while (c < e) {
    1442        1474 :                 if (!isupper(*c)) {
    1443             :                         register unsigned char *r;
    1444        1060 :                         zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
    1445             : 
    1446         530 :                         if (c != (unsigned char*)ZSTR_VAL(s)) {
    1447         201 :                                 memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
    1448             :                         }
    1449         530 :                         r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
    1450        5373 :                         while (c < e) {
    1451        4313 :                                 *r = toupper(*c);
    1452        4313 :                                 r++;
    1453        4313 :                                 c++;
    1454             :                         }
    1455         530 :                         *r = '\0';
    1456         530 :                         return res;
    1457             :                 }
    1458         944 :                 c++;
    1459             :         }
    1460          87 :         return zend_string_copy(s);
    1461             : }
    1462             : /* }}} */
    1463             : 
    1464             : /* {{{ proto string strtoupper(string str)
    1465             :    Makes a string uppercase */
    1466         454 : PHP_FUNCTION(strtoupper)
    1467             : {
    1468             :         zend_string *arg;
    1469             : 
    1470             : #ifndef FAST_ZPP
    1471             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
    1472             :                 return;
    1473             :         }
    1474             : #else
    1475         454 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1476        1356 :                 Z_PARAM_STR(arg)
    1477         454 :         ZEND_PARSE_PARAMETERS_END();
    1478             : #endif
    1479             : 
    1480         451 :         RETURN_STR(php_string_toupper(arg));
    1481             : }
    1482             : /* }}} */
    1483             : 
    1484             : /* {{{ php_strtolower
    1485             :  */
    1486      227033 : PHPAPI char *php_strtolower(char *s, size_t len)
    1487             : {
    1488             :         unsigned char *c, *e;
    1489             : 
    1490      227033 :         c = (unsigned char *)s;
    1491      227033 :         e = c+len;
    1492             : 
    1493     5765520 :         while (c < e) {
    1494     5311454 :                 *c = tolower(*c);
    1495     5311454 :                 c++;
    1496             :         }
    1497      227033 :         return s;
    1498             : }
    1499             : /* }}} */
    1500             : 
    1501             : /* {{{ php_string_tolower
    1502             :  */
    1503        2037 : PHPAPI zend_string *php_string_tolower(zend_string *s)
    1504             : {
    1505             :         unsigned char *c, *e;
    1506             : 
    1507        2037 :         c = (unsigned char *)ZSTR_VAL(s);
    1508        2037 :         e = c + ZSTR_LEN(s);
    1509             : 
    1510        6142 :         while (c < e) {
    1511        3767 :                 if (!islower(*c)) {
    1512             :                         register unsigned char *r;
    1513        3398 :                         zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
    1514             : 
    1515        1699 :                         if (c != (unsigned char*)ZSTR_VAL(s)) {
    1516         359 :                                 memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
    1517             :                         }
    1518        1699 :                         r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
    1519      106037 :                         while (c < e) {
    1520      102639 :                                 *r = tolower(*c);
    1521      102639 :                                 r++;
    1522      102639 :                                 c++;
    1523             :                         }
    1524        1699 :                         *r = '\0';
    1525        1699 :                         return res;
    1526             :                 }
    1527        2068 :                 c++;
    1528             :         }
    1529         338 :         return zend_string_copy(s);
    1530             : }
    1531             : /* }}} */
    1532             : 
    1533             : /* {{{ proto string strtolower(string str)
    1534             :    Makes a string lowercase */
    1535         363 : PHP_FUNCTION(strtolower)
    1536             : {
    1537             :         zend_string *str;
    1538             : 
    1539             : #ifndef FAST_ZPP
    1540             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    1541             :                 return;
    1542             :         }
    1543             : #else
    1544         363 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1545        1083 :                 Z_PARAM_STR(str)
    1546         363 :         ZEND_PARSE_PARAMETERS_END();
    1547             : #endif
    1548             : 
    1549         360 :         RETURN_STR(php_string_tolower(str));
    1550             : }
    1551             : /* }}} */
    1552             : 
    1553             : /* {{{ php_basename
    1554             :  */
    1555       16215 : PHPAPI zend_string *php_basename(const char *s, size_t len, char *suffix, size_t sufflen)
    1556             : {
    1557             :         char *c, *comp, *cend;
    1558             :         size_t inc_len, cnt;
    1559             :         int state;
    1560             :         zend_string *ret;
    1561             : 
    1562       16215 :         c = comp = cend = (char*)s;
    1563       16215 :         cnt = len;
    1564       16215 :         state = 0;
    1565      975411 :         while (cnt > 0) {
    1566      942981 :                 inc_len = (*c == '\0' ? 1 : php_mblen(c, cnt));
    1567             : 
    1568      942981 :                 switch (inc_len) {
    1569             :                         case -2:
    1570             :                         case -1:
    1571           1 :                                 inc_len = 1;
    1572           1 :                                 php_mb_reset();
    1573           1 :                                 break;
    1574             :                         case 0:
    1575           0 :                                 goto quit_loop;
    1576             :                         case 1:
    1577             : #if defined(PHP_WIN32) || defined(NETWARE)
    1578             :                                 if (*c == '/' || *c == '\\') {
    1579             : #else
    1580      942980 :                                 if (*c == '/') {
    1581             : #endif
    1582      106846 :                                         if (state == 1) {
    1583       91900 :                                                 state = 0;
    1584       91900 :                                                 cend = c;
    1585             :                                         }
    1586             : #if defined(PHP_WIN32) || defined(NETWARE)
    1587             :                                 /* Catch relative paths in c:file.txt style. They're not to confuse
    1588             :                                    with the NTFS streams. This part ensures also, that no drive
    1589             :                                    letter traversing happens. */
    1590             :                                 } else if ((*c == ':' && (c - comp == 1))) {
    1591             :                                         if (state == 0) {
    1592             :                                                 comp = c;
    1593             :                                                 state = 1;
    1594             :                                         } else {
    1595             :                                                 cend = c;
    1596             :                                                 state = 0;
    1597             :                                         }
    1598             : #endif
    1599             :                                 } else {
    1600      836134 :                                         if (state == 0) {
    1601      107878 :                                                 comp = c;
    1602      107878 :                                                 state = 1;
    1603             :                                         }
    1604             :                                 }
    1605      942980 :                                 break;
    1606             :                         default:
    1607           0 :                                 if (state == 0) {
    1608           0 :                                         comp = c;
    1609           0 :                                         state = 1;
    1610             :                                 }
    1611             :                                 break;
    1612             :                 }
    1613      942981 :                 c += inc_len;
    1614      942981 :                 cnt -= inc_len;
    1615             :         }
    1616             : 
    1617             : quit_loop:
    1618       16215 :         if (state == 1) {
    1619       15978 :                 cend = c;
    1620             :         }
    1621       30887 :         if (suffix != NULL && sufflen < (size_t)(cend - comp) &&
    1622       14672 :                         memcmp(cend - sufflen, suffix, sufflen) == 0) {
    1623       14587 :                 cend -= sufflen;
    1624             :         }
    1625             : 
    1626       16215 :         len = cend - comp;
    1627             : 
    1628       16215 :         ret = zend_string_init(comp, len, 0);
    1629       16215 :         return ret;
    1630             : }
    1631             : /* }}} */
    1632             : 
    1633             : /* {{{ proto string basename(string path [, string suffix])
    1634             :    Returns the filename component of the path */
    1635       15026 : PHP_FUNCTION(basename)
    1636             : {
    1637       15026 :         char *string, *suffix = NULL;
    1638       15026 :         size_t   string_len, suffix_len = 0;
    1639             : 
    1640       15026 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &string, &string_len, &suffix, &suffix_len) == FAILURE) {
    1641          30 :                 return;
    1642             :         }
    1643             : 
    1644       14996 :         RETURN_STR(php_basename(string, string_len, suffix, suffix_len));
    1645             : }
    1646             : /* }}} */
    1647             : 
    1648             : /* {{{ php_dirname
    1649             :    Returns directory name component of path */
    1650         462 : PHPAPI size_t php_dirname(char *path, size_t len)
    1651             : {
    1652         462 :         return zend_dirname(path, len);
    1653             : }
    1654             : /* }}} */
    1655             : 
    1656             : /* {{{ proto string dirname(string path[, int levels])
    1657             :    Returns the directory name component of the path */
    1658       24460 : PHP_FUNCTION(dirname)
    1659             : {
    1660             :         char *str;
    1661             :         size_t str_len;
    1662             :         zend_string *ret;
    1663       24460 :         zend_long levels = 1;
    1664             : 
    1665       24460 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &levels) == FAILURE) {
    1666           9 :                 return;
    1667             :         }
    1668             : 
    1669       48902 :         ret = zend_string_init(str, str_len, 0);
    1670             : 
    1671       24451 :         if (levels == 1) {
    1672             :                 /* Defaut case */
    1673       24445 :                 ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len);
    1674           6 :         } else if (levels < 1) {
    1675           2 :                 php_error_docref(NULL, E_WARNING, "Invalid argument, levels must be >= 1");
    1676             :                 zend_string_free(ret);
    1677           2 :                 return;
    1678             :         } else {
    1679             :                 /* Some levels up */
    1680             :                 do {
    1681          13 :                         ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len = ZSTR_LEN(ret));
    1682          13 :                 } while (ZSTR_LEN(ret) < str_len && --levels);
    1683             :         }
    1684             : 
    1685       24449 :         RETURN_NEW_STR(ret);
    1686             : }
    1687             : /* }}} */
    1688             : 
    1689             : /* {{{ proto array pathinfo(string path[, int options])
    1690             :    Returns information about a certain string */
    1691         615 : PHP_FUNCTION(pathinfo)
    1692             : {
    1693             :         zval tmp;
    1694             :         char *path, *dirname;
    1695             :         size_t path_len;
    1696             :         int have_basename;
    1697         615 :         zend_long opt = PHP_PATHINFO_ALL;
    1698         615 :         zend_string *ret = NULL;
    1699             : 
    1700         615 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &path, &path_len, &opt) == FAILURE) {
    1701          25 :                 return;
    1702             :         }
    1703             : 
    1704         590 :         have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
    1705             : 
    1706         590 :         array_init(&tmp);
    1707             : 
    1708         590 :         if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
    1709         247 :                 dirname = estrndup(path, path_len);
    1710         247 :                 php_dirname(dirname, path_len);
    1711         247 :                 if (*dirname) {
    1712         224 :                         add_assoc_string(&tmp, "dirname", dirname);
    1713             :                 }
    1714         247 :                 efree(dirname);
    1715             :         }
    1716             : 
    1717         590 :         if (have_basename) {
    1718         227 :                 ret = php_basename(path, path_len, NULL, 0);
    1719         227 :                 add_assoc_str(&tmp, "basename", zend_string_copy(ret));
    1720             :         }
    1721             : 
    1722         590 :         if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
    1723             :                 const char *p;
    1724             :                 ptrdiff_t idx;
    1725             : 
    1726         238 :                 if (!have_basename) {
    1727         120 :                         ret = php_basename(path, path_len, NULL, 0);
    1728             :                 }
    1729             : 
    1730         476 :                 p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
    1731             : 
    1732         238 :                 if (p) {
    1733         130 :                         idx = p - ZSTR_VAL(ret);
    1734         130 :                         add_assoc_stringl(&tmp, "extension", ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
    1735             :                 }
    1736             :         }
    1737             : 
    1738         590 :         if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
    1739             :                 const char *p;
    1740             :                 ptrdiff_t idx;
    1741             : 
    1742             :                 /* Have we already looked up the basename? */
    1743         232 :                 if (!have_basename && !ret) {
    1744         110 :                         ret = php_basename(path, path_len, NULL, 0);
    1745             :                 }
    1746             : 
    1747         464 :                 p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
    1748             : 
    1749         232 :                 idx = p ? (p - ZSTR_VAL(ret)) : ZSTR_LEN(ret);
    1750         232 :                 add_assoc_stringl(&tmp, "filename", ZSTR_VAL(ret), idx);
    1751             :         }
    1752             : 
    1753         590 :         if (ret) {
    1754             :                 zend_string_release(ret);
    1755             :         }
    1756             : 
    1757         590 :         if (opt == PHP_PATHINFO_ALL) {
    1758         113 :                 ZVAL_COPY_VALUE(return_value, &tmp);
    1759             :         } else {
    1760             :                 zval *element;
    1761         477 :                 if ((element = zend_hash_get_current_data(Z_ARRVAL(tmp))) != NULL) {
    1762         401 :                         ZVAL_DEREF(element);
    1763         401 :                         ZVAL_COPY(return_value, element);
    1764             :                 } else {
    1765          76 :                         ZVAL_EMPTY_STRING(return_value);
    1766             :                 }
    1767         477 :                 zval_ptr_dtor(&tmp);
    1768             :         }
    1769             : }
    1770             : /* }}} */
    1771             : 
    1772             : /* {{{ php_stristr
    1773             :    case insensitve strstr */
    1774        6248 : PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
    1775             : {
    1776        6248 :         php_strtolower(s, s_len);
    1777        6248 :         php_strtolower(t, t_len);
    1778       12496 :         return (char*)php_memnstr(s, t, t_len, s + s_len);
    1779             : }
    1780             : /* }}} */
    1781             : 
    1782             : /* {{{ php_strspn
    1783             :  */
    1784        3381 : PHPAPI size_t php_strspn(char *s1, char *s2, char *s1_end, char *s2_end)
    1785             : {
    1786        3381 :         register const char *p = s1, *spanp;
    1787        3381 :         register char c = *p;
    1788             : 
    1789             : cont:
    1790       44022 :         for (spanp = s2; p != s1_end && spanp != s2_end;) {
    1791       34080 :                 if (*spanp++ == c) {
    1792        3180 :                         c = *(++p);
    1793        3180 :                         goto cont;
    1794             :                 }
    1795             :         }
    1796        3381 :         return (p - s1);
    1797             : }
    1798             : /* }}} */
    1799             : 
    1800             : /* {{{ php_strcspn
    1801             :  */
    1802        3234 : PHPAPI size_t php_strcspn(char *s1, char *s2, char *s1_end, char *s2_end)
    1803             : {
    1804             :         register const char *p, *spanp;
    1805        3234 :         register char c = *s1;
    1806             : 
    1807        3234 :         for (p = s1;;) {
    1808       24666 :                 spanp = s2;
    1809             :                 do {
    1810       55604 :                         if (*spanp == c || p == s1_end) {
    1811        3234 :                                 return p - s1;
    1812             :                         }
    1813       52370 :                 } while (spanp++ < (s2_end - 1));
    1814       21432 :                 c = *++p;
    1815       21432 :         }
    1816             :         /* NOTREACHED */
    1817             : }
    1818             : /* }}} */
    1819             : 
    1820             : /* {{{ php_needle_char
    1821             :  */
    1822         305 : static int php_needle_char(zval *needle, char *target)
    1823             : {
    1824         305 :         switch (Z_TYPE_P(needle)) {
    1825             :                 case IS_LONG:
    1826          62 :                         *target = (char)Z_LVAL_P(needle);
    1827          62 :                         return SUCCESS;
    1828             :                 case IS_NULL:
    1829             :                 case IS_FALSE:
    1830         139 :                         *target = '\0';
    1831         139 :                         return SUCCESS;
    1832             :                 case IS_TRUE:
    1833          24 :                         *target = '\1';
    1834          24 :                         return SUCCESS;
    1835             :                 case IS_DOUBLE:
    1836          47 :                         *target = (char)(int)Z_DVAL_P(needle);
    1837          47 :                         return SUCCESS;
    1838             :                 case IS_OBJECT:
    1839           9 :                         *target = (char) zval_get_long(needle);
    1840           9 :                         return SUCCESS;
    1841             :                 default:
    1842          24 :                         php_error_docref(NULL, E_WARNING, "needle is not a string or an integer");
    1843          24 :                         return FAILURE;
    1844             :         }
    1845             : }
    1846             : /* }}} */
    1847             : 
    1848             : /* {{{ proto string stristr(string haystack, string needle[, bool part])
    1849             :    Finds first occurrence of a string within another, case insensitive */
    1850        6182 : PHP_FUNCTION(stristr)
    1851             : {
    1852             :         zval *needle;
    1853             :         zend_string *haystack;
    1854        6182 :         char *found = NULL;
    1855             :         size_t  found_offset;
    1856             :         char *haystack_dup;
    1857             :         char needle_char[2];
    1858        6182 :         zend_bool part = 0;
    1859             : 
    1860        6182 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|b", &haystack, &needle, &part) == FAILURE) {
    1861          11 :                 return;
    1862             :         }
    1863             : 
    1864        6171 :         haystack_dup = estrndup(ZSTR_VAL(haystack), ZSTR_LEN(haystack));
    1865             : 
    1866       12342 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1867             :                 char *orig_needle;
    1868        6148 :                 if (!Z_STRLEN_P(needle)) {
    1869           4 :                         php_error_docref(NULL, E_WARNING, "Empty needle");
    1870           4 :                         efree(haystack_dup);
    1871           4 :                         RETURN_FALSE;
    1872             :                 }
    1873        6144 :                 orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
    1874        6144 :                 found = php_stristr(haystack_dup, orig_needle, ZSTR_LEN(haystack), Z_STRLEN_P(needle));
    1875        6144 :                 efree(orig_needle);
    1876             :         } else {
    1877          23 :                 if (php_needle_char(needle, needle_char) != SUCCESS) {
    1878           5 :                         efree(haystack_dup);
    1879           5 :                         RETURN_FALSE;
    1880             :                 }
    1881          18 :                 needle_char[1] = 0;
    1882             : 
    1883          18 :                 found = php_stristr(haystack_dup, needle_char, ZSTR_LEN(haystack), 1);
    1884             :         }
    1885             : 
    1886        6162 :         if (found) {
    1887        1304 :                 found_offset = found - haystack_dup;
    1888        1304 :                 if (part) {
    1889           8 :                         RETVAL_STRINGL(ZSTR_VAL(haystack), found_offset);
    1890             :                 } else {
    1891        2600 :                         RETVAL_STRINGL(ZSTR_VAL(haystack) + found_offset, ZSTR_LEN(haystack) - found_offset);
    1892             :                 }
    1893             :         } else {
    1894        4858 :                 RETVAL_FALSE;
    1895             :         }
    1896             : 
    1897        6162 :         efree(haystack_dup);
    1898             : }
    1899             : /* }}} */
    1900             : 
    1901             : /* {{{ proto string strstr(string haystack, string needle[, bool part])
    1902             :    Finds first occurrence of a string within another */
    1903        8538 : PHP_FUNCTION(strstr)
    1904             : {
    1905             :         zval *needle;
    1906             :         zend_string *haystack;
    1907        8538 :         char *found = NULL;
    1908             :         char needle_char[2];
    1909             :         zend_long found_offset;
    1910        8538 :         zend_bool part = 0;
    1911             : 
    1912        8538 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|b", &haystack, &needle, &part) == FAILURE) {
    1913           6 :                 return;
    1914             :         }
    1915             : 
    1916       17064 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1917        8520 :                 if (!Z_STRLEN_P(needle)) {
    1918           5 :                         php_error_docref(NULL, E_WARNING, "Empty needle");
    1919           5 :                         RETURN_FALSE;
    1920             :                 }
    1921             : 
    1922       17030 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack), Z_STRVAL_P(needle), Z_STRLEN_P(needle), ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
    1923             :         } else {
    1924          12 :                 if (php_needle_char(needle, needle_char) != SUCCESS) {
    1925           0 :                         RETURN_FALSE;
    1926             :                 }
    1927          12 :                 needle_char[1] = 0;
    1928             : 
    1929          24 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack), needle_char, 1, ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
    1930             :         }
    1931             : 
    1932        8527 :         if (found) {
    1933        3065 :                 found_offset = found - ZSTR_VAL(haystack);
    1934        3065 :                 if (part) {
    1935          10 :                         RETURN_STRINGL(ZSTR_VAL(haystack), found_offset);
    1936             :                 } else {
    1937        6120 :                         RETURN_STRINGL(found, ZSTR_LEN(haystack) - found_offset);
    1938             :                 }
    1939             :         }
    1940        5462 :         RETURN_FALSE;
    1941             : }
    1942             : /* }}} */
    1943             : 
    1944             : /* {{{ proto string strchr(string haystack, string needle)
    1945             :    An alias for strstr */
    1946             : /* }}} */
    1947             : 
    1948             : /* {{{ proto int strpos(string haystack, string needle [, int offset])
    1949             :    Finds position of first occurrence of a string within another */
    1950      895069 : PHP_FUNCTION(strpos)
    1951             : {
    1952             :         zval *needle;
    1953             :         zend_string *haystack;
    1954      895069 :         char *found = NULL;
    1955             :         char  needle_char[2];
    1956      895069 :         zend_long  offset = 0;
    1957             : 
    1958             : #ifndef FAST_ZPP
    1959             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &haystack, &needle, &offset) == FAILURE) {
    1960             :                 return;
    1961             :         }
    1962             : #else
    1963      895069 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1964     2685192 :                 Z_PARAM_STR(haystack)
    1965      895061 :                 Z_PARAM_ZVAL(needle)
    1966      895061 :                 Z_PARAM_OPTIONAL
    1967      912037 :                 Z_PARAM_LONG(offset)
    1968      895069 :         ZEND_PARSE_PARAMETERS_END();
    1969             : #endif
    1970             : 
    1971      895058 :         if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
    1972           9 :                 php_error_docref(NULL, E_WARNING, "Offset not contained in string");
    1973           9 :                 RETURN_FALSE;
    1974             :         }
    1975             : 
    1976     1790098 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1977      895036 :                 if (!Z_STRLEN_P(needle)) {
    1978           6 :                         php_error_docref(NULL, E_WARNING, "Empty needle");
    1979           6 :                         RETURN_FALSE;
    1980             :                 }
    1981             : 
    1982     4475150 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
    1983      895030 :                                         Z_STRVAL_P(needle),
    1984      895030 :                                         Z_STRLEN_P(needle),
    1985     1790060 :                                         ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
    1986             :         } else {
    1987          13 :                 if (php_needle_char(needle, needle_char) != SUCCESS) {
    1988           0 :                         RETURN_FALSE;
    1989             :                 }
    1990          13 :                 needle_char[1] = 0;
    1991             : 
    1992          39 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
    1993             :                                                         needle_char,
    1994             :                                                         1,
    1995          26 :                                     ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
    1996             :         }
    1997             : 
    1998      895043 :         if (found) {
    1999      488826 :                 RETURN_LONG(found - ZSTR_VAL(haystack));
    2000             :         } else {
    2001      406217 :                 RETURN_FALSE;
    2002             :         }
    2003             : }
    2004             : /* }}} */
    2005             : 
    2006             : /* {{{ proto int stripos(string haystack, string needle [, int offset])
    2007             :    Finds position of first occurrence of a string within another, case insensitive */
    2008         614 : PHP_FUNCTION(stripos)
    2009             : {
    2010         614 :         char *found = NULL;
    2011             :         zend_string *haystack;
    2012         614 :         zend_long offset = 0;
    2013             :         char needle_char[2];
    2014             :         zval *needle;
    2015         614 :         zend_string *needle_dup = NULL, *haystack_dup;
    2016             : 
    2017         614 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &haystack, &needle, &offset) == FAILURE) {
    2018          39 :                 return;
    2019             :         }
    2020             : 
    2021         575 :         if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
    2022          22 :                 php_error_docref(NULL, E_WARNING, "Offset not contained in string");
    2023          22 :                 RETURN_FALSE;
    2024             :         }
    2025             : 
    2026         553 :         if (ZSTR_LEN(haystack) == 0) {
    2027          30 :                 RETURN_FALSE;
    2028             :         }
    2029             : 
    2030        1046 :         if (Z_TYPE_P(needle) == IS_STRING) {
    2031         445 :                 if (Z_STRLEN_P(needle) == 0 || Z_STRLEN_P(needle) > ZSTR_LEN(haystack)) {
    2032          20 :                         RETURN_FALSE;
    2033             :                 }
    2034             : 
    2035         425 :                 haystack_dup = php_string_tolower(haystack);
    2036         425 :                 needle_dup = php_string_tolower(Z_STR_P(needle));
    2037        1275 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack_dup) + offset,
    2038         425 :                                 ZSTR_VAL(needle_dup), ZSTR_LEN(needle_dup), ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack));
    2039             :         } else {
    2040          78 :                 if (php_needle_char(needle, needle_char) != SUCCESS) {
    2041           6 :                         RETURN_FALSE;
    2042             :                 }
    2043          72 :                 haystack_dup = php_string_tolower(haystack);
    2044          72 :                 needle_char[0] = tolower(needle_char[0]);
    2045          72 :                 needle_char[1] = '\0';
    2046         216 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack_dup) + offset,
    2047             :                                                         needle_char,
    2048             :                                                         sizeof(needle_char) - 1,
    2049          72 :                                                         ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack));
    2050             :         }
    2051             : 
    2052             : 
    2053         497 :         if (found) {
    2054         326 :                 RETVAL_LONG(found - ZSTR_VAL(haystack_dup));
    2055             :         } else {
    2056         171 :                 RETVAL_FALSE;
    2057             :         }
    2058             : 
    2059             :         zend_string_release(haystack_dup);
    2060         497 :         if (needle_dup) {
    2061             :                 zend_string_release(needle_dup);
    2062             :         }
    2063             : }
    2064             : /* }}} */
    2065             : 
    2066             : /* {{{ proto int strrpos(string haystack, string needle [, int offset])
    2067             :    Finds position of last occurrence of a string within another string */
    2068         461 : PHP_FUNCTION(strrpos)
    2069             : {
    2070             :         zval *zneedle;
    2071             :         char *needle;
    2072             :         zend_string *haystack;
    2073             :         size_t needle_len;
    2074         461 :         zend_long offset = 0;
    2075             :         char *p, *e, ord_needle[2];
    2076             :         char *found;
    2077             : 
    2078             : #ifndef FAST_ZPP
    2079             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &haystack, &zneedle, &offset) == FAILURE) {
    2080             :                 RETURN_FALSE;
    2081             :         }
    2082             : #else
    2083         461 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    2084        1374 :                 Z_PARAM_STR(haystack)
    2085         440 :                 Z_PARAM_ZVAL(zneedle)
    2086         440 :                 Z_PARAM_OPTIONAL
    2087         772 :                 Z_PARAM_LONG(offset)
    2088         461 :         ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
    2089             : #endif
    2090             : 
    2091         880 :         if (Z_TYPE_P(zneedle) == IS_STRING) {
    2092         360 :                 needle = Z_STRVAL_P(zneedle);
    2093         360 :                 needle_len = Z_STRLEN_P(zneedle);
    2094             :         } else {
    2095          80 :                 if (php_needle_char(zneedle, ord_needle) != SUCCESS) {
    2096           6 :                         RETURN_FALSE;
    2097             :                 }
    2098          74 :                 ord_needle[1] = '\0';
    2099          74 :                 needle = ord_needle;
    2100          74 :                 needle_len = 1;
    2101             :         }
    2102             : 
    2103         434 :         if ((ZSTR_LEN(haystack) == 0) || (needle_len == 0)) {
    2104          38 :                 RETURN_FALSE;
    2105             :         }
    2106             : 
    2107         396 :         if (offset >= 0) {
    2108         380 :                 if ((size_t)offset > ZSTR_LEN(haystack)) {
    2109           2 :                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2110           2 :                         RETURN_FALSE;
    2111             :                 }
    2112         378 :                 p = ZSTR_VAL(haystack) + (size_t)offset;
    2113         378 :                 e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
    2114             :         } else {
    2115          16 :                 if (offset < -INT_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) {
    2116           3 :                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2117           3 :                         RETURN_FALSE;
    2118             :                 }
    2119          13 :                 p = ZSTR_VAL(haystack);
    2120          13 :                 if (-offset < needle_len) {
    2121           3 :                         e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
    2122             :                 } else {
    2123          10 :                         e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack) + offset + needle_len;
    2124             :                 }
    2125             :         }
    2126             : 
    2127         391 :         if ((found = (char *)zend_memnrstr(p, needle, needle_len, e))) {
    2128         236 :                 RETURN_LONG(found - ZSTR_VAL(haystack));
    2129             :         }
    2130             : 
    2131         155 :         RETURN_FALSE;
    2132             : }
    2133             : /* }}} */
    2134             : 
    2135             : /* {{{ proto int strripos(string haystack, string needle [, int offset])
    2136             :    Finds position of last occurrence of a string within another string */
    2137         364 : PHP_FUNCTION(strripos)
    2138             : {
    2139             :         zval *zneedle;
    2140             :         zend_string *needle;
    2141             :         zend_string *haystack;
    2142         364 :         zend_long offset = 0;
    2143             :         char *p, *e;
    2144             :         char *found;
    2145         364 :         zend_string *needle_dup, *haystack_dup, *ord_needle = NULL;
    2146             :         ALLOCA_FLAG(use_heap);
    2147             : 
    2148             : 
    2149         364 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &haystack, &zneedle, &offset) == FAILURE) {
    2150           3 :                 RETURN_FALSE;
    2151             :         }
    2152             : 
    2153         722 :         ZSTR_ALLOCA_ALLOC(ord_needle, 1, use_heap);
    2154         722 :         if (Z_TYPE_P(zneedle) == IS_STRING) {
    2155         324 :                 needle = Z_STR_P(zneedle);
    2156             :         } else {
    2157          37 :                 if (php_needle_char(zneedle, ZSTR_VAL(ord_needle)) != SUCCESS) {
    2158           1 :                         ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2159           1 :                         RETURN_FALSE;
    2160             :                 }
    2161          36 :                 ZSTR_VAL(ord_needle)[1] = '\0';
    2162          36 :                 needle = ord_needle;
    2163             :         }
    2164             : 
    2165         360 :         if ((ZSTR_LEN(haystack) == 0) || (ZSTR_LEN(needle) == 0)) {
    2166          12 :                 ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2167          12 :                 RETURN_FALSE;
    2168             :         }
    2169             : 
    2170         348 :         if (ZSTR_LEN(needle) == 1) {
    2171             :                 /* Single character search can shortcut memcmps
    2172             :                    Can also avoid tolower emallocs */
    2173         162 :                 if (offset >= 0) {
    2174         119 :                         if ((size_t)offset > ZSTR_LEN(haystack)) {
    2175           0 :                                 ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2176           0 :                                 php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2177           0 :                                 RETURN_FALSE;
    2178             :                         }
    2179         119 :                         p = ZSTR_VAL(haystack) + (size_t)offset;
    2180         119 :                         e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - 1;
    2181             :                 } else {
    2182          43 :                         p = ZSTR_VAL(haystack);
    2183          43 :                         if (offset < -INT_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) {
    2184           1 :                                 ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2185           1 :                                 php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2186           1 :                                 RETURN_FALSE;
    2187             :                         }
    2188          42 :                         e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack) + (size_t)offset;
    2189             :                 }
    2190             :                 /* Borrow that ord_needle buffer to avoid repeatedly tolower()ing needle */
    2191         161 :                 *ZSTR_VAL(ord_needle) = tolower(*ZSTR_VAL(needle));
    2192        4087 :                 while (e >= p) {
    2193        3890 :                         if (tolower(*e) == *ZSTR_VAL(ord_needle)) {
    2194         125 :                                 ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2195         125 :                                 RETURN_LONG(e - p + (offset > 0 ? offset : 0));
    2196             :                         }
    2197        3765 :                         e--;
    2198             :                 }
    2199          36 :                 ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2200          36 :                 RETURN_FALSE;
    2201             :         }
    2202             : 
    2203         186 :         haystack_dup = php_string_tolower(haystack);
    2204         186 :         if (offset >= 0) {
    2205         143 :                 if ((size_t)offset > ZSTR_LEN(haystack)) {
    2206             :                         zend_string_release(haystack_dup);
    2207           2 :                         ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2208           2 :                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2209           2 :                         RETURN_FALSE;
    2210             :                 }
    2211         141 :                 p = ZSTR_VAL(haystack_dup) + offset;
    2212         141 :                 e = ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack);
    2213             :         } else {
    2214          43 :                 if (offset < -INT_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) {
    2215             :                         zend_string_release(haystack_dup);
    2216           0 :                         ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2217           0 :                         php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
    2218           0 :                         RETURN_FALSE;
    2219             :                 }
    2220          43 :                 p = ZSTR_VAL(haystack_dup);
    2221          43 :                 if (-offset < ZSTR_LEN(needle)) {
    2222          37 :                         e = ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack);
    2223             :                 } else {
    2224           6 :                         e = ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack) + offset + ZSTR_LEN(needle);
    2225             :                 }
    2226             :         }
    2227             : 
    2228         184 :         needle_dup = php_string_tolower(needle);
    2229         368 :         if ((found = (char *)zend_memnrstr(p, ZSTR_VAL(needle_dup), ZSTR_LEN(needle_dup), e))) {
    2230         133 :                 RETVAL_LONG(found - ZSTR_VAL(haystack_dup));
    2231             :                 zend_string_release(needle_dup);
    2232             :                 zend_string_release(haystack_dup);
    2233         133 :                 ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2234             :         } else {
    2235             :                 zend_string_release(needle_dup);
    2236             :                 zend_string_release(haystack_dup);
    2237          51 :                 ZSTR_ALLOCA_FREE(ord_needle, use_heap);
    2238          51 :                 RETURN_FALSE;
    2239             :         }
    2240             : }
    2241             : /* }}} */
    2242             : 
    2243             : /* {{{ proto string strrchr(string haystack, string needle)
    2244             :    Finds the last occurrence of a character in a string within another */
    2245         244 : PHP_FUNCTION(strrchr)
    2246             : {
    2247             :         zval *needle;
    2248             :         zend_string *haystack;
    2249         244 :         const char *found = NULL;
    2250             :         zend_long found_offset;
    2251             : 
    2252         244 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &haystack, &needle) == FAILURE) {
    2253          15 :                 return;
    2254             :         }
    2255             : 
    2256         458 :         if (Z_TYPE_P(needle) == IS_STRING) {
    2257         334 :                 found = zend_memrchr(ZSTR_VAL(haystack), *Z_STRVAL_P(needle), ZSTR_LEN(haystack));
    2258             :         } else {
    2259             :                 char needle_chr;
    2260          62 :                 if (php_needle_char(needle, &needle_chr) != SUCCESS) {
    2261           6 :                         RETURN_FALSE;
    2262             :                 }
    2263             : 
    2264         112 :                 found = zend_memrchr(ZSTR_VAL(haystack),  needle_chr, ZSTR_LEN(haystack));
    2265             :         }
    2266             : 
    2267         223 :         if (found) {
    2268         143 :                 found_offset = found - ZSTR_VAL(haystack);
    2269         286 :                 RETURN_STRINGL(found, ZSTR_LEN(haystack) - found_offset);
    2270             :         } else {
    2271          80 :                 RETURN_FALSE;
    2272             :         }
    2273             : }
    2274             : /* }}} */
    2275             : 
    2276             : /* {{{ php_chunk_split
    2277             :  */
    2278         132 : static zend_string *php_chunk_split(char *src, size_t srclen, char *end, size_t endlen, size_t chunklen)
    2279             : {
    2280             :         char *p, *q;
    2281             :         size_t chunks; /* complete chunks! */
    2282             :         size_t restlen;
    2283             :         size_t out_len;
    2284             :         zend_string *dest;
    2285             : 
    2286         132 :         chunks = srclen / chunklen;
    2287         132 :         restlen = srclen - chunks * chunklen; /* srclen % chunklen */
    2288             : 
    2289         132 :         if (chunks > INT_MAX - 1) {
    2290           0 :                 return NULL;
    2291             :         }
    2292         132 :         out_len = chunks + 1;
    2293         132 :         if (endlen !=0 && out_len > INT_MAX/endlen) {
    2294           2 :                 return NULL;
    2295             :         }
    2296         130 :         out_len *= endlen;
    2297         130 :         if (out_len > INT_MAX - srclen - 1) {
    2298           0 :                 return NULL;
    2299             :         }
    2300         130 :         out_len += srclen + 1;
    2301             : 
    2302         130 :         dest = zend_string_alloc(out_len * sizeof(char), 0);
    2303             : 
    2304        1497 :         for (p = src, q = ZSTR_VAL(dest); p < (src + srclen - chunklen + 1); ) {
    2305        1237 :                 memcpy(q, p, chunklen);
    2306        1237 :                 q += chunklen;
    2307        1237 :                 memcpy(q, end, endlen);
    2308        1237 :                 q += endlen;
    2309        1237 :                 p += chunklen;
    2310             :         }
    2311             : 
    2312         130 :         if (restlen) {
    2313         116 :                 memcpy(q, p, restlen);
    2314         116 :                 q += restlen;
    2315         116 :                 memcpy(q, end, endlen);
    2316         116 :                 q += endlen;
    2317             :         }
    2318             : 
    2319         130 :         *q = '\0';
    2320         130 :         ZSTR_LEN(dest) = q - ZSTR_VAL(dest);
    2321             : 
    2322         130 :         return dest;
    2323             : }
    2324             : /* }}} */
    2325             : 
    2326             : /* {{{ proto string chunk_split(string str [, int chunklen [, string ending]])
    2327             :    Returns split line */
    2328         204 : PHP_FUNCTION(chunk_split)
    2329             : {
    2330             :         zend_string *str;
    2331         204 :         char *end    = "\r\n";
    2332         204 :         size_t endlen   = 2;
    2333         204 :         zend_long chunklen = 76;
    2334             :         zend_string *result;
    2335             : 
    2336         204 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|ls", &str, &chunklen, &end, &endlen) == FAILURE) {
    2337          28 :                 return;
    2338             :         }
    2339             : 
    2340         176 :         if (chunklen <= 0) {
    2341          15 :                 php_error_docref(NULL, E_WARNING, "Chunk length should be greater than zero");
    2342          15 :                 RETURN_FALSE;
    2343             :         }
    2344             : 
    2345         161 :         if ((size_t)chunklen > ZSTR_LEN(str)) {
    2346             :                 /* to maintain BC, we must return original string + ending */
    2347          58 :                 result = zend_string_alloc(endlen + ZSTR_LEN(str), 0);
    2348          29 :                 memcpy(ZSTR_VAL(result), ZSTR_VAL(str), ZSTR_LEN(str));
    2349          29 :                 memcpy(ZSTR_VAL(result) + ZSTR_LEN(str), end, endlen);
    2350          29 :                 ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
    2351          29 :                 RETURN_NEW_STR(result);
    2352             :         }
    2353             : 
    2354         132 :         if (!ZSTR_LEN(str)) {
    2355           0 :                 RETURN_EMPTY_STRING();
    2356             :         }
    2357             : 
    2358         132 :         result = php_chunk_split(ZSTR_VAL(str), ZSTR_LEN(str), end, endlen, (size_t)chunklen);
    2359             : 
    2360         132 :         if (result) {
    2361         130 :                 RETURN_STR(result);
    2362             :         } else {
    2363           2 :                 RETURN_FALSE;
    2364             :         }
    2365             : }
    2366             : /* }}} */
    2367             : 
    2368             : /* {{{ proto string substr(string str, int start [, int length])
    2369             :    Returns part of a string */
    2370      553308 : PHP_FUNCTION(substr)
    2371             : {
    2372             :         zend_string *str;
    2373      553308 :         zend_long l = 0, f;
    2374      553308 :         int argc = ZEND_NUM_ARGS();
    2375             : 
    2376             : #ifndef FAST_ZPP
    2377             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|l", &str, &f, &l) == FAILURE) {
    2378             :                 return;
    2379             :         }
    2380             : #else
    2381      553308 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    2382     1659906 :                 Z_PARAM_STR(str)
    2383     1659906 :                 Z_PARAM_LONG(f)
    2384      553302 :                 Z_PARAM_OPTIONAL
    2385     1556246 :                 Z_PARAM_LONG(l)
    2386      553308 :         ZEND_PARSE_PARAMETERS_END();
    2387             : #endif
    2388             : 
    2389      553302 :         if (argc > 2) {
    2390      501472 :                 if ((l < 0 && (size_t)(-l) > ZSTR_LEN(str))) {
    2391           8 :                         RETURN_FALSE;
    2392      501464 :                 } else if (l > (zend_long)ZSTR_LEN(str)) {
    2393         630 :                         l = ZSTR_LEN(str);
    2394             :                 }
    2395             :         } else {
    2396       51830 :                 l = ZSTR_LEN(str);
    2397             :         }
    2398             : 
    2399      553294 :         if (f > (zend_long)ZSTR_LEN(str)) {
    2400          14 :                 RETURN_FALSE;
    2401      553280 :         } else if (f < 0 && -f > ZSTR_LEN(str)) {
    2402        2019 :                 f = 0;
    2403             :         }
    2404             : 
    2405      553280 :         if (l < 0 && (l + (zend_long)ZSTR_LEN(str) - f) < 0) {
    2406           2 :                 RETURN_FALSE;
    2407             :         }
    2408             : 
    2409             :         /* if "from" position is negative, count start position from the end
    2410             :          * of the string
    2411             :          */
    2412      553278 :         if (f < 0) {
    2413       48624 :                 f = (zend_long)ZSTR_LEN(str) + f;
    2414       48624 :                 if (f < 0) {
    2415           0 :                         f = 0;
    2416             :                 }
    2417             :         }
    2418             : 
    2419             :         /* if "length" position is negative, set it to the length
    2420             :          * needed to stop that many chars from the end of the string
    2421             :          */
    2422      553278 :         if (l < 0) {
    2423         110 :                 l = ((zend_long)ZSTR_LEN(str) - f) + l;
    2424         110 :                 if (l < 0) {
    2425           5 :                         l = 0;
    2426             :                 }
    2427             :         }
    2428             : 
    2429      553278 :         if (f > (zend_long)ZSTR_LEN(str)) {
    2430           0 :                 RETURN_FALSE;
    2431             :         }
    2432             : 
    2433      553278 :         if ((f + l) > (zend_long)ZSTR_LEN(str)) {
    2434       50271 :                 l = ZSTR_LEN(str) - f;
    2435             :         }
    2436             : 
    2437     1106556 :         RETURN_STRINGL(ZSTR_VAL(str) + f, l);
    2438             : }
    2439             : /* }}} */
    2440             : 
    2441             : /* {{{ proto mixed substr_replace(mixed str, mixed repl, mixed start [, mixed length])
    2442             :    Replaces part of a string with another string */
    2443          60 : PHP_FUNCTION(substr_replace)
    2444             : {
    2445             :         zval *str;
    2446             :         zval *from;
    2447          60 :         zval *len = NULL;
    2448             :         zval *repl;
    2449          60 :         zend_long l = 0;
    2450             :         zend_long f;
    2451          60 :         int argc = ZEND_NUM_ARGS();
    2452             :         zend_string *result;
    2453             :         HashPosition from_idx, repl_idx, len_idx;
    2454          60 :         zval *tmp_str = NULL, *tmp_from = NULL, *tmp_repl = NULL, *tmp_len= NULL;
    2455             : 
    2456          60 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz|z/", &str, &repl, &from, &len) == FAILURE) {
    2457           3 :                 return;
    2458             :         }
    2459             : 
    2460         114 :         if (Z_TYPE_P(str) != IS_ARRAY) {
    2461          24 :                 convert_to_string_ex(str);
    2462             :         }
    2463         114 :         if (Z_TYPE_P(repl) != IS_ARRAY) {
    2464          66 :                 convert_to_string_ex(repl);
    2465             :         }
    2466         114 :         if (Z_TYPE_P(from) != IS_ARRAY) {
    2467          42 :                 convert_to_long_ex(from);
    2468             :         }
    2469             : 
    2470          57 :         if (argc > 3) {
    2471          94 :                 if (Z_TYPE_P(len) != IS_ARRAY) {
    2472          56 :                         l = zval_get_long(len);
    2473             :                 }
    2474             :         } else {
    2475          20 :                 if (Z_TYPE_P(str) != IS_ARRAY) {
    2476           4 :                         l = Z_STRLEN_P(str);
    2477             :                 }
    2478             :         }
    2479             : 
    2480         114 :         if (Z_TYPE_P(str) == IS_STRING) {
    2481          24 :                 if (
    2482           4 :                         (argc == 3 && Z_TYPE_P(from) == IS_ARRAY) ||
    2483          16 :                         (argc == 4 && Z_TYPE_P(from) != Z_TYPE_P(len))
    2484             :                 ) {
    2485           2 :                         php_error_docref(NULL, E_WARNING, "'from' and 'len' should be of same type - numerical or array ");
    2486           2 :                         RETURN_STR_COPY(Z_STR_P(str));
    2487             :                 }
    2488          17 :                 if (argc == 4 && Z_TYPE_P(from) == IS_ARRAY) {
    2489           2 :                         if (zend_hash_num_elements(Z_ARRVAL_P(from)) != zend_hash_num_elements(Z_ARRVAL_P(len))) {
    2490           1 :                                 php_error_docref(NULL, E_WARNING, "'from' and 'len' should have the same number of elements");
    2491           1 :                                 RETURN_STR_COPY(Z_STR_P(str));
    2492             :                         }
    2493             :                 }
    2494             :         }
    2495             : 
    2496         108 :         if (Z_TYPE_P(str) != IS_ARRAY) {
    2497          18 :                 if (Z_TYPE_P(from) != IS_ARRAY) {
    2498           8 :                         size_t repl_len = 0;
    2499             : 
    2500           8 :                         f = Z_LVAL_P(from);
    2501             : 
    2502             :                         /* if "from" position is negative, count start position from the end
    2503             :                          * of the string
    2504             :                          */
    2505           8 :                         if (f < 0) {
    2506           0 :                                 f = (zend_long)Z_STRLEN_P(str) + f;
    2507           0 :                                 if (f < 0) {
    2508           0 :                                         f = 0;
    2509             :                                 }
    2510           8 :                         } else if (f > Z_STRLEN_P(str)) {
    2511           1 :                                 f = Z_STRLEN_P(str);
    2512             :                         }
    2513             :                         /* if "length" position is negative, set it to the length
    2514             :                          * needed to stop that many chars from the end of the string
    2515             :                          */
    2516           8 :                         if (l < 0) {
    2517           1 :                                 l = ((zend_long)Z_STRLEN_P(str) - f) + l;
    2518           1 :                                 if (l < 0) {
    2519           0 :                                         l = 0;
    2520             :                                 }
    2521             :                         }
    2522             : 
    2523           8 :                         if (l > Z_STRLEN_P(str) || (l < 0 && (size_t)(-l) > Z_STRLEN_P(str))) {
    2524           1 :                                 l = Z_STRLEN_P(str);
    2525             :                         }
    2526             : 
    2527           8 :                         if ((f + l) > (zend_long)Z_STRLEN_P(str)) {
    2528           4 :                                 l = Z_STRLEN_P(str) - f;
    2529             :                         }
    2530          16 :                         if (Z_TYPE_P(repl) == IS_ARRAY) {
    2531           2 :                                 repl_idx = 0;
    2532           4 :                                 while (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2533           2 :                                         tmp_repl = &Z_ARRVAL_P(repl)->arData[repl_idx].val;
    2534           2 :                                         if (Z_TYPE_P(tmp_repl) != IS_UNDEF) {
    2535           2 :                                                 break;
    2536             :                                         }
    2537           0 :                                         repl_idx++;
    2538             :                                 }
    2539           2 :                                 if (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2540           2 :                                         convert_to_string_ex(tmp_repl);
    2541           2 :                                         repl_len = Z_STRLEN_P(tmp_repl);
    2542             :                                 }
    2543             :                         } else {
    2544           6 :                                 repl_len = Z_STRLEN_P(repl);
    2545             :                         }
    2546             : 
    2547          16 :                         result = zend_string_alloc(Z_STRLEN_P(str) - l + repl_len, 0);
    2548             : 
    2549           8 :                         memcpy(ZSTR_VAL(result), Z_STRVAL_P(str), f);
    2550           8 :                         if (repl_len) {
    2551          16 :                                 memcpy((ZSTR_VAL(result) + f), (Z_TYPE_P(repl) == IS_ARRAY ? Z_STRVAL_P(tmp_repl) : Z_STRVAL_P(repl)), repl_len);
    2552             :                         }
    2553           8 :                         memcpy((ZSTR_VAL(result) + f + repl_len), Z_STRVAL_P(str) + f + l, Z_STRLEN_P(str) - f - l);
    2554           8 :                         ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
    2555           8 :                         RETURN_NEW_STR(result);
    2556             :                 } else {
    2557           1 :                         php_error_docref(NULL, E_WARNING, "Functionality of 'from' and 'len' as arrays is not implemented");
    2558           1 :                         RETURN_STR_COPY(Z_STR_P(str));
    2559             :                 }
    2560             :         } else { /* str is array of strings */
    2561          45 :                 zend_string *str_index = NULL;
    2562             :                 size_t result_len;
    2563             :                 zend_ulong num_index;
    2564             : 
    2565          45 :                 array_init(return_value);
    2566             : 
    2567          45 :                 from_idx = len_idx = repl_idx = 0;
    2568             : 
    2569         203 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(str), num_index, str_index, tmp_str) {
    2570          79 :                         zend_string *orig_str = zval_get_string(tmp_str);
    2571             : 
    2572         158 :                         if (Z_TYPE_P(from) == IS_ARRAY) {
    2573         114 :                                 while (from_idx < Z_ARRVAL_P(from)->nNumUsed) {
    2574          51 :                                         tmp_from = &Z_ARRVAL_P(from)->arData[from_idx].val;
    2575          51 :                                         if (Z_TYPE_P(tmp_from) != IS_UNDEF) {
    2576          51 :                                                 break;
    2577             :                                         }
    2578           0 :                                         from_idx++;
    2579             :                                 }
    2580          57 :                                 if (from_idx < Z_ARRVAL_P(from)->nNumUsed) {
    2581          51 :                                         f = zval_get_long(tmp_from);
    2582             : 
    2583          51 :                                         if (f < 0) {
    2584           0 :                                                 f = (zend_long)ZSTR_LEN(orig_str) + f;
    2585           0 :                                                 if (f < 0) {
    2586           0 :                                                         f = 0;
    2587             :                                                 }
    2588          51 :                                         } else if (f > (zend_long)ZSTR_LEN(orig_str)) {
    2589           0 :                                                 f = ZSTR_LEN(orig_str);
    2590             :                                         }
    2591          51 :                                         from_idx++;
    2592             :                                 } else {
    2593           6 :                                         f = 0;
    2594             :                                 }
    2595             :                         } else {
    2596          22 :                                 f = Z_LVAL_P(from);
    2597          22 :                                 if (f < 0) {
    2598           0 :                                         f = (zend_long)ZSTR_LEN(orig_str) + f;
    2599           0 :                                         if (f < 0) {
    2600           0 :                                                 f = 0;
    2601             :                                         }
    2602          22 :                                 } else if (f > (zend_long)ZSTR_LEN(orig_str)) {
    2603           0 :                                         f = ZSTR_LEN(orig_str);
    2604             :                                 }
    2605             :                         }
    2606             : 
    2607         181 :                         if (argc > 3 && Z_TYPE_P(len) == IS_ARRAY) {
    2608          58 :                                 while (len_idx < Z_ARRVAL_P(len)->nNumUsed) {
    2609          23 :                                         tmp_len = &Z_ARRVAL_P(len)->arData[len_idx].val;
    2610          23 :                                         if (Z_TYPE_P(tmp_len) != IS_UNDEF) {
    2611          23 :                                                 break;
    2612             :                                         }
    2613           0 :                                         len_idx++;
    2614             :                                 }
    2615          29 :                                 if (len_idx < Z_ARRVAL_P(len)->nNumUsed) {
    2616          23 :                                         l = zval_get_long(tmp_len);
    2617          23 :                                         len_idx++;
    2618             :                                 } else {
    2619           6 :                                         l = ZSTR_LEN(orig_str);
    2620             :                                 }
    2621          50 :                         } else if (argc > 3) {
    2622          44 :                                 l = Z_LVAL_P(len);
    2623             :                         } else {
    2624           6 :                                 l = ZSTR_LEN(orig_str);
    2625             :                         }
    2626             : 
    2627          79 :                         if (l < 0) {
    2628          23 :                                 l = (ZSTR_LEN(orig_str) - f) + l;
    2629          23 :                                 if (l < 0) {
    2630           0 :                                         l = 0;
    2631             :                                 }
    2632             :                         }
    2633             : 
    2634          79 :                         if ((f + l) > (zend_long)ZSTR_LEN(orig_str)) {
    2635          14 :                                 l = ZSTR_LEN(orig_str) - f;
    2636             :                         }
    2637             : 
    2638          79 :                         result_len = ZSTR_LEN(orig_str) - l;
    2639             : 
    2640         158 :                         if (Z_TYPE_P(repl) == IS_ARRAY) {
    2641          76 :                                 while (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2642          23 :                                         tmp_repl = &Z_ARRVAL_P(repl)->arData[repl_idx].val;
    2643          23 :                                         if (Z_TYPE_P(tmp_repl) != IS_UNDEF) {
    2644          23 :                                                 break;
    2645             :                                         }
    2646           0 :                                         repl_idx++;
    2647             :                                 }
    2648          38 :                                 if (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2649          23 :                                         zend_string *repl_str = zval_get_string(tmp_repl);
    2650             : 
    2651          23 :                                         result_len += ZSTR_LEN(repl_str);
    2652          23 :                                         repl_idx++;
    2653          23 :                                         result = zend_string_alloc(result_len, 0);
    2654             : 
    2655          23 :                                         memcpy(ZSTR_VAL(result), ZSTR_VAL(orig_str), f);
    2656          23 :                                         memcpy((ZSTR_VAL(result) + f), ZSTR_VAL(repl_str), ZSTR_LEN(repl_str));
    2657          23 :                                         memcpy((ZSTR_VAL(result) + f + ZSTR_LEN(repl_str)), ZSTR_VAL(orig_str) + f + l, ZSTR_LEN(orig_str) - f - l);
    2658             :                                         zend_string_release(repl_str);
    2659             :                                 } else {
    2660          15 :                                         result = zend_string_alloc(result_len, 0);
    2661             : 
    2662          15 :                                         memcpy(ZSTR_VAL(result), ZSTR_VAL(orig_str), f);
    2663          15 :                                         memcpy((ZSTR_VAL(result) + f), ZSTR_VAL(orig_str) + f + l, ZSTR_LEN(orig_str) - f - l);
    2664             :                                 }
    2665             :                         } else {
    2666          41 :                                 result_len += Z_STRLEN_P(repl);
    2667             : 
    2668          41 :                                 result = zend_string_alloc(result_len, 0);
    2669             : 
    2670          41 :                                 memcpy(ZSTR_VAL(result), ZSTR_VAL(orig_str), f);
    2671          41 :                                 memcpy((ZSTR_VAL(result) + f), Z_STRVAL_P(repl), Z_STRLEN_P(repl));
    2672          41 :                                 memcpy((ZSTR_VAL(result) + f + Z_STRLEN_P(repl)), ZSTR_VAL(orig_str) + f + l, ZSTR_LEN(orig_str) - f - l);
    2673             :                         }
    2674             : 
    2675          79 :                         ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
    2676             : 
    2677          79 :                         if (str_index) {
    2678             :                                 zval tmp;
    2679             : 
    2680           2 :                                 ZVAL_NEW_STR(&tmp, result);
    2681           2 :                                 zend_symtable_update(Z_ARRVAL_P(return_value), str_index, &tmp);
    2682             :                         } else {
    2683          77 :                                 add_index_str(return_value, num_index, result);
    2684             :                         }
    2685             : 
    2686             :                         zend_string_release(orig_str);
    2687             :                 } ZEND_HASH_FOREACH_END();
    2688             :         } /* if */
    2689             : }
    2690             : /* }}} */
    2691             : 
    2692             : /* {{{ proto string quotemeta(string str)
    2693             :    Quotes meta characters */
    2694           6 : PHP_FUNCTION(quotemeta)
    2695             : {
    2696             :         zend_string *old;
    2697             :         char *old_end;
    2698             :         char *p, *q;
    2699             :         char c;
    2700             :         zend_string *str;
    2701             : 
    2702           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &old) == FAILURE) {
    2703           2 :                 return;
    2704             :         }
    2705             : 
    2706           4 :         old_end = ZSTR_VAL(old) + ZSTR_LEN(old);
    2707             : 
    2708           4 :         if (ZSTR_VAL(old) == old_end) {
    2709           0 :                 RETURN_FALSE;
    2710             :         }
    2711             : 
    2712           8 :         str = zend_string_alloc(2 * ZSTR_LEN(old), 0);
    2713             : 
    2714          60 :         for (p = ZSTR_VAL(old), q = ZSTR_VAL(str); p != old_end; p++) {
    2715          56 :                 c = *p;
    2716          56 :                 switch (c) {
    2717             :                         case '.':
    2718             :                         case '\\':
    2719             :                         case '+':
    2720             :                         case '*':
    2721             :                         case '?':
    2722             :                         case '[':
    2723             :                         case '^':
    2724             :                         case ']':
    2725             :                         case '$':
    2726             :                         case '(':
    2727             :                         case ')':
    2728          24 :                                 *q++ = '\\';
    2729             :                                 /* break is missing _intentionally_ */
    2730             :                         default:
    2731          56 :                                 *q++ = c;
    2732             :                 }
    2733             :         }
    2734             : 
    2735           4 :         *q = '\0';
    2736             : 
    2737           8 :         RETURN_NEW_STR(zend_string_truncate(str, q - ZSTR_VAL(str), 0));
    2738             : }
    2739             : /* }}} */
    2740             : 
    2741             : /* {{{ proto int ord(string character)
    2742             :    Returns ASCII value of character */
    2743       51505 : PHP_FUNCTION(ord)
    2744             : {
    2745             :         char   *str;
    2746             :         size_t str_len;
    2747             : 
    2748             : #ifndef FAST_ZPP
    2749             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) == FAILURE) {
    2750             :                 return;
    2751             :         }
    2752             : #else
    2753       51505 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2754      154503 :                 Z_PARAM_STRING(str, str_len)
    2755       51505 :         ZEND_PARSE_PARAMETERS_END();
    2756             : #endif
    2757             : 
    2758       51496 :         RETURN_LONG((unsigned char) str[0]);
    2759             : }
    2760             : /* }}} */
    2761             : 
    2762             : /* {{{ proto string chr(int ascii)
    2763             :    Converts ASCII code to a character */
    2764      662750 : PHP_FUNCTION(chr)
    2765             : {
    2766             :         zend_long c;
    2767             : 
    2768      662750 :         if (ZEND_NUM_ARGS() != 1) {
    2769           4 :                 WRONG_PARAM_COUNT;
    2770             :         }
    2771             : 
    2772             : #ifndef FAST_ZPP
    2773             :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "l", &c) == FAILURE) {
    2774             :                 c = 0;
    2775             :         }
    2776             : #else
    2777      662746 :         ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 1)
    2778     1988238 :                 Z_PARAM_LONG(c)
    2779      662746 :         ZEND_PARSE_PARAMETERS_END_EX(c = 0);
    2780             : #endif
    2781             : 
    2782      662746 :         c &= 0xff;
    2783      662746 :         if (CG(one_char_string)[c]) {
    2784           0 :                 ZVAL_INTERNED_STR(return_value, CG(one_char_string)[c]);
    2785             :         } else {
    2786     1325492 :                 ZVAL_NEW_STR(return_value, zend_string_alloc(1, 0));
    2787      662746 :                 Z_STRVAL_P(return_value)[0] = (char)c;
    2788      662746 :                 Z_STRVAL_P(return_value)[1] = '\0';
    2789             :         }
    2790             : }
    2791             : /* }}} */
    2792             : 
    2793             : /* {{{ php_ucfirst
    2794             :    Uppercase the first character of the word in a native string */
    2795          59 : static void php_ucfirst(char *str)
    2796             : {
    2797             :         register char *r;
    2798          59 :         r = str;
    2799          59 :         *r = toupper((unsigned char) *r);
    2800          59 : }
    2801             : /* }}} */
    2802             : 
    2803             : /* {{{ proto string ucfirst(string str)
    2804             :    Makes a string's first character uppercase */
    2805          67 : PHP_FUNCTION(ucfirst)
    2806             : {
    2807             :         zend_string *str;
    2808             : 
    2809             : #ifndef FAST_ZPP
    2810             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    2811             :                 return;
    2812             :         }
    2813             : #else
    2814          67 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2815         192 :                 Z_PARAM_STR(str)
    2816          67 :         ZEND_PARSE_PARAMETERS_END();
    2817             : #endif
    2818             : 
    2819          63 :         if (!ZSTR_LEN(str)) {
    2820           4 :                 RETURN_EMPTY_STRING();
    2821             :         }
    2822             : 
    2823         118 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    2824          59 :         php_ucfirst(Z_STRVAL_P(return_value));
    2825             : }
    2826             : /* }}} */
    2827             : 
    2828             : /* {{{
    2829             :    Lowercase the first character of the word in a native string */
    2830          41 : static void php_lcfirst(char *str)
    2831             : {
    2832             :         register char *r;
    2833          41 :         r = str;
    2834          41 :         *r = tolower((unsigned char) *r);
    2835          41 : }
    2836             : /* }}} */
    2837             : 
    2838             : /* {{{ proto string lcfirst(string str)
    2839             :    Make a string's first character lowercase */
    2840          49 : PHP_FUNCTION(lcfirst)
    2841             : {
    2842             :         zend_string  *str;
    2843             : 
    2844          49 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    2845           4 :                 return;
    2846             :         }
    2847             : 
    2848          45 :         if (!ZSTR_LEN(str)) {
    2849           4 :                 RETURN_EMPTY_STRING();
    2850             :         }
    2851             : 
    2852          82 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    2853          41 :         php_lcfirst(Z_STRVAL_P(return_value));
    2854             : }
    2855             : /* }}} */
    2856             : 
    2857             : /* {{{ proto string ucwords(string str [, string delims])
    2858             :    Uppercase the first character of every word in a string */
    2859         115 : PHP_FUNCTION(ucwords)
    2860             : {
    2861             :         zend_string *str;
    2862         115 :         char *delims = " \t\r\n\f\v";
    2863             :         register char *r, *r_end;
    2864         115 :         size_t delims_len = 6;
    2865             :         char mask[256];
    2866             : 
    2867             : #ifndef FAST_ZPP
    2868             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|s", &str, &delims, &delims_len) == FAILURE) {
    2869             :                 return;
    2870             :         }
    2871             : #else
    2872         115 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2873         339 :                 Z_PARAM_STR(str)
    2874         107 :                 Z_PARAM_OPTIONAL
    2875         115 :                 Z_PARAM_STRING(delims, delims_len)
    2876         115 :         ZEND_PARSE_PARAMETERS_END();
    2877             : #endif
    2878             : 
    2879         107 :         if (!ZSTR_LEN(str)) {
    2880          10 :                 RETURN_EMPTY_STRING();
    2881             :         }
    2882             : 
    2883          97 :         php_charmask((unsigned char *)delims, delims_len, mask);
    2884             : 
    2885         194 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    2886          97 :         r = Z_STRVAL_P(return_value);
    2887             : 
    2888          97 :         *r = toupper((unsigned char) *r);
    2889        2021 :         for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) {
    2890        1827 :                 if (mask[(unsigned char)*r++]) {
    2891         208 :                         *r = toupper((unsigned char) *r);
    2892             :                 }
    2893             :         }
    2894             : }
    2895             : /* }}} */
    2896             : 
    2897             : /* {{{ php_strtr
    2898             :  */
    2899          31 : PHPAPI char *php_strtr(char *str, size_t len, char *str_from, char *str_to, size_t trlen)
    2900             : {
    2901             :         size_t i;
    2902             : 
    2903          31 :         if (UNEXPECTED(trlen < 1)) {
    2904           0 :                 return str;
    2905          31 :         } else if (trlen == 1) {
    2906           0 :                 char ch_from = *str_from;
    2907           0 :                 char ch_to = *str_to;
    2908             : 
    2909           0 :                 for (i = 0; i < len; i++) {
    2910           0 :                         if (str[i] == ch_from) {
    2911           0 :                                 str[i] = ch_to;
    2912             :                         }
    2913             :                 }
    2914             :         } else {
    2915          31 :                 unsigned char xlat[256], j = 0;
    2916             : 
    2917        7936 :                 do { xlat[j] = j; } while (++j != 0);
    2918             : 
    2919        1539 :                 for (i = 0; i < trlen; i++) {
    2920        1508 :                         xlat[(size_t)(unsigned char) str_from[i]] = str_to[i];
    2921             :                 }
    2922             :                 
    2923       66288 :                 for (i = 0; i < len; i++) {
    2924       66257 :                         str[i] = xlat[(size_t)(unsigned char) str[i]];
    2925             :                 }
    2926             :         }
    2927             : 
    2928          31 :         return str;
    2929             : }
    2930             : /* }}} */
    2931             : 
    2932             : /* {{{ php_strtr_ex
    2933             :  */
    2934         113 : static zend_string *php_strtr_ex(zend_string *str, char *str_from, char *str_to, size_t trlen)
    2935             : {
    2936         113 :         zend_string *new_str = NULL;
    2937             :         size_t i;
    2938             : 
    2939         113 :         if (UNEXPECTED(trlen < 1)) {
    2940          12 :                 return zend_string_copy(str);
    2941         101 :         } else if (trlen == 1) {
    2942          17 :                 char ch_from = *str_from;
    2943          17 :                 char ch_to = *str_to;
    2944             : 
    2945          66 :                 for (i = 0; i < ZSTR_LEN(str); i++) {
    2946          66 :                         if (ZSTR_VAL(str)[i] == ch_from) {
    2947          34 :                                 new_str = zend_string_alloc(ZSTR_LEN(str), 0);
    2948          17 :                                 memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), i);
    2949          17 :                                 ZSTR_VAL(new_str)[i] = ch_to;
    2950          17 :                                 break;
    2951             :                         }
    2952             :                 }
    2953          90 :                 for (; i < ZSTR_LEN(str); i++) {
    2954          73 :                         ZSTR_VAL(new_str)[i] = (ZSTR_VAL(str)[i] != ch_from) ? ZSTR_VAL(str)[i] : ch_to;
    2955             :                 }
    2956             :         } else {
    2957          84 :                 unsigned char xlat[256], j = 0;
    2958             : 
    2959       21504 :                 do { xlat[j] = j; } while (++j != 0);
    2960             : 
    2961        1658 :                 for (i = 0; i < trlen; i++) {
    2962        1574 :                         xlat[(size_t)(unsigned char) str_from[i]] = str_to[i];
    2963             :                 }
    2964             : 
    2965         253 :                 for (i = 0; i < ZSTR_LEN(str); i++) {
    2966         243 :                         if (ZSTR_VAL(str)[i] != xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]]) {
    2967         148 :                                 new_str = zend_string_alloc(ZSTR_LEN(str), 0);
    2968          74 :                                 memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), i);
    2969          74 :                                 ZSTR_VAL(new_str)[i] = xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]];
    2970          74 :                                 break;
    2971             :                         }
    2972             :                 }
    2973             : 
    2974       16814 :                 for (;i < ZSTR_LEN(str); i++) {
    2975       16730 :                         ZSTR_VAL(new_str)[i] = xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]];
    2976             :                 }
    2977             :         }
    2978             : 
    2979         101 :         if (!new_str) {
    2980          10 :                 return zend_string_copy(str);
    2981             :         }
    2982             : 
    2983          91 :         ZSTR_VAL(new_str)[ZSTR_LEN(new_str)] = 0;
    2984          91 :         return new_str;
    2985             : }
    2986             : /* }}} */
    2987             : 
    2988             : /* {{{ php_strtr_array */
    2989          38 : static void php_strtr_array(zval *return_value, zend_string *input, HashTable *pats)
    2990             : {
    2991          38 :         char *str = ZSTR_VAL(input);
    2992          38 :         size_t slen = ZSTR_LEN(input);
    2993             :         zend_ulong num_key;
    2994             :         zend_string *str_key;
    2995             :         size_t len, pos, old_pos;
    2996          38 :         int num_keys = 0;
    2997          38 :         size_t minlen = 128*1024;
    2998          38 :         size_t maxlen = 0;
    2999             :         HashTable str_hash;
    3000             :         zval *entry;
    3001             :         char *key;
    3002          38 :         smart_str result = {0};
    3003             :         zend_ulong bitset[256/sizeof(zend_ulong)];
    3004             :         zend_ulong *num_bitset;
    3005             : 
    3006             :         /* we will collect all possible key lengths */
    3007          38 :         num_bitset = ecalloc((slen + (sizeof(zend_ulong)-1)) / sizeof(zend_ulong), sizeof(zend_ulong));
    3008          38 :         memset(bitset, 0, sizeof(bitset));
    3009             : 
    3010             :         /* check if original array has numeric keys */
    3011         274 :         ZEND_HASH_FOREACH_STR_KEY(pats, str_key) {
    3012         118 :                 if (UNEXPECTED(!str_key)) {
    3013           9 :                         num_keys = 1;
    3014             :                 } else {
    3015         109 :                         len = ZSTR_LEN(str_key);
    3016         109 :                         if (UNEXPECTED(len < 1)) {
    3017           0 :                                 RETURN_FALSE;
    3018         109 :                         } else if (UNEXPECTED(len > slen)) {
    3019             :                                 /* skip long patterns */
    3020          15 :                                 continue;
    3021             :                         }
    3022          94 :                         if (len > maxlen) {
    3023          72 :                                 maxlen = len;
    3024             :                         }
    3025          94 :                         if (len < minlen) {
    3026          40 :                                 minlen = len;
    3027             :                         }
    3028             :                         /* remember possible key length */
    3029          94 :                         num_bitset[len / sizeof(zend_ulong)] |= Z_UL(1) << (len % sizeof(zend_ulong));
    3030          94 :                         bitset[((unsigned char)ZSTR_VAL(str_key)[0]) / sizeof(zend_ulong)] |= Z_UL(1) << (((unsigned char)ZSTR_VAL(str_key)[0]) % sizeof(zend_ulong));
    3031             :                 }
    3032             :         } ZEND_HASH_FOREACH_END();
    3033             : 
    3034          38 :         if (UNEXPECTED(num_keys)) {
    3035             :                 zend_string *key_used;
    3036             :                 /* we have to rebuild HashTable with numeric keys */
    3037           8 :                 zend_hash_init(&str_hash, zend_hash_num_elements(pats), NULL, NULL, 0);
    3038          68 :                 ZEND_HASH_FOREACH_KEY_VAL(pats, num_key, str_key, entry) {
    3039          30 :                         if (UNEXPECTED(!str_key)) {
    3040           9 :                                 key_used = zend_long_to_str(num_key);
    3041           9 :                                 len = ZSTR_LEN(key_used);
    3042           9 :                                 if (UNEXPECTED(len > slen)) {
    3043             :                                         /* skip long patterns */
    3044           0 :                                         continue;
    3045             :                                 }
    3046           9 :                                 if (len > maxlen) {
    3047           1 :                                         maxlen = len;
    3048             :                                 }
    3049           9 :                                 if (len < minlen) {
    3050           1 :                                         minlen = len;
    3051             :                                 }
    3052             :                                 /* remember possible key length */
    3053           9 :                                 num_bitset[len / sizeof(zend_ulong)] |= Z_UL(1) << (len % sizeof(zend_ulong));
    3054           9 :                                 bitset[((unsigned char)ZSTR_VAL(key_used)[0]) / sizeof(zend_ulong)] |= Z_UL(1) << (((unsigned char)ZSTR_VAL(key_used)[0]) % sizeof(zend_ulong));
    3055             :                         } else {
    3056          21 :                                 key_used = str_key;
    3057          21 :                                 len = ZSTR_LEN(key_used);
    3058          21 :                                 if (UNEXPECTED(len > slen)) {
    3059             :                                         /* skip long patterns */
    3060           8 :                                         continue;
    3061             :                                 }
    3062             :                         }
    3063          22 :                         zend_hash_add(&str_hash, key_used, entry);
    3064          22 :                         if (UNEXPECTED(!str_key)) {
    3065             :                                 zend_string_release(key_used);
    3066             :                         }
    3067             :                 } ZEND_HASH_FOREACH_END();
    3068           8 :                 pats = &str_hash;
    3069             :         }
    3070             : 
    3071          38 :         if (UNEXPECTED(minlen > maxlen)) {
    3072             :                 /* return the original string */
    3073           0 :                 if (pats == &str_hash) {
    3074           0 :                         zend_hash_destroy(&str_hash);
    3075             :                 }
    3076           0 :                 efree(num_bitset);
    3077           0 :                 RETURN_STR_COPY(input);
    3078             :         }
    3079             : 
    3080          38 :         old_pos = pos = 0;
    3081         979 :         while (pos <= slen - minlen) {
    3082         903 :                 key = str + pos;
    3083         903 :                 if (bitset[((unsigned char)key[0]) / sizeof(zend_ulong)] & (Z_UL(1) << (((unsigned char)key[0]) % sizeof(zend_ulong)))) {
    3084          95 :                         len = maxlen;
    3085          95 :                         if (len > slen - pos) {
    3086           2 :                                 len = slen - pos;
    3087             :                         }
    3088         305 :                         while (len >= minlen) {
    3089         206 :                                 if ((num_bitset[len / sizeof(zend_ulong)] & (Z_UL(1) << (len % sizeof(zend_ulong))))) {
    3090         160 :                                         entry = zend_hash_str_find(pats, key, len);
    3091         160 :                                         if (entry != NULL) {
    3092          91 :                                                 zend_string *s = zval_get_string(entry);
    3093          91 :                                                 smart_str_appendl(&result, str + old_pos, pos - old_pos);
    3094             :                                                 smart_str_append(&result, s);
    3095          91 :                                                 old_pos = pos + len;
    3096          91 :                                                 pos = old_pos - 1;
    3097             :                                                 zend_string_release(s);
    3098          91 :                                                 break;
    3099             :                                         }
    3100             :                                 }
    3101         115 :                                 len--;
    3102             :                         }
    3103             :                 }
    3104         903 :                 pos++;
    3105             :         }
    3106             : 
    3107          38 :         if (result.s) {
    3108          26 :                 smart_str_appendl(&result, str + old_pos, slen - old_pos);
    3109             :                 smart_str_0(&result);
    3110          26 :                 RETVAL_NEW_STR(result.s);
    3111             :         } else {
    3112             :                 smart_str_free(&result);
    3113          12 :                 RETVAL_STR_COPY(input);
    3114             :         }
    3115             : 
    3116          38 :         if (pats == &str_hash) {
    3117           8 :                 zend_hash_destroy(&str_hash);
    3118             :         }
    3119          38 :         efree(num_bitset);
    3120             : }
    3121             : /* }}} */
    3122             : 
    3123             : /* {{{ php_char_to_str_ex
    3124             :  */
    3125        4400 : static zend_string* php_char_to_str_ex(zend_string *str, char from, char *to, size_t to_len, int case_sensitivity, zend_long *replace_count)
    3126             : {
    3127             :         zend_string *result;
    3128        4400 :         size_t char_count = 0;
    3129        4400 :         char lc_from = 0;
    3130        4400 :         char *source, *target, *source_end= ZSTR_VAL(str) + ZSTR_LEN(str);
    3131             : 
    3132        4400 :         if (case_sensitivity) {
    3133        4390 :                 char *p = ZSTR_VAL(str), *e = p + ZSTR_LEN(str);
    3134       15864 :                 while ((p = memchr(p, from, (e - p)))) {
    3135        7084 :                         char_count++;
    3136        7084 :                         p++;
    3137             :                 }
    3138             :         } else {
    3139          10 :                 lc_from = tolower(from);
    3140         327 :                 for (source = ZSTR_VAL(str); source < source_end; source++) {
    3141         317 :                         if (tolower(*source) == lc_from) {
    3142          29 :                                 char_count++;
    3143             :                         }
    3144             :                 }
    3145             :         }
    3146             : 
    3147        4400 :         if (char_count == 0) {
    3148         285 :                 return zend_string_copy(str);
    3149             :         }
    3150             : 
    3151        4115 :         if (to_len > 0) {
    3152        1184 :                 result = zend_string_safe_alloc(char_count, to_len - 1, ZSTR_LEN(str), 0);
    3153             :         } else {
    3154        7046 :                 result = zend_string_alloc(ZSTR_LEN(str) - char_count, 0);
    3155             :         }
    3156        4115 :         target = ZSTR_VAL(result);
    3157             : 
    3158        4115 :         if (case_sensitivity) {
    3159        4110 :                 char *p = ZSTR_VAL(str), *e = p + ZSTR_LEN(str), *s = ZSTR_VAL(str);
    3160       15304 :                 while ((p = memchr(p, from, (e - p)))) {
    3161        7084 :                         memcpy(target, s, (p - s));
    3162        7084 :                         target += p - s;
    3163        7084 :                         memcpy(target, to, to_len);
    3164        7084 :                         target += to_len;
    3165        7084 :                         p++;
    3166        7084 :                         s = p;
    3167        7084 :                         if (replace_count) {
    3168        6813 :                                 *replace_count += 1;
    3169             :                         }
    3170             :                 }
    3171        4110 :                 if (s < e) {
    3172         321 :                         memcpy(target, s, (e - s));
    3173         321 :                         target += e - s;
    3174             :                 }
    3175             :         } else {
    3176         212 :                 for (source = ZSTR_VAL(str); source < source_end; source++) {
    3177         207 :                         if (tolower(*source) == lc_from) {
    3178          29 :                                 if (replace_count) {
    3179          29 :                                         *replace_count += 1;
    3180             :                                 }
    3181          29 :                                 memcpy(target, to, to_len);
    3182          29 :                                 target += to_len;
    3183             :                         } else {
    3184         178 :                                 *target = *source;
    3185         178 :                                 target++;
    3186             :                         }
    3187             :                 }
    3188             :         }
    3189        4115 :         *target = 0;
    3190        4115 :         return result;
    3191             : }
    3192             : /* }}} */
    3193             : 
    3194             : /* {{{ php_str_to_str_ex
    3195             :  */
    3196      172441 : static zend_string *php_str_to_str_ex(zend_string *haystack,
    3197             :         char *needle, size_t needle_len, char *str, size_t str_len, zend_long *replace_count)
    3198             : {
    3199             :         zend_string *new_str;
    3200             : 
    3201      172441 :         if (needle_len < ZSTR_LEN(haystack)) {
    3202             :                 char *end;
    3203             :                 char *e, *s, *p, *r;
    3204             : 
    3205      170021 :                 if (needle_len == str_len) {
    3206       25079 :                         new_str = NULL;
    3207       25079 :                         end = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
    3208       51344 :                         for (p = ZSTR_VAL(haystack); (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3209         593 :                                 if (!new_str) {
    3210         818 :                                         new_str = zend_string_init(ZSTR_VAL(haystack), ZSTR_LEN(haystack), 0);
    3211             :                                 }
    3212         593 :                                 memcpy(ZSTR_VAL(new_str) + (r - ZSTR_VAL(haystack)), str, str_len);
    3213         593 :                                 (*replace_count)++;
    3214             :                         }
    3215       25079 :                         if (!new_str) {
    3216       24670 :                                 goto nothing_todo;
    3217             :                         }
    3218         409 :                         return new_str;
    3219             :                 } else {
    3220      144942 :                         size_t count = 0;
    3221      144942 :                         char *o = ZSTR_VAL(haystack);
    3222      144942 :                         char *n = needle;
    3223      144942 :                         char *endp = o + ZSTR_LEN(haystack);
    3224             : 
    3225      386556 :                         while ((o = (char*)php_memnstr(o, n, needle_len, endp))) {
    3226       96672 :                                 o += needle_len;
    3227       96672 :                                 count++;
    3228             :                         }
    3229      144942 :                         if (count == 0) {
    3230             :                                 /* Needle doesn't occur, shortcircuit the actual replacement. */
    3231      103547 :                                 goto nothing_todo;
    3232             :                         }
    3233       82790 :                         new_str = zend_string_alloc(count * (str_len - needle_len) + ZSTR_LEN(haystack), 0);
    3234             : 
    3235       41395 :                         e = s = ZSTR_VAL(new_str);
    3236       41395 :                         end = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
    3237      276134 :                         for (p = ZSTR_VAL(haystack); (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3238       96672 :                                 memcpy(e, p, r - p);
    3239       96672 :                                 e += r - p;
    3240       96672 :                                 memcpy(e, str, str_len);
    3241       96672 :                                 e += str_len;
    3242       96672 :                                 (*replace_count)++;
    3243             :                         }
    3244             : 
    3245       41395 :                         if (p < end) {
    3246       40225 :                                 memcpy(e, p, end - p);
    3247       40225 :                                 e += end - p;
    3248             :                         }
    3249             : 
    3250       41395 :                         *e = '\0';
    3251       41395 :                         return new_str;
    3252             :                 }
    3253        2420 :         } else if (needle_len > ZSTR_LEN(haystack) || memcmp(ZSTR_VAL(haystack), needle, ZSTR_LEN(haystack))) {
    3254             : nothing_todo:
    3255      130610 :                 return zend_string_copy(haystack);
    3256             :         } else {
    3257          27 :                 new_str = zend_string_init(str, str_len, 0);
    3258          27 :                 (*replace_count)++;
    3259          27 :                 return new_str;
    3260             :         }
    3261             : }
    3262             : /* }}} */
    3263             : 
    3264             : /* {{{ php_str_to_str_i_ex
    3265             :  */
    3266         106 : static zend_string *php_str_to_str_i_ex(zend_string *haystack, char *lc_haystack,
    3267             :         zend_string *needle, char *str, size_t str_len, zend_long *replace_count)
    3268             : {
    3269         106 :         zend_string *new_str = NULL;
    3270             :         zend_string *lc_needle;
    3271             : 
    3272         106 :         if (ZSTR_LEN(needle) < ZSTR_LEN(haystack)) {
    3273             :                 char *end;
    3274             :                 char *e, *s, *p, *r;
    3275             : 
    3276          71 :                 if (ZSTR_LEN(needle) == str_len) {
    3277           2 :                         lc_needle = php_string_tolower(needle);
    3278           2 :                         end = lc_haystack + ZSTR_LEN(haystack);
    3279          32 :                         for (p = lc_haystack; (r = (char*)php_memnstr(p, ZSTR_VAL(lc_needle), ZSTR_LEN(lc_needle), end)); p = r + ZSTR_LEN(lc_needle)) {
    3280          14 :                                 if (!new_str) {
    3281           4 :                                         new_str = zend_string_init(ZSTR_VAL(haystack), ZSTR_LEN(haystack), 0);
    3282             :                                 }
    3283          14 :                                 memcpy(ZSTR_VAL(new_str) + (r - lc_haystack), str, str_len);
    3284          14 :                                 (*replace_count)++;
    3285             :                         }
    3286             :                         zend_string_release(lc_needle);
    3287             : 
    3288           2 :                         if (!new_str) {
    3289           0 :                                 goto nothing_todo;
    3290             :                         }
    3291           2 :                         return new_str;
    3292             :                 } else {
    3293          69 :                         size_t count = 0;
    3294          69 :                         char *o = lc_haystack;
    3295             :                         char *n;
    3296          69 :                         char *endp = o + ZSTR_LEN(haystack);
    3297             : 
    3298          69 :                         lc_needle = php_string_tolower(needle);
    3299          69 :                         n = ZSTR_VAL(lc_needle);
    3300             : 
    3301         509 :                         while ((o = (char*)php_memnstr(o, n, ZSTR_LEN(lc_needle), endp))) {
    3302         151 :                                 o += ZSTR_LEN(lc_needle);
    3303         151 :                                 count++;
    3304             :                         }
    3305          69 :                         if (count == 0) {
    3306             :                                 /* Needle doesn't occur, shortcircuit the actual replacement. */
    3307             :                                 zend_string_release(lc_needle);
    3308           8 :                                 goto nothing_todo;
    3309             :                         }
    3310             : 
    3311         122 :                         new_str = zend_string_alloc(count * (str_len - ZSTR_LEN(lc_needle)) + ZSTR_LEN(haystack), 0);
    3312             : 
    3313          61 :                         e = s = ZSTR_VAL(new_str);
    3314          61 :                         end = lc_haystack + ZSTR_LEN(haystack);
    3315             : 
    3316         424 :                         for (p = lc_haystack; (r = (char*)php_memnstr(p, ZSTR_VAL(lc_needle), ZSTR_LEN(lc_needle), end)); p = r + ZSTR_LEN(lc_needle)) {
    3317         151 :                                 memcpy(e, ZSTR_VAL(haystack) + (p - lc_haystack), r - p);
    3318         151 :                                 e += r - p;
    3319         151 :                                 memcpy(e, str, str_len);
    3320         151 :                                 e += str_len;
    3321         151 :                                 (*replace_count)++;
    3322             :                         }
    3323             : 
    3324          61 :                         if (p < end) {
    3325          21 :                                 memcpy(e, ZSTR_VAL(haystack) + (p - lc_haystack), end - p);
    3326          21 :                                 e += end - p;
    3327             :                         }
    3328          61 :                         *e = '\0';
    3329             : 
    3330             :                         zend_string_release(lc_needle);
    3331             : 
    3332          61 :                         return new_str;
    3333             :                 }
    3334          35 :         } else if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
    3335             : nothing_todo:
    3336           9 :                 return zend_string_copy(haystack);
    3337             :         } else {
    3338          35 :                 lc_needle = php_string_tolower(needle);
    3339             : 
    3340          35 :                 if (memcmp(lc_haystack, ZSTR_VAL(lc_needle), ZSTR_LEN(lc_needle))) {
    3341             :                         zend_string_release(lc_needle);
    3342           1 :                         goto nothing_todo;
    3343             :                 }
    3344             :                 zend_string_release(lc_needle);
    3345             : 
    3346          34 :                 new_str = zend_string_init(str, str_len, 0);
    3347             : 
    3348          34 :                 (*replace_count)++;
    3349          34 :                 return new_str;
    3350             :         }
    3351             : }
    3352             : /* }}} */
    3353             : 
    3354             : /* {{{ php_str_to_str
    3355             :  */
    3356        1439 : PHPAPI zend_string *php_str_to_str(char *haystack, size_t length, char *needle, size_t needle_len, char *str, size_t str_len)
    3357             : {
    3358             :         zend_string *new_str;
    3359             : 
    3360        1439 :         if (needle_len < length) {
    3361             :                 char *end;
    3362             :                 char *e, *s, *p, *r;
    3363             : 
    3364        1051 :                 if (needle_len == str_len) {
    3365           0 :                         new_str = zend_string_init(haystack, length, 0);
    3366           0 :                         end = ZSTR_VAL(new_str) + length;
    3367           0 :                         for (p = ZSTR_VAL(new_str); (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3368           0 :                                 memcpy(r, str, str_len);
    3369             :                         }
    3370           0 :                         return new_str;
    3371             :                 } else {
    3372        1051 :                         if (str_len < needle_len) {
    3373           0 :                                 new_str = zend_string_alloc(length, 0);
    3374             :                         } else {
    3375        1051 :                                 size_t count = 0;
    3376        1051 :                                 char *o = haystack;
    3377        1051 :                                 char *n = needle;
    3378        1051 :                                 char *endp = o + length;
    3379             : 
    3380        2123 :                                 while ((o = (char*)php_memnstr(o, n, needle_len, endp))) {
    3381          21 :                                         o += needle_len;
    3382          21 :                                         count++;
    3383             :                                 }
    3384        1051 :                                 if (count == 0) {
    3385             :                                         /* Needle doesn't occur, shortcircuit the actual replacement. */
    3386        1040 :                                         new_str = zend_string_init(haystack, length, 0);
    3387        1040 :                                         return new_str;
    3388             :                                 } else {
    3389          22 :                                         new_str = zend_string_alloc(count * (str_len - needle_len) + length, 0);
    3390             :                                 }
    3391             :                         }
    3392             : 
    3393          11 :                         e = s = ZSTR_VAL(new_str);
    3394          11 :                         end = haystack + length;
    3395          64 :                         for (p = haystack; (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3396          21 :                                 memcpy(e, p, r - p);
    3397          21 :                                 e += r - p;
    3398          21 :                                 memcpy(e, str, str_len);
    3399          21 :                                 e += str_len;
    3400             :                         }
    3401             : 
    3402          11 :                         if (p < end) {
    3403           8 :                                 memcpy(e, p, end - p);
    3404           8 :                                 e += end - p;
    3405             :                         }
    3406             : 
    3407          11 :                         *e = '\0';
    3408          22 :                         new_str = zend_string_truncate(new_str, e - s, 0);
    3409          11 :                         return new_str;
    3410             :                 }
    3411         388 :         } else if (needle_len > length || memcmp(haystack, needle, length)) {
    3412         380 :                 new_str = zend_string_init(haystack, length, 0);
    3413         380 :                 return new_str;
    3414             :         } else {
    3415           8 :                 new_str = zend_string_init(str, str_len, 0);
    3416             : 
    3417           8 :                 return new_str;
    3418             :         }
    3419             : }
    3420             : /* }}} */
    3421             : 
    3422             : /* {{{ proto string strtr(string str, string from[, string to])
    3423             :    Translates characters in str using given translation tables */
    3424         216 : PHP_FUNCTION(strtr)
    3425             : {
    3426             :         zval *from;
    3427             :         zend_string *str;
    3428         216 :         char *to = NULL;
    3429         216 :         size_t to_len = 0;
    3430         216 :         int ac = ZEND_NUM_ARGS();
    3431             : 
    3432             : #ifndef FAST_ZPP
    3433             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|s", &str, &from, &to, &to_len) == FAILURE) {
    3434             :                 return;
    3435             :         }
    3436             : #else
    3437         216 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    3438         639 :                 Z_PARAM_STR(str)
    3439         197 :                 Z_PARAM_ZVAL(from)
    3440         197 :                 Z_PARAM_OPTIONAL
    3441         421 :                 Z_PARAM_STRING(to, to_len)
    3442         216 :         ZEND_PARSE_PARAMETERS_END();
    3443             : #endif
    3444             : 
    3445         278 :         if (ac == 2 && Z_TYPE_P(from) != IS_ARRAY) {
    3446          31 :                 php_error_docref(NULL, E_WARNING, "The second argument is not an array");
    3447          31 :                 RETURN_FALSE;
    3448             :         }
    3449             : 
    3450             :         /* shortcut for empty string */
    3451         162 :         if (ZSTR_LEN(str) == 0) {
    3452          27 :                 RETURN_EMPTY_STRING();
    3453             :         }
    3454             : 
    3455         135 :         if (ac == 2) {
    3456          92 :                 HashTable *pats = HASH_OF(from);
    3457             : 
    3458          46 :                 if (zend_hash_num_elements(pats) < 1) {
    3459           2 :                         RETURN_STR_COPY(str);
    3460          44 :                 } else if (zend_hash_num_elements(pats) == 1) {
    3461             :                         zend_long num_key;
    3462             :                         zend_string *str_key, *replace;
    3463             :                         zval *entry, tmp;
    3464             : 
    3465          18 :                         ZEND_HASH_FOREACH_KEY_VAL(pats, num_key, str_key, entry) {
    3466           6 :                                 ZVAL_UNDEF(&tmp);
    3467           6 :                                 if (UNEXPECTED(!str_key)) {
    3468           2 :                                         ZVAL_LONG(&tmp, num_key);
    3469           2 :                                         convert_to_string(&tmp);
    3470           2 :                                         str_key = Z_STR(tmp);
    3471             :                                 }               
    3472           6 :                                 replace = zval_get_string(entry);
    3473           6 :                                 if (ZSTR_LEN(str_key) < 1) {
    3474           0 :                                         RETVAL_STR_COPY(str);
    3475           6 :                                 } else if (ZSTR_LEN(str_key) == 1) {
    3476           3 :                                         RETVAL_STR(php_char_to_str_ex(str,
    3477             :                                                                 ZSTR_VAL(str_key)[0],
    3478             :                                                                 ZSTR_VAL(replace),
    3479             :                                                                 ZSTR_LEN(replace),
    3480             :                                                                 1,
    3481             :                                                                 NULL));
    3482             :                                 } else {
    3483             :                                         zend_long dummy;
    3484           3 :                                         RETVAL_STR(php_str_to_str_ex(str,
    3485             :                                                                 ZSTR_VAL(str_key), ZSTR_LEN(str_key),
    3486             :                                                                 ZSTR_VAL(replace), ZSTR_LEN(replace), &dummy));
    3487             :                                 }
    3488             :                                 zend_string_release(replace);
    3489             :                                 zval_dtor(&tmp);
    3490           6 :                                 return;
    3491             :                         } ZEND_HASH_FOREACH_END();
    3492             :                 } else {
    3493          38 :                         php_strtr_array(return_value, str, pats);
    3494             :                 }
    3495             :         } else {
    3496         206 :                 convert_to_string_ex(from);
    3497             : 
    3498          89 :                 RETURN_STR(php_strtr_ex(str,
    3499             :                                   Z_STRVAL_P(from),
    3500             :                                   to,
    3501             :                                   MIN(Z_STRLEN_P(from), to_len)));
    3502             :         }
    3503             : }
    3504             : /* }}} */
    3505             : 
    3506             : /* {{{ proto string strrev(string str)
    3507             :    Reverse a string */
    3508         102 : PHP_FUNCTION(strrev)
    3509             : {
    3510             :         zend_string *str;
    3511             :         char *e, *p;
    3512             :         zend_string *n;
    3513             : 
    3514         102 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3515           8 :                 return;
    3516             :         }
    3517             : 
    3518         188 :         n = zend_string_alloc(ZSTR_LEN(str), 0);
    3519          94 :         p = ZSTR_VAL(n);
    3520             : 
    3521          94 :         e = ZSTR_VAL(str) + ZSTR_LEN(str);
    3522             : 
    3523        1786 :         while (--e >= ZSTR_VAL(str)) {
    3524        1598 :                 *p++ = *e;
    3525             :         }
    3526             : 
    3527          94 :         *p = '\0';
    3528             : 
    3529          94 :         RETVAL_NEW_STR(n);
    3530             : }
    3531             : /* }}} */
    3532             : 
    3533             : /* {{{ php_similar_str
    3534             :  */
    3535          10 : static void php_similar_str(const char *txt1, size_t len1, const char *txt2, size_t len2, size_t *pos1, size_t *pos2, size_t *max)
    3536             : {
    3537             :         char *p, *q;
    3538          10 :         char *end1 = (char *) txt1 + len1;
    3539          10 :         char *end2 = (char *) txt2 + len2;
    3540             :         size_t l;
    3541             : 
    3542          10 :         *max = 0;
    3543         104 :         for (p = (char *) txt1; p < end1; p++) {
    3544         602 :                 for (q = (char *) txt2; q < end2; q++) {
    3545         508 :                         for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
    3546         508 :                         if (l > *max) {
    3547           6 :                                 *max = l;
    3548           6 :                                 *pos1 = p - txt1;
    3549           6 :                                 *pos2 = q - txt2;
    3550             :                         }
    3551             :                 }
    3552             :         }
    3553          10 : }
    3554             : /* }}} */
    3555             : 
    3556             : /* {{{ php_similar_char
    3557             :  */
    3558          10 : static size_t php_similar_char(const char *txt1, size_t len1, const char *txt2, size_t len2)
    3559             : {
    3560             :         size_t sum;
    3561          10 :         size_t pos1 = 0, pos2 = 0, max;
    3562             : 
    3563          10 :         php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
    3564          10 :         if ((sum = max)) {
    3565           6 :                 if (pos1 && pos2) {
    3566           0 :                         sum += php_similar_char(txt1, pos1,
    3567             :                                                                         txt2, pos2);
    3568             :                 }
    3569           6 :                 if ((pos1 + max < len1) && (pos2 + max < len2)) {
    3570           2 :                         sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
    3571           2 :                                                                         txt2 + pos2 + max, len2 - pos2 - max);
    3572             :                 }
    3573             :         }
    3574             : 
    3575          10 :         return sum;
    3576             : }
    3577             : /* }}} */
    3578             : 
    3579             : /* {{{ proto int similar_text(string str1, string str2 [, float percent])
    3580             :    Calculates the similarity between two strings */
    3581          10 : PHP_FUNCTION(similar_text)
    3582             : {
    3583             :         zend_string *t1, *t2;
    3584          10 :         zval *percent = NULL;
    3585          10 :         int ac = ZEND_NUM_ARGS();
    3586             :         size_t sim;
    3587             : 
    3588          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|z/", &t1, &t2, &percent) == FAILURE) {
    3589           2 :                 return;
    3590             :         }
    3591             : 
    3592           8 :         if (ac > 2) {
    3593           8 :                 convert_to_double_ex(percent);
    3594             :         }
    3595             : 
    3596           8 :         if (ZSTR_LEN(t1) + ZSTR_LEN(t2) == 0) {
    3597           0 :                 if (ac > 2) {
    3598           0 :                         Z_DVAL_P(percent) = 0;
    3599             :                 }
    3600             : 
    3601           0 :                 RETURN_LONG(0);
    3602             :         }
    3603             : 
    3604           8 :         sim = php_similar_char(ZSTR_VAL(t1), ZSTR_LEN(t1), ZSTR_VAL(t2), ZSTR_LEN(t2));
    3605             : 
    3606           8 :         if (ac > 2) {
    3607           4 :                 Z_DVAL_P(percent) = sim * 200.0 / (ZSTR_LEN(t1) + ZSTR_LEN(t2));
    3608             :         }
    3609             : 
    3610           8 :         RETURN_LONG(sim);
    3611             : }
    3612             : /* }}} */
    3613             : 
    3614             : /* {{{ php_stripslashes
    3615             :  *
    3616             :  * be careful, this edits the string in-place */
    3617         103 : PHPAPI void php_stripslashes(zend_string *str)
    3618             : {
    3619             :         char *s, *t;
    3620             :         size_t l;
    3621             : 
    3622         103 :         s = ZSTR_VAL(str);
    3623         103 :         t = ZSTR_VAL(str);
    3624         103 :         l = ZSTR_LEN(str);
    3625             : 
    3626        1609 :         while (l > 0) {
    3627        1403 :                 if (*t == '\\') {
    3628         116 :                         t++;                            /* skip the slash */
    3629         116 :                         ZSTR_LEN(str)--;
    3630         116 :                         l--;
    3631         116 :                         if (l > 0) {
    3632         116 :                                 if (*t == '0') {
    3633          15 :                                         *s++='\0';
    3634          15 :                                         t++;
    3635             :                                 } else {
    3636         101 :                                         *s++ = *t++;    /* preserve the next character */
    3637             :                                 }
    3638         116 :                                 l--;
    3639             :                         }
    3640             :                 } else {
    3641        1287 :                         *s++ = *t++;
    3642        1287 :                         l--;
    3643             :                 }
    3644             :         }
    3645         103 :         if (s != t) {
    3646          67 :                 *s = '\0';
    3647             :         }
    3648         103 : }
    3649             : /* }}} */
    3650             : 
    3651             : /* {{{ proto string addcslashes(string str, string charlist)
    3652             :    Escapes all chars mentioned in charlist with backslash. It creates octal representations if asked to backslash characters with 8th bit set or with ASCII<32 (except '\n', '\r', '\t' etc...) */
    3653          45 : PHP_FUNCTION(addcslashes)
    3654             : {
    3655             :         zend_string *str, *what;
    3656             : 
    3657          45 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &str, &what) == FAILURE) {
    3658           4 :                 return;
    3659             :         }
    3660             : 
    3661          41 :         if (ZSTR_LEN(str) == 0) {
    3662           6 :                 RETURN_EMPTY_STRING();
    3663             :         }
    3664             : 
    3665          35 :         if (ZSTR_LEN(what) == 0) {
    3666          10 :                 RETURN_STRINGL(ZSTR_VAL(str), ZSTR_LEN(str));
    3667             :         }
    3668             : 
    3669          30 :         RETURN_STR(php_addcslashes(str, 0, ZSTR_VAL(what), ZSTR_LEN(what)));
    3670             : }
    3671             : /* }}} */
    3672             : 
    3673             : /* {{{ proto string addslashes(string str)
    3674             :    Escapes single quote, double quotes and backslash characters in a string with backslashes */
    3675      466260 : PHP_FUNCTION(addslashes)
    3676             : {
    3677             :         zend_string *str;
    3678             : 
    3679             : #ifndef FAST_ZPP
    3680             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3681             :                 return;
    3682             :         }
    3683             : #else
    3684      466260 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    3685     1398774 :                 Z_PARAM_STR(str)
    3686      466260 :         ZEND_PARSE_PARAMETERS_END();
    3687             : #endif
    3688             : 
    3689      466252 :         if (ZSTR_LEN(str) == 0) {
    3690      119673 :                 RETURN_EMPTY_STRING();
    3691             :         }
    3692             : 
    3693      346579 :         RETURN_STR(php_addslashes(str, 0));
    3694             : }
    3695             : /* }}} */
    3696             : 
    3697             : /* {{{ proto string stripcslashes(string str)
    3698             :    Strips backslashes from a string. Uses C-style conventions */
    3699          41 : PHP_FUNCTION(stripcslashes)
    3700             : {
    3701             :         zend_string *str;
    3702             : 
    3703          41 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3704           8 :                 return;
    3705             :         }
    3706             : 
    3707          66 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    3708          33 :         php_stripcslashes(Z_STR_P(return_value));
    3709             : }
    3710             : /* }}} */
    3711             : 
    3712             : /* {{{ proto string stripslashes(string str)
    3713             :    Strips backslashes from a string */
    3714         111 : PHP_FUNCTION(stripslashes)
    3715             : {
    3716             :         zend_string *str;
    3717             : 
    3718         111 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3719           8 :                 return;
    3720             :         }
    3721             : 
    3722         206 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    3723         103 :         php_stripslashes(Z_STR_P(return_value));
    3724             : }
    3725             : /* }}} */
    3726             : 
    3727             : #ifndef HAVE_STRERROR
    3728             : /* {{{ php_strerror
    3729             :  */
    3730             : char *php_strerror(int errnum)
    3731             : {
    3732             :         extern int sys_nerr;
    3733             :         extern char *sys_errlist[];
    3734             : 
    3735             :         if ((unsigned int) errnum < sys_nerr) {
    3736             :                 return(sys_errlist[errnum]);
    3737             :         }
    3738             : 
    3739             :         (void) snprintf(BG(str_ebuf), sizeof(php_basic_globals.str_ebuf), "Unknown error: %d", errnum);
    3740             :         return(BG(str_ebuf));
    3741             : }
    3742             : /* }}} */
    3743             : #endif
    3744             : 
    3745             : /* {{{ php_stripcslashes
    3746             :  */
    3747          33 : PHPAPI void php_stripcslashes(zend_string *str)
    3748             : {
    3749             :         char *source, *target, *end;
    3750          33 :         size_t  nlen = ZSTR_LEN(str), i;
    3751             :         char numtmp[4];
    3752             : 
    3753         157 :         for (source = (char*)ZSTR_VAL(str), end = source + ZSTR_LEN(str), target = ZSTR_VAL(str); source < end; source++) {
    3754         165 :                 if (*source == '\\' && source + 1 < end) {
    3755          41 :                         source++;
    3756          41 :                         switch (*source) {
    3757           2 :                                 case 'n':  *target++='\n'; nlen--; break;
    3758           2 :                                 case 'r':  *target++='\r'; nlen--; break;
    3759           1 :                                 case 'a':  *target++='\a'; nlen--; break;
    3760           1 :                                 case 't':  *target++='\t'; nlen--; break;
    3761           1 :                                 case 'v':  *target++='\v'; nlen--; break;
    3762           1 :                                 case 'b':  *target++='\b'; nlen--; break;
    3763           1 :                                 case 'f':  *target++='\f'; nlen--; break;
    3764           1 :                                 case '\\': *target++='\\'; nlen--; break;
    3765             :                                 case 'x':
    3766          11 :                                         if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3767          11 :                                                 numtmp[0] = *++source;
    3768          22 :                                                 if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3769          11 :                                                         numtmp[1] = *++source;
    3770          11 :                                                         numtmp[2] = '\0';
    3771          11 :                                                         nlen-=3;
    3772             :                                                 } else {
    3773           0 :                                                         numtmp[1] = '\0';
    3774           0 :                                                         nlen-=2;
    3775             :                                                 }
    3776          11 :                                                 *target++=(char)strtol(numtmp, NULL, 16);
    3777          11 :                                                 break;
    3778             :                                         }
    3779             :                                         /* break is left intentionally */
    3780             :                                 default:
    3781          20 :                                         i=0;
    3782          73 :                                         while (source < end && *source >= '0' && *source <= '7' && i<3) {
    3783          33 :                                                 numtmp[i++] = *source++;
    3784             :                                         }
    3785          20 :                                         if (i) {
    3786          11 :                                                 numtmp[i]='\0';
    3787          11 :                                                 *target++=(char)strtol(numtmp, NULL, 8);
    3788          11 :                                                 nlen-=i;
    3789          11 :                                                 source--;
    3790             :                                         } else {
    3791           9 :                                                 *target++=*source;
    3792           9 :                                                 nlen--;
    3793             :                                         }
    3794             :                         }
    3795             :                 } else {
    3796          83 :                         *target++=*source;
    3797             :                 }
    3798             :         }
    3799             : 
    3800          33 :         if (nlen != 0) {
    3801          24 :                 *target='\0';
    3802             :         }
    3803             : 
    3804          33 :         ZSTR_LEN(str) = nlen;
    3805          33 : }
    3806             : /* }}} */
    3807             : 
    3808             : /* {{{ php_addcslashes
    3809             :  */
    3810        1861 : PHPAPI zend_string *php_addcslashes(zend_string *str, int should_free, char *what, size_t wlength)
    3811             : {
    3812             :         char flags[256];
    3813             :         char *source, *target;
    3814             :         char *end;
    3815             :         char c;
    3816             :         size_t  newlen;
    3817        3722 :         zend_string *new_str = zend_string_alloc(4 * ZSTR_LEN(str), 0);
    3818             : 
    3819        1861 :         php_charmask((unsigned char *)what, wlength, flags);
    3820             : 
    3821       21202 :         for (source = (char*)ZSTR_VAL(str), end = source + ZSTR_LEN(str), target = ZSTR_VAL(new_str); source < end; source++) {
    3822       19341 :                 c = *source;
    3823       19341 :                 if (flags[(unsigned char)c]) {
    3824         163 :                         if ((unsigned char) c < 32 || (unsigned char) c > 126) {
    3825          16 :                                 *target++ = '\\';
    3826          16 :                                 switch (c) {
    3827           2 :                                         case '\n': *target++ = 'n'; break;
    3828           2 :                                         case '\t': *target++ = 't'; break;
    3829           2 :                                         case '\r': *target++ = 'r'; break;
    3830           0 :                                         case '\a': *target++ = 'a'; break;
    3831           2 :                                         case '\v': *target++ = 'v'; break;
    3832           0 :                                         case '\b': *target++ = 'b'; break;
    3833           2 :                                         case '\f': *target++ = 'f'; break;
    3834           6 :                                         default: target += sprintf(target, "%03o", (unsigned char) c);
    3835             :                                 }
    3836          16 :                                 continue;
    3837             :                         }
    3838         147 :                         *target++ = '\\';
    3839             :                 }
    3840       19325 :                 *target++ = c;
    3841             :         }
    3842        1861 :         *target = 0;
    3843        1861 :         newlen = target - ZSTR_VAL(new_str);
    3844        1861 :         if (newlen < ZSTR_LEN(str) * 4) {
    3845        1812 :                 new_str = zend_string_truncate(new_str, newlen, 0);
    3846             :         }
    3847        1861 :         if (should_free) {
    3848             :                 zend_string_release(str);
    3849             :         }
    3850        1861 :         return new_str;
    3851             : }
    3852             : /* }}} */
    3853             : 
    3854             : /* {{{ php_addslashes
    3855             :  */
    3856      346645 : PHPAPI zend_string *php_addslashes(zend_string *str, int should_free)
    3857             : {
    3858             :         /* maximum string length, worst case situation */
    3859             :         char *source, *target;
    3860             :         char *end;
    3861             :         size_t offset;
    3862             :         zend_string *new_str;
    3863             : 
    3864      346645 :         if (!str) {
    3865           0 :                 return ZSTR_EMPTY_ALLOC();
    3866             :         }
    3867             : 
    3868      346645 :         source = ZSTR_VAL(str);
    3869      346645 :         end = source + ZSTR_LEN(str);
    3870             : 
    3871     2339892 :         while (source < end) {
    3872     1646716 :                 switch (*source) {
    3873             :                         case '\0':
    3874             :                         case '\'':
    3875             :                         case '\"':
    3876             :                         case '\\':
    3877         114 :                                 goto do_escape;
    3878             :                         default:
    3879     1646602 :                                 source++;
    3880             :                                 break;
    3881             :                 }
    3882             :         }
    3883             : 
    3884      346531 :         if (!should_free) {
    3885      346531 :                 return zend_string_copy(str);
    3886             :         }
    3887             : 
    3888           0 :         return str;
    3889             : 
    3890             : do_escape:
    3891         114 :         offset = source - (char *)ZSTR_VAL(str);
    3892         228 :         new_str = zend_string_alloc(offset +  (2 * (ZSTR_LEN(str) - offset)), 0);
    3893         114 :         memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), offset);
    3894         114 :         target = ZSTR_VAL(new_str) + offset;
    3895             : 
    3896        2008 :         while (source < end) {
    3897        1780 :                 switch (*source) {
    3898             :                         case '\0':
    3899          29 :                                 *target++ = '\\';
    3900          29 :                                 *target++ = '0';
    3901          29 :                                 break;
    3902             :                         case '\'':
    3903             :                         case '\"':
    3904             :                         case '\\':
    3905         223 :                                 *target++ = '\\';
    3906             :                                 /* break is missing *intentionally* */
    3907             :                         default:
    3908        1751 :                                 *target++ = *source;
    3909             :                                 break;
    3910             :                 }
    3911             : 
    3912        1780 :                 source++;
    3913             :         }
    3914             : 
    3915         114 :         *target = 0;
    3916         114 :         if (should_free) {
    3917             :                 zend_string_release(str);
    3918             :         }
    3919             : 
    3920         114 :         if (ZSTR_LEN(new_str) - (target - ZSTR_VAL(new_str)) > 16) {
    3921          48 :                 new_str = zend_string_truncate(new_str, target - ZSTR_VAL(new_str), 0);
    3922             :         } else {
    3923          90 :                 ZSTR_LEN(new_str) = target - ZSTR_VAL(new_str);
    3924             :         }
    3925             : 
    3926         114 :         return new_str;
    3927             : }
    3928             : /* }}} */
    3929             : 
    3930             : #define _HEB_BLOCK_TYPE_ENG 1
    3931             : #define _HEB_BLOCK_TYPE_HEB 2
    3932             : #define isheb(c)      (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0)
    3933             : #define _isblank(c)   (((((unsigned char) c) == ' '  || ((unsigned char) c) == '\t')) ? 1 : 0)
    3934             : #define _isnewline(c) (((((unsigned char) c) == '\n' || ((unsigned char) c) == '\r')) ? 1 : 0)
    3935             : 
    3936             : /* {{{ php_str_replace_in_subject
    3937             :  */
    3938      160171 : static zend_long php_str_replace_in_subject(zval *search, zval *replace, zval *subject, zval *result, int case_sensitivity)
    3939             : {
    3940             :         zval            *search_entry,
    3941      160171 :                                 *replace_entry = NULL;
    3942             :         zend_string     *tmp_result,
    3943      160171 :                                 *replace_entry_str = NULL;
    3944      160171 :         char            *replace_value = NULL;
    3945      160171 :         size_t           replace_len = 0;
    3946      160171 :         zend_long        replace_count = 0;
    3947             :         zend_string     *subject_str;
    3948      160171 :         zend_string *lc_subject_str = NULL;
    3949             :         uint32_t     replace_idx;
    3950             : 
    3951             :         /* Make sure we're dealing with strings. */
    3952      160171 :         subject_str = zval_get_string(subject);
    3953      160171 :         if (ZSTR_LEN(subject_str) == 0) {
    3954             :                 zend_string_release(subject_str);
    3955          99 :                 ZVAL_EMPTY_STRING(result);
    3956          99 :                 return 0;
    3957             :         }
    3958             : 
    3959             :         /* If search is an array */
    3960      160072 :         if (Z_TYPE_P(search) == IS_ARRAY) {
    3961             :                 /* Duplicate subject string for repeated replacement */
    3962       33476 :                 ZVAL_STR_COPY(result, subject_str);
    3963             : 
    3964       33476 :                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3965          29 :                         replace_idx = 0;
    3966             :                 } else {
    3967             :                         /* Set replacement value to the passed one */
    3968       33447 :                         replace_value = Z_STRVAL_P(replace);
    3969       33447 :                         replace_len = Z_STRLEN_P(replace);
    3970             :                 }
    3971             : 
    3972             :                 /* For each entry in the search array, get the entry */
    3973      134204 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(search), search_entry) {
    3974             :                         /* Make sure we're dealing with strings. */
    3975       50365 :                         ZVAL_DEREF(search_entry);
    3976      151071 :                         SEPARATE_ZVAL_NOREF(search_entry);
    3977       50365 :                         convert_to_string(search_entry);
    3978       50365 :                         if (Z_STRLEN_P(search_entry) == 0) {
    3979           0 :                                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3980           0 :                                         replace_idx++;
    3981             :                                 }
    3982           0 :                                 continue;
    3983             :                         }
    3984             : 
    3985             :                         /* If replace is an array. */
    3986       50365 :                         if (Z_TYPE_P(replace) == IS_ARRAY) {
    3987             :                                 /* Get current entry */
    3988         144 :                                 while (replace_idx < Z_ARRVAL_P(replace)->nNumUsed) {
    3989          62 :                                         replace_entry = &Z_ARRVAL_P(replace)->arData[replace_idx].val;
    3990          62 :                                         if (Z_TYPE_P(replace_entry) != IS_UNDEF) {
    3991          62 :                                                 break;
    3992             :                                         }
    3993           0 :                                         replace_idx++;
    3994             :                                 }
    3995          72 :                                 if (replace_idx < Z_ARRVAL_P(replace)->nNumUsed) {
    3996             :                                         /* Make sure we're dealing with strings. */
    3997          62 :                                         replace_entry_str = zval_get_string(replace_entry);
    3998             : 
    3999             :                                         /* Set replacement value to the one we got from array */
    4000          62 :                                         replace_value = ZSTR_VAL(replace_entry_str);
    4001          62 :                                         replace_len = ZSTR_LEN(replace_entry_str);
    4002             : 
    4003          62 :                                         replace_idx++;
    4004             :                                 } else {
    4005             :                                         /* We've run out of replacement strings, so use an empty one. */
    4006          10 :                                         replace_value = "";
    4007          10 :                                         replace_len = 0;
    4008             :                                 }
    4009             :                         }
    4010             : 
    4011       50365 :                         if (Z_STRLEN_P(search_entry) == 1) {
    4012         626 :                                 zend_long old_replace_count = replace_count;
    4013             : 
    4014         626 :                                 tmp_result = php_char_to_str_ex(Z_STR_P(result),
    4015         626 :                                                                 Z_STRVAL_P(search_entry)[0],
    4016             :                                                                 replace_value,
    4017             :                                                                 replace_len,
    4018             :                                                                 case_sensitivity,
    4019             :                                                                 &replace_count);
    4020         626 :                                 if (lc_subject_str && replace_count != old_replace_count) {
    4021             :                                         zend_string_release(lc_subject_str);
    4022           3 :                                         lc_subject_str = NULL;
    4023             :                                 }
    4024       49739 :                         } else if (Z_STRLEN_P(search_entry) > 1) {
    4025       49739 :                                 if (case_sensitivity) {
    4026       99446 :                                         tmp_result = php_str_to_str_ex(Z_STR_P(result),
    4027       99446 :                                                         Z_STRVAL_P(search_entry), Z_STRLEN_P(search_entry),
    4028             :                                                         replace_value, replace_len, &replace_count);
    4029             :                                 } else {
    4030          16 :                                         zend_long old_replace_count = replace_count;
    4031             : 
    4032          16 :                                         if (!lc_subject_str) {
    4033          16 :                                                 lc_subject_str = php_string_tolower(Z_STR_P(result));
    4034             :                                         }
    4035          16 :                                         tmp_result = php_str_to_str_i_ex(Z_STR_P(result), ZSTR_VAL(lc_subject_str),
    4036             :                                                         Z_STR_P(search_entry), replace_value, replace_len, &replace_count);
    4037          16 :                                         if (replace_count != old_replace_count) {
    4038             :                                                 zend_string_release(lc_subject_str);
    4039           9 :                                                 lc_subject_str = NULL;
    4040             :                                         }
    4041             :                                 }                               
    4042             :                         }
    4043             : 
    4044       50365 :                         if (replace_entry_str) {
    4045             :                                 zend_string_release(replace_entry_str);
    4046          62 :                                 replace_entry_str = NULL;
    4047             :                         }
    4048       50365 :                         zend_string_release(Z_STR_P(result));
    4049       50365 :                         ZVAL_STR(result, tmp_result);
    4050             : 
    4051       50365 :                         if (Z_STRLEN_P(result) == 0) {
    4052           2 :                                 if (lc_subject_str) {
    4053             :                                         zend_string_release(lc_subject_str);
    4054             :                                 }
    4055             :                                 zend_string_release(subject_str);
    4056           2 :                                 return replace_count;
    4057             :                         }
    4058             :                 } ZEND_HASH_FOREACH_END();
    4059       33474 :                 if (lc_subject_str) {
    4060             :                         zend_string_release(lc_subject_str);
    4061             :                 }
    4062             :         } else {
    4063      126596 :                 if (Z_STRLEN_P(search) == 1) {
    4064        3737 :                         ZVAL_STR(result,
    4065             :                                 php_char_to_str_ex(subject_str,
    4066             :                                                         Z_STRVAL_P(search)[0],
    4067             :                                                         Z_STRVAL_P(replace),
    4068             :                                                         Z_STRLEN_P(replace),
    4069             :                                                         case_sensitivity,
    4070             :                                                         &replace_count));
    4071      122859 :                 } else if (Z_STRLEN_P(search) > 1) {
    4072      122805 :                         if (case_sensitivity) {
    4073      122715 :                                 ZVAL_STR(result, php_str_to_str_ex(subject_str,
    4074             :                                                 Z_STRVAL_P(search), Z_STRLEN_P(search),
    4075             :                                                 Z_STRVAL_P(replace), Z_STRLEN_P(replace), &replace_count));
    4076             :                         } else {
    4077          90 :                                 lc_subject_str = php_string_tolower(subject_str);
    4078          90 :                                 ZVAL_STR(result, php_str_to_str_i_ex(subject_str, ZSTR_VAL(lc_subject_str),
    4079             :                                                 Z_STR_P(search),
    4080             :                                                 Z_STRVAL_P(replace), Z_STRLEN_P(replace), &replace_count));
    4081             :                                 zend_string_release(lc_subject_str);
    4082             :                         }
    4083             :                 } else {
    4084          54 :                         ZVAL_STR_COPY(result, subject_str);
    4085             :                 }
    4086             :         }
    4087             :         zend_string_release(subject_str);
    4088      160070 :         return replace_count;
    4089             : }
    4090             : /* }}} */
    4091             : 
    4092             : /* {{{ php_str_replace_common
    4093             :  */
    4094      159917 : static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
    4095             : {
    4096      159917 :         zval *subject, *search, *replace, *subject_entry, *zcount = NULL;
    4097             :         zval result;
    4098             :         zend_string *string_key;
    4099             :         zend_ulong num_key;
    4100      159917 :         zend_long count = 0;
    4101      159917 :         int argc = ZEND_NUM_ARGS();
    4102             : 
    4103             : #ifndef FAST_ZPP
    4104             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz|z/", &search, &replace, &subject, &zcount) == FAILURE) {
    4105             :                 return;
    4106             :         }
    4107             : #else
    4108      159917 :         ZEND_PARSE_PARAMETERS_START(3, 4)
    4109      159902 :                 Z_PARAM_ZVAL(search)
    4110      159902 :                 Z_PARAM_ZVAL(replace)
    4111      159902 :                 Z_PARAM_ZVAL(subject)
    4112      159902 :                 Z_PARAM_OPTIONAL
    4113      160038 :                 Z_PARAM_ZVAL_EX(zcount, 0, 1)
    4114      159917 :         ZEND_PARSE_PARAMETERS_END();
    4115             : #endif
    4116             : 
    4117             :         /* Make sure we're dealing with strings and do the replacement. */
    4118      319804 :         if (Z_TYPE_P(search) != IS_ARRAY) {
    4119      252920 :                 convert_to_string_ex(search);
    4120      252890 :                 if (Z_TYPE_P(replace) != IS_STRING) {
    4121          24 :                         convert_to_string_ex(replace);
    4122             :                 }
    4123       66914 :         } else if (Z_TYPE_P(replace) != IS_ARRAY) {
    4124       66874 :                 convert_to_string_ex(replace);
    4125             :         }
    4126             : 
    4127             :         /* if subject is an array */
    4128      319804 :         if (Z_TYPE_P(subject) == IS_ARRAY) {
    4129          45 :                 array_init(return_value);
    4130             : 
    4131             :                 /* For each subject entry, convert it to string, then perform replacement
    4132             :                    and add the result to the return_value array. */
    4133         729 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(subject), num_key, string_key, subject_entry) {
    4134         970 :                         if (Z_TYPE_P(subject_entry) != IS_ARRAY && Z_TYPE_P(subject_entry) != IS_OBJECT) {
    4135         314 :                                 count += php_str_replace_in_subject(search, replace, subject_entry, &result, case_sensitivity);
    4136             :                         } else {
    4137          28 :                                 ZVAL_COPY(&result, subject_entry);
    4138             :                         }
    4139             :                         /* Add to return array */
    4140         342 :                         if (string_key) {
    4141           4 :                                 zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, &result);
    4142             :                         } else {
    4143         338 :                                 zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result);
    4144             :                         }
    4145             :                 } ZEND_HASH_FOREACH_END();
    4146             :         } else {        /* if subject is not an array */
    4147      159857 :                 count = php_str_replace_in_subject(search, replace, subject, return_value, case_sensitivity);
    4148             :         }
    4149      159902 :         if (argc > 3) {
    4150         135 :                 zval_ptr_dtor(zcount);
    4151         135 :                 ZVAL_LONG(zcount, count);
    4152             :         }
    4153             : }
    4154             : /* }}} */
    4155             : 
    4156             : /* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count])
    4157             :    Replaces all occurrences of search in haystack with replace */
    4158      159812 : PHP_FUNCTION(str_replace)
    4159             : {
    4160      159812 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4161      159812 : }
    4162             : /* }}} */
    4163             : 
    4164             : /* {{{ proto mixed str_ireplace(mixed search, mixed replace, mixed subject [, int &replace_count])
    4165             :    Replaces all occurrences of search in haystack with replace / case-insensitive */
    4166         105 : PHP_FUNCTION(str_ireplace)
    4167             : {
    4168         105 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4169         105 : }
    4170             : /* }}} */
    4171             : 
    4172             : /* {{{ php_hebrev
    4173             :  *
    4174             :  * Converts Logical Hebrew text (Hebrew Windows style) to Visual text
    4175             :  * Cheers/complaints/flames - Zeev Suraski <zeev@php.net>
    4176             :  */
    4177         116 : static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
    4178             : {
    4179             :         char *str;
    4180             :         char *heb_str, *tmp, *target;
    4181             :         size_t block_start, block_end, block_type, block_length, i;
    4182         116 :         zend_long max_chars=0;
    4183             :         size_t begin, end, char_count, orig_begin;
    4184             :         size_t str_len;
    4185             :         zend_string *broken_str;
    4186             : 
    4187         116 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &max_chars) == FAILURE) {
    4188          26 :                 return;
    4189             :         }
    4190             : 
    4191          90 :         if (str_len == 0) {
    4192          12 :                 RETURN_FALSE;
    4193             :         }
    4194             : 
    4195          78 :         tmp = str;
    4196          78 :         block_start=block_end=0;
    4197             : 
    4198          78 :         heb_str = (char *) emalloc(str_len+1);
    4199          78 :         target = heb_str+str_len;
    4200          78 :         *target = 0;
    4201          78 :         target--;
    4202             : 
    4203          78 :         block_length=0;
    4204             : 
    4205          78 :         if (isheb(*tmp)) {
    4206           0 :                 block_type = _HEB_BLOCK_TYPE_HEB;
    4207             :         } else {
    4208          78 :                 block_type = _HEB_BLOCK_TYPE_ENG;
    4209             :         }
    4210             : 
    4211             :         do {
    4212         307 :                 if (block_type == _HEB_BLOCK_TYPE_HEB) {
    4213         696 :                         while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) {
    4214         414 :                                 tmp++;
    4215         414 :                                 block_end++;
    4216         414 :                                 block_length++;
    4217             :                         }
    4218         555 :                         for (i = block_start+1; i<= block_end+1; i++) {
    4219         414 :                                 *target = str[i-1];
    4220         414 :                                 switch (*target) {
    4221             :                                         case '(':
    4222          23 :                                                 *target = ')';
    4223          23 :                                                 break;
    4224             :                                         case ')':
    4225          23 :                                                 *target = '(';
    4226          23 :                                                 break;
    4227             :                                         case '[':
    4228           1 :                                                 *target = ']';
    4229           1 :                                                 break;
    4230             :                                         case ']':
    4231           1 :                                                 *target = '[';
    4232           1 :                                                 break;
    4233             :                                         case '{':
    4234           1 :                                                 *target = '}';
    4235           1 :                                                 break;
    4236             :                                         case '}':
    4237           1 :                                                 *target = '{';
    4238           1 :                                                 break;
    4239             :                                         case '<':
    4240           1 :                                                 *target = '>';
    4241           1 :                                                 break;
    4242             :                                         case '>':
    4243          23 :                                                 *target = '<';
    4244          23 :                                                 break;
    4245             :                                         case '\\':
    4246           1 :                                                 *target = '/';
    4247           1 :                                                 break;
    4248             :                                         case '/':
    4249           0 :                                                 *target = '\\';
    4250             :                                                 break;
    4251             :                                         default:
    4252             :                                                 break;
    4253             :                                 }
    4254         414 :                                 target--;
    4255             :                         }
    4256         141 :                         block_type = _HEB_BLOCK_TYPE_ENG;
    4257             :                 } else {
    4258        7419 :                         while (!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end < str_len-1) {
    4259        7087 :                                 tmp++;
    4260        7087 :                                 block_end++;
    4261        7087 :                                 block_length++;
    4262             :                         }
    4263         504 :                         while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
    4264         172 :                                 tmp--;
    4265         172 :                                 block_end--;
    4266             :                         }
    4267        7159 :                         for (i = block_end+1; i >= block_start+1; i--) {
    4268        6993 :                                 *target = str[i-1];
    4269        6993 :                                 target--;
    4270             :                         }
    4271         166 :                         block_type = _HEB_BLOCK_TYPE_HEB;
    4272             :                 }
    4273         307 :                 block_start=block_end+1;
    4274         307 :         } while (block_end < str_len-1);
    4275             : 
    4276             : 
    4277         156 :         broken_str = zend_string_alloc(str_len, 0);
    4278          78 :         begin = end = str_len-1;
    4279          78 :         target = ZSTR_VAL(broken_str);
    4280             : 
    4281             :         while (1) {
    4282        1412 :                 char_count=0;
    4283        8883 :                 while ((!max_chars || (max_chars > 0 && char_count < max_chars)) && begin > 0) {
    4284        6205 :                         char_count++;
    4285        6205 :                         begin--;
    4286        6205 :                         if (begin <= 0 || _isnewline(heb_str[begin])) {
    4287         292 :                                 while (begin > 0 && _isnewline(heb_str[begin-1])) {
    4288           0 :                                         begin--;
    4289           0 :                                         char_count++;
    4290             :                                 }
    4291         146 :                                 break;
    4292             :                         }
    4293             :                 }
    4294        1412 :                 if (max_chars >= 0 && char_count == max_chars) { /* try to avoid breaking words */
    4295         627 :                         size_t new_char_count=char_count, new_begin=begin;
    4296             : 
    4297        2037 :                         while (new_char_count > 0) {
    4298         939 :                                 if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
    4299             :                                         break;
    4300             :                                 }
    4301         783 :                                 new_begin++;
    4302         783 :                                 new_char_count--;
    4303             :                         }
    4304         627 :                         if (new_char_count > 0) {
    4305         156 :                                 begin=new_begin;
    4306             :                         }
    4307             :                 }
    4308        1412 :                 orig_begin=begin;
    4309             : 
    4310        1412 :                 if (_isblank(heb_str[begin])) {
    4311         239 :                         heb_str[begin]='\n';
    4312             :                 }
    4313        3203 :                 while (begin <= end && _isnewline(heb_str[begin])) { /* skip leading newlines */
    4314         379 :                         begin++;
    4315             :                 }
    4316        8440 :                 for (i = begin; i <= end; i++) { /* copy content */
    4317        7028 :                         *target = heb_str[i];
    4318        7028 :                         target++;
    4319             :                 }
    4320        1791 :                 for (i = orig_begin; i <= end && _isnewline(heb_str[i]); i++) {
    4321         379 :                         *target = heb_str[i];
    4322         379 :                         target++;
    4323             :                 }
    4324        1412 :                 begin=orig_begin;
    4325             : 
    4326        1412 :                 if (begin <= 0) {
    4327          78 :                         *target = 0;
    4328          78 :                         break;
    4329             :                 }
    4330        1334 :                 begin--;
    4331        1334 :                 end=begin;
    4332        1334 :         }
    4333          78 :         efree(heb_str);
    4334             : 
    4335          78 :         if (convert_newlines) {
    4336          34 :                 RETVAL_STR(php_char_to_str_ex(broken_str, '\n', "<br />\n", 7, 1, NULL));
    4337             :                 zend_string_release(broken_str);
    4338             :         } else {
    4339          44 :                 RETURN_NEW_STR(broken_str);
    4340             :         }
    4341             : }
    4342             : /* }}} */
    4343             : 
    4344             : /* {{{ proto string hebrev(string str [, int max_chars_per_line])
    4345             :    Converts logical Hebrew text to visual text */
    4346          63 : PHP_FUNCTION(hebrev)
    4347             : {
    4348          63 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4349          63 : }
    4350             : /* }}} */
    4351             : 
    4352             : /* {{{ proto string hebrevc(string str [, int max_chars_per_line])
    4353             :    Converts logical Hebrew text to visual text with newline conversion */
    4354          53 : PHP_FUNCTION(hebrevc)
    4355             : {
    4356          53 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4357          53 : }
    4358             : /* }}} */
    4359             : 
    4360             : /* {{{ proto string nl2br(string str [, bool is_xhtml])
    4361             :    Converts newlines to HTML line breaks */
    4362          60 : PHP_FUNCTION(nl2br)
    4363             : {
    4364             :         /* in brief this inserts <br /> or <br> before matched regexp \n\r?|\r\n? */
    4365             :         char    *tmp;
    4366             :         zend_string *str;
    4367             :         char    *end, *target;
    4368          60 :         size_t  repl_cnt = 0;
    4369          60 :         zend_bool       is_xhtml = 1;
    4370             :         zend_string *result;
    4371             : 
    4372             : #ifndef FAST_ZPP
    4373             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &str, &is_xhtml) == FAILURE) {
    4374             :                 return;
    4375             :         }
    4376             : #else
    4377          60 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    4378         174 :                 Z_PARAM_STR(str)
    4379          52 :                 Z_PARAM_OPTIONAL
    4380          52 :                 Z_PARAM_BOOL(is_xhtml)
    4381          60 :         ZEND_PARSE_PARAMETERS_END();
    4382             : #endif
    4383             : 
    4384          52 :         tmp = ZSTR_VAL(str);
    4385          52 :         end = ZSTR_VAL(str) + ZSTR_LEN(str);
    4386             : 
    4387             :         /* it is really faster to scan twice and allocate mem once instead of scanning once
    4388             :            and constantly reallocing */
    4389         513 :         while (tmp < end) {
    4390         409 :                 if (*tmp == '\r') {
    4391          33 :                         if (*(tmp+1) == '\n') {
    4392          14 :                                 tmp++;
    4393             :                         }
    4394          33 :                         repl_cnt++;
    4395         376 :                 } else if (*tmp == '\n') {
    4396          46 :                         if (*(tmp+1) == '\r') {
    4397          13 :                                 tmp++;
    4398             :                         }
    4399          46 :                         repl_cnt++;
    4400             :                 }
    4401             : 
    4402         409 :                 tmp++;
    4403             :         }
    4404             : 
    4405          52 :         if (repl_cnt == 0) {
    4406          29 :                 RETURN_STR_COPY(str);
    4407             :         }
    4408             : 
    4409             :         {
    4410          23 :                 size_t repl_len = is_xhtml ? (sizeof("<br />") - 1) : (sizeof("<br>") - 1);
    4411             : 
    4412          46 :                 result = zend_string_alloc(repl_cnt * repl_len + ZSTR_LEN(str), 0);
    4413          23 :                 target = ZSTR_VAL(result);
    4414             :         }
    4415             : 
    4416          23 :         tmp = ZSTR_VAL(str);
    4417         303 :         while (tmp < end) {
    4418         257 :                 switch (*tmp) {
    4419             :                         case '\r':
    4420             :                         case '\n':
    4421          79 :                                 *target++ = '<';
    4422          79 :                                 *target++ = 'b';
    4423          79 :                                 *target++ = 'r';
    4424             : 
    4425          79 :                                 if (is_xhtml) {
    4426          79 :                                         *target++ = ' ';
    4427          79 :                                         *target++ = '/';
    4428             :                                 }
    4429             : 
    4430          79 :                                 *target++ = '>';
    4431             : 
    4432          79 :                                 if ((*tmp == '\r' && *(tmp+1) == '\n') || (*tmp == '\n' && *(tmp+1) == '\r')) {
    4433          27 :                                         *target++ = *tmp++;
    4434             :                                 }
    4435             :                                 /* lack of a break; is intentional */
    4436             :                         default:
    4437         257 :                                 *target++ = *tmp;
    4438             :                 }
    4439             : 
    4440         257 :                 tmp++;
    4441             :         }
    4442             : 
    4443          23 :         *target = '\0';
    4444             : 
    4445          23 :         RETURN_NEW_STR(result);
    4446             : }
    4447             : /* }}} */
    4448             : 
    4449             : /* {{{ proto string strip_tags(string str [, string allowable_tags])
    4450             :    Strips HTML and PHP tags from a string */
    4451         203 : PHP_FUNCTION(strip_tags)
    4452             : {
    4453             :         zend_string *buf;
    4454             :         zend_string *str;
    4455         203 :         zval *allow=NULL;
    4456         203 :         char *allowed_tags=NULL;
    4457         203 :         size_t allowed_tags_len=0;
    4458             : 
    4459         203 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &str, &allow) == FAILURE) {
    4460          14 :                 return;
    4461             :         }
    4462             : 
    4463             :         /* To maintain a certain BC, we allow anything for the second parameter and return original string */
    4464         189 :         if (allow) {
    4465         226 :                 convert_to_string(allow);
    4466         113 :                 allowed_tags = Z_STRVAL_P(allow);
    4467         113 :                 allowed_tags_len = Z_STRLEN_P(allow);
    4468             :         }
    4469             : 
    4470         378 :         buf = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 0);
    4471         189 :         ZSTR_LEN(buf) = php_strip_tags_ex(ZSTR_VAL(buf), ZSTR_LEN(str), NULL, allowed_tags, allowed_tags_len, 0);
    4472         189 :         RETURN_NEW_STR(buf);
    4473             : }
    4474             : /* }}} */
    4475             : 
    4476             : /* {{{ proto string setlocale(mixed category, string locale [, string ...])
    4477             :    Set locale information */
    4478        1016 : PHP_FUNCTION(setlocale)
    4479             : {
    4480        1016 :         zval *args = NULL;
    4481             :         zval *plocale;
    4482             :         zend_string *loc;
    4483             :         char *retval;
    4484             :         zend_long cat;
    4485        1016 :         int num_args, i = 0;
    4486             :         uint32_t idx;
    4487             : 
    4488        1016 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l+", &cat, &args, &num_args) == FAILURE) {
    4489           2 :                 return;
    4490             :         }
    4491             : 
    4492             : #ifdef HAVE_SETLOCALE
    4493        1014 :         idx = 0;
    4494             :         while (1) {
    4495        2066 :                 if (Z_TYPE(args[0]) == IS_ARRAY) {
    4496          10 :                         while (idx < Z_ARRVAL(args[0])->nNumUsed) {
    4497           4 :                                 plocale = &Z_ARRVAL(args[0])->arData[idx].val;
    4498           4 :                                 if (Z_TYPE_P(plocale) != IS_UNDEF) {
    4499           4 :                                         break;
    4500             :                                 }
    4501           0 :                                 idx++;
    4502             :                         }
    4503           5 :                         if (idx >= Z_ARRVAL(args[0])->nNumUsed) {
    4504           1 :                                 break;
    4505             :                         }
    4506             :                 } else {
    4507        1028 :                         plocale = &args[i];
    4508             :                 }
    4509             : 
    4510        1032 :                 loc = zval_get_string(plocale);
    4511             : 
    4512        1032 :                 if (!strcmp("0", ZSTR_VAL(loc))) {
    4513             :                         zend_string_release(loc);
    4514           8 :                         loc = NULL;
    4515             :                 } else {
    4516        1024 :                         if (ZSTR_LEN(loc) >= 255) {
    4517           1 :                                 php_error_docref(NULL, E_WARNING, "Specified locale name is too long");
    4518             :                                 zend_string_release(loc);
    4519           1 :                                 break;
    4520             :                         }
    4521             :                 }
    4522             : 
    4523        1031 :                 retval = php_my_setlocale(cat, loc ? ZSTR_VAL(loc) : NULL);
    4524             :                 zend_update_current_locale();
    4525        1031 :                 if (retval) {
    4526        1011 :                         if (loc) {
    4527             :                                 /* Remember if locale was changed */
    4528        1003 :                                 size_t len = strlen(retval);
    4529             : 
    4530        1003 :                                 BG(locale_changed) = 1;
    4531        1003 :                                 if (cat == LC_CTYPE || cat == LC_ALL) {
    4532         986 :                                         if (BG(locale_string)) {
    4533         815 :                                                 zend_string_release(BG(locale_string));
    4534             :                                         }
    4535         986 :                                         if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
    4536         980 :                                                 BG(locale_string) = zend_string_copy(loc);
    4537         980 :                                                 RETURN_STR(BG(locale_string));
    4538             :                                         } else {
    4539           6 :                                                 BG(locale_string) = zend_string_init(retval, len, 0);
    4540             :                                                 zend_string_release(loc);
    4541           6 :                                                 RETURN_STR_COPY(BG(locale_string));
    4542             :                                         }
    4543          17 :                                 } else if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
    4544          15 :                                         RETURN_STR(loc);
    4545             :                                 }
    4546             :                                 zend_string_release(loc);
    4547             :                         }
    4548          20 :                         RETURN_STRING(retval);
    4549             :                 }
    4550          20 :                 if (loc) {
    4551             :                         zend_string_release(loc);
    4552             :                 }
    4553             : 
    4554          40 :                 if (Z_TYPE(args[0]) == IS_ARRAY) {
    4555           3 :                         idx++;
    4556             :                 } else {
    4557          17 :                         if (++i >= num_args) break;
    4558             :                 }
    4559          19 :         }
    4560             : 
    4561             : #endif
    4562           3 :         RETURN_FALSE;
    4563             : }
    4564             : /* }}} */
    4565             : 
    4566             : /* {{{ proto void parse_str(string encoded_string [, array result])
    4567             :    Parses GET/POST/COOKIE data and sets global variables */
    4568          30 : PHP_FUNCTION(parse_str)
    4569             : {
    4570             :         char *arg;
    4571          30 :         zval *arrayArg = NULL;
    4572          30 :         char *res = NULL;
    4573             :         size_t arglen;
    4574             : 
    4575          30 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z/", &arg, &arglen, &arrayArg) == FAILURE) {
    4576           2 :                 return;
    4577             :         }
    4578             : 
    4579          28 :         res = estrndup(arg, arglen);
    4580             : 
    4581          28 :         if (arrayArg == NULL) {
    4582             :                 zval tmp;
    4583          14 :                 zend_array *symbol_table = zend_rebuild_symbol_table();
    4584             : 
    4585          14 :                 ZVAL_ARR(&tmp, symbol_table);
    4586          14 :                 sapi_module.treat_data(PARSE_STRING, res, &tmp);
    4587             :         } else  {
    4588             :                 zval ret;
    4589             : 
    4590             :                 /* Clear out the array that was passed in. */
    4591          14 :                 zval_dtor(arrayArg);
    4592          14 :                 array_init(&ret);
    4593          14 :                 sapi_module.treat_data(PARSE_STRING, res, &ret);
    4594          14 :                 ZVAL_COPY_VALUE(arrayArg, &ret);
    4595             :         }
    4596             : }
    4597             : /* }}} */
    4598             : 
    4599             : #define PHP_TAG_BUF_SIZE 1023
    4600             : 
    4601             : /* {{{ php_tag_find
    4602             :  *
    4603             :  * Check if tag is in a set of tags
    4604             :  *
    4605             :  * states:
    4606             :  *
    4607             :  * 0 start tag
    4608             :  * 1 first non-whitespace char seen
    4609             :  */
    4610         567 : int php_tag_find(char *tag, size_t len, const char *set) {
    4611             :         char c, *n, *t;
    4612         567 :         int state=0, done=0;
    4613             :         char *norm;
    4614             : 
    4615         567 :         if (len <= 0) {
    4616           0 :                 return 0;
    4617             :         }
    4618             : 
    4619         567 :         norm = emalloc(len+1);
    4620             : 
    4621         567 :         n = norm;
    4622         567 :         t = tag;
    4623         567 :         c = tolower(*t);
    4624             :         /*
    4625             :            normalize the tag removing leading and trailing whitespace
    4626             :            and turn any <a whatever...> into just <a> and any </tag>
    4627             :            into <tag>
    4628             :         */
    4629        3954 :         while (!done) {
    4630        2820 :                 switch (c) {
    4631             :                         case '<':
    4632         566 :                                 *(n++) = c;
    4633         566 :                                 break;
    4634             :                         case '>':
    4635         536 :                                 done =1;
    4636         536 :                                 break;
    4637             :                         default:
    4638        1718 :                                 if (!isspace((int)c)) {
    4639        1685 :                                         if (state == 0) {
    4640         566 :                                                 state=1;
    4641             :                                         }
    4642        1685 :                                         if (c != '/') {
    4643        1418 :                                                 *(n++) = c;
    4644             :                                         }
    4645             :                                 } else {
    4646          33 :                                         if (state == 1)
    4647          31 :                                                 done=1;
    4648             :                                 }
    4649             :                                 break;
    4650             :                 }
    4651        2820 :                 c = tolower(*(++t));
    4652             :         }
    4653         567 :         *(n++) = '>';
    4654         567 :         *n = '\0';
    4655         567 :         if (strstr(set, norm)) {
    4656         152 :                 done=1;
    4657             :         } else {
    4658         415 :                 done=0;
    4659             :         }
    4660         567 :         efree(norm);
    4661         567 :         return done;
    4662             : }
    4663             : /* }}} */
    4664             : 
    4665         237 : PHPAPI size_t php_strip_tags(char *rbuf, size_t len, int *stateptr, const char *allow, size_t allow_len) /* {{{ */
    4666             : {
    4667         237 :         return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0);
    4668             : }
    4669             : /* }}} */
    4670             : 
    4671             : /* {{{ php_strip_tags
    4672             : 
    4673             :         A simple little state-machine to strip out html and php tags
    4674             : 
    4675             :         State 0 is the output state, State 1 means we are inside a
    4676             :         normal html tag and state 2 means we are inside a php tag.
    4677             : 
    4678             :         The state variable is passed in to allow a function like fgetss
    4679             :         to maintain state across calls to the function.
    4680             : 
    4681             :         lc holds the last significant character read and br is a bracket
    4682             :         counter.
    4683             : 
    4684             :         When an allow string is passed in we keep track of the string
    4685             :         in state 1 and when the tag is closed check it against the
    4686             :         allow string to see if we should allow it.
    4687             : 
    4688             :         swm: Added ability to strip <?xml tags without assuming it PHP
    4689             :         code.
    4690             : */
    4691         738 : PHPAPI size_t php_strip_tags_ex(char *rbuf, size_t len, int *stateptr, const char *allow, size_t allow_len, zend_bool allow_tag_spaces)
    4692             : {
    4693             :         char *tbuf, *buf, *p, *tp, *rp, c, lc;
    4694         738 :         int br, depth=0, in_q = 0;
    4695         738 :         int state = 0;
    4696         738 :         size_t pos, i = 0;
    4697         738 :         char *allow_free = NULL;
    4698             :         const char *allow_actual;
    4699             : 
    4700         738 :         if (stateptr)
    4701         237 :                 state = *stateptr;
    4702             : 
    4703         738 :         buf = estrndup(rbuf, len);
    4704         738 :         c = *buf;
    4705         738 :         lc = '\0';
    4706         738 :         p = buf;
    4707         738 :         rp = rbuf;
    4708         738 :         br = 0;
    4709         738 :         if (allow) {
    4710         286 :                 allow_free = zend_str_tolower_dup_ex(allow, allow_len);
    4711         286 :                 allow_actual = allow_free ? allow_free : allow;
    4712         286 :                 tbuf = emalloc(PHP_TAG_BUF_SIZE + 1);
    4713         286 :                 tp = tbuf;
    4714             :         } else {
    4715         452 :                 tbuf = tp = NULL;
    4716             :         }
    4717             : 
    4718      132635 :         while (i < len) {
    4719      131159 :                 switch (c) {
    4720             :                         case '\0':
    4721           2 :                                 break;
    4722             :                         case '<':
    4723        1021 :                                 if (in_q) {
    4724           3 :                                         break;
    4725             :                                 }
    4726        1018 :                                 if (isspace(*(p + 1)) && !allow_tag_spaces) {
    4727           6 :                                         goto reg_char;
    4728             :                                 }
    4729        1012 :                                 if (state == 0) {
    4730         987 :                                         lc = '<';
    4731         987 :                                         state = 1;
    4732         987 :                                         if (allow) {
    4733         675 :                                                 if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4734           0 :                                                         pos = tp - tbuf;
    4735           0 :                                                         tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4736           0 :                                                         tp = tbuf + pos;
    4737             :                                                 }
    4738         675 :                                                 *(tp++) = '<';
    4739             :                                         }
    4740          25 :                                 } else if (state == 1) {
    4741          20 :                                         depth++;
    4742             :                                 }
    4743        1012 :                                 break;
    4744             : 
    4745             :                         case '(':
    4746         130 :                                 if (state == 2) {
    4747           0 :                                         if (lc != '"' && lc != '\'') {
    4748           0 :                                                 lc = '(';
    4749           0 :                                                 br++;
    4750             :                                         }
    4751         131 :                                 } else if (allow && state == 1) {
    4752           1 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4753           0 :                                                 pos = tp - tbuf;
    4754           0 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4755           0 :                                                 tp = tbuf + pos;
    4756             :                                         }
    4757           1 :                                         *(tp++) = c;
    4758         129 :                                 } else if (state == 0) {
    4759         128 :                                         *(rp++) = c;
    4760             :                                 }
    4761         130 :                                 break;
    4762             : 
    4763             :                         case ')':
    4764         130 :                                 if (state == 2) {
    4765           0 :                                         if (lc != '"' && lc != '\'') {
    4766           0 :                                                 lc = ')';
    4767           0 :                                                 br--;
    4768             :                                         }
    4769         131 :                                 } else if (allow && state == 1) {
    4770           1 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4771           0 :                                                 pos = tp - tbuf;
    4772           0 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4773           0 :                                                 tp = tbuf + pos;
    4774             :                                         }
    4775           1 :                                         *(tp++) = c;
    4776         129 :                                 } else if (state == 0) {
    4777         128 :                                         *(rp++) = c;
    4778             :                                 }
    4779         130 :                                 break;
    4780             : 
    4781             :                         case '>':
    4782        4371 :                                 if (depth) {
    4783          20 :                                         depth--;
    4784          20 :                                         break;
    4785             :                                 }
    4786             : 
    4787        4351 :                                 if (in_q) {
    4788           4 :                                         break;
    4789             :                                 }
    4790             : 
    4791        4347 :                                 switch (state) {
    4792             :                                         case 1: /* HTML/XML */
    4793         848 :                                                 lc = '>';
    4794         848 :                                                 in_q = state = 0;
    4795         848 :                                                 if (allow) {
    4796         567 :                                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4797           1 :                                                                 pos = tp - tbuf;
    4798           1 :                                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4799           1 :                                                                 tp = tbuf + pos;
    4800             :                                                         }
    4801         567 :                                                         *(tp++) = '>';
    4802         567 :                                                         *tp='\0';
    4803         567 :                                                         if (php_tag_find(tbuf, tp-tbuf, allow_actual)) {
    4804         152 :                                                                 memcpy(rp, tbuf, tp-tbuf);
    4805         152 :                                                                 rp += tp-tbuf;
    4806             :                                                         }
    4807         567 :                                                         tp = tbuf;
    4808             :                                                 }
    4809         848 :                                                 break;
    4810             : 
    4811             :                                         case 2: /* PHP */
    4812          97 :                                                 if (!br && lc != '\"' && *(p-1) == '?') {
    4813          91 :                                                         in_q = state = 0;
    4814          91 :                                                         tp = tbuf;
    4815             :                                                 }
    4816          97 :                                                 break;
    4817             : 
    4818             :                                         case 3:
    4819           1 :                                                 in_q = state = 0;
    4820           1 :                                                 tp = tbuf;
    4821           1 :                                                 break;
    4822             : 
    4823             :                                         case 4: /* JavaScript/CSS/etc... */
    4824          37 :                                                 if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') {
    4825          36 :                                                         in_q = state = 0;
    4826          36 :                                                         tp = tbuf;
    4827             :                                                 }
    4828          37 :                                                 break;
    4829             : 
    4830             :                                         default:
    4831        3364 :                                                 *(rp++) = c;
    4832             :                                                 break;
    4833             :                                 }
    4834        4347 :                                 break;
    4835             : 
    4836             :                         case '"':
    4837             :                         case '\'':
    4838        1256 :                                 if (state == 4) {
    4839             :                                         /* Inside <!-- comment --> */
    4840           1 :                                         break;
    4841        1319 :                                 } else if (state == 2 && *(p-1) != '\\') {
    4842          64 :                                         if (lc == c) {
    4843          32 :                                                 lc = '\0';
    4844          32 :                                         } else if (lc != '\\') {
    4845          32 :                                                 lc = c;
    4846             :                                         }
    4847        1191 :                                 } else if (state == 0) {
    4848        1012 :                                         *(rp++) = c;
    4849         179 :                                 } else if (allow && state == 1) {
    4850          43 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4851           1 :                                                 pos = tp - tbuf;
    4852           1 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4853           1 :                                                 tp = tbuf + pos;
    4854             :                                         }
    4855          43 :                                         *(tp++) = c;
    4856             :                                 }
    4857        1255 :                                 if (state && p != buf && (state == 1 || *(p-1) != '\\') && (!in_q || *p == in_q)) {
    4858         238 :                                         if (in_q) {
    4859         118 :                                                 in_q = 0;
    4860             :                                         } else {
    4861         120 :                                                 in_q = *p;
    4862             :                                         }
    4863             :                                 }
    4864        1255 :                                 break;
    4865             : 
    4866             :                         case '!':
    4867             :                                 /* JavaScript & Other HTML scripting languages */
    4868         109 :                                 if (state == 1 && *(p-1) == '<') {
    4869          40 :                                         state = 3;
    4870          40 :                                         lc = c;
    4871             :                                 } else {
    4872          29 :                                         if (state == 0) {
    4873          20 :                                                 *(rp++) = c;
    4874           9 :                                         } else if (allow && state == 1) {
    4875           6 :                                                 if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4876           0 :                                                         pos = tp - tbuf;
    4877           0 :                                                         tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4878           0 :                                                         tp = tbuf + pos;
    4879             :                                                 }
    4880           6 :                                                 *(tp++) = c;
    4881             :                                         }
    4882             :                                 }
    4883          69 :                                 break;
    4884             : 
    4885             :                         case '-':
    4886        1204 :                                 if (state == 3 && p >= buf + 2 && *(p-1) == '-' && *(p-2) == '!') {
    4887          36 :                                         state = 4;
    4888             :                                 } else {
    4889             :                                         goto reg_char;
    4890             :                                 }
    4891          36 :                                 break;
    4892             : 
    4893             :                         case '?':
    4894             : 
    4895         204 :                                 if (state == 1 && *(p-1) == '<') {
    4896          94 :                                         br=0;
    4897          94 :                                         state=2;
    4898          94 :                                         break;
    4899             :                                 }
    4900             : 
    4901             :                         case 'E':
    4902             :                         case 'e':
    4903             :                                 /* !DOCTYPE exception */
    4904        9870 :                                 if (state==3 && p > buf+6
    4905           6 :                                                      && tolower(*(p-1)) == 'p'
    4906           6 :                                                  && tolower(*(p-2)) == 'y'
    4907           6 :                                                      && tolower(*(p-3)) == 't'
    4908           6 :                                                      && tolower(*(p-4)) == 'c'
    4909           6 :                                                      && tolower(*(p-5)) == 'o'
    4910           6 :                                                      && tolower(*(p-6)) == 'd') {
    4911           3 :                                         state = 1;
    4912           3 :                                         break;
    4913             :                                 }
    4914             :                                 /* fall-through */
    4915             : 
    4916             :                         case 'l':
    4917             :                         case 'L':
    4918             : 
    4919             :                                 /* swm: If we encounter '<?xml' then we shouldn't be in
    4920             :                                  * state == 2 (PHP). Switch back to HTML.
    4921             :                                  */
    4922             : 
    4923       15120 :                                 if (state == 2 && p > buf+2 && strncasecmp(p-2, "xm", 2) == 0) {
    4924           2 :                                         state = 1;
    4925           2 :                                         break;
    4926             :                                 }
    4927             : 
    4928             :                                 /* fall-through */
    4929             :                         default:
    4930             : reg_char:
    4931      124051 :                                 if (state == 0) {
    4932      112913 :                                         *(rp++) = c;
    4933       11138 :                                 } else if (allow && state == 1) {
    4934        4175 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4935        1041 :                                                 pos = tp - tbuf;
    4936        1041 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4937        1041 :                                                 tp = tbuf + pos;
    4938             :                                         }
    4939        4175 :                                         *(tp++) = c;
    4940             :                                 }
    4941             :                                 break;
    4942             :                 }
    4943      131159 :                 c = *(++p);
    4944      131159 :                 i++;
    4945             :         }
    4946         738 :         if (rp < rbuf + len) {
    4947         270 :                 *rp = '\0';
    4948             :         }
    4949         738 :         efree(buf);
    4950         738 :         if (allow) {
    4951         286 :                 efree(tbuf);
    4952         286 :                 if (allow_free) {
    4953          10 :                         efree(allow_free);
    4954             :                 }
    4955             :         }
    4956         738 :         if (stateptr)
    4957         237 :                 *stateptr = state;
    4958             : 
    4959         738 :         return (size_t)(rp - rbuf);
    4960             : }
    4961             : /* }}} */
    4962             : 
    4963             : /* {{{ proto array str_getcsv(string input[, string delimiter[, string enclosure[, string escape]]])
    4964             : Parse a CSV string into an array */
    4965          16 : PHP_FUNCTION(str_getcsv)
    4966             : {
    4967             :         zend_string *str;
    4968          16 :         char delim = ',', enc = '"', esc = '\\';
    4969          16 :         char *delim_str = NULL, *enc_str = NULL, *esc_str = NULL;
    4970          16 :         size_t delim_len = 0, enc_len = 0, esc_len = 0;
    4971             : 
    4972          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|sss", &str, &delim_str, &delim_len,
    4973             :                 &enc_str, &enc_len, &esc_str, &esc_len) == FAILURE) {
    4974           0 :                 return;
    4975             :         }
    4976             : 
    4977          16 :         delim = delim_len ? delim_str[0] : delim;
    4978          16 :         enc = enc_len ? enc_str[0] : enc;
    4979          16 :         esc = esc_len ? esc_str[0] : esc;
    4980             : 
    4981          16 :         php_fgetcsv(NULL, delim, enc, esc, ZSTR_LEN(str), ZSTR_VAL(str), return_value);
    4982             : }
    4983             : /* }}} */
    4984             : 
    4985             : /* {{{ proto string str_repeat(string input, int mult)
    4986             :    Returns the input string repeat mult times */
    4987      174405 : PHP_FUNCTION(str_repeat)
    4988             : {
    4989             :         zend_string             *input_str;             /* Input string */
    4990             :         zend_long               mult;                   /* Multiplier */
    4991             :         zend_string     *result;                /* Resulting string */
    4992             :         size_t          result_len;             /* Length of the resulting string */
    4993             : 
    4994      174405 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl", &input_str, &mult) == FAILURE) {
    4995          80 :                 return;
    4996             :         }
    4997             : 
    4998      174325 :         if (mult < 0) {
    4999           1 :                 php_error_docref(NULL, E_WARNING, "Second argument has to be greater than or equal to 0");
    5000           1 :                 return;
    5001             :         }
    5002             : 
    5003             :         /* Don't waste our time if it's empty */
    5004             :         /* ... or if the multiplier is zero */
    5005      174324 :         if (ZSTR_LEN(input_str) == 0 || mult == 0)
    5006          52 :                 RETURN_EMPTY_STRING();
    5007             : 
    5008             :         /* Initialize the result string */
    5009      348544 :         result = zend_string_safe_alloc(ZSTR_LEN(input_str), mult, 0, 0);
    5010      174272 :         result_len = ZSTR_LEN(input_str) * mult;
    5011             : 
    5012             :         /* Heavy optimization for situations where input string is 1 byte long */
    5013      174272 :         if (ZSTR_LEN(input_str) == 1) {
    5014      160653 :                 memset(ZSTR_VAL(result), *ZSTR_VAL(input_str), mult);
    5015             :         } else {
    5016             :                 char *s, *e, *ee;
    5017       13619 :                 ptrdiff_t l=0;
    5018       13619 :                 memcpy(ZSTR_VAL(result), ZSTR_VAL(input_str), ZSTR_LEN(input_str));
    5019       13619 :                 s = ZSTR_VAL(result);
    5020       13619 :                 e = ZSTR_VAL(result) + ZSTR_LEN(input_str);
    5021       13619 :                 ee = ZSTR_VAL(result) + result_len;
    5022             : 
    5023       40353 :                 while (e<ee) {
    5024       13115 :                         l = (e-s) < (ee-e) ? (e-s) : (ee-e);
    5025       13115 :                         memmove(e, s, l);
    5026       13115 :                         e += l;
    5027             :                 }
    5028             :         }
    5029             : 
    5030      174272 :         ZSTR_VAL(result)[result_len] = '\0';
    5031             : 
    5032      174272 :         RETURN_NEW_STR(result);
    5033             : }
    5034             : /* }}} */
    5035             : 
    5036             : /* {{{ proto mixed count_chars(string input [, int mode])
    5037             :    Returns info about what characters are used in input */
    5038          60 : PHP_FUNCTION(count_chars)
    5039             : {
    5040             :         zend_string *input;
    5041             :         int chars[256];
    5042          60 :         zend_long mymode=0;
    5043             :         unsigned char *buf;
    5044             :         int inx;
    5045             :         char retstr[256];
    5046          60 :         size_t retlen=0;
    5047          60 :         size_t tmp = 0;
    5048             : 
    5049          60 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &input, &mymode) == FAILURE) {
    5050          11 :                 return;
    5051             :         }
    5052             : 
    5053          49 :         if (mymode < 0 || mymode > 4) {
    5054           7 :                 php_error_docref(NULL, E_WARNING, "Unknown mode");
    5055           7 :                 RETURN_FALSE;
    5056             :         }
    5057             : 
    5058          42 :         buf = (unsigned char *) ZSTR_VAL(input);
    5059          42 :         memset((void*) chars, 0, sizeof(chars));
    5060             : 
    5061        1462 :         while (tmp < ZSTR_LEN(input)) {
    5062        1378 :                 chars[*buf]++;
    5063        1378 :                 buf++;
    5064        1378 :                 tmp++;
    5065             :         }
    5066             : 
    5067          42 :         if (mymode < 3) {
    5068          38 :                 array_init(return_value);
    5069             :         }
    5070             : 
    5071       10794 :         for (inx = 0; inx < 256; inx++) {
    5072       10752 :                 switch (mymode) {
    5073             :                         case 0:
    5074        2816 :                                 add_index_long(return_value, inx, chars[inx]);
    5075        2816 :                                 break;
    5076             :                         case 1:
    5077        6400 :                                 if (chars[inx] != 0) {
    5078         180 :                                         add_index_long(return_value, inx, chars[inx]);
    5079             :                                 }
    5080        6400 :                                 break;
    5081             :                         case 2:
    5082         512 :                                 if (chars[inx] == 0) {
    5083         475 :                                         add_index_long(return_value, inx, chars[inx]);
    5084             :                                 }
    5085         512 :                                 break;
    5086             :                         case 3:
    5087         512 :                                 if (chars[inx] != 0) {
    5088          37 :                                         retstr[retlen++] = inx;
    5089             :                                 }
    5090         512 :                                 break;
    5091             :                         case 4:
    5092         512 :                                 if (chars[inx] == 0) {
    5093         475 :                                         retstr[retlen++] = inx;
    5094             :                                 }
    5095             :                                 break;
    5096             :                 }
    5097             :         }
    5098             : 
    5099          42 :         if (mymode >= 3 && mymode <= 4) {
    5100           8 :                 RETURN_STRINGL(retstr, retlen);
    5101             :         }
    5102             : }
    5103             : /* }}} */
    5104             : 
    5105             : /* {{{ php_strnatcmp
    5106             :  */
    5107          54 : static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
    5108             : {
    5109             :         zend_string *s1, *s2;
    5110             : 
    5111          54 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &s1, &s2) == FAILURE) {
    5112           4 :                 return;
    5113             :         }
    5114             : 
    5115          50 :         RETURN_LONG(strnatcmp_ex(ZSTR_VAL(s1), ZSTR_LEN(s1),
    5116             :                                                          ZSTR_VAL(s2), ZSTR_LEN(s2),
    5117             :                                                          fold_case));
    5118             : }
    5119             : /* }}} */
    5120             : 
    5121         238 : PHPAPI int string_natural_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */
    5122             : {
    5123         238 :         zend_string *str1 = zval_get_string(op1);
    5124         238 :         zend_string *str2 = zval_get_string(op2);
    5125             : 
    5126         238 :         ZVAL_LONG(result, strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), case_insensitive));
    5127             : 
    5128             :         zend_string_release(str1);
    5129             :         zend_string_release(str2);
    5130         238 :         return SUCCESS;
    5131             : }
    5132             : /* }}} */
    5133             : 
    5134         105 : PHPAPI int string_natural_case_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
    5135             : {
    5136         105 :         return string_natural_compare_function_ex(result, op1, op2, 1);
    5137             : }
    5138             : /* }}} */
    5139             : 
    5140         133 : PHPAPI int string_natural_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
    5141             : {
    5142         133 :         return string_natural_compare_function_ex(result, op1, op2, 0);
    5143             : }
    5144             : /* }}} */
    5145             : 
    5146             : /* {{{ proto int strnatcmp(string s1, string s2)
    5147             :    Returns the result of string comparison using 'natural' algorithm */
    5148          33 : PHP_FUNCTION(strnatcmp)
    5149             : {
    5150          33 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    5151          33 : }
    5152             : /* }}} */
    5153             : 
    5154             : /* {{{ proto array localeconv(void)
    5155             :    Returns numeric formatting information based on the current locale */
    5156          11 : PHP_FUNCTION(localeconv)
    5157             : {
    5158             :         zval grouping, mon_grouping;
    5159             :         int len, i;
    5160             : 
    5161             :         /* We don't need no stinkin' parameters... */
    5162          11 :         if (zend_parse_parameters_none() == FAILURE) {
    5163           0 :                 return;
    5164             :         }
    5165             : 
    5166          11 :         array_init(return_value);
    5167          11 :         array_init(&grouping);
    5168          11 :         array_init(&mon_grouping);
    5169             : 
    5170             : #ifdef HAVE_LOCALECONV
    5171             :         {
    5172             :                 struct lconv currlocdata;
    5173             : 
    5174          11 :                 localeconv_r( &currlocdata );
    5175             : 
    5176             :                 /* Grab the grouping data out of the array */
    5177          11 :                 len = (int)strlen(currlocdata.grouping);
    5178             : 
    5179          33 :                 for (i = 0; i < len; i++) {
    5180          22 :                         add_index_long(&grouping, i, currlocdata.grouping[i]);
    5181             :                 }
    5182             : 
    5183             :                 /* Grab the monetary grouping data out of the array */
    5184          11 :                 len = (int)strlen(currlocdata.mon_grouping);
    5185             : 
    5186          31 :                 for (i = 0; i < len; i++) {
    5187          20 :                         add_index_long(&mon_grouping, i, currlocdata.mon_grouping[i]);
    5188             :                 }
    5189             : 
    5190          11 :                 add_assoc_string(return_value, "decimal_point",     currlocdata.decimal_point);
    5191          11 :                 add_assoc_string(return_value, "thousands_sep",     currlocdata.thousands_sep);
    5192          11 :                 add_assoc_string(return_value, "int_curr_symbol",   currlocdata.int_curr_symbol);
    5193          11 :                 add_assoc_string(return_value, "currency_symbol",   currlocdata.currency_symbol);
    5194          11 :                 add_assoc_string(return_value, "mon_decimal_point", currlocdata.mon_decimal_point);
    5195          11 :                 add_assoc_string(return_value, "mon_thousands_sep", currlocdata.mon_thousands_sep);
    5196          11 :                 add_assoc_string(return_value, "positive_sign",     currlocdata.positive_sign);
    5197          11 :                 add_assoc_string(return_value, "negative_sign",     currlocdata.negative_sign);
    5198          11 :                 add_assoc_long(  return_value, "int_frac_digits",   currlocdata.int_frac_digits);
    5199          11 :                 add_assoc_long(  return_value, "frac_digits",       currlocdata.frac_digits);
    5200          11 :                 add_assoc_long(  return_value, "p_cs_precedes",     currlocdata.p_cs_precedes);
    5201          11 :                 add_assoc_long(  return_value, "p_sep_by_space",    currlocdata.p_sep_by_space);
    5202          11 :                 add_assoc_long(  return_value, "n_cs_precedes",     currlocdata.n_cs_precedes);
    5203          11 :                 add_assoc_long(  return_value, "n_sep_by_space",    currlocdata.n_sep_by_space);
    5204          11 :                 add_assoc_long(  return_value, "p_sign_posn",       currlocdata.p_sign_posn);
    5205          11 :                 add_assoc_long(  return_value, "n_sign_posn",       currlocdata.n_sign_posn);
    5206             :         }
    5207             : #else
    5208             :         /* Ok, it doesn't look like we have locale info floating around, so I guess it
    5209             :            wouldn't hurt to just go ahead and return the POSIX locale information?  */
    5210             : 
    5211             :         add_index_long(&grouping, 0, -1);
    5212             :         add_index_long(&mon_grouping, 0, -1);
    5213             : 
    5214             :         add_assoc_string(return_value, "decimal_point",     "\x2E");
    5215             :         add_assoc_string(return_value, "thousands_sep",     "");
    5216             :         add_assoc_string(return_value, "int_curr_symbol",   "");
    5217             :         add_assoc_string(return_value, "currency_symbol",   "");
    5218             :         add_assoc_string(return_value, "mon_decimal_point", "\x2E");
    5219             :         add_assoc_string(return_value, "mon_thousands_sep", "");
    5220             :         add_assoc_string(return_value, "positive_sign",     "");
    5221             :         add_assoc_string(return_value, "negative_sign",     "");
    5222             :         add_assoc_long(  return_value, "int_frac_digits",   CHAR_MAX);
    5223             :         add_assoc_long(  return_value, "frac_digits",       CHAR_MAX);
    5224             :         add_assoc_long(  return_value, "p_cs_precedes",     CHAR_MAX);
    5225             :         add_assoc_long(  return_value, "p_sep_by_space",    CHAR_MAX);
    5226             :         add_assoc_long(  return_value, "n_cs_precedes",     CHAR_MAX);
    5227             :         add_assoc_long(  return_value, "n_sep_by_space",    CHAR_MAX);
    5228             :         add_assoc_long(  return_value, "p_sign_posn",       CHAR_MAX);
    5229             :         add_assoc_long(  return_value, "n_sign_posn",       CHAR_MAX);
    5230             : #endif
    5231             : 
    5232          11 :         zend_hash_str_update(Z_ARRVAL_P(return_value), "grouping", sizeof("grouping")-1, &grouping);
    5233          11 :         zend_hash_str_update(Z_ARRVAL_P(return_value), "mon_grouping", sizeof("mon_grouping")-1, &mon_grouping);
    5234             : }
    5235             : /* }}} */
    5236             : 
    5237             : /* {{{ proto int strnatcasecmp(string s1, string s2)
    5238             :    Returns the result of case-insensitive string comparison using 'natural' algorithm */
    5239          21 : PHP_FUNCTION(strnatcasecmp)
    5240             : {
    5241          21 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    5242          21 : }
    5243             : /* }}} */
    5244             : 
    5245             : /* {{{ proto int substr_count(string haystack, string needle [, int offset [, int length]])
    5246             :    Returns the number of times a substring occurs in the string */
    5247          47 : PHP_FUNCTION(substr_count)
    5248             : {
    5249             :         char *haystack, *needle;
    5250          47 :         zend_long offset = 0, length = 0;
    5251          47 :         int ac = ZEND_NUM_ARGS();
    5252          47 :         int count = 0;
    5253             :         size_t haystack_len, needle_len;
    5254             :         char *p, *endp, cmp;
    5255             : 
    5256          47 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ll", &haystack, &haystack_len, &needle, &needle_len, &offset, &length) == FAILURE) {
    5257           6 :                 return;
    5258             :         }
    5259             : 
    5260          41 :         if (needle_len == 0) {
    5261           2 :                 php_error_docref(NULL, E_WARNING, "Empty substring");
    5262           2 :                 RETURN_FALSE;
    5263             :         }
    5264             : 
    5265          39 :         p = haystack;
    5266          39 :         endp = p + haystack_len;
    5267             : 
    5268          39 :         if (offset < 0) {
    5269           1 :                 php_error_docref(NULL, E_WARNING, "Offset should be greater than or equal to 0");
    5270           1 :                 RETURN_FALSE;
    5271             :         }
    5272             : 
    5273          38 :         if ((size_t)offset > haystack_len) {
    5274           4 :                 php_error_docref(NULL, E_WARNING, "Offset value " ZEND_LONG_FMT " exceeds string length", offset);
    5275           4 :                 RETURN_FALSE;
    5276             :         }
    5277          34 :         p += offset;
    5278             : 
    5279          34 :         if (ac == 4) {
    5280             : 
    5281           6 :                 if (length <= 0) {
    5282           1 :                         php_error_docref(NULL, E_WARNING, "Length should be greater than 0");
    5283           1 :                         RETURN_FALSE;
    5284             :                 }
    5285           5 :                 if (length > (haystack_len - offset)) {
    5286           1 :                         php_error_docref(NULL, E_WARNING, "Length value " ZEND_LONG_FMT " exceeds string length", length);
    5287           1 :                         RETURN_FALSE;
    5288             :                 }
    5289           4 :                 endp = p + length;
    5290             :         }
    5291             : 
    5292          32 :         if (needle_len == 1) {
    5293          19 :                 cmp = needle[0];
    5294             : 
    5295          56 :                 while ((p = memchr(p, cmp, endp - p))) {
    5296          18 :                         count++;
    5297          18 :                         p++;
    5298             :                 }
    5299             :         } else {
    5300        1107 :                 while ((p = (char*)php_memnstr(p, needle, needle_len, endp))) {
    5301         534 :                         p += needle_len;
    5302         534 :                         count++;
    5303             :                 }
    5304             :         }
    5305             : 
    5306          32 :         RETURN_LONG(count);
    5307             : }
    5308             : /* }}} */
    5309             : 
    5310             : /* {{{ proto string str_pad(string input, int pad_length [, string pad_string [, int pad_type]])
    5311             :    Returns input string padded on the left or right to specified length with pad_string */
    5312         580 : PHP_FUNCTION(str_pad)
    5313             : {
    5314             :         /* Input arguments */
    5315             :         zend_string *input;                             /* Input string */
    5316             :         zend_long pad_length;                   /* Length to pad to */
    5317             : 
    5318             :         /* Helper variables */
    5319             :         size_t num_pad_chars;           /* Number of padding characters (total - input size) */
    5320         580 :         char *pad_str = " "; /* Pointer to padding string */
    5321         580 :         size_t pad_str_len = 1;
    5322         580 :         zend_long   pad_type_val = STR_PAD_RIGHT; /* The padding type value */
    5323         580 :         size_t     i, left_pad=0, right_pad=0;
    5324         580 :         zend_string *result = NULL;     /* Resulting string */
    5325             : 
    5326         580 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|sl", &input, &pad_length, &pad_str, &pad_str_len, &pad_type_val) == FAILURE) {
    5327          23 :                 return;
    5328             :         }
    5329             : 
    5330             :         /* If resulting string turns out to be shorter than input string,
    5331             :            we simply copy the input and return. */
    5332         557 :         if (pad_length < 0  || (size_t)pad_length <= ZSTR_LEN(input)) {
    5333         278 :                 RETURN_STRINGL(ZSTR_VAL(input), ZSTR_LEN(input));
    5334             :         }
    5335             : 
    5336         418 :         if (pad_str_len == 0) {
    5337           8 :                 php_error_docref(NULL, E_WARNING, "Padding string cannot be empty");
    5338           8 :                 return;
    5339             :         }
    5340             : 
    5341         410 :         if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) {
    5342           7 :                 php_error_docref(NULL, E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH");
    5343           7 :                 return;
    5344             :         }
    5345             : 
    5346         403 :         num_pad_chars = pad_length - ZSTR_LEN(input);
    5347         403 :         if (num_pad_chars >= INT_MAX) {
    5348           0 :                 php_error_docref(NULL, E_WARNING, "Padding length is too long");
    5349           0 :                 return;
    5350             :         }
    5351             : 
    5352         806 :         result = zend_string_alloc(ZSTR_LEN(input) + num_pad_chars, 0);
    5353         403 :         ZSTR_LEN(result) = 0;
    5354             : 
    5355             :         /* We need to figure out the left/right padding lengths. */
    5356         403 :         switch (pad_type_val) {
    5357             :                 case STR_PAD_RIGHT:
    5358         320 :                         left_pad = 0;
    5359         320 :                         right_pad = num_pad_chars;
    5360         320 :                         break;
    5361             : 
    5362             :                 case STR_PAD_LEFT:
    5363          49 :                         left_pad = num_pad_chars;
    5364          49 :                         right_pad = 0;
    5365          49 :                         break;
    5366             : 
    5367             :                 case STR_PAD_BOTH:
    5368          34 :                         left_pad = num_pad_chars / 2;
    5369          34 :                         right_pad = num_pad_chars - left_pad;
    5370             :                         break;
    5371             :         }
    5372             : 
    5373             :         /* First we pad on the left. */
    5374         950 :         for (i = 0; i < left_pad; i++)
    5375         547 :                 ZSTR_VAL(result)[ZSTR_LEN(result)++] = pad_str[i % pad_str_len];
    5376             : 
    5377             :         /* Then we copy the input string. */
    5378         403 :         memcpy(ZSTR_VAL(result) + ZSTR_LEN(result), ZSTR_VAL(input), ZSTR_LEN(input));
    5379         403 :         ZSTR_LEN(result) += ZSTR_LEN(input);
    5380             : 
    5381             :         /* Finally, we pad on the right. */
    5382        7471 :         for (i = 0; i < right_pad; i++)
    5383        7068 :                 ZSTR_VAL(result)[ZSTR_LEN(result)++] = pad_str[i % pad_str_len];
    5384             : 
    5385         403 :         ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
    5386             : 
    5387         403 :         RETURN_NEW_STR(result);
    5388             : }
    5389             : /* }}} */
    5390             : 
    5391             : /* {{{ proto mixed sscanf(string str, string format [, string ...])
    5392             :    Implements an ANSI C compatible sscanf */
    5393          81 : PHP_FUNCTION(sscanf)
    5394             : {
    5395          81 :         zval *args = NULL;
    5396             :         char *str, *format;
    5397             :         size_t str_len, format_len;
    5398          81 :         int result, num_args = 0;
    5399             : 
    5400          81 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss*", &str, &str_len, &format, &format_len,
    5401             :                 &args, &num_args) == FAILURE) {
    5402          10 :                 return;
    5403             :         }
    5404             : 
    5405          71 :         result = php_sscanf_internal(str, format, num_args, args, 0, return_value);
    5406             : 
    5407          71 :         if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
    5408           0 :                 WRONG_PARAM_COUNT;
    5409             :         }
    5410             : }
    5411             : /* }}} */
    5412             : 
    5413             : static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    5414             : static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
    5415             : 
    5416             : /* {{{ proto string str_rot13(string str)
    5417             :    Perform the rot13 transform on a string */
    5418          29 : PHP_FUNCTION(str_rot13)
    5419             : {
    5420             :         zend_string *arg;
    5421             : 
    5422          29 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
    5423           5 :                 return;
    5424             :         }
    5425             : 
    5426          24 :         if (ZSTR_LEN(arg) == 0) {
    5427           0 :                 RETURN_EMPTY_STRING();
    5428             :         } else {
    5429          24 :                 RETURN_STR(php_strtr_ex(arg, rot13_from, rot13_to, 52));
    5430             :         }
    5431             : }
    5432             : /* }}} */
    5433             : 
    5434       91009 : static void php_string_shuffle(char *str, zend_long len) /* {{{ */
    5435             : {
    5436             :         zend_long n_elems, rnd_idx, n_left;
    5437             :         char temp;
    5438             :         /* The implementation is stolen from array_data_shuffle       */
    5439             :         /* Thus the characteristics of the randomization are the same */
    5440       91009 :         n_elems = len;
    5441             : 
    5442       91009 :         if (n_elems <= 1) {
    5443           0 :                 return;
    5444             :         }
    5445             : 
    5446       91009 :         n_left = n_elems;
    5447             : 
    5448      455116 :         while (--n_left) {
    5449      273098 :                 rnd_idx = php_rand();
    5450      273098 :                 RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    5451      273098 :                 if (rnd_idx != n_left) {
    5452      174637 :                         temp = str[n_left];
    5453      174637 :                         str[n_left] = str[rnd_idx];
    5454      174637 :                         str[rnd_idx] = temp;
    5455             :                 }
    5456             :         }
    5457             : }
    5458             : /* }}} */
    5459             : 
    5460             : /* {{{ proto void str_shuffle(string str)
    5461             :    Shuffles string. One permutation of all possible is created */
    5462       91025 : PHP_FUNCTION(str_shuffle)
    5463             : {
    5464             :         zend_string *arg;
    5465             : 
    5466       91025 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
    5467           6 :                 return;
    5468             :         }
    5469             : 
    5470      182038 :         RETVAL_STRINGL(ZSTR_VAL(arg), ZSTR_LEN(arg));
    5471       91019 :         if (Z_STRLEN_P(return_value) > 1) {
    5472       91009 :                 php_string_shuffle(Z_STRVAL_P(return_value), (zend_long) Z_STRLEN_P(return_value));
    5473             :         }
    5474             : }
    5475             : /* }}} */
    5476             : 
    5477             : /* {{{ proto mixed str_word_count(string str, [int format [, string charlist]])
    5478             :         Counts the number of words inside a string. If format of 1 is specified,
    5479             :         then the function will return an array containing all the words
    5480             :         found inside the string. If format of 2 is specified, then the function
    5481             :         will return an associated array where the position of the word is the key
    5482             :         and the word itself is the value.
    5483             : 
    5484             :         For the purpose of this function, 'word' is defined as a locale dependent
    5485             :         string containing alphabetic characters, which also may contain, but not start
    5486             :         with "'" and "-" characters.
    5487             : */
    5488          35 : PHP_FUNCTION(str_word_count)
    5489             : {
    5490             :         zend_string *str;
    5491          35 :         char *char_list = NULL, *p, *e, *s, ch[256];
    5492          35 :         size_t char_list_len = 0, word_count = 0;
    5493          35 :         zend_long type = 0;
    5494             : 
    5495          35 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|ls", &str, &type, &char_list, &char_list_len) == FAILURE) {
    5496           8 :                 return;
    5497             :         }
    5498             : 
    5499          27 :         switch(type) {
    5500             :                 case 1:
    5501             :                 case 2:
    5502          15 :                         array_init(return_value);
    5503          15 :                         if (!ZSTR_LEN(str)) {
    5504           0 :                                 return;
    5505             :                         }
    5506          15 :                         break;
    5507             :                 case 0:
    5508           6 :                         if (!ZSTR_LEN(str)) {
    5509           1 :                                 RETURN_LONG(0);
    5510             :                         }
    5511             :                         /* nothing to be done */
    5512           5 :                         break;
    5513             :                 default:
    5514           6 :                         php_error_docref(NULL, E_WARNING, "Invalid format value " ZEND_LONG_FMT, type);
    5515           6 :                         RETURN_FALSE;
    5516             :         }
    5517             : 
    5518          20 :         if (char_list) {
    5519          15 :                 php_charmask((unsigned char *)char_list, char_list_len, ch);
    5520             :         }
    5521             : 
    5522          20 :         p = ZSTR_VAL(str);
    5523          20 :         e = ZSTR_VAL(str) + ZSTR_LEN(str);
    5524             : 
    5525             :         /* first character cannot be ' or -, unless explicitly allowed by the user */
    5526          20 :         if ((*p == '\'' && (!char_list || !ch['\''])) || (*p == '-' && (!char_list || !ch['-']))) {
    5527           2 :                 p++;
    5528             :         }
    5529             :         /* last character cannot be -, unless explicitly allowed by the user */
    5530          20 :         if (*(e - 1) == '-' && (!char_list || !ch['-'])) {
    5531           1 :                 e--;
    5532             :         }
    5533             : 
    5534         187 :         while (p < e) {
    5535         147 :                 s = p;
    5536         576 :                 while (p < e && (isalpha((unsigned char)*p) || (char_list && ch[(unsigned char)*p]) || *p == '\'' || *p == '-')) {
    5537         282 :                         p++;
    5538             :                 }
    5539         147 :                 if (p > s) {
    5540          93 :                         switch (type)
    5541             :                         {
    5542             :                                 case 1:
    5543          29 :                                         add_next_index_stringl(return_value, s, p - s);
    5544          29 :                                         break;
    5545             :                                 case 2:
    5546          35 :                                         add_index_stringl(return_value, (s - ZSTR_VAL(str)), s, p - s);
    5547          35 :                                         break;
    5548             :                                 default:
    5549          29 :                                         word_count++;
    5550             :                                         break;
    5551             :                         }
    5552             :                 }
    5553         147 :                 p++;
    5554             :         }
    5555             : 
    5556          20 :         if (!type) {
    5557           5 :                 RETURN_LONG(word_count);
    5558             :         }
    5559             : }
    5560             : 
    5561             : /* }}} */
    5562             : 
    5563             : #if HAVE_STRFMON
    5564             : /* {{{ proto string money_format(string format , float value)
    5565             :    Convert monetary value(s) to string */
    5566          71 : PHP_FUNCTION(money_format)
    5567             : {
    5568          71 :         size_t format_len = 0;
    5569             :         char *format, *p, *e;
    5570             :         double value;
    5571          71 :         zend_bool check = 0;
    5572             :         zend_string *str;
    5573             :         ssize_t res_len;
    5574             : 
    5575          71 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sd", &format, &format_len, &value) == FAILURE) {
    5576          17 :                 return;
    5577             :         }
    5578             : 
    5579          54 :         p = format;
    5580          54 :         e = p + format_len;
    5581         141 :         while ((p = memchr(p, '%', (e - p)))) {
    5582          34 :                 if (*(p + 1) == '%') {
    5583           0 :                         p += 2;
    5584          34 :                 } else if (!check) {
    5585          33 :                         check = 1;
    5586          33 :                         p++;
    5587             :                 } else {
    5588           1 :                         php_error_docref(NULL, E_WARNING, "Only a single %%i or %%n token can be used");
    5589           1 :                         RETURN_FALSE;
    5590             :                 }
    5591             :         }
    5592             : 
    5593         106 :         str = zend_string_alloc(format_len + 1024, 0);
    5594          53 :         if ((res_len = strfmon(ZSTR_VAL(str), ZSTR_LEN(str), format, value)) < 0) {
    5595             :                 zend_string_free(str);
    5596           0 :                 RETURN_FALSE;
    5597             :         }
    5598          53 :         ZSTR_LEN(str) = (size_t)res_len;
    5599          53 :         ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
    5600             : 
    5601         106 :         RETURN_NEW_STR(zend_string_truncate(str, ZSTR_LEN(str), 0));
    5602             : }
    5603             : /* }}} */
    5604             : #endif
    5605             : 
    5606             : /* {{{ proto array str_split(string str [, int split_length])
    5607             :    Convert a string to an array. If split_length is specified, break the string down into chunks each split_length characters long. */
    5608         190 : PHP_FUNCTION(str_split)
    5609             : {
    5610             :         zend_string *str;
    5611         190 :         zend_long split_length = 1;
    5612             :         char *p;
    5613             :         size_t n_reg_segments;
    5614             : 
    5615         190 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &str, &split_length) == FAILURE) {
    5616          19 :                 return;
    5617             :         }
    5618             : 
    5619         171 :         if (split_length <= 0) {
    5620          15 :                 php_error_docref(NULL, E_WARNING, "The length of each segment must be greater than zero");
    5621          15 :                 RETURN_FALSE;
    5622             :         }
    5623             : 
    5624             : 
    5625         156 :         if (0 == ZSTR_LEN(str) || (size_t)split_length >= ZSTR_LEN(str)) {
    5626          29 :                 array_init_size(return_value, 1);
    5627          29 :                 add_next_index_stringl(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    5628          29 :                 return;
    5629             :         }
    5630             : 
    5631         127 :         array_init_size(return_value, (uint32_t)(((ZSTR_LEN(str) - 1) / split_length) + 1));
    5632             : 
    5633         127 :         n_reg_segments = ZSTR_LEN(str) / split_length;
    5634         127 :         p = ZSTR_VAL(str);
    5635             : 
    5636       22191 :         while (n_reg_segments-- > 0) {
    5637       21937 :                 add_next_index_stringl(return_value, p, split_length);
    5638       21937 :                 p += split_length;
    5639             :         }
    5640             : 
    5641         127 :         if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
    5642          31 :                 add_next_index_stringl(return_value, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
    5643             :         }
    5644             : }
    5645             : /* }}} */
    5646             : 
    5647             : /* {{{ proto array strpbrk(string haystack, string char_list)
    5648             :    Search a string for any of a set of characters */
    5649          20 : PHP_FUNCTION(strpbrk)
    5650             : {
    5651             :         zend_string *haystack, *char_list;
    5652             :         char *haystack_ptr, *cl_ptr;
    5653             : 
    5654          20 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &haystack, &char_list) == FAILURE) {
    5655           4 :                 RETURN_FALSE;
    5656             :         }
    5657             : 
    5658          16 :         if (!ZSTR_LEN(char_list)) {
    5659           1 :                 php_error_docref(NULL, E_WARNING, "The character list cannot be empty");
    5660           1 :                 RETURN_FALSE;
    5661             :         }
    5662             : 
    5663          96 :         for (haystack_ptr = ZSTR_VAL(haystack); haystack_ptr < (ZSTR_VAL(haystack) + ZSTR_LEN(haystack)); ++haystack_ptr) {
    5664         228 :                 for (cl_ptr = ZSTR_VAL(char_list); cl_ptr < (ZSTR_VAL(char_list) + ZSTR_LEN(char_list)); ++cl_ptr) {
    5665         147 :                         if (*cl_ptr == *haystack_ptr) {
    5666          20 :                                 RETURN_STRINGL(haystack_ptr, (ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - haystack_ptr));
    5667             :                         }
    5668             :                 }
    5669             :         }
    5670             : 
    5671           5 :         RETURN_FALSE;
    5672             : }
    5673             : /* }}} */
    5674             : 
    5675             : /* {{{ proto int substr_compare(string main_str, string str, int offset [, int length [, bool case_sensitivity]])
    5676             :    Binary safe optionally case insensitive comparison of 2 strings from an offset, up to length characters */
    5677          50 : PHP_FUNCTION(substr_compare)
    5678             : {
    5679             :         zend_string *s1, *s2;
    5680          50 :         zend_long offset, len=0;
    5681          50 :         zend_bool cs=0;
    5682             :         size_t cmp_len;
    5683             : 
    5684          50 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSl|lb", &s1, &s2, &offset, &len, &cs) == FAILURE) {
    5685           2 :                 RETURN_FALSE;
    5686             :         }
    5687             : 
    5688          48 :         if (ZEND_NUM_ARGS() >= 4 && len <= 0) {
    5689           4 :                 if (len == 0) {
    5690           2 :                         RETURN_LONG(0L);
    5691             :                 } else {
    5692           2 :                         php_error_docref(NULL, E_WARNING, "The length must be greater than or equal to zero");
    5693           2 :                         RETURN_FALSE;
    5694             :                 }
    5695             :         }
    5696             : 
    5697          44 :         if (offset < 0) {
    5698           2 :                 offset = ZSTR_LEN(s1) + offset;
    5699           2 :                 offset = (offset < 0) ? 0 : offset;
    5700             :         }
    5701             : 
    5702          44 :         if ((size_t)offset >= ZSTR_LEN(s1)) {
    5703           2 :                 php_error_docref(NULL, E_WARNING, "The start position cannot exceed initial string length");
    5704           2 :                 RETURN_FALSE;
    5705             :         }
    5706             : 
    5707          42 :         cmp_len = (size_t) (len ? len : MAX(ZSTR_LEN(s2), (ZSTR_LEN(s1) - offset)));
    5708             : 
    5709          42 :         if (!cs) {
    5710          41 :                 RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1) + offset, (ZSTR_LEN(s1) - offset), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len));
    5711             :         } else {
    5712           1 :                 RETURN_LONG(zend_binary_strncasecmp_l(ZSTR_VAL(s1) + offset, (ZSTR_LEN(s1) - offset), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len));
    5713             :         }
    5714             : }
    5715             : /* }}} */
    5716             : 
    5717             : /*
    5718             :  * Local variables:
    5719             :  * tab-width: 4
    5720             :  * c-basic-offset: 4
    5721             :  * End:
    5722             :  * vim600: noet sw=4 ts=4 fdm=marker
    5723             :  * vim<600: noet sw=4 ts=4
    5724             :  */

Generated by: LCOV version 1.10

Generated at Wed, 02 Sep 2015 17:19:20 +0000 (43 hours ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.