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: 2462 2576 95.6 %
Date: 2016-06-25 Functions: 111 114 97.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1997-2016 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       22587 : void register_string_constants(INIT_FUNC_ARGS)
      83             : {
      84       22587 :         REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
      85       22587 :         REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
      86       22587 :         REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
      87       22587 :         REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
      88       22587 :         REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
      89       22587 :         REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
      90       22587 :         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       22587 :         REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
     101             : #endif
     102             : 
     103             : #ifdef HAVE_LOCALE_H
     104       22587 :         REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT);
     105       22587 :         REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT);
     106       22587 :         REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT);
     107       22587 :         REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT);
     108       22587 :         REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT);
     109       22587 :         REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT);
     110             : # ifdef LC_MESSAGES
     111       22587 :         REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
     112             : # endif
     113             : #endif
     114             : 
     115       22587 : }
     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       22532 : 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       22532 :         result = zend_string_safe_alloc(oldlen, 2 * sizeof(char), 0, 0);
     144             : 
     145      140499 :         for (i = j = 0; i < oldlen; i++) {
     146      117967 :                 ZSTR_VAL(result)[j++] = hexconvtab[old[i] >> 4];
     147      117967 :                 ZSTR_VAL(result)[j++] = hexconvtab[old[i] & 15];
     148             :         }
     149       22532 :         ZSTR_VAL(result)[j] = '\0';
     150             : 
     151       22532 :         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       22538 : PHP_FUNCTION(bin2hex)
     256             : {
     257             :         zend_string *result;
     258             :         zend_string *data;
     259             : 
     260       22538 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &data) == FAILURE) {
     261           6 :                 return;
     262             :         }
     263             : 
     264       22532 :         result = php_bin2hex((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data));
     265             : 
     266       22532 :         if (!result) {
     267           0 :                 RETURN_FALSE;
     268             :         }
     269             : 
     270       22532 :         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       22587 : 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       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
     378       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
     379       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
     380       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
     381       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
     382       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
     383       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
     384             : #endif
     385             : #ifdef DAY_1
     386       22587 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
     387       22587 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
     388       22587 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
     389       22587 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
     390       22587 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
     391       22587 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
     392       22587 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
     393             : #endif
     394             : #ifdef ABMON_1
     395       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
     396       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
     397       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
     398       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
     399       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
     400       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
     401       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
     402       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
     403       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
     404       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
     405       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
     406       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
     407             : #endif
     408             : #ifdef MON_1
     409       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_1);
     410       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_2);
     411       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_3);
     412       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_4);
     413       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_5);
     414       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_6);
     415       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_7);
     416       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_8);
     417       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_9);
     418       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_10);
     419       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_11);
     420       22587 :         REGISTER_NL_LANGINFO_CONSTANT(MON_12);
     421             : #endif
     422             : #ifdef AM_STR
     423       22587 :         REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
     424             : #endif
     425             : #ifdef PM_STR
     426       22587 :         REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
     427             : #endif
     428             : #ifdef D_T_FMT
     429       22587 :         REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
     430             : #endif
     431             : #ifdef D_FMT
     432       22587 :         REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
     433             : #endif
     434             : #ifdef T_FMT
     435       22587 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
     436             : #endif
     437             : #ifdef T_FMT_AMPM
     438       22587 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
     439             : #endif
     440             : #ifdef ERA
     441       22587 :         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       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
     448             : #endif
     449             : #ifdef ERA_D_FMT
     450       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
     451             : #endif
     452             : #ifdef ERA_T_FMT
     453       22587 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
     454             : #endif
     455             : #ifdef ALT_DIGITS
     456       22587 :         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       22587 :         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       22587 :         REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
     511             : #endif
     512             : #ifdef THOUSANDS_SEP
     513             :         REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
     514             : #endif
     515             : #ifdef THOUSEP
     516       22587 :         REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
     517             : #endif
     518             : #ifdef GROUPING
     519             :         REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
     520             : #endif
     521             : #ifdef YESEXPR
     522       22587 :         REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
     523             : #endif
     524             : #ifdef NOEXPR
     525       22587 :         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       22587 :         REGISTER_NL_LANGINFO_CONSTANT(CODESET);
     535             : #endif
     536             : #undef REGISTER_NL_LANGINFO_CONSTANT
     537       22587 :         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        2199 : static inline int php_charmask(unsigned char *input, size_t len, char *mask)
     751             : {
     752             :         unsigned char *end;
     753             :         unsigned char c;
     754        2199 :         int result = SUCCESS;
     755             : 
     756        2199 :         memset(mask, 0, 256);
     757        7455 :         for (end = input+len; input < end; input++) {
     758        5256 :                 c=*input;
     759        5314 :                 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        5230 :                 } 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        5215 :                         mask[c]=1;
     787             :                 }
     788             :         }
     789        2199 :         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     1052192 : PHPAPI zend_string *php_trim(zend_string *str, char *what, size_t what_len, int mode)
     800             : {
     801     1052192 :         const char *c = ZSTR_VAL(str);
     802     1052192 :         size_t len = ZSTR_LEN(str);
     803             :         register size_t i;
     804     1052192 :         size_t trimmed = 0;
     805             :         char mask[256];
     806             : 
     807     1052192 :         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     1051950 :                 if (mode & 1) {
     862     1059694 :                         for (i = 0; i < len; i++) {
     863      925674 :                                 if ((unsigned char)c[i] <= ' ' &&
     864       12116 :                                     (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v' || c[i] == '\0')) {
     865        7941 :                                         trimmed++;
     866             :                                 } else {
     867             :                                         break;
     868             :                                 }
     869             :                         }
     870     1051753 :                         len -= trimmed;
     871     1051753 :                         c += trimmed;
     872             :                 }
     873     1051950 :                 if (mode & 2) {
     874     1031048 :                         if (len > 0) {
     875      904688 :                                 i = len - 1;
     876             :                                 do {
     877     1067147 :                                         if ((unsigned char)c[i] <= ' ' &&
     878      107947 :                                             (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v' || c[i] == '\0')) {
     879       54515 :                                                 len--;
     880             :                                         } else {
     881             :                                                 break;
     882             :                                         }
     883       54515 :                                 } while (i-- != 0);
     884             :                         }
     885             :                 }
     886             :         }
     887             : 
     888     1052192 :         if (ZSTR_LEN(str) == len) {
     889      999314 :                 return zend_string_copy(str);
     890             :         } else {
     891       52878 :                 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     1029613 : static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
     900             : {
     901             :         zend_string *str;
     902     1029613 :         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     1029613 :         ZEND_PARSE_PARAMETERS_START(1, 2)
     910     3088794 :                 Z_PARAM_STR(str)
     911     1029574 :                 Z_PARAM_OPTIONAL
     912     1030094 :                 Z_PARAM_STR(what)
     913     1029613 :         ZEND_PARSE_PARAMETERS_END();
     914             : #endif
     915             : 
     916     1029556 :         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     1008308 : PHP_FUNCTION(trim)
     923             : {
     924     1008308 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
     925     1008308 : }
     926             : /* }}} */
     927             : 
     928             : /* {{{ proto string rtrim(string str [, string character_mask])
     929             :    Removes trailing whitespace */
     930         337 : PHP_FUNCTION(rtrim)
     931             : {
     932         337 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
     933         337 : }
     934             : /* }}} */
     935             : 
     936             : /* {{{ proto string ltrim(string str [, string character_mask])
     937             :    Strips whitespace from the beginning of a string */
     938       20968 : PHP_FUNCTION(ltrim)
     939             : {
     940       20968 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     941       20968 : }
     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_safe_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_safe_alloc(ZSTR_LEN(text), breakchar_len + 1, 0, 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      578118 : PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
    1087             : {
    1088      578118 :         char *p1 = ZSTR_VAL(str);
    1089      578118 :         char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
    1090     1156236 :         char *p2 = (char *) php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
    1091             :         zval  tmp;
    1092             : 
    1093      578118 :         if (p2 == NULL) {
    1094         153 :                 ZVAL_STR_COPY(&tmp, str);
    1095         153 :                 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1096             :         } else {
    1097             :                 do {
    1098     1175204 :                         ZVAL_STRINGL(&tmp, p1, p2 - p1);
    1099      587602 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1100      587602 :                         p1 = p2 + ZSTR_LEN(delim);
    1101     1175204 :                         p2 = (char *) php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
    1102      587602 :                 } while (p2 != NULL && --limit > 1);
    1103             : 
    1104      577965 :                 if (p1 <= endp) {
    1105     1155930 :                         ZVAL_STRINGL(&tmp, p1, endp - p1);
    1106      577965 :                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
    1107             :                 }
    1108             :         }
    1109      578118 : }
    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      578234 : PHP_FUNCTION(explode)
    1157             : {
    1158             :         zend_string *str, *delim;
    1159      578234 :         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      578234 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1168     1734687 :                 Z_PARAM_STR(delim)
    1169     1734660 :                 Z_PARAM_STR(str)
    1170      578216 :                 Z_PARAM_OPTIONAL
    1171     1532482 :                 Z_PARAM_LONG(limit)
    1172      578234 :         ZEND_PARSE_PARAMETERS_END();
    1173             : #endif
    1174             : 
    1175      578211 :         if (ZSTR_LEN(delim) == 0) {
    1176          28 :                 php_error_docref(NULL, E_WARNING, "Empty delimiter");
    1177          28 :                 RETURN_FALSE;
    1178             :         }
    1179             : 
    1180      578183 :         array_init(return_value);
    1181             : 
    1182      578183 :         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      578171 :         if (limit > 1) {
    1191      578118 :                 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       91003 : 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       91003 :         size_t        len = 0;
    1214             :         zend_string **strings, **strptr;
    1215             : 
    1216       91003 :         numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
    1217             : 
    1218       91003 :         if (numelems == 0) {
    1219          35 :                 RETURN_EMPTY_STRING();
    1220       90968 :         } else if (numelems == 1) {
    1221             :                 /* loop to search the first not undefined element... */
    1222        1209 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
    1223         806 :                         RETURN_STR(zval_get_string(tmp));
    1224             :                 } ZEND_HASH_FOREACH_END();
    1225             :         }
    1226             : 
    1227       90565 :         strings = emalloc((sizeof(zend_long) + sizeof(zend_string *)) * numelems);
    1228       90565 :         strptr = strings - 1;
    1229             : 
    1230      819809 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(arr), tmp) {
    1231      364600 :                 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        7746 :                         *++strptr = zval_get_string(tmp);
    1245        3873 :                         len += ZSTR_LEN(*strptr);
    1246             :                 }
    1247             :         } ZEND_HASH_FOREACH_END();
    1248             :         /* numelems can not be 0, we checked above */
    1249      181130 :         str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(delim), len, 0);
    1250       90565 :         cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
    1251       90565 :         *cptr = 0;
    1252             : 
    1253             :         do {
    1254      274035 :                 if (*strptr) {
    1255        3362 :                         cptr -= ZSTR_LEN(*strptr);
    1256        3362 :                         memcpy(cptr, ZSTR_VAL(*strptr), ZSTR_LEN(*strptr));
    1257        3362 :                         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      274035 :                 cptr -= ZSTR_LEN(delim);
    1267      274035 :                 memcpy(cptr, ZSTR_VAL(delim), ZSTR_LEN(delim));
    1268      274035 :         } while (--strptr > strings);
    1269             : 
    1270       90565 :         if (*strptr) {
    1271         511 :                 memcpy(ZSTR_VAL(str), ZSTR_VAL(*strptr), ZSTR_LEN(*strptr));
    1272         511 :                 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       90565 :         efree(strings);
    1281       90565 :         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       91038 : PHP_FUNCTION(implode)
    1288             : {
    1289       91038 :         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       91038 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    1298       91034 :                 Z_PARAM_ZVAL(arg1)
    1299       91034 :                 Z_PARAM_OPTIONAL
    1300       91034 :                 Z_PARAM_ZVAL(arg2)
    1301       91038 :         ZEND_PARSE_PARAMETERS_END();
    1302             : #endif
    1303             : 
    1304       91034 :         if (arg2 == NULL) {
    1305          20 :                 if (Z_TYPE_P(arg1) != IS_ARRAY) {
    1306           4 :                         php_error_docref(NULL, E_WARNING, "Argument must be an array");
    1307           4 :                         return;
    1308             :                 }
    1309             : 
    1310           6 :                 delim = ZSTR_EMPTY_ALLOC();
    1311           6 :                 arr = arg1;
    1312             :         } else {
    1313      182048 :                 if (Z_TYPE_P(arg1) == IS_ARRAY) {
    1314          74 :                         delim = zval_get_string(arg2);
    1315          37 :                         arr = arg1;
    1316      181974 :                 } else if (Z_TYPE_P(arg2) == IS_ARRAY) {
    1317      181920 :                         delim = zval_get_string(arg1);
    1318       90960 :                         arr = arg2;
    1319             :                 } else {
    1320          27 :                         php_error_docref(NULL, E_WARNING, "Invalid arguments passed");
    1321          27 :                         return;
    1322             :                 }
    1323             :         }
    1324             : 
    1325       91003 :         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        1139 : PHPAPI zend_string *php_string_toupper(zend_string *s)
    1435             : {
    1436             :         unsigned char *c, *e;
    1437             : 
    1438        1139 :         c = (unsigned char *)ZSTR_VAL(s);
    1439        1139 :         e = c + ZSTR_LEN(s);
    1440             : 
    1441        5233 :         while (c < e) {
    1442        3806 :                 if (islower(*c)) {
    1443             :                         register unsigned char *r;
    1444        1702 :                         zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
    1445             : 
    1446         851 :                         if (c != (unsigned char*)ZSTR_VAL(s)) {
    1447          87 :                                 memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
    1448             :                         }
    1449         851 :                         r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
    1450        7726 :                         while (c < e) {
    1451        6024 :                                 *r = toupper(*c);
    1452        6024 :                                 r++;
    1453        6024 :                                 c++;
    1454             :                         }
    1455         851 :                         *r = '\0';
    1456         851 :                         return res;
    1457             :                 }
    1458        2955 :                 c++;
    1459             :         }
    1460         288 :         return zend_string_copy(s);
    1461             : }
    1462             : /* }}} */
    1463             : 
    1464             : /* {{{ proto string strtoupper(string str)
    1465             :    Makes a string uppercase */
    1466         976 : 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         976 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1476        2922 :                 Z_PARAM_STR(arg)
    1477         976 :         ZEND_PARSE_PARAMETERS_END();
    1478             : #endif
    1479             : 
    1480         973 :         RETURN_STR(php_string_toupper(arg));
    1481             : }
    1482             : /* }}} */
    1483             : 
    1484             : /* {{{ php_strtolower
    1485             :  */
    1486      239935 : PHPAPI char *php_strtolower(char *s, size_t len)
    1487             : {
    1488             :         unsigned char *c, *e;
    1489             : 
    1490      239935 :         c = (unsigned char *)s;
    1491      239935 :         e = c+len;
    1492             : 
    1493     6108050 :         while (c < e) {
    1494     5628180 :                 *c = tolower(*c);
    1495     5628180 :                 c++;
    1496             :         }
    1497      239935 :         return s;
    1498             : }
    1499             : /* }}} */
    1500             : 
    1501             : /* {{{ php_string_tolower
    1502             :  */
    1503        2034 : PHPAPI zend_string *php_string_tolower(zend_string *s)
    1504             : {
    1505             :         unsigned char *c, *e;
    1506             : 
    1507        2034 :         c = (unsigned char *)ZSTR_VAL(s);
    1508        2034 :         e = c + ZSTR_LEN(s);
    1509             : 
    1510        8605 :         while (c < e) {
    1511        5818 :                 if (isupper(*c)) {
    1512             :                         register unsigned char *r;
    1513        2562 :                         zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
    1514             : 
    1515        1281 :                         if (c != (unsigned char*)ZSTR_VAL(s)) {
    1516         404 :                                 memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
    1517             :                         }
    1518        1281 :                         r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
    1519      105197 :                         while (c < e) {
    1520      102635 :                                 *r = tolower(*c);
    1521      102635 :                                 r++;
    1522      102635 :                                 c++;
    1523             :                         }
    1524        1281 :                         *r = '\0';
    1525        1281 :                         return res;
    1526             :                 }
    1527        4537 :                 c++;
    1528             :         }
    1529         753 :         return zend_string_copy(s);
    1530             : }
    1531             : /* }}} */
    1532             : 
    1533             : /* {{{ proto string strtolower(string str)
    1534             :    Makes a string lowercase */
    1535         368 : 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         368 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    1545        1098 :                 Z_PARAM_STR(str)
    1546         368 :         ZEND_PARSE_PARAMETERS_END();
    1547             : #endif
    1548             : 
    1549         365 :         RETURN_STR(php_string_tolower(str));
    1550             : }
    1551             : /* }}} */
    1552             : 
    1553             : /* {{{ php_basename
    1554             :  */
    1555       16984 : 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       16984 :         c = comp = cend = (char*)s;
    1563       16984 :         cnt = len;
    1564       16984 :         state = 0;
    1565     1021185 :         while (cnt > 0) {
    1566      987217 :                 inc_len = (*c == '\0' ? 1 : php_mblen(c, cnt));
    1567             : 
    1568      987217 :                 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      987216 :                                 if (*c == '/') {
    1581             : #endif
    1582      112191 :                                         if (state == 1) {
    1583       96476 :                                                 state = 0;
    1584       96476 :                                                 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      875025 :                                         if (state == 0) {
    1601      113223 :                                                 comp = c;
    1602      113223 :                                                 state = 1;
    1603             :                                         }
    1604             :                                 }
    1605      987216 :                                 break;
    1606             :                         default:
    1607           0 :                                 if (state == 0) {
    1608           0 :                                         comp = c;
    1609           0 :                                         state = 1;
    1610             :                                 }
    1611             :                                 break;
    1612             :                 }
    1613      987217 :                 c += inc_len;
    1614      987217 :                 cnt -= inc_len;
    1615             :         }
    1616             : 
    1617             : quit_loop:
    1618       16984 :         if (state == 1) {
    1619       16747 :                 cend = c;
    1620             :         }
    1621       32425 :         if (suffix != NULL && sufflen < (size_t)(cend - comp) &&
    1622       15441 :                         memcmp(cend - sufflen, suffix, sufflen) == 0) {
    1623       15356 :                 cend -= sufflen;
    1624             :         }
    1625             : 
    1626       16984 :         len = cend - comp;
    1627             : 
    1628       16984 :         ret = zend_string_init(comp, len, 0);
    1629       16984 :         return ret;
    1630             : }
    1631             : /* }}} */
    1632             : 
    1633             : /* {{{ proto string basename(string path [, string suffix])
    1634             :    Returns the filename component of the path */
    1635       15795 : PHP_FUNCTION(basename)
    1636             : {
    1637       15795 :         char *string, *suffix = NULL;
    1638       15795 :         size_t   string_len, suffix_len = 0;
    1639             : 
    1640       15795 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s", &string, &string_len, &suffix, &suffix_len) == FAILURE) {
    1641          30 :                 return;
    1642             :         }
    1643             : 
    1644       15765 :         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       26800 : PHP_FUNCTION(dirname)
    1659             : {
    1660             :         char *str;
    1661             :         size_t str_len;
    1662             :         zend_string *ret;
    1663       26800 :         zend_long levels = 1;
    1664             : 
    1665       26800 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &levels) == FAILURE) {
    1666           9 :                 return;
    1667             :         }
    1668             : 
    1669       53582 :         ret = zend_string_init(str, str_len, 0);
    1670             : 
    1671       26791 :         if (levels == 1) {
    1672             :                 /* Defaut case */
    1673       26785 :                 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       26789 :         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        6397 : PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
    1775             : {
    1776        6397 :         php_strtolower(s, s_len);
    1777        6397 :         php_strtolower(t, t_len);
    1778       12794 :         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        6331 : PHP_FUNCTION(stristr)
    1851             : {
    1852             :         zval *needle;
    1853             :         zend_string *haystack;
    1854        6331 :         char *found = NULL;
    1855             :         size_t  found_offset;
    1856             :         char *haystack_dup;
    1857             :         char needle_char[2];
    1858        6331 :         zend_bool part = 0;
    1859             : 
    1860        6331 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|b", &haystack, &needle, &part) == FAILURE) {
    1861          11 :                 return;
    1862             :         }
    1863             : 
    1864        6320 :         haystack_dup = estrndup(ZSTR_VAL(haystack), ZSTR_LEN(haystack));
    1865             : 
    1866       12640 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1867             :                 char *orig_needle;
    1868        6297 :                 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        6293 :                 orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
    1874        6293 :                 found = php_stristr(haystack_dup, orig_needle, ZSTR_LEN(haystack), Z_STRLEN_P(needle));
    1875        6293 :                 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        6311 :         if (found) {
    1887        1317 :                 found_offset = found - haystack_dup;
    1888        1317 :                 if (part) {
    1889           8 :                         RETVAL_STRINGL(ZSTR_VAL(haystack), found_offset);
    1890             :                 } else {
    1891        2626 :                         RETVAL_STRINGL(ZSTR_VAL(haystack) + found_offset, ZSTR_LEN(haystack) - found_offset);
    1892             :                 }
    1893             :         } else {
    1894        4994 :                 RETVAL_FALSE;
    1895             :         }
    1896             : 
    1897        6311 :         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        8547 : PHP_FUNCTION(strstr)
    1904             : {
    1905             :         zval *needle;
    1906             :         zend_string *haystack;
    1907        8547 :         char *found = NULL;
    1908             :         char needle_char[2];
    1909             :         zend_long found_offset;
    1910        8547 :         zend_bool part = 0;
    1911             : 
    1912        8547 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|b", &haystack, &needle, &part) == FAILURE) {
    1913           6 :                 return;
    1914             :         }
    1915             : 
    1916       17082 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1917        8529 :                 if (!Z_STRLEN_P(needle)) {
    1918           5 :                         php_error_docref(NULL, E_WARNING, "Empty needle");
    1919           5 :                         RETURN_FALSE;
    1920             :                 }
    1921             : 
    1922       17048 :                 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        8536 :         if (found) {
    1933        3069 :                 found_offset = found - ZSTR_VAL(haystack);
    1934        3069 :                 if (part) {
    1935          10 :                         RETURN_STRINGL(ZSTR_VAL(haystack), found_offset);
    1936             :                 } else {
    1937        6128 :                         RETURN_STRINGL(found, ZSTR_LEN(haystack) - found_offset);
    1938             :                 }
    1939             :         }
    1940        5467 :         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      920408 : PHP_FUNCTION(strpos)
    1951             : {
    1952             :         zval *needle;
    1953             :         zend_string *haystack;
    1954      920408 :         char *found = NULL;
    1955             :         char  needle_char[2];
    1956      920408 :         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      920408 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1964     2761209 :                 Z_PARAM_STR(haystack)
    1965      920400 :                 Z_PARAM_ZVAL(needle)
    1966      920400 :                 Z_PARAM_OPTIONAL
    1967      938362 :                 Z_PARAM_LONG(offset)
    1968      920408 :         ZEND_PARSE_PARAMETERS_END();
    1969             : #endif
    1970             : 
    1971      920397 :         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     1840776 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1977      920375 :                 if (!Z_STRLEN_P(needle)) {
    1978           6 :                         php_error_docref(NULL, E_WARNING, "Empty needle");
    1979           6 :                         RETURN_FALSE;
    1980             :                 }
    1981             : 
    1982     4601845 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
    1983      920369 :                                         Z_STRVAL_P(needle),
    1984      920369 :                                         Z_STRLEN_P(needle),
    1985     1840738 :                                         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      920382 :         if (found) {
    1999      498412 :                 RETURN_LONG(found - ZSTR_VAL(haystack));
    2000             :         } else {
    2001      421970 :                 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         610 : PHP_FUNCTION(stripos)
    2009             : {
    2010         610 :         char *found = NULL;
    2011             :         zend_string *haystack;
    2012         610 :         zend_long offset = 0;
    2013             :         char needle_char[2];
    2014             :         zval *needle;
    2015         610 :         zend_string *needle_dup = NULL, *haystack_dup;
    2016             : 
    2017         610 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &haystack, &needle, &offset) == FAILURE) {
    2018          39 :                 return;
    2019             :         }
    2020             : 
    2021         571 :         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         549 :         if (ZSTR_LEN(haystack) == 0) {
    2027          30 :                 RETURN_FALSE;
    2028             :         }
    2029             : 
    2030        1038 :         if (Z_TYPE_P(needle) == IS_STRING) {
    2031         441 :                 if (Z_STRLEN_P(needle) == 0 || Z_STRLEN_P(needle) > ZSTR_LEN(haystack)) {
    2032          20 :                         RETURN_FALSE;
    2033             :                 }
    2034             : 
    2035         421 :                 haystack_dup = php_string_tolower(haystack);
    2036         421 :                 needle_dup = php_string_tolower(Z_STR_P(needle));
    2037        1263 :                 found = (char*)php_memnstr(ZSTR_VAL(haystack_dup) + offset,
    2038         421 :                                 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         493 :         if (found) {
    2054         322 :                 RETVAL_LONG(found - ZSTR_VAL(haystack_dup));
    2055             :         } else {
    2056         171 :                 RETVAL_FALSE;
    2057             :         }
    2058             : 
    2059             :         zend_string_release(haystack_dup);
    2060         493 :         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         465 : PHP_FUNCTION(strrpos)
    2069             : {
    2070             :         zval *zneedle;
    2071             :         char *needle;
    2072             :         zend_string *haystack;
    2073             :         size_t needle_len;
    2074         465 :         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         465 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    2084        1386 :                 Z_PARAM_STR(haystack)
    2085         444 :                 Z_PARAM_ZVAL(zneedle)
    2086         444 :                 Z_PARAM_OPTIONAL
    2087         776 :                 Z_PARAM_LONG(offset)
    2088         465 :         ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
    2089             : #endif
    2090             : 
    2091         888 :         if (Z_TYPE_P(zneedle) == IS_STRING) {
    2092         364 :                 needle = Z_STRVAL_P(zneedle);
    2093         364 :                 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         438 :         if ((ZSTR_LEN(haystack) == 0) || (needle_len == 0)) {
    2104          38 :                 RETURN_FALSE;
    2105             :         }
    2106             : 
    2107         400 :         if (offset >= 0) {
    2108         384 :                 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         382 :                 p = ZSTR_VAL(haystack) + (size_t)offset;
    2113         382 :                 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         395 :         if ((found = (char *)zend_memnrstr(p, needle, needle_len, e))) {
    2128         240 :                 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_safe_alloc(ZSTR_LEN(str), 1, endlen, 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      563610 : PHP_FUNCTION(substr)
    2371             : {
    2372             :         zend_string *str;
    2373      563610 :         zend_long l = 0, f;
    2374      563610 :         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      563610 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    2382     1690812 :                 Z_PARAM_STR(str)
    2383     1690812 :                 Z_PARAM_LONG(f)
    2384      563604 :                 Z_PARAM_OPTIONAL
    2385     1583512 :                 Z_PARAM_LONG(l)
    2386      563610 :         ZEND_PARSE_PARAMETERS_END();
    2387             : #endif
    2388             : 
    2389      563604 :         if (argc > 2) {
    2390      509954 :                 if ((l < 0 && (size_t)(-l) > ZSTR_LEN(str))) {
    2391           8 :                         RETURN_FALSE;
    2392      509946 :                 } else if (l > (zend_long)ZSTR_LEN(str)) {
    2393         700 :                         l = ZSTR_LEN(str);
    2394             :                 }
    2395             :         } else {
    2396       53650 :                 l = ZSTR_LEN(str);
    2397             :         }
    2398             : 
    2399      563596 :         if (f > (zend_long)ZSTR_LEN(str)) {
    2400          14 :                 RETURN_FALSE;
    2401      563582 :         } else if (f < 0 && -f > ZSTR_LEN(str)) {
    2402        2087 :                 f = 0;
    2403             :         }
    2404             : 
    2405      563582 :         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      563580 :         if (f < 0) {
    2413       50379 :                 f = (zend_long)ZSTR_LEN(str) + f;
    2414       50379 :                 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      563580 :         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      563580 :         if ((f + l) > (zend_long)ZSTR_LEN(str)) {
    2430       52029 :                 l = ZSTR_LEN(str) - f;
    2431             :         }
    2432             : 
    2433     1127160 :         RETURN_STRINGL(ZSTR_VAL(str) + f, l);
    2434             : }
    2435             : /* }}} */
    2436             : 
    2437             : /* {{{ proto mixed substr_replace(mixed str, mixed repl, mixed start [, mixed length])
    2438             :    Replaces part of a string with another string */
    2439          61 : PHP_FUNCTION(substr_replace)
    2440             : {
    2441             :         zval *str;
    2442             :         zval *from;
    2443          61 :         zval *len = NULL;
    2444             :         zval *repl;
    2445          61 :         zend_long l = 0;
    2446             :         zend_long f;
    2447          61 :         int argc = ZEND_NUM_ARGS();
    2448             :         zend_string *result;
    2449             :         HashPosition from_idx, repl_idx, len_idx;
    2450          61 :         zval *tmp_str = NULL, *tmp_from = NULL, *tmp_repl = NULL, *tmp_len= NULL;
    2451             : 
    2452          61 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz|z/", &str, &repl, &from, &len) == FAILURE) {
    2453           3 :                 return;
    2454             :         }
    2455             : 
    2456         116 :         if (Z_TYPE_P(str) != IS_ARRAY) {
    2457          26 :                 convert_to_string_ex(str);
    2458             :         }
    2459         116 :         if (Z_TYPE_P(repl) != IS_ARRAY) {
    2460          66 :                 convert_to_string_ex(repl);
    2461             :         }
    2462         116 :         if (Z_TYPE_P(from) != IS_ARRAY) {
    2463          44 :                 convert_to_long_ex(from);
    2464             :         }
    2465             : 
    2466          58 :         if (argc > 3) {
    2467          94 :                 if (Z_TYPE_P(len) != IS_ARRAY) {
    2468          56 :                         l = zval_get_long(len);
    2469             :                 }
    2470             :         } else {
    2471          22 :                 if (Z_TYPE_P(str) != IS_ARRAY) {
    2472           5 :                         l = Z_STRLEN_P(str);
    2473             :                 }
    2474             :         }
    2475             : 
    2476         116 :         if (Z_TYPE_P(str) == IS_STRING) {
    2477          26 :                 if (
    2478           5 :                         (argc == 3 && Z_TYPE_P(from) == IS_ARRAY) ||
    2479          16 :                         (argc == 4 && Z_TYPE_P(from) != Z_TYPE_P(len))
    2480             :                 ) {
    2481           2 :                         php_error_docref(NULL, E_WARNING, "'from' and 'len' should be of same type - numerical or array ");
    2482           2 :                         RETURN_STR_COPY(Z_STR_P(str));
    2483             :                 }
    2484          18 :                 if (argc == 4 && Z_TYPE_P(from) == IS_ARRAY) {
    2485           2 :                         if (zend_hash_num_elements(Z_ARRVAL_P(from)) != zend_hash_num_elements(Z_ARRVAL_P(len))) {
    2486           1 :                                 php_error_docref(NULL, E_WARNING, "'from' and 'len' should have the same number of elements");
    2487           1 :                                 RETURN_STR_COPY(Z_STR_P(str));
    2488             :                         }
    2489             :                 }
    2490             :         }
    2491             : 
    2492         110 :         if (Z_TYPE_P(str) != IS_ARRAY) {
    2493          20 :                 if (Z_TYPE_P(from) != IS_ARRAY) {
    2494             :                         zend_string *repl_str;
    2495           9 :                         zend_bool repl_release = 0;
    2496           9 :                         f = Z_LVAL_P(from);
    2497             : 
    2498             :                         /* if "from" position is negative, count start position from the end
    2499             :                          * of the string
    2500             :                          */
    2501           9 :                         if (f < 0) {
    2502           0 :                                 f = (zend_long)Z_STRLEN_P(str) + f;
    2503           0 :                                 if (f < 0) {
    2504           0 :                                         f = 0;
    2505             :                                 }
    2506           9 :                         } else if (f > Z_STRLEN_P(str)) {
    2507           1 :                                 f = Z_STRLEN_P(str);
    2508             :                         }
    2509             :                         /* if "length" position is negative, set it to the length
    2510             :                          * needed to stop that many chars from the end of the string
    2511             :                          */
    2512           9 :                         if (l < 0) {
    2513           1 :                                 l = ((zend_long)Z_STRLEN_P(str) - f) + l;
    2514           1 :                                 if (l < 0) {
    2515           0 :                                         l = 0;
    2516             :                                 }
    2517             :                         }
    2518             : 
    2519           9 :                         if (l > Z_STRLEN_P(str) || (l < 0 && (size_t)(-l) > Z_STRLEN_P(str))) {
    2520           1 :                                 l = Z_STRLEN_P(str);
    2521             :                         }
    2522             : 
    2523           9 :                         if ((f + l) > (zend_long)Z_STRLEN_P(str)) {
    2524           5 :                                 l = Z_STRLEN_P(str) - f;
    2525             :                         }
    2526          18 :                         if (Z_TYPE_P(repl) == IS_ARRAY) {
    2527           3 :                                 repl_idx = 0;
    2528           6 :                                 while (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2529           3 :                                         tmp_repl = &Z_ARRVAL_P(repl)->arData[repl_idx].val;
    2530           3 :                                         if (Z_TYPE_P(tmp_repl) != IS_UNDEF) {
    2531           3 :                                                 break;
    2532             :                                         }
    2533           0 :                                         repl_idx++;
    2534             :                                 }
    2535           3 :                                 if (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2536           3 :                                         repl_str = zval_get_string(tmp_repl);
    2537           3 :                                         repl_release = 1;
    2538             :                                 } else {
    2539           0 :                                         repl_str = STR_EMPTY_ALLOC();
    2540             :                                 }
    2541             :                         } else {
    2542           6 :                                 repl_str = Z_STR_P(repl);
    2543             :                         }
    2544             : 
    2545          18 :                         result = zend_string_alloc(Z_STRLEN_P(str) - l + ZSTR_LEN(repl_str), 0);
    2546             : 
    2547           9 :                         memcpy(ZSTR_VAL(result), Z_STRVAL_P(str), f);
    2548           9 :                         if (ZSTR_LEN(repl_str)) {
    2549           9 :                                 memcpy((ZSTR_VAL(result) + f), ZSTR_VAL(repl_str), ZSTR_LEN(repl_str));
    2550             :                         }
    2551           9 :                         memcpy((ZSTR_VAL(result) + f + ZSTR_LEN(repl_str)), Z_STRVAL_P(str) + f + l, Z_STRLEN_P(str) - f - l);
    2552           9 :                         ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
    2553           9 :                         if (repl_release) {
    2554             :                                 zend_string_release(repl_str);
    2555             :                         }
    2556           9 :                         RETURN_NEW_STR(result);
    2557             :                 } else {
    2558           1 :                         php_error_docref(NULL, E_WARNING, "Functionality of 'from' and 'len' as arrays is not implemented");
    2559           1 :                         RETURN_STR_COPY(Z_STR_P(str));
    2560             :                 }
    2561             :         } else { /* str is array of strings */
    2562          45 :                 zend_string *str_index = NULL;
    2563             :                 size_t result_len;
    2564             :                 zend_ulong num_index;
    2565             : 
    2566          45 :                 array_init(return_value);
    2567             : 
    2568          45 :                 from_idx = len_idx = repl_idx = 0;
    2569             : 
    2570         203 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(str), num_index, str_index, tmp_str) {
    2571          79 :                         zend_string *orig_str = zval_get_string(tmp_str);
    2572             : 
    2573         158 :                         if (Z_TYPE_P(from) == IS_ARRAY) {
    2574         114 :                                 while (from_idx < Z_ARRVAL_P(from)->nNumUsed) {
    2575          51 :                                         tmp_from = &Z_ARRVAL_P(from)->arData[from_idx].val;
    2576          51 :                                         if (Z_TYPE_P(tmp_from) != IS_UNDEF) {
    2577          51 :                                                 break;
    2578             :                                         }
    2579           0 :                                         from_idx++;
    2580             :                                 }
    2581          57 :                                 if (from_idx < Z_ARRVAL_P(from)->nNumUsed) {
    2582          51 :                                         f = zval_get_long(tmp_from);
    2583             : 
    2584          51 :                                         if (f < 0) {
    2585           0 :                                                 f = (zend_long)ZSTR_LEN(orig_str) + f;
    2586           0 :                                                 if (f < 0) {
    2587           0 :                                                         f = 0;
    2588             :                                                 }
    2589          51 :                                         } else if (f > (zend_long)ZSTR_LEN(orig_str)) {
    2590           0 :                                                 f = ZSTR_LEN(orig_str);
    2591             :                                         }
    2592          51 :                                         from_idx++;
    2593             :                                 } else {
    2594           6 :                                         f = 0;
    2595             :                                 }
    2596             :                         } else {
    2597          22 :                                 f = Z_LVAL_P(from);
    2598          22 :                                 if (f < 0) {
    2599           0 :                                         f = (zend_long)ZSTR_LEN(orig_str) + f;
    2600           0 :                                         if (f < 0) {
    2601           0 :                                                 f = 0;
    2602             :                                         }
    2603          22 :                                 } else if (f > (zend_long)ZSTR_LEN(orig_str)) {
    2604           0 :                                         f = ZSTR_LEN(orig_str);
    2605             :                                 }
    2606             :                         }
    2607             : 
    2608         181 :                         if (argc > 3 && Z_TYPE_P(len) == IS_ARRAY) {
    2609          58 :                                 while (len_idx < Z_ARRVAL_P(len)->nNumUsed) {
    2610          23 :                                         tmp_len = &Z_ARRVAL_P(len)->arData[len_idx].val;
    2611          23 :                                         if (Z_TYPE_P(tmp_len) != IS_UNDEF) {
    2612          23 :                                                 break;
    2613             :                                         }
    2614           0 :                                         len_idx++;
    2615             :                                 }
    2616          29 :                                 if (len_idx < Z_ARRVAL_P(len)->nNumUsed) {
    2617          23 :                                         l = zval_get_long(tmp_len);
    2618          23 :                                         len_idx++;
    2619             :                                 } else {
    2620           6 :                                         l = ZSTR_LEN(orig_str);
    2621             :                                 }
    2622          50 :                         } else if (argc > 3) {
    2623          44 :                                 l = Z_LVAL_P(len);
    2624             :                         } else {
    2625           6 :                                 l = ZSTR_LEN(orig_str);
    2626             :                         }
    2627             : 
    2628          79 :                         if (l < 0) {
    2629          23 :                                 l = (ZSTR_LEN(orig_str) - f) + l;
    2630          23 :                                 if (l < 0) {
    2631           0 :                                         l = 0;
    2632             :                                 }
    2633             :                         }
    2634             : 
    2635          79 :                         if ((f + l) > (zend_long)ZSTR_LEN(orig_str)) {
    2636          14 :                                 l = ZSTR_LEN(orig_str) - f;
    2637             :                         }
    2638             : 
    2639          79 :                         result_len = ZSTR_LEN(orig_str) - l;
    2640             : 
    2641         158 :                         if (Z_TYPE_P(repl) == IS_ARRAY) {
    2642          76 :                                 while (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2643          23 :                                         tmp_repl = &Z_ARRVAL_P(repl)->arData[repl_idx].val;
    2644          23 :                                         if (Z_TYPE_P(tmp_repl) != IS_UNDEF) {
    2645          23 :                                                 break;
    2646             :                                         }
    2647           0 :                                         repl_idx++;
    2648             :                                 }
    2649          38 :                                 if (repl_idx < Z_ARRVAL_P(repl)->nNumUsed) {
    2650          23 :                                         zend_string *repl_str = zval_get_string(tmp_repl);
    2651             : 
    2652          23 :                                         result_len += ZSTR_LEN(repl_str);
    2653          23 :                                         repl_idx++;
    2654          23 :                                         result = zend_string_alloc(result_len, 0);
    2655             : 
    2656          23 :                                         memcpy(ZSTR_VAL(result), ZSTR_VAL(orig_str), f);
    2657          23 :                                         memcpy((ZSTR_VAL(result) + f), ZSTR_VAL(repl_str), ZSTR_LEN(repl_str));
    2658          23 :                                         memcpy((ZSTR_VAL(result) + f + ZSTR_LEN(repl_str)), ZSTR_VAL(orig_str) + f + l, ZSTR_LEN(orig_str) - f - l);
    2659             :                                         zend_string_release(repl_str);
    2660             :                                 } else {
    2661          15 :                                         result = zend_string_alloc(result_len, 0);
    2662             : 
    2663          15 :                                         memcpy(ZSTR_VAL(result), ZSTR_VAL(orig_str), f);
    2664          15 :                                         memcpy((ZSTR_VAL(result) + f), ZSTR_VAL(orig_str) + f + l, ZSTR_LEN(orig_str) - f - l);
    2665             :                                 }
    2666             :                         } else {
    2667          41 :                                 result_len += Z_STRLEN_P(repl);
    2668             : 
    2669          41 :                                 result = zend_string_alloc(result_len, 0);
    2670             : 
    2671          41 :                                 memcpy(ZSTR_VAL(result), ZSTR_VAL(orig_str), f);
    2672          41 :                                 memcpy((ZSTR_VAL(result) + f), Z_STRVAL_P(repl), Z_STRLEN_P(repl));
    2673          41 :                                 memcpy((ZSTR_VAL(result) + f + Z_STRLEN_P(repl)), ZSTR_VAL(orig_str) + f + l, ZSTR_LEN(orig_str) - f - l);
    2674             :                         }
    2675             : 
    2676          79 :                         ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
    2677             : 
    2678          79 :                         if (str_index) {
    2679             :                                 zval tmp;
    2680             : 
    2681           2 :                                 ZVAL_NEW_STR(&tmp, result);
    2682           2 :                                 zend_symtable_update(Z_ARRVAL_P(return_value), str_index, &tmp);
    2683             :                         } else {
    2684          77 :                                 add_index_str(return_value, num_index, result);
    2685             :                         }
    2686             : 
    2687             :                         zend_string_release(orig_str);
    2688             :                 } ZEND_HASH_FOREACH_END();
    2689             :         } /* if */
    2690             : }
    2691             : /* }}} */
    2692             : 
    2693             : /* {{{ proto string quotemeta(string str)
    2694             :    Quotes meta characters */
    2695           6 : PHP_FUNCTION(quotemeta)
    2696             : {
    2697             :         zend_string *old;
    2698             :         char *old_end;
    2699             :         char *p, *q;
    2700             :         char c;
    2701             :         zend_string *str;
    2702             : 
    2703           6 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &old) == FAILURE) {
    2704           2 :                 return;
    2705             :         }
    2706             : 
    2707           4 :         old_end = ZSTR_VAL(old) + ZSTR_LEN(old);
    2708             : 
    2709           4 :         if (ZSTR_VAL(old) == old_end) {
    2710           0 :                 RETURN_FALSE;
    2711             :         }
    2712             : 
    2713           8 :         str = zend_string_safe_alloc(2, ZSTR_LEN(old), 0, 0);
    2714             : 
    2715          60 :         for (p = ZSTR_VAL(old), q = ZSTR_VAL(str); p != old_end; p++) {
    2716          56 :                 c = *p;
    2717          56 :                 switch (c) {
    2718             :                         case '.':
    2719             :                         case '\\':
    2720             :                         case '+':
    2721             :                         case '*':
    2722             :                         case '?':
    2723             :                         case '[':
    2724             :                         case '^':
    2725             :                         case ']':
    2726             :                         case '$':
    2727             :                         case '(':
    2728             :                         case ')':
    2729          24 :                                 *q++ = '\\';
    2730             :                                 /* break is missing _intentionally_ */
    2731             :                         default:
    2732          56 :                                 *q++ = c;
    2733             :                 }
    2734             :         }
    2735             : 
    2736           4 :         *q = '\0';
    2737             : 
    2738           8 :         RETURN_NEW_STR(zend_string_truncate(str, q - ZSTR_VAL(str), 0));
    2739             : }
    2740             : /* }}} */
    2741             : 
    2742             : /* {{{ proto int ord(string character)
    2743             :    Returns ASCII value of character */
    2744       71506 : PHP_FUNCTION(ord)
    2745             : {
    2746             :         char   *str;
    2747             :         size_t str_len;
    2748             : 
    2749             : #ifndef FAST_ZPP
    2750             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) == FAILURE) {
    2751             :                 return;
    2752             :         }
    2753             : #else
    2754       71506 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2755      214506 :                 Z_PARAM_STRING(str, str_len)
    2756       71506 :         ZEND_PARSE_PARAMETERS_END();
    2757             : #endif
    2758             : 
    2759       71497 :         RETURN_LONG((unsigned char) str[0]);
    2760             : }
    2761             : /* }}} */
    2762             : 
    2763             : /* {{{ proto string chr(int ascii)
    2764             :    Converts ASCII code to a character */
    2765      661617 : PHP_FUNCTION(chr)
    2766             : {
    2767             :         zend_long c;
    2768             : 
    2769      661617 :         if (ZEND_NUM_ARGS() != 1) {
    2770           4 :                 WRONG_PARAM_COUNT;
    2771             :         }
    2772             : 
    2773             : #ifndef FAST_ZPP
    2774             :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "l", &c) == FAILURE) {
    2775             :                 c = 0;
    2776             :         }
    2777             : #else
    2778      661613 :         ZEND_PARSE_PARAMETERS_START_EX(ZEND_PARSE_PARAMS_QUIET, 1, 1)
    2779     1984839 :                 Z_PARAM_LONG(c)
    2780      661613 :         ZEND_PARSE_PARAMETERS_END_EX(c = 0);
    2781             : #endif
    2782             : 
    2783      661613 :         c &= 0xff;
    2784      661613 :         if (CG(one_char_string)[c]) {
    2785           0 :                 ZVAL_INTERNED_STR(return_value, CG(one_char_string)[c]);
    2786             :         } else {
    2787     1323226 :                 ZVAL_NEW_STR(return_value, zend_string_alloc(1, 0));
    2788      661613 :                 Z_STRVAL_P(return_value)[0] = (char)c;
    2789      661613 :                 Z_STRVAL_P(return_value)[1] = '\0';
    2790             :         }
    2791             : }
    2792             : /* }}} */
    2793             : 
    2794             : /* {{{ php_ucfirst
    2795             :    Uppercase the first character of the word in a native string */
    2796          59 : static void php_ucfirst(char *str)
    2797             : {
    2798             :         register char *r;
    2799          59 :         r = str;
    2800          59 :         *r = toupper((unsigned char) *r);
    2801          59 : }
    2802             : /* }}} */
    2803             : 
    2804             : /* {{{ proto string ucfirst(string str)
    2805             :    Makes a string's first character uppercase */
    2806          67 : PHP_FUNCTION(ucfirst)
    2807             : {
    2808             :         zend_string *str;
    2809             : 
    2810             : #ifndef FAST_ZPP
    2811             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    2812             :                 return;
    2813             :         }
    2814             : #else
    2815          67 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    2816         192 :                 Z_PARAM_STR(str)
    2817          67 :         ZEND_PARSE_PARAMETERS_END();
    2818             : #endif
    2819             : 
    2820          63 :         if (!ZSTR_LEN(str)) {
    2821           4 :                 RETURN_EMPTY_STRING();
    2822             :         }
    2823             : 
    2824         118 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    2825          59 :         php_ucfirst(Z_STRVAL_P(return_value));
    2826             : }
    2827             : /* }}} */
    2828             : 
    2829             : /* {{{
    2830             :    Lowercase the first character of the word in a native string */
    2831          41 : static void php_lcfirst(char *str)
    2832             : {
    2833             :         register char *r;
    2834          41 :         r = str;
    2835          41 :         *r = tolower((unsigned char) *r);
    2836          41 : }
    2837             : /* }}} */
    2838             : 
    2839             : /* {{{ proto string lcfirst(string str)
    2840             :    Make a string's first character lowercase */
    2841          49 : PHP_FUNCTION(lcfirst)
    2842             : {
    2843             :         zend_string  *str;
    2844             : 
    2845          49 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    2846           4 :                 return;
    2847             :         }
    2848             : 
    2849          45 :         if (!ZSTR_LEN(str)) {
    2850           4 :                 RETURN_EMPTY_STRING();
    2851             :         }
    2852             : 
    2853          82 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    2854          41 :         php_lcfirst(Z_STRVAL_P(return_value));
    2855             : }
    2856             : /* }}} */
    2857             : 
    2858             : /* {{{ proto string ucwords(string str [, string delims])
    2859             :    Uppercase the first character of every word in a string */
    2860         115 : PHP_FUNCTION(ucwords)
    2861             : {
    2862             :         zend_string *str;
    2863         115 :         char *delims = " \t\r\n\f\v";
    2864             :         register char *r, *r_end;
    2865         115 :         size_t delims_len = 6;
    2866             :         char mask[256];
    2867             : 
    2868             : #ifndef FAST_ZPP
    2869             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|s", &str, &delims, &delims_len) == FAILURE) {
    2870             :                 return;
    2871             :         }
    2872             : #else
    2873         115 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2874         339 :                 Z_PARAM_STR(str)
    2875         107 :                 Z_PARAM_OPTIONAL
    2876         115 :                 Z_PARAM_STRING(delims, delims_len)
    2877         115 :         ZEND_PARSE_PARAMETERS_END();
    2878             : #endif
    2879             : 
    2880         107 :         if (!ZSTR_LEN(str)) {
    2881          10 :                 RETURN_EMPTY_STRING();
    2882             :         }
    2883             : 
    2884          97 :         php_charmask((unsigned char *)delims, delims_len, mask);
    2885             : 
    2886         194 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    2887          97 :         r = Z_STRVAL_P(return_value);
    2888             : 
    2889          97 :         *r = toupper((unsigned char) *r);
    2890        2021 :         for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) {
    2891        1827 :                 if (mask[(unsigned char)*r++]) {
    2892         208 :                         *r = toupper((unsigned char) *r);
    2893             :                 }
    2894             :         }
    2895             : }
    2896             : /* }}} */
    2897             : 
    2898             : /* {{{ php_strtr
    2899             :  */
    2900          31 : PHPAPI char *php_strtr(char *str, size_t len, char *str_from, char *str_to, size_t trlen)
    2901             : {
    2902             :         size_t i;
    2903             : 
    2904          31 :         if (UNEXPECTED(trlen < 1)) {
    2905           0 :                 return str;
    2906          31 :         } else if (trlen == 1) {
    2907           0 :                 char ch_from = *str_from;
    2908           0 :                 char ch_to = *str_to;
    2909             : 
    2910           0 :                 for (i = 0; i < len; i++) {
    2911           0 :                         if (str[i] == ch_from) {
    2912           0 :                                 str[i] = ch_to;
    2913             :                         }
    2914             :                 }
    2915             :         } else {
    2916          31 :                 unsigned char xlat[256], j = 0;
    2917             : 
    2918        7936 :                 do { xlat[j] = j; } while (++j != 0);
    2919             : 
    2920        1539 :                 for (i = 0; i < trlen; i++) {
    2921        1508 :                         xlat[(size_t)(unsigned char) str_from[i]] = str_to[i];
    2922             :                 }
    2923             :                 
    2924       66288 :                 for (i = 0; i < len; i++) {
    2925       66257 :                         str[i] = xlat[(size_t)(unsigned char) str[i]];
    2926             :                 }
    2927             :         }
    2928             : 
    2929          31 :         return str;
    2930             : }
    2931             : /* }}} */
    2932             : 
    2933             : /* {{{ php_strtr_ex
    2934             :  */
    2935         113 : static zend_string *php_strtr_ex(zend_string *str, char *str_from, char *str_to, size_t trlen)
    2936             : {
    2937         113 :         zend_string *new_str = NULL;
    2938             :         size_t i;
    2939             : 
    2940         113 :         if (UNEXPECTED(trlen < 1)) {
    2941          12 :                 return zend_string_copy(str);
    2942         101 :         } else if (trlen == 1) {
    2943          17 :                 char ch_from = *str_from;
    2944          17 :                 char ch_to = *str_to;
    2945             : 
    2946          66 :                 for (i = 0; i < ZSTR_LEN(str); i++) {
    2947          66 :                         if (ZSTR_VAL(str)[i] == ch_from) {
    2948          34 :                                 new_str = zend_string_alloc(ZSTR_LEN(str), 0);
    2949          17 :                                 memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), i);
    2950          17 :                                 ZSTR_VAL(new_str)[i] = ch_to;
    2951          17 :                                 break;
    2952             :                         }
    2953             :                 }
    2954          90 :                 for (; i < ZSTR_LEN(str); i++) {
    2955          73 :                         ZSTR_VAL(new_str)[i] = (ZSTR_VAL(str)[i] != ch_from) ? ZSTR_VAL(str)[i] : ch_to;
    2956             :                 }
    2957             :         } else {
    2958          84 :                 unsigned char xlat[256], j = 0;
    2959             : 
    2960       21504 :                 do { xlat[j] = j; } while (++j != 0);
    2961             : 
    2962        1658 :                 for (i = 0; i < trlen; i++) {
    2963        1574 :                         xlat[(size_t)(unsigned char) str_from[i]] = str_to[i];
    2964             :                 }
    2965             : 
    2966         253 :                 for (i = 0; i < ZSTR_LEN(str); i++) {
    2967         243 :                         if (ZSTR_VAL(str)[i] != xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]]) {
    2968         148 :                                 new_str = zend_string_alloc(ZSTR_LEN(str), 0);
    2969          74 :                                 memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), i);
    2970          74 :                                 ZSTR_VAL(new_str)[i] = xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]];
    2971          74 :                                 break;
    2972             :                         }
    2973             :                 }
    2974             : 
    2975       16814 :                 for (;i < ZSTR_LEN(str); i++) {
    2976       16730 :                         ZSTR_VAL(new_str)[i] = xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]];
    2977             :                 }
    2978             :         }
    2979             : 
    2980         101 :         if (!new_str) {
    2981          10 :                 return zend_string_copy(str);
    2982             :         }
    2983             : 
    2984          91 :         ZSTR_VAL(new_str)[ZSTR_LEN(new_str)] = 0;
    2985          91 :         return new_str;
    2986             : }
    2987             : /* }}} */
    2988             : 
    2989             : /* {{{ php_strtr_array */
    2990          39 : static void php_strtr_array(zval *return_value, zend_string *input, HashTable *pats)
    2991             : {
    2992          39 :         char *str = ZSTR_VAL(input);
    2993          39 :         size_t slen = ZSTR_LEN(input);
    2994             :         zend_ulong num_key;
    2995             :         zend_string *str_key;
    2996             :         size_t len, pos, old_pos;
    2997          39 :         int num_keys = 0;
    2998          39 :         size_t minlen = 128*1024;
    2999          39 :         size_t maxlen = 0;
    3000             :         HashTable str_hash;
    3001             :         zval *entry;
    3002             :         char *key;
    3003          39 :         smart_str result = {0};
    3004             :         zend_ulong bitset[256/sizeof(zend_ulong)];
    3005             :         zend_ulong *num_bitset;
    3006             : 
    3007             :         /* we will collect all possible key lengths */
    3008          39 :         num_bitset = ecalloc((slen + sizeof(zend_ulong)) / sizeof(zend_ulong), sizeof(zend_ulong));
    3009          39 :         memset(bitset, 0, sizeof(bitset));
    3010             : 
    3011             :         /* check if original array has numeric keys */
    3012         279 :         ZEND_HASH_FOREACH_STR_KEY(pats, str_key) {
    3013         120 :                 if (UNEXPECTED(!str_key)) {
    3014           9 :                         num_keys = 1;
    3015             :                 } else {
    3016         111 :                         len = ZSTR_LEN(str_key);
    3017         111 :                         if (UNEXPECTED(len < 1)) {
    3018           0 :                                 RETURN_FALSE;
    3019         111 :                         } else if (UNEXPECTED(len > slen)) {
    3020             :                                 /* skip long patterns */
    3021          15 :                                 continue;
    3022             :                         }
    3023          96 :                         if (len > maxlen) {
    3024          74 :                                 maxlen = len;
    3025             :                         }
    3026          96 :                         if (len < minlen) {
    3027          41 :                                 minlen = len;
    3028             :                         }
    3029             :                         /* remember possible key length */
    3030          96 :                         num_bitset[len / sizeof(zend_ulong)] |= Z_UL(1) << (len % sizeof(zend_ulong));
    3031          96 :                         bitset[((unsigned char)ZSTR_VAL(str_key)[0]) / sizeof(zend_ulong)] |= Z_UL(1) << (((unsigned char)ZSTR_VAL(str_key)[0]) % sizeof(zend_ulong));
    3032             :                 }
    3033             :         } ZEND_HASH_FOREACH_END();
    3034             : 
    3035          39 :         if (UNEXPECTED(num_keys)) {
    3036             :                 zend_string *key_used;
    3037             :                 /* we have to rebuild HashTable with numeric keys */
    3038           8 :                 zend_hash_init(&str_hash, zend_hash_num_elements(pats), NULL, NULL, 0);
    3039          68 :                 ZEND_HASH_FOREACH_KEY_VAL(pats, num_key, str_key, entry) {
    3040          30 :                         if (UNEXPECTED(!str_key)) {
    3041           9 :                                 key_used = zend_long_to_str(num_key);
    3042           9 :                                 len = ZSTR_LEN(key_used);
    3043           9 :                                 if (UNEXPECTED(len > slen)) {
    3044             :                                         /* skip long patterns */
    3045           0 :                                         continue;
    3046             :                                 }
    3047           9 :                                 if (len > maxlen) {
    3048           1 :                                         maxlen = len;
    3049             :                                 }
    3050           9 :                                 if (len < minlen) {
    3051           1 :                                         minlen = len;
    3052             :                                 }
    3053             :                                 /* remember possible key length */
    3054           9 :                                 num_bitset[len / sizeof(zend_ulong)] |= Z_UL(1) << (len % sizeof(zend_ulong));
    3055           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));
    3056             :                         } else {
    3057          21 :                                 key_used = str_key;
    3058          21 :                                 len = ZSTR_LEN(key_used);
    3059          21 :                                 if (UNEXPECTED(len > slen)) {
    3060             :                                         /* skip long patterns */
    3061           8 :                                         continue;
    3062             :                                 }
    3063             :                         }
    3064          22 :                         zend_hash_add(&str_hash, key_used, entry);
    3065          22 :                         if (UNEXPECTED(!str_key)) {
    3066             :                                 zend_string_release(key_used);
    3067             :                         }
    3068             :                 } ZEND_HASH_FOREACH_END();
    3069           8 :                 pats = &str_hash;
    3070             :         }
    3071             : 
    3072          39 :         if (UNEXPECTED(minlen > maxlen)) {
    3073             :                 /* return the original string */
    3074           0 :                 if (pats == &str_hash) {
    3075           0 :                         zend_hash_destroy(&str_hash);
    3076             :                 }
    3077           0 :                 efree(num_bitset);
    3078           0 :                 RETURN_STR_COPY(input);
    3079             :         }
    3080             : 
    3081          39 :         old_pos = pos = 0;
    3082         983 :         while (pos <= slen - minlen) {
    3083         905 :                 key = str + pos;
    3084         905 :                 if (bitset[((unsigned char)key[0]) / sizeof(zend_ulong)] & (Z_UL(1) << (((unsigned char)key[0]) % sizeof(zend_ulong)))) {
    3085          95 :                         len = maxlen;
    3086          95 :                         if (len > slen - pos) {
    3087           2 :                                 len = slen - pos;
    3088             :                         }
    3089         305 :                         while (len >= minlen) {
    3090         206 :                                 if ((num_bitset[len / sizeof(zend_ulong)] & (Z_UL(1) << (len % sizeof(zend_ulong))))) {
    3091         160 :                                         entry = zend_hash_str_find(pats, key, len);
    3092         160 :                                         if (entry != NULL) {
    3093          91 :                                                 zend_string *s = zval_get_string(entry);
    3094          91 :                                                 smart_str_appendl(&result, str + old_pos, pos - old_pos);
    3095             :                                                 smart_str_append(&result, s);
    3096          91 :                                                 old_pos = pos + len;
    3097          91 :                                                 pos = old_pos - 1;
    3098             :                                                 zend_string_release(s);
    3099          91 :                                                 break;
    3100             :                                         }
    3101             :                                 }
    3102         115 :                                 len--;
    3103             :                         }
    3104             :                 }
    3105         905 :                 pos++;
    3106             :         }
    3107             : 
    3108          39 :         if (result.s) {
    3109          26 :                 smart_str_appendl(&result, str + old_pos, slen - old_pos);
    3110             :                 smart_str_0(&result);
    3111          26 :                 RETVAL_NEW_STR(result.s);
    3112             :         } else {
    3113             :                 smart_str_free(&result);
    3114          13 :                 RETVAL_STR_COPY(input);
    3115             :         }
    3116             : 
    3117          39 :         if (pats == &str_hash) {
    3118           8 :                 zend_hash_destroy(&str_hash);
    3119             :         }
    3120          39 :         efree(num_bitset);
    3121             : }
    3122             : /* }}} */
    3123             : 
    3124             : /* {{{ php_char_to_str_ex
    3125             :  */
    3126        6531 : 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)
    3127             : {
    3128             :         zend_string *result;
    3129        6531 :         size_t char_count = 0;
    3130        6531 :         char lc_from = 0;
    3131        6531 :         char *source, *target, *source_end= ZSTR_VAL(str) + ZSTR_LEN(str);
    3132             : 
    3133        6531 :         if (case_sensitivity) {
    3134        6521 :                 char *p = ZSTR_VAL(str), *e = p + ZSTR_LEN(str);
    3135       22247 :                 while ((p = memchr(p, from, (e - p)))) {
    3136        9205 :                         char_count++;
    3137        9205 :                         p++;
    3138             :                 }
    3139             :         } else {
    3140          10 :                 lc_from = tolower(from);
    3141         327 :                 for (source = ZSTR_VAL(str); source < source_end; source++) {
    3142         317 :                         if (tolower(*source) == lc_from) {
    3143          29 :                                 char_count++;
    3144             :                         }
    3145             :                 }
    3146             :         }
    3147             : 
    3148        6531 :         if (char_count == 0) {
    3149        1355 :                 return zend_string_copy(str);
    3150             :         }
    3151             : 
    3152        5176 :         if (to_len > 0) {
    3153        3306 :                 result = zend_string_safe_alloc(char_count, to_len - 1, ZSTR_LEN(str), 0);
    3154             :         } else {
    3155        7046 :                 result = zend_string_alloc(ZSTR_LEN(str) - char_count, 0);
    3156             :         }
    3157        5176 :         target = ZSTR_VAL(result);
    3158             : 
    3159        5176 :         if (case_sensitivity) {
    3160        5171 :                 char *p = ZSTR_VAL(str), *e = p + ZSTR_LEN(str), *s = ZSTR_VAL(str);
    3161       19547 :                 while ((p = memchr(p, from, (e - p)))) {
    3162        9205 :                         memcpy(target, s, (p - s));
    3163        9205 :                         target += p - s;
    3164        9205 :                         memcpy(target, to, to_len);
    3165        9205 :                         target += to_len;
    3166        9205 :                         p++;
    3167        9205 :                         s = p;
    3168        9205 :                         if (replace_count) {
    3169        8934 :                                 *replace_count += 1;
    3170             :                         }
    3171             :                 }
    3172        5171 :                 if (s < e) {
    3173        1381 :                         memcpy(target, s, (e - s));
    3174        1381 :                         target += e - s;
    3175             :                 }
    3176             :         } else {
    3177         212 :                 for (source = ZSTR_VAL(str); source < source_end; source++) {
    3178         207 :                         if (tolower(*source) == lc_from) {
    3179          29 :                                 if (replace_count) {
    3180          29 :                                         *replace_count += 1;
    3181             :                                 }
    3182          29 :                                 memcpy(target, to, to_len);
    3183          29 :                                 target += to_len;
    3184             :                         } else {
    3185         178 :                                 *target = *source;
    3186         178 :                                 target++;
    3187             :                         }
    3188             :                 }
    3189             :         }
    3190        5176 :         *target = 0;
    3191        5176 :         return result;
    3192             : }
    3193             : /* }}} */
    3194             : 
    3195             : /* {{{ php_str_to_str_ex
    3196             :  */
    3197      181381 : static zend_string *php_str_to_str_ex(zend_string *haystack,
    3198             :         char *needle, size_t needle_len, char *str, size_t str_len, zend_long *replace_count)
    3199             : {
    3200             :         zend_string *new_str;
    3201             : 
    3202      181381 :         if (needle_len < ZSTR_LEN(haystack)) {
    3203             :                 char *end;
    3204             :                 char *e, *s, *p, *r;
    3205             : 
    3206      178853 :                 if (needle_len == str_len) {
    3207       26384 :                         new_str = NULL;
    3208       26384 :                         end = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
    3209       54088 :                         for (p = ZSTR_VAL(haystack); (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3210         660 :                                 if (!new_str) {
    3211         848 :                                         new_str = zend_string_init(ZSTR_VAL(haystack), ZSTR_LEN(haystack), 0);
    3212             :                                 }
    3213         660 :                                 memcpy(ZSTR_VAL(new_str) + (r - ZSTR_VAL(haystack)), str, str_len);
    3214         660 :                                 (*replace_count)++;
    3215             :                         }
    3216       26384 :                         if (!new_str) {
    3217       25960 :                                 goto nothing_todo;
    3218             :                         }
    3219         424 :                         return new_str;
    3220             :                 } else {
    3221      152469 :                         size_t count = 0;
    3222      152469 :                         char *o = ZSTR_VAL(haystack);
    3223      152469 :                         char *n = needle;
    3224      152469 :                         char *endp = o + ZSTR_LEN(haystack);
    3225             : 
    3226      405353 :                         while ((o = (char*)php_memnstr(o, n, needle_len, endp))) {
    3227      100415 :                                 o += needle_len;
    3228      100415 :                                 count++;
    3229             :                         }
    3230      152469 :                         if (count == 0) {
    3231             :                                 /* Needle doesn't occur, shortcircuit the actual replacement. */
    3232      109024 :                                 goto nothing_todo;
    3233             :                         }
    3234       43445 :                         if (str_len > needle_len) {
    3235       21328 :                                 new_str = zend_string_safe_alloc(count, str_len - needle_len, ZSTR_LEN(haystack), 0);
    3236             :                         } else {
    3237       65562 :                                 new_str = zend_string_alloc(count * (str_len - needle_len) + ZSTR_LEN(haystack), 0);
    3238             :                         }
    3239             : 
    3240       43445 :                         e = s = ZSTR_VAL(new_str);
    3241       43445 :                         end = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
    3242      287720 :                         for (p = ZSTR_VAL(haystack); (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3243      100415 :                                 memcpy(e, p, r - p);
    3244      100415 :                                 e += r - p;
    3245      100415 :                                 memcpy(e, str, str_len);
    3246      100415 :                                 e += str_len;
    3247      100415 :                                 (*replace_count)++;
    3248             :                         }
    3249             : 
    3250       43445 :                         if (p < end) {
    3251       42242 :                                 memcpy(e, p, end - p);
    3252       42242 :                                 e += end - p;
    3253             :                         }
    3254             : 
    3255       43445 :                         *e = '\0';
    3256       43445 :                         return new_str;
    3257             :                 }
    3258        2528 :         } else if (needle_len > ZSTR_LEN(haystack) || memcmp(ZSTR_VAL(haystack), needle, ZSTR_LEN(haystack))) {
    3259             : nothing_todo:
    3260      137485 :                 return zend_string_copy(haystack);
    3261             :         } else {
    3262          27 :                 new_str = zend_string_init(str, str_len, 0);
    3263          27 :                 (*replace_count)++;
    3264          27 :                 return new_str;
    3265             :         }
    3266             : }
    3267             : /* }}} */
    3268             : 
    3269             : /* {{{ php_str_to_str_i_ex
    3270             :  */
    3271         106 : static zend_string *php_str_to_str_i_ex(zend_string *haystack, char *lc_haystack,
    3272             :         zend_string *needle, char *str, size_t str_len, zend_long *replace_count)
    3273             : {
    3274         106 :         zend_string *new_str = NULL;
    3275             :         zend_string *lc_needle;
    3276             : 
    3277         106 :         if (ZSTR_LEN(needle) < ZSTR_LEN(haystack)) {
    3278             :                 char *end;
    3279             :                 char *e, *s, *p, *r;
    3280             : 
    3281          71 :                 if (ZSTR_LEN(needle) == str_len) {
    3282           2 :                         lc_needle = php_string_tolower(needle);
    3283           2 :                         end = lc_haystack + ZSTR_LEN(haystack);
    3284          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)) {
    3285          14 :                                 if (!new_str) {
    3286           4 :                                         new_str = zend_string_init(ZSTR_VAL(haystack), ZSTR_LEN(haystack), 0);
    3287             :                                 }
    3288          14 :                                 memcpy(ZSTR_VAL(new_str) + (r - lc_haystack), str, str_len);
    3289          14 :                                 (*replace_count)++;
    3290             :                         }
    3291             :                         zend_string_release(lc_needle);
    3292             : 
    3293           2 :                         if (!new_str) {
    3294           0 :                                 goto nothing_todo;
    3295             :                         }
    3296           2 :                         return new_str;
    3297             :                 } else {
    3298          69 :                         size_t count = 0;
    3299          69 :                         char *o = lc_haystack;
    3300             :                         char *n;
    3301          69 :                         char *endp = o + ZSTR_LEN(haystack);
    3302             : 
    3303          69 :                         lc_needle = php_string_tolower(needle);
    3304          69 :                         n = ZSTR_VAL(lc_needle);
    3305             : 
    3306         509 :                         while ((o = (char*)php_memnstr(o, n, ZSTR_LEN(lc_needle), endp))) {
    3307         151 :                                 o += ZSTR_LEN(lc_needle);
    3308         151 :                                 count++;
    3309             :                         }
    3310          69 :                         if (count == 0) {
    3311             :                                 /* Needle doesn't occur, shortcircuit the actual replacement. */
    3312             :                                 zend_string_release(lc_needle);
    3313           8 :                                 goto nothing_todo;
    3314             :                         }
    3315             :                         
    3316          61 :                         if (str_len > ZSTR_LEN(lc_needle)) {
    3317          26 :                                 new_str = zend_string_safe_alloc(count, str_len - ZSTR_LEN(lc_needle), ZSTR_LEN(haystack), 0);
    3318             :                         } else {
    3319          96 :                                 new_str = zend_string_alloc(count * (str_len - ZSTR_LEN(lc_needle)) + ZSTR_LEN(haystack), 0);
    3320             :                         }
    3321             : 
    3322          61 :                         e = s = ZSTR_VAL(new_str);
    3323          61 :                         end = lc_haystack + ZSTR_LEN(haystack);
    3324             : 
    3325         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)) {
    3326         151 :                                 memcpy(e, ZSTR_VAL(haystack) + (p - lc_haystack), r - p);
    3327         151 :                                 e += r - p;
    3328         151 :                                 memcpy(e, str, str_len);
    3329         151 :                                 e += str_len;
    3330         151 :                                 (*replace_count)++;
    3331             :                         }
    3332             : 
    3333          61 :                         if (p < end) {
    3334          21 :                                 memcpy(e, ZSTR_VAL(haystack) + (p - lc_haystack), end - p);
    3335          21 :                                 e += end - p;
    3336             :                         }
    3337          61 :                         *e = '\0';
    3338             : 
    3339             :                         zend_string_release(lc_needle);
    3340             : 
    3341          61 :                         return new_str;
    3342             :                 }
    3343          35 :         } else if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
    3344             : nothing_todo:
    3345           9 :                 return zend_string_copy(haystack);
    3346             :         } else {
    3347          35 :                 lc_needle = php_string_tolower(needle);
    3348             : 
    3349          35 :                 if (memcmp(lc_haystack, ZSTR_VAL(lc_needle), ZSTR_LEN(lc_needle))) {
    3350             :                         zend_string_release(lc_needle);
    3351           1 :                         goto nothing_todo;
    3352             :                 }
    3353             :                 zend_string_release(lc_needle);
    3354             : 
    3355          34 :                 new_str = zend_string_init(str, str_len, 0);
    3356             : 
    3357          34 :                 (*replace_count)++;
    3358          34 :                 return new_str;
    3359             :         }
    3360             : }
    3361             : /* }}} */
    3362             : 
    3363             : /* {{{ php_str_to_str
    3364             :  */
    3365        1440 : PHPAPI zend_string *php_str_to_str(char *haystack, size_t length, char *needle, size_t needle_len, char *str, size_t str_len)
    3366             : {
    3367             :         zend_string *new_str;
    3368             : 
    3369        1440 :         if (needle_len < length) {
    3370             :                 char *end;
    3371             :                 char *e, *s, *p, *r;
    3372             : 
    3373        1052 :                 if (needle_len == str_len) {
    3374           0 :                         new_str = zend_string_init(haystack, length, 0);
    3375           0 :                         end = ZSTR_VAL(new_str) + length;
    3376           0 :                         for (p = ZSTR_VAL(new_str); (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3377           0 :                                 memcpy(r, str, str_len);
    3378             :                         }
    3379           0 :                         return new_str;
    3380             :                 } else {
    3381        1052 :                         if (str_len < needle_len) {
    3382           0 :                                 new_str = zend_string_alloc(length, 0);
    3383             :                         } else {
    3384        1052 :                                 size_t count = 0;
    3385        1052 :                                 char *o = haystack;
    3386        1052 :                                 char *n = needle;
    3387        1052 :                                 char *endp = o + length;
    3388             : 
    3389        2125 :                                 while ((o = (char*)php_memnstr(o, n, needle_len, endp))) {
    3390          21 :                                         o += needle_len;
    3391          21 :                                         count++;
    3392             :                                 }
    3393        1052 :                                 if (count == 0) {
    3394             :                                         /* Needle doesn't occur, shortcircuit the actual replacement. */
    3395        1041 :                                         new_str = zend_string_init(haystack, length, 0);
    3396        1041 :                                         return new_str;
    3397             :                                 } else {
    3398          11 :                                         if (str_len > needle_len) {
    3399          22 :                                                 new_str = zend_string_safe_alloc(count, str_len - needle_len, length, 0);
    3400             :                                         } else {
    3401           0 :                                                 new_str = zend_string_alloc(count * (str_len - needle_len) + length, 0);
    3402             :                                         }
    3403             :                                 }
    3404             :                         }
    3405             : 
    3406          11 :                         e = s = ZSTR_VAL(new_str);
    3407          11 :                         end = haystack + length;
    3408          64 :                         for (p = haystack; (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3409          21 :                                 memcpy(e, p, r - p);
    3410          21 :                                 e += r - p;
    3411          21 :                                 memcpy(e, str, str_len);
    3412          21 :                                 e += str_len;
    3413             :                         }
    3414             : 
    3415          11 :                         if (p < end) {
    3416           8 :                                 memcpy(e, p, end - p);
    3417           8 :                                 e += end - p;
    3418             :                         }
    3419             : 
    3420          11 :                         *e = '\0';
    3421          22 :                         new_str = zend_string_truncate(new_str, e - s, 0);
    3422          11 :                         return new_str;
    3423             :                 }
    3424         388 :         } else if (needle_len > length || memcmp(haystack, needle, length)) {
    3425         380 :                 new_str = zend_string_init(haystack, length, 0);
    3426         380 :                 return new_str;
    3427             :         } else {
    3428           8 :                 new_str = zend_string_init(str, str_len, 0);
    3429             : 
    3430           8 :                 return new_str;
    3431             :         }
    3432             : }
    3433             : /* }}} */
    3434             : 
    3435             : /* {{{ proto string strtr(string str, string from[, string to])
    3436             :    Translates characters in str using given translation tables */
    3437         217 : PHP_FUNCTION(strtr)
    3438             : {
    3439             :         zval *from;
    3440             :         zend_string *str;
    3441         217 :         char *to = NULL;
    3442         217 :         size_t to_len = 0;
    3443         217 :         int ac = ZEND_NUM_ARGS();
    3444             : 
    3445             : #ifndef FAST_ZPP
    3446             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|s", &str, &from, &to, &to_len) == FAILURE) {
    3447             :                 return;
    3448             :         }
    3449             : #else
    3450         217 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    3451         642 :                 Z_PARAM_STR(str)
    3452         198 :                 Z_PARAM_ZVAL(from)
    3453         198 :                 Z_PARAM_OPTIONAL
    3454         422 :                 Z_PARAM_STRING(to, to_len)
    3455         217 :         ZEND_PARSE_PARAMETERS_END();
    3456             : #endif
    3457             : 
    3458         280 :         if (ac == 2 && Z_TYPE_P(from) != IS_ARRAY) {
    3459          31 :                 php_error_docref(NULL, E_WARNING, "The second argument is not an array");
    3460          31 :                 RETURN_FALSE;
    3461             :         }
    3462             : 
    3463             :         /* shortcut for empty string */
    3464         163 :         if (ZSTR_LEN(str) == 0) {
    3465          27 :                 RETURN_EMPTY_STRING();
    3466             :         }
    3467             : 
    3468         136 :         if (ac == 2) {
    3469          47 :                 HashTable *pats = Z_ARRVAL_P(from);
    3470             : 
    3471          47 :                 if (zend_hash_num_elements(pats) < 1) {
    3472           2 :                         RETURN_STR_COPY(str);
    3473          45 :                 } else if (zend_hash_num_elements(pats) == 1) {
    3474             :                         zend_long num_key;
    3475             :                         zend_string *str_key, *replace;
    3476             :                         zval *entry, tmp;
    3477             : 
    3478          18 :                         ZEND_HASH_FOREACH_KEY_VAL(pats, num_key, str_key, entry) {
    3479           6 :                                 ZVAL_UNDEF(&tmp);
    3480           6 :                                 if (UNEXPECTED(!str_key)) {
    3481           2 :                                         ZVAL_LONG(&tmp, num_key);
    3482           2 :                                         convert_to_string(&tmp);
    3483           2 :                                         str_key = Z_STR(tmp);
    3484             :                                 }               
    3485           6 :                                 replace = zval_get_string(entry);
    3486           6 :                                 if (ZSTR_LEN(str_key) < 1) {
    3487           0 :                                         RETVAL_STR_COPY(str);
    3488           6 :                                 } else if (ZSTR_LEN(str_key) == 1) {
    3489           3 :                                         RETVAL_STR(php_char_to_str_ex(str,
    3490             :                                                                 ZSTR_VAL(str_key)[0],
    3491             :                                                                 ZSTR_VAL(replace),
    3492             :                                                                 ZSTR_LEN(replace),
    3493             :                                                                 1,
    3494             :                                                                 NULL));
    3495             :                                 } else {
    3496             :                                         zend_long dummy;
    3497           3 :                                         RETVAL_STR(php_str_to_str_ex(str,
    3498             :                                                                 ZSTR_VAL(str_key), ZSTR_LEN(str_key),
    3499             :                                                                 ZSTR_VAL(replace), ZSTR_LEN(replace), &dummy));
    3500             :                                 }
    3501             :                                 zend_string_release(replace);
    3502             :                                 zval_dtor(&tmp);
    3503           6 :                                 return;
    3504             :                         } ZEND_HASH_FOREACH_END();
    3505             :                 } else {
    3506          39 :                         php_strtr_array(return_value, str, pats);
    3507             :                 }
    3508             :         } else {
    3509         206 :                 convert_to_string_ex(from);
    3510             : 
    3511          89 :                 RETURN_STR(php_strtr_ex(str,
    3512             :                                   Z_STRVAL_P(from),
    3513             :                                   to,
    3514             :                                   MIN(Z_STRLEN_P(from), to_len)));
    3515             :         }
    3516             : }
    3517             : /* }}} */
    3518             : 
    3519             : /* {{{ proto string strrev(string str)
    3520             :    Reverse a string */
    3521         104 : PHP_FUNCTION(strrev)
    3522             : {
    3523             :         zend_string *str;
    3524             :         char *e, *p;
    3525             :         zend_string *n;
    3526             : 
    3527         104 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3528           8 :                 return;
    3529             :         }
    3530             : 
    3531         192 :         n = zend_string_alloc(ZSTR_LEN(str), 0);
    3532          96 :         p = ZSTR_VAL(n);
    3533             : 
    3534          96 :         e = ZSTR_VAL(str) + ZSTR_LEN(str);
    3535             : 
    3536        4317 :         while (--e >= ZSTR_VAL(str)) {
    3537        4125 :                 *p++ = *e;
    3538             :         }
    3539             : 
    3540          96 :         *p = '\0';
    3541             : 
    3542          96 :         RETVAL_NEW_STR(n);
    3543             : }
    3544             : /* }}} */
    3545             : 
    3546             : /* {{{ php_similar_str
    3547             :  */
    3548          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)
    3549             : {
    3550             :         char *p, *q;
    3551          10 :         char *end1 = (char *) txt1 + len1;
    3552          10 :         char *end2 = (char *) txt2 + len2;
    3553             :         size_t l;
    3554             : 
    3555          10 :         *max = 0;
    3556         104 :         for (p = (char *) txt1; p < end1; p++) {
    3557         602 :                 for (q = (char *) txt2; q < end2; q++) {
    3558         508 :                         for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
    3559         508 :                         if (l > *max) {
    3560           6 :                                 *max = l;
    3561           6 :                                 *pos1 = p - txt1;
    3562           6 :                                 *pos2 = q - txt2;
    3563             :                         }
    3564             :                 }
    3565             :         }
    3566          10 : }
    3567             : /* }}} */
    3568             : 
    3569             : /* {{{ php_similar_char
    3570             :  */
    3571          10 : static size_t php_similar_char(const char *txt1, size_t len1, const char *txt2, size_t len2)
    3572             : {
    3573             :         size_t sum;
    3574          10 :         size_t pos1 = 0, pos2 = 0, max;
    3575             : 
    3576          10 :         php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
    3577          10 :         if ((sum = max)) {
    3578           6 :                 if (pos1 && pos2) {
    3579           0 :                         sum += php_similar_char(txt1, pos1,
    3580             :                                                                         txt2, pos2);
    3581             :                 }
    3582           6 :                 if ((pos1 + max < len1) && (pos2 + max < len2)) {
    3583           2 :                         sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
    3584           2 :                                                                         txt2 + pos2 + max, len2 - pos2 - max);
    3585             :                 }
    3586             :         }
    3587             : 
    3588          10 :         return sum;
    3589             : }
    3590             : /* }}} */
    3591             : 
    3592             : /* {{{ proto int similar_text(string str1, string str2 [, float percent])
    3593             :    Calculates the similarity between two strings */
    3594          10 : PHP_FUNCTION(similar_text)
    3595             : {
    3596             :         zend_string *t1, *t2;
    3597          10 :         zval *percent = NULL;
    3598          10 :         int ac = ZEND_NUM_ARGS();
    3599             :         size_t sim;
    3600             : 
    3601          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS|z/", &t1, &t2, &percent) == FAILURE) {
    3602           2 :                 return;
    3603             :         }
    3604             : 
    3605           8 :         if (ac > 2) {
    3606           8 :                 convert_to_double_ex(percent);
    3607             :         }
    3608             : 
    3609           8 :         if (ZSTR_LEN(t1) + ZSTR_LEN(t2) == 0) {
    3610           0 :                 if (ac > 2) {
    3611           0 :                         Z_DVAL_P(percent) = 0;
    3612             :                 }
    3613             : 
    3614           0 :                 RETURN_LONG(0);
    3615             :         }
    3616             : 
    3617           8 :         sim = php_similar_char(ZSTR_VAL(t1), ZSTR_LEN(t1), ZSTR_VAL(t2), ZSTR_LEN(t2));
    3618             : 
    3619           8 :         if (ac > 2) {
    3620           4 :                 Z_DVAL_P(percent) = sim * 200.0 / (ZSTR_LEN(t1) + ZSTR_LEN(t2));
    3621             :         }
    3622             : 
    3623           8 :         RETURN_LONG(sim);
    3624             : }
    3625             : /* }}} */
    3626             : 
    3627             : /* {{{ php_stripslashes
    3628             :  *
    3629             :  * be careful, this edits the string in-place */
    3630         103 : PHPAPI void php_stripslashes(zend_string *str)
    3631             : {
    3632             :         char *s, *t;
    3633             :         size_t l;
    3634             : 
    3635         103 :         s = ZSTR_VAL(str);
    3636         103 :         t = ZSTR_VAL(str);
    3637         103 :         l = ZSTR_LEN(str);
    3638             : 
    3639        1609 :         while (l > 0) {
    3640        1403 :                 if (*t == '\\') {
    3641         116 :                         t++;                            /* skip the slash */
    3642         116 :                         ZSTR_LEN(str)--;
    3643         116 :                         l--;
    3644         116 :                         if (l > 0) {
    3645         116 :                                 if (*t == '0') {
    3646          15 :                                         *s++='\0';
    3647          15 :                                         t++;
    3648             :                                 } else {
    3649         101 :                                         *s++ = *t++;    /* preserve the next character */
    3650             :                                 }
    3651         116 :                                 l--;
    3652             :                         }
    3653             :                 } else {
    3654        1287 :                         *s++ = *t++;
    3655        1287 :                         l--;
    3656             :                 }
    3657             :         }
    3658         103 :         if (s != t) {
    3659          67 :                 *s = '\0';
    3660             :         }
    3661         103 : }
    3662             : /* }}} */
    3663             : 
    3664             : /* {{{ proto string addcslashes(string str, string charlist)
    3665             :    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...) */
    3666          45 : PHP_FUNCTION(addcslashes)
    3667             : {
    3668             :         zend_string *str, *what;
    3669             : 
    3670          45 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &str, &what) == FAILURE) {
    3671           4 :                 return;
    3672             :         }
    3673             : 
    3674          41 :         if (ZSTR_LEN(str) == 0) {
    3675           6 :                 RETURN_EMPTY_STRING();
    3676             :         }
    3677             : 
    3678          35 :         if (ZSTR_LEN(what) == 0) {
    3679          10 :                 RETURN_STRINGL(ZSTR_VAL(str), ZSTR_LEN(str));
    3680             :         }
    3681             : 
    3682          30 :         RETURN_STR(php_addcslashes(str, 0, ZSTR_VAL(what), ZSTR_LEN(what)));
    3683             : }
    3684             : /* }}} */
    3685             : 
    3686             : /* {{{ proto string addslashes(string str)
    3687             :    Escapes single quote, double quotes and backslash characters in a string with backslashes */
    3688      475096 : PHP_FUNCTION(addslashes)
    3689             : {
    3690             :         zend_string *str;
    3691             : 
    3692             : #ifndef FAST_ZPP
    3693             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3694             :                 return;
    3695             :         }
    3696             : #else
    3697      475096 :         ZEND_PARSE_PARAMETERS_START(1, 1)
    3698     1425282 :                 Z_PARAM_STR(str)
    3699      475096 :         ZEND_PARSE_PARAMETERS_END();
    3700             : #endif
    3701             : 
    3702      475088 :         if (ZSTR_LEN(str) == 0) {
    3703      125994 :                 RETURN_EMPTY_STRING();
    3704             :         }
    3705             : 
    3706      349094 :         RETURN_STR(php_addslashes(str, 0));
    3707             : }
    3708             : /* }}} */
    3709             : 
    3710             : /* {{{ proto string stripcslashes(string str)
    3711             :    Strips backslashes from a string. Uses C-style conventions */
    3712          41 : PHP_FUNCTION(stripcslashes)
    3713             : {
    3714             :         zend_string *str;
    3715             : 
    3716          41 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3717           8 :                 return;
    3718             :         }
    3719             : 
    3720          66 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    3721          33 :         php_stripcslashes(Z_STR_P(return_value));
    3722             : }
    3723             : /* }}} */
    3724             : 
    3725             : /* {{{ proto string stripslashes(string str)
    3726             :    Strips backslashes from a string */
    3727         111 : PHP_FUNCTION(stripslashes)
    3728             : {
    3729             :         zend_string *str;
    3730             : 
    3731         111 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
    3732           8 :                 return;
    3733             :         }
    3734             : 
    3735         206 :         ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    3736         103 :         php_stripslashes(Z_STR_P(return_value));
    3737             : }
    3738             : /* }}} */
    3739             : 
    3740             : #ifndef HAVE_STRERROR
    3741             : /* {{{ php_strerror
    3742             :  */
    3743             : char *php_strerror(int errnum)
    3744             : {
    3745             :         extern int sys_nerr;
    3746             :         extern char *sys_errlist[];
    3747             : 
    3748             :         if ((unsigned int) errnum < sys_nerr) {
    3749             :                 return(sys_errlist[errnum]);
    3750             :         }
    3751             : 
    3752             :         (void) snprintf(BG(str_ebuf), sizeof(php_basic_globals.str_ebuf), "Unknown error: %d", errnum);
    3753             :         return(BG(str_ebuf));
    3754             : }
    3755             : /* }}} */
    3756             : #endif
    3757             : 
    3758             : /* {{{ php_stripcslashes
    3759             :  */
    3760          33 : PHPAPI void php_stripcslashes(zend_string *str)
    3761             : {
    3762             :         char *source, *target, *end;
    3763          33 :         size_t  nlen = ZSTR_LEN(str), i;
    3764             :         char numtmp[4];
    3765             : 
    3766         157 :         for (source = (char*)ZSTR_VAL(str), end = source + ZSTR_LEN(str), target = ZSTR_VAL(str); source < end; source++) {
    3767         165 :                 if (*source == '\\' && source + 1 < end) {
    3768          41 :                         source++;
    3769          41 :                         switch (*source) {
    3770           2 :                                 case 'n':  *target++='\n'; nlen--; break;
    3771           2 :                                 case 'r':  *target++='\r'; nlen--; break;
    3772           1 :                                 case 'a':  *target++='\a'; nlen--; break;
    3773           1 :                                 case 't':  *target++='\t'; nlen--; break;
    3774           1 :                                 case 'v':  *target++='\v'; nlen--; break;
    3775           1 :                                 case 'b':  *target++='\b'; nlen--; break;
    3776           1 :                                 case 'f':  *target++='\f'; nlen--; break;
    3777           1 :                                 case '\\': *target++='\\'; nlen--; break;
    3778             :                                 case 'x':
    3779          11 :                                         if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3780          11 :                                                 numtmp[0] = *++source;
    3781          22 :                                                 if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3782          11 :                                                         numtmp[1] = *++source;
    3783          11 :                                                         numtmp[2] = '\0';
    3784          11 :                                                         nlen-=3;
    3785             :                                                 } else {
    3786           0 :                                                         numtmp[1] = '\0';
    3787           0 :                                                         nlen-=2;
    3788             :                                                 }
    3789          11 :                                                 *target++=(char)strtol(numtmp, NULL, 16);
    3790          11 :                                                 break;
    3791             :                                         }
    3792             :                                         /* break is left intentionally */
    3793             :                                 default:
    3794          20 :                                         i=0;
    3795          73 :                                         while (source < end && *source >= '0' && *source <= '7' && i<3) {
    3796          33 :                                                 numtmp[i++] = *source++;
    3797             :                                         }
    3798          20 :                                         if (i) {
    3799          11 :                                                 numtmp[i]='\0';
    3800          11 :                                                 *target++=(char)strtol(numtmp, NULL, 8);
    3801          11 :                                                 nlen-=i;
    3802          11 :                                                 source--;
    3803             :                                         } else {
    3804           9 :                                                 *target++=*source;
    3805           9 :                                                 nlen--;
    3806             :                                         }
    3807             :                         }
    3808             :                 } else {
    3809          83 :                         *target++=*source;
    3810             :                 }
    3811             :         }
    3812             : 
    3813          33 :         if (nlen != 0) {
    3814          24 :                 *target='\0';
    3815             :         }
    3816             : 
    3817          33 :         ZSTR_LEN(str) = nlen;
    3818          33 : }
    3819             : /* }}} */
    3820             : 
    3821             : /* {{{ php_addcslashes
    3822             :  */
    3823        1879 : PHPAPI zend_string *php_addcslashes(zend_string *str, int should_free, char *what, size_t wlength)
    3824             : {
    3825             :         char flags[256];
    3826             :         char *source, *target;
    3827             :         char *end;
    3828             :         char c;
    3829             :         size_t  newlen;
    3830        3758 :         zend_string *new_str = zend_string_safe_alloc(4, ZSTR_LEN(str), 0, 0);
    3831             : 
    3832        1879 :         php_charmask((unsigned char *)what, wlength, flags);
    3833             : 
    3834       21334 :         for (source = (char*)ZSTR_VAL(str), end = source + ZSTR_LEN(str), target = ZSTR_VAL(new_str); source < end; source++) {
    3835       19455 :                 c = *source;
    3836       19455 :                 if (flags[(unsigned char)c]) {
    3837         165 :                         if ((unsigned char) c < 32 || (unsigned char) c > 126) {
    3838          16 :                                 *target++ = '\\';
    3839          16 :                                 switch (c) {
    3840           2 :                                         case '\n': *target++ = 'n'; break;
    3841           2 :                                         case '\t': *target++ = 't'; break;
    3842           2 :                                         case '\r': *target++ = 'r'; break;
    3843           0 :                                         case '\a': *target++ = 'a'; break;
    3844           2 :                                         case '\v': *target++ = 'v'; break;
    3845           0 :                                         case '\b': *target++ = 'b'; break;
    3846           2 :                                         case '\f': *target++ = 'f'; break;
    3847           6 :                                         default: target += sprintf(target, "%03o", (unsigned char) c);
    3848             :                                 }
    3849          16 :                                 continue;
    3850             :                         }
    3851         149 :                         *target++ = '\\';
    3852             :                 }
    3853       19439 :                 *target++ = c;
    3854             :         }
    3855        1879 :         *target = 0;
    3856        1879 :         newlen = target - ZSTR_VAL(new_str);
    3857        1879 :         if (newlen < ZSTR_LEN(str) * 4) {
    3858        1830 :                 new_str = zend_string_truncate(new_str, newlen, 0);
    3859             :         }
    3860        1879 :         if (should_free) {
    3861             :                 zend_string_release(str);
    3862             :         }
    3863        1879 :         return new_str;
    3864             : }
    3865             : /* }}} */
    3866             : 
    3867             : /* {{{ php_addslashes
    3868             :  */
    3869      349154 : PHPAPI zend_string *php_addslashes(zend_string *str, int should_free)
    3870             : {
    3871             :         /* maximum string length, worst case situation */
    3872             :         char *source, *target;
    3873             :         char *end;
    3874             :         size_t offset;
    3875             :         zend_string *new_str;
    3876             : 
    3877      349154 :         if (!str) {
    3878           0 :                 return ZSTR_EMPTY_ALLOC();
    3879             :         }
    3880             : 
    3881      349154 :         source = ZSTR_VAL(str);
    3882      349154 :         end = source + ZSTR_LEN(str);
    3883             : 
    3884     2415327 :         while (source < end) {
    3885     1717133 :                 switch (*source) {
    3886             :                         case '\0':
    3887             :                         case '\'':
    3888             :                         case '\"':
    3889             :                         case '\\':
    3890         114 :                                 goto do_escape;
    3891             :                         default:
    3892     1717019 :                                 source++;
    3893             :                                 break;
    3894             :                 }
    3895             :         }
    3896             : 
    3897      349040 :         if (!should_free) {
    3898      349040 :                 return zend_string_copy(str);
    3899             :         }
    3900             : 
    3901           0 :         return str;
    3902             : 
    3903             : do_escape:
    3904         114 :         offset = source - (char *)ZSTR_VAL(str);
    3905         228 :         new_str = zend_string_safe_alloc(2, ZSTR_LEN(str) - offset, offset, 0);
    3906         114 :         memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), offset);
    3907         114 :         target = ZSTR_VAL(new_str) + offset;
    3908             : 
    3909        2008 :         while (source < end) {
    3910        1780 :                 switch (*source) {
    3911             :                         case '\0':
    3912          29 :                                 *target++ = '\\';
    3913          29 :                                 *target++ = '0';
    3914          29 :                                 break;
    3915             :                         case '\'':
    3916             :                         case '\"':
    3917             :                         case '\\':
    3918         223 :                                 *target++ = '\\';
    3919             :                                 /* break is missing *intentionally* */
    3920             :                         default:
    3921        1751 :                                 *target++ = *source;
    3922             :                                 break;
    3923             :                 }
    3924             : 
    3925        1780 :                 source++;
    3926             :         }
    3927             : 
    3928         114 :         *target = 0;
    3929         114 :         if (should_free) {
    3930             :                 zend_string_release(str);
    3931             :         }
    3932             : 
    3933         114 :         if (ZSTR_LEN(new_str) - (target - ZSTR_VAL(new_str)) > 16) {
    3934          48 :                 new_str = zend_string_truncate(new_str, target - ZSTR_VAL(new_str), 0);
    3935             :         } else {
    3936          90 :                 ZSTR_LEN(new_str) = target - ZSTR_VAL(new_str);
    3937             :         }
    3938             : 
    3939         114 :         return new_str;
    3940             : }
    3941             : /* }}} */
    3942             : 
    3943             : #define _HEB_BLOCK_TYPE_ENG 1
    3944             : #define _HEB_BLOCK_TYPE_HEB 2
    3945             : #define isheb(c)      (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0)
    3946             : #define _isblank(c)   (((((unsigned char) c) == ' '  || ((unsigned char) c) == '\t')) ? 1 : 0)
    3947             : #define _isnewline(c) (((((unsigned char) c) == '\n' || ((unsigned char) c) == '\r')) ? 1 : 0)
    3948             : 
    3949             : /* {{{ php_str_replace_in_subject
    3950             :  */
    3951      169310 : static zend_long php_str_replace_in_subject(zval *search, zval *replace, zval *subject, zval *result, int case_sensitivity)
    3952             : {
    3953             :         zval            *search_entry,
    3954      169310 :                                 *replace_entry = NULL;
    3955             :         zend_string     *tmp_result,
    3956      169310 :                                 *replace_entry_str = NULL;
    3957      169310 :         char            *replace_value = NULL;
    3958      169310 :         size_t           replace_len = 0;
    3959      169310 :         zend_long        replace_count = 0;
    3960             :         zend_string     *subject_str;
    3961      169310 :         zend_string *lc_subject_str = NULL;
    3962             :         uint32_t     replace_idx;
    3963             : 
    3964             :         /* Make sure we're dealing with strings. */
    3965      169310 :         subject_str = zval_get_string(subject);
    3966      169310 :         if (ZSTR_LEN(subject_str) == 0) {
    3967             :                 zend_string_release(subject_str);
    3968          99 :                 ZVAL_EMPTY_STRING(result);
    3969          99 :                 return 0;
    3970             :         }
    3971             : 
    3972             :         /* If search is an array */
    3973      169211 :         if (Z_TYPE_P(search) == IS_ARRAY) {
    3974             :                 /* Duplicate subject string for repeated replacement */
    3975       36277 :                 ZVAL_STR_COPY(result, subject_str);
    3976             : 
    3977       36277 :                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3978          30 :                         replace_idx = 0;
    3979             :                 } else {
    3980             :                         /* Set replacement value to the passed one */
    3981       36247 :                         replace_value = Z_STRVAL_P(replace);
    3982       36247 :                         replace_len = Z_STRLEN_P(replace);
    3983             :                 }
    3984             : 
    3985             :                 /* For each entry in the search array, get the entry */
    3986      146471 :                 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(search), search_entry) {
    3987             :                         /* Make sure we're dealing with strings. */
    3988       55098 :                         zend_string *search_str = zval_get_string(search_entry);
    3989       55098 :                         if (ZSTR_LEN(search_str) == 0) {
    3990           0 :                                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3991           0 :                                         replace_idx++;
    3992             :                                 }
    3993             :                                 zend_string_release(search_str);
    3994           0 :                                 continue;
    3995             :                         }
    3996             : 
    3997             :                         /* If replace is an array. */
    3998       55098 :                         if (Z_TYPE_P(replace) == IS_ARRAY) {
    3999             :                                 /* Get current entry */
    4000         150 :                                 while (replace_idx < Z_ARRVAL_P(replace)->nNumUsed) {
    4001          65 :                                         replace_entry = &Z_ARRVAL_P(replace)->arData[replace_idx].val;
    4002          65 :                                         if (Z_TYPE_P(replace_entry) != IS_UNDEF) {
    4003          65 :                                                 break;
    4004             :                                         }
    4005           0 :                                         replace_idx++;
    4006             :                                 }
    4007          75 :                                 if (replace_idx < Z_ARRVAL_P(replace)->nNumUsed) {
    4008             :                                         /* Make sure we're dealing with strings. */
    4009          65 :                                         replace_entry_str = zval_get_string(replace_entry);
    4010             : 
    4011             :                                         /* Set replacement value to the one we got from array */
    4012          65 :                                         replace_value = ZSTR_VAL(replace_entry_str);
    4013          65 :                                         replace_len = ZSTR_LEN(replace_entry_str);
    4014             : 
    4015          65 :                                         replace_idx++;
    4016             :                                 } else {
    4017             :                                         /* We've run out of replacement strings, so use an empty one. */
    4018          10 :                                         replace_value = "";
    4019          10 :                                         replace_len = 0;
    4020             :                                 }
    4021             :                         }
    4022             : 
    4023       55098 :                         if (ZSTR_LEN(search_str) == 1) {
    4024        2749 :                                 zend_long old_replace_count = replace_count;
    4025             : 
    4026        2749 :                                 tmp_result = php_char_to_str_ex(Z_STR_P(result),
    4027        2749 :                                                                 ZSTR_VAL(search_str)[0],
    4028             :                                                                 replace_value,
    4029             :                                                                 replace_len,
    4030             :                                                                 case_sensitivity,
    4031             :                                                                 &replace_count);
    4032        2749 :                                 if (lc_subject_str && replace_count != old_replace_count) {
    4033             :                                         zend_string_release(lc_subject_str);
    4034           3 :                                         lc_subject_str = NULL;
    4035             :                                 }
    4036       52349 :                         } else if (ZSTR_LEN(search_str) > 1) {
    4037       52349 :                                 if (case_sensitivity) {
    4038       52333 :                                         tmp_result = php_str_to_str_ex(Z_STR_P(result),
    4039             :                                                         ZSTR_VAL(search_str), ZSTR_LEN(search_str),
    4040             :                                                         replace_value, replace_len, &replace_count);
    4041             :                                 } else {
    4042          16 :                                         zend_long old_replace_count = replace_count;
    4043             : 
    4044          16 :                                         if (!lc_subject_str) {
    4045          16 :                                                 lc_subject_str = php_string_tolower(Z_STR_P(result));
    4046             :                                         }
    4047          16 :                                         tmp_result = php_str_to_str_i_ex(Z_STR_P(result), ZSTR_VAL(lc_subject_str),
    4048             :                                                         search_str, replace_value, replace_len, &replace_count);
    4049          16 :                                         if (replace_count != old_replace_count) {
    4050             :                                                 zend_string_release(lc_subject_str);
    4051           9 :                                                 lc_subject_str = NULL;
    4052             :                                         }
    4053             :                                 }                               
    4054             :                         }
    4055             : 
    4056             :                         zend_string_release(search_str);
    4057             : 
    4058       55098 :                         if (replace_entry_str) {
    4059             :                                 zend_string_release(replace_entry_str);
    4060          65 :                                 replace_entry_str = NULL;
    4061             :                         }
    4062       55098 :                         zend_string_release(Z_STR_P(result));
    4063       55098 :                         ZVAL_STR(result, tmp_result);
    4064             : 
    4065       55098 :                         if (Z_STRLEN_P(result) == 0) {
    4066           2 :                                 if (lc_subject_str) {
    4067             :                                         zend_string_release(lc_subject_str);
    4068             :                                 }
    4069             :                                 zend_string_release(subject_str);
    4070           2 :                                 return replace_count;
    4071             :                         }
    4072             :                 } ZEND_HASH_FOREACH_END();
    4073       36275 :                 if (lc_subject_str) {
    4074             :                         zend_string_release(lc_subject_str);
    4075             :                 }
    4076             :         } else {
    4077             :                 ZEND_ASSERT(Z_TYPE_P(search) == IS_STRING);
    4078      132934 :                 if (Z_STRLEN_P(search) == 1) {
    4079        3745 :                         ZVAL_STR(result,
    4080             :                                 php_char_to_str_ex(subject_str,
    4081             :                                                         Z_STRVAL_P(search)[0],
    4082             :                                                         Z_STRVAL_P(replace),
    4083             :                                                         Z_STRLEN_P(replace),
    4084             :                                                         case_sensitivity,
    4085             :                                                         &replace_count));
    4086      129189 :                 } else if (Z_STRLEN_P(search) > 1) {
    4087      129135 :                         if (case_sensitivity) {
    4088      129045 :                                 ZVAL_STR(result, php_str_to_str_ex(subject_str,
    4089             :                                                 Z_STRVAL_P(search), Z_STRLEN_P(search),
    4090             :                                                 Z_STRVAL_P(replace), Z_STRLEN_P(replace), &replace_count));
    4091             :                         } else {
    4092          90 :                                 lc_subject_str = php_string_tolower(subject_str);
    4093          90 :                                 ZVAL_STR(result, php_str_to_str_i_ex(subject_str, ZSTR_VAL(lc_subject_str),
    4094             :                                                 Z_STR_P(search),
    4095             :                                                 Z_STRVAL_P(replace), Z_STRLEN_P(replace), &replace_count));
    4096             :                                 zend_string_release(lc_subject_str);
    4097             :                         }
    4098             :                 } else {
    4099          54 :                         ZVAL_STR_COPY(result, subject_str);
    4100             :                 }
    4101             :         }
    4102             :         zend_string_release(subject_str);
    4103      169209 :         return replace_count;
    4104             : }
    4105             : /* }}} */
    4106             : 
    4107             : /* {{{ php_str_replace_common
    4108             :  */
    4109      169054 : static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
    4110             : {
    4111      169054 :         zval *subject, *search, *replace, *subject_entry, *zcount = NULL;
    4112             :         zval result;
    4113             :         zend_string *string_key;
    4114             :         zend_ulong num_key;
    4115      169054 :         zend_long count = 0;
    4116      169054 :         int argc = ZEND_NUM_ARGS();
    4117             : 
    4118             : #ifndef FAST_ZPP
    4119             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "zzz|z/", &search, &replace, &subject, &zcount) == FAILURE) {
    4120             :                 return;
    4121             :         }
    4122             : #else
    4123      169054 :         ZEND_PARSE_PARAMETERS_START(3, 4)
    4124      169039 :                 Z_PARAM_ZVAL(search)
    4125      169039 :                 Z_PARAM_ZVAL(replace)
    4126      169039 :                 Z_PARAM_ZVAL(subject)
    4127      169039 :                 Z_PARAM_OPTIONAL
    4128      169175 :                 Z_PARAM_ZVAL_EX(zcount, 0, 1)
    4129      169054 :         ZEND_PARSE_PARAMETERS_END();
    4130             : #endif
    4131             : 
    4132             :         /* Make sure we're dealing with strings and do the replacement. */
    4133      338078 :         if (Z_TYPE_P(search) != IS_ARRAY) {
    4134      265592 :                 convert_to_string_ex(search);
    4135      265562 :                 if (Z_TYPE_P(replace) != IS_STRING) {
    4136          24 :                         convert_to_string_ex(replace);
    4137             :                 }
    4138       72516 :         } else if (Z_TYPE_P(replace) != IS_ARRAY) {
    4139       72474 :                 convert_to_string_ex(replace);
    4140             :         }
    4141             : 
    4142             :         /* if subject is an array */
    4143      338078 :         if (Z_TYPE_P(subject) == IS_ARRAY) {
    4144          46 :                 array_init(return_value);
    4145             : 
    4146             :                 /* For each subject entry, convert it to string, then perform replacement
    4147             :                    and add the result to the return_value array. */
    4148         736 :                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(subject), num_key, string_key, subject_entry) {
    4149         979 :                         if (Z_TYPE_P(subject_entry) != IS_ARRAY && Z_TYPE_P(subject_entry) != IS_OBJECT) {
    4150         317 :                                 count += php_str_replace_in_subject(search, replace, subject_entry, &result, case_sensitivity);
    4151             :                         } else {
    4152          28 :                                 ZVAL_COPY(&result, subject_entry);
    4153             :                         }
    4154             :                         /* Add to return array */
    4155         345 :                         if (string_key) {
    4156           4 :                                 zend_hash_add_new(Z_ARRVAL_P(return_value), string_key, &result);
    4157             :                         } else {
    4158         341 :                                 zend_hash_index_add_new(Z_ARRVAL_P(return_value), num_key, &result);
    4159             :                         }
    4160             :                 } ZEND_HASH_FOREACH_END();
    4161             :         } else {        /* if subject is not an array */
    4162      168993 :                 count = php_str_replace_in_subject(search, replace, subject, return_value, case_sensitivity);
    4163             :         }
    4164      169039 :         if (argc > 3) {
    4165         135 :                 zval_ptr_dtor(zcount);
    4166         135 :                 ZVAL_LONG(zcount, count);
    4167             :         }
    4168             : }
    4169             : /* }}} */
    4170             : 
    4171             : /* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count])
    4172             :    Replaces all occurrences of search in haystack with replace */
    4173      168949 : PHP_FUNCTION(str_replace)
    4174             : {
    4175      168949 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4176      168949 : }
    4177             : /* }}} */
    4178             : 
    4179             : /* {{{ proto mixed str_ireplace(mixed search, mixed replace, mixed subject [, int &replace_count])
    4180             :    Replaces all occurrences of search in haystack with replace / case-insensitive */
    4181         105 : PHP_FUNCTION(str_ireplace)
    4182             : {
    4183         105 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4184         105 : }
    4185             : /* }}} */
    4186             : 
    4187             : /* {{{ php_hebrev
    4188             :  *
    4189             :  * Converts Logical Hebrew text (Hebrew Windows style) to Visual text
    4190             :  * Cheers/complaints/flames - Zeev Suraski <zeev@php.net>
    4191             :  */
    4192         116 : static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
    4193             : {
    4194             :         char *str;
    4195             :         char *heb_str, *tmp, *target;
    4196             :         size_t block_start, block_end, block_type, block_length, i;
    4197         116 :         zend_long max_chars=0;
    4198             :         size_t begin, end, char_count, orig_begin;
    4199             :         size_t str_len;
    4200             :         zend_string *broken_str;
    4201             : 
    4202         116 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &max_chars) == FAILURE) {
    4203          26 :                 return;
    4204             :         }
    4205             : 
    4206          90 :         if (str_len == 0) {
    4207          12 :                 RETURN_FALSE;
    4208             :         }
    4209             : 
    4210          78 :         tmp = str;
    4211          78 :         block_start=block_end=0;
    4212             : 
    4213          78 :         heb_str = (char *) emalloc(str_len+1);
    4214          78 :         target = heb_str+str_len;
    4215          78 :         *target = 0;
    4216          78 :         target--;
    4217             : 
    4218          78 :         block_length=0;
    4219             : 
    4220          78 :         if (isheb(*tmp)) {
    4221           0 :                 block_type = _HEB_BLOCK_TYPE_HEB;
    4222             :         } else {
    4223          78 :                 block_type = _HEB_BLOCK_TYPE_ENG;
    4224             :         }
    4225             : 
    4226             :         do {
    4227         307 :                 if (block_type == _HEB_BLOCK_TYPE_HEB) {
    4228         696 :                         while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) {
    4229         414 :                                 tmp++;
    4230         414 :                                 block_end++;
    4231         414 :                                 block_length++;
    4232             :                         }
    4233         555 :                         for (i = block_start+1; i<= block_end+1; i++) {
    4234         414 :                                 *target = str[i-1];
    4235         414 :                                 switch (*target) {
    4236             :                                         case '(':
    4237          23 :                                                 *target = ')';
    4238          23 :                                                 break;
    4239             :                                         case ')':
    4240          23 :                                                 *target = '(';
    4241          23 :                                                 break;
    4242             :                                         case '[':
    4243           1 :                                                 *target = ']';
    4244           1 :                                                 break;
    4245             :                                         case ']':
    4246           1 :                                                 *target = '[';
    4247           1 :                                                 break;
    4248             :                                         case '{':
    4249           1 :                                                 *target = '}';
    4250           1 :                                                 break;
    4251             :                                         case '}':
    4252           1 :                                                 *target = '{';
    4253           1 :                                                 break;
    4254             :                                         case '<':
    4255           1 :                                                 *target = '>';
    4256           1 :                                                 break;
    4257             :                                         case '>':
    4258          23 :                                                 *target = '<';
    4259          23 :                                                 break;
    4260             :                                         case '\\':
    4261           1 :                                                 *target = '/';
    4262           1 :                                                 break;
    4263             :                                         case '/':
    4264           0 :                                                 *target = '\\';
    4265             :                                                 break;
    4266             :                                         default:
    4267             :                                                 break;
    4268             :                                 }
    4269         414 :                                 target--;
    4270             :                         }
    4271         141 :                         block_type = _HEB_BLOCK_TYPE_ENG;
    4272             :                 } else {
    4273        7419 :                         while (!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end < str_len-1) {
    4274        7087 :                                 tmp++;
    4275        7087 :                                 block_end++;
    4276        7087 :                                 block_length++;
    4277             :                         }
    4278         504 :                         while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
    4279         172 :                                 tmp--;
    4280         172 :                                 block_end--;
    4281             :                         }
    4282        7159 :                         for (i = block_end+1; i >= block_start+1; i--) {
    4283        6993 :                                 *target = str[i-1];
    4284        6993 :                                 target--;
    4285             :                         }
    4286         166 :                         block_type = _HEB_BLOCK_TYPE_HEB;
    4287             :                 }
    4288         307 :                 block_start=block_end+1;
    4289         307 :         } while (block_end < str_len-1);
    4290             : 
    4291             : 
    4292         156 :         broken_str = zend_string_alloc(str_len, 0);
    4293          78 :         begin = end = str_len-1;
    4294          78 :         target = ZSTR_VAL(broken_str);
    4295             : 
    4296             :         while (1) {
    4297        1412 :                 char_count=0;
    4298        8883 :                 while ((!max_chars || (max_chars > 0 && char_count < max_chars)) && begin > 0) {
    4299        6205 :                         char_count++;
    4300        6205 :                         begin--;
    4301        6205 :                         if (begin <= 0 || _isnewline(heb_str[begin])) {
    4302         292 :                                 while (begin > 0 && _isnewline(heb_str[begin-1])) {
    4303           0 :                                         begin--;
    4304           0 :                                         char_count++;
    4305             :                                 }
    4306         146 :                                 break;
    4307             :                         }
    4308             :                 }
    4309        1412 :                 if (max_chars >= 0 && char_count == max_chars) { /* try to avoid breaking words */
    4310         627 :                         size_t new_char_count=char_count, new_begin=begin;
    4311             : 
    4312        2037 :                         while (new_char_count > 0) {
    4313         939 :                                 if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
    4314             :                                         break;
    4315             :                                 }
    4316         783 :                                 new_begin++;
    4317         783 :                                 new_char_count--;
    4318             :                         }
    4319         627 :                         if (new_char_count > 0) {
    4320         156 :                                 begin=new_begin;
    4321             :                         }
    4322             :                 }
    4323        1412 :                 orig_begin=begin;
    4324             : 
    4325        1412 :                 if (_isblank(heb_str[begin])) {
    4326         239 :                         heb_str[begin]='\n';
    4327             :                 }
    4328        3203 :                 while (begin <= end && _isnewline(heb_str[begin])) { /* skip leading newlines */
    4329         379 :                         begin++;
    4330             :                 }
    4331        8440 :                 for (i = begin; i <= end; i++) { /* copy content */
    4332        7028 :                         *target = heb_str[i];
    4333        7028 :                         target++;
    4334             :                 }
    4335        1791 :                 for (i = orig_begin; i <= end && _isnewline(heb_str[i]); i++) {
    4336         379 :                         *target = heb_str[i];
    4337         379 :                         target++;
    4338             :                 }
    4339        1412 :                 begin=orig_begin;
    4340             : 
    4341        1412 :                 if (begin <= 0) {
    4342          78 :                         *target = 0;
    4343          78 :                         break;
    4344             :                 }
    4345        1334 :                 begin--;
    4346        1334 :                 end=begin;
    4347        1334 :         }
    4348          78 :         efree(heb_str);
    4349             : 
    4350          78 :         if (convert_newlines) {
    4351          34 :                 RETVAL_STR(php_char_to_str_ex(broken_str, '\n', "<br />\n", 7, 1, NULL));
    4352             :                 zend_string_release(broken_str);
    4353             :         } else {
    4354          44 :                 RETURN_NEW_STR(broken_str);
    4355             :         }
    4356             : }
    4357             : /* }}} */
    4358             : 
    4359             : /* {{{ proto string hebrev(string str [, int max_chars_per_line])
    4360             :    Converts logical Hebrew text to visual text */
    4361          63 : PHP_FUNCTION(hebrev)
    4362             : {
    4363          63 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4364          63 : }
    4365             : /* }}} */
    4366             : 
    4367             : /* {{{ proto string hebrevc(string str [, int max_chars_per_line])
    4368             :    Converts logical Hebrew text to visual text with newline conversion */
    4369          53 : PHP_FUNCTION(hebrevc)
    4370             : {
    4371          53 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4372          53 : }
    4373             : /* }}} */
    4374             : 
    4375             : /* {{{ proto string nl2br(string str [, bool is_xhtml])
    4376             :    Converts newlines to HTML line breaks */
    4377          60 : PHP_FUNCTION(nl2br)
    4378             : {
    4379             :         /* in brief this inserts <br /> or <br> before matched regexp \n\r?|\r\n? */
    4380             :         char    *tmp;
    4381             :         zend_string *str;
    4382             :         char    *end, *target;
    4383          60 :         size_t  repl_cnt = 0;
    4384          60 :         zend_bool       is_xhtml = 1;
    4385             :         zend_string *result;
    4386             : 
    4387             : #ifndef FAST_ZPP
    4388             :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|b", &str, &is_xhtml) == FAILURE) {
    4389             :                 return;
    4390             :         }
    4391             : #else
    4392          60 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    4393         174 :                 Z_PARAM_STR(str)
    4394          52 :                 Z_PARAM_OPTIONAL
    4395          52 :                 Z_PARAM_BOOL(is_xhtml)
    4396          60 :         ZEND_PARSE_PARAMETERS_END();
    4397             : #endif
    4398             : 
    4399          52 :         tmp = ZSTR_VAL(str);
    4400          52 :         end = ZSTR_VAL(str) + ZSTR_LEN(str);
    4401             : 
    4402             :         /* it is really faster to scan twice and allocate mem once instead of scanning once
    4403             :            and constantly reallocing */
    4404         513 :         while (tmp < end) {
    4405         409 :                 if (*tmp == '\r') {
    4406          33 :                         if (*(tmp+1) == '\n') {
    4407          14 :                                 tmp++;
    4408             :                         }
    4409          33 :                         repl_cnt++;
    4410         376 :                 } else if (*tmp == '\n') {
    4411          46 :                         if (*(tmp+1) == '\r') {
    4412          13 :                                 tmp++;
    4413             :                         }
    4414          46 :                         repl_cnt++;
    4415             :                 }
    4416             : 
    4417         409 :                 tmp++;
    4418             :         }
    4419             : 
    4420          52 :         if (repl_cnt == 0) {
    4421          29 :                 RETURN_STR_COPY(str);
    4422             :         }
    4423             : 
    4424             :         {
    4425          23 :                 size_t repl_len = is_xhtml ? (sizeof("<br />") - 1) : (sizeof("<br>") - 1);
    4426             : 
    4427          46 :                 result = zend_string_safe_alloc(repl_cnt, repl_len, ZSTR_LEN(str), 0);
    4428          23 :                 target = ZSTR_VAL(result);
    4429             :         }
    4430             : 
    4431          23 :         tmp = ZSTR_VAL(str);
    4432         303 :         while (tmp < end) {
    4433         257 :                 switch (*tmp) {
    4434             :                         case '\r':
    4435             :                         case '\n':
    4436          79 :                                 *target++ = '<';
    4437          79 :                                 *target++ = 'b';
    4438          79 :                                 *target++ = 'r';
    4439             : 
    4440          79 :                                 if (is_xhtml) {
    4441          79 :                                         *target++ = ' ';
    4442          79 :                                         *target++ = '/';
    4443             :                                 }
    4444             : 
    4445          79 :                                 *target++ = '>';
    4446             : 
    4447          79 :                                 if ((*tmp == '\r' && *(tmp+1) == '\n') || (*tmp == '\n' && *(tmp+1) == '\r')) {
    4448          27 :                                         *target++ = *tmp++;
    4449             :                                 }
    4450             :                                 /* lack of a break; is intentional */
    4451             :                         default:
    4452         257 :                                 *target++ = *tmp;
    4453             :                 }
    4454             : 
    4455         257 :                 tmp++;
    4456             :         }
    4457             : 
    4458          23 :         *target = '\0';
    4459             : 
    4460          23 :         RETURN_NEW_STR(result);
    4461             : }
    4462             : /* }}} */
    4463             : 
    4464             : /* {{{ proto string strip_tags(string str [, string allowable_tags])
    4465             :    Strips HTML and PHP tags from a string */
    4466         207 : PHP_FUNCTION(strip_tags)
    4467             : {
    4468             :         zend_string *buf;
    4469             :         zend_string *str;
    4470         207 :         zval *allow=NULL;
    4471         207 :         char *allowed_tags=NULL;
    4472         207 :         size_t allowed_tags_len=0;
    4473             : 
    4474         207 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &str, &allow) == FAILURE) {
    4475          14 :                 return;
    4476             :         }
    4477             : 
    4478             :         /* To maintain a certain BC, we allow anything for the second parameter and return original string */
    4479         193 :         if (allow) {
    4480         226 :                 convert_to_string(allow);
    4481         113 :                 allowed_tags = Z_STRVAL_P(allow);
    4482         113 :                 allowed_tags_len = Z_STRLEN_P(allow);
    4483             :         }
    4484             : 
    4485         386 :         buf = zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 0);
    4486         193 :         ZSTR_LEN(buf) = php_strip_tags_ex(ZSTR_VAL(buf), ZSTR_LEN(str), NULL, allowed_tags, allowed_tags_len, 0);
    4487         193 :         RETURN_NEW_STR(buf);
    4488             : }
    4489             : /* }}} */
    4490             : 
    4491             : /* {{{ proto string setlocale(mixed category, string locale [, string ...])
    4492             :    Set locale information */
    4493        1016 : PHP_FUNCTION(setlocale)
    4494             : {
    4495        1016 :         zval *args = NULL;
    4496             :         zval *plocale;
    4497             :         zend_string *loc;
    4498             :         char *retval;
    4499             :         zend_long cat;
    4500        1016 :         int num_args, i = 0;
    4501             :         uint32_t idx;
    4502             : 
    4503        1016 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "l+", &cat, &args, &num_args) == FAILURE) {
    4504           2 :                 return;
    4505             :         }
    4506             : 
    4507             : #ifdef HAVE_SETLOCALE
    4508        1014 :         idx = 0;
    4509             :         while (1) {
    4510        2066 :                 if (Z_TYPE(args[0]) == IS_ARRAY) {
    4511          10 :                         while (idx < Z_ARRVAL(args[0])->nNumUsed) {
    4512           4 :                                 plocale = &Z_ARRVAL(args[0])->arData[idx].val;
    4513           4 :                                 if (Z_TYPE_P(plocale) != IS_UNDEF) {
    4514           4 :                                         break;
    4515             :                                 }
    4516           0 :                                 idx++;
    4517             :                         }
    4518           5 :                         if (idx >= Z_ARRVAL(args[0])->nNumUsed) {
    4519           1 :                                 break;
    4520             :                         }
    4521             :                 } else {
    4522        1028 :                         plocale = &args[i];
    4523             :                 }
    4524             : 
    4525        1032 :                 loc = zval_get_string(plocale);
    4526             : 
    4527        1032 :                 if (!strcmp("0", ZSTR_VAL(loc))) {
    4528             :                         zend_string_release(loc);
    4529           8 :                         loc = NULL;
    4530             :                 } else {
    4531        1024 :                         if (ZSTR_LEN(loc) >= 255) {
    4532           1 :                                 php_error_docref(NULL, E_WARNING, "Specified locale name is too long");
    4533             :                                 zend_string_release(loc);
    4534           1 :                                 break;
    4535             :                         }
    4536             :                 }
    4537             : 
    4538        1031 :                 retval = php_my_setlocale(cat, loc ? ZSTR_VAL(loc) : NULL);
    4539             :                 zend_update_current_locale();
    4540        1031 :                 if (retval) {
    4541        1011 :                         if (loc) {
    4542             :                                 /* Remember if locale was changed */
    4543        1003 :                                 size_t len = strlen(retval);
    4544             : 
    4545        1003 :                                 BG(locale_changed) = 1;
    4546        1003 :                                 if (cat == LC_CTYPE || cat == LC_ALL) {
    4547         986 :                                         if (BG(locale_string)) {
    4548         815 :                                                 zend_string_release(BG(locale_string));
    4549             :                                         }
    4550         986 :                                         if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
    4551         980 :                                                 BG(locale_string) = zend_string_copy(loc);
    4552         980 :                                                 RETURN_STR(BG(locale_string));
    4553             :                                         } else {
    4554           6 :                                                 BG(locale_string) = zend_string_init(retval, len, 0);
    4555             :                                                 zend_string_release(loc);
    4556           6 :                                                 RETURN_STR_COPY(BG(locale_string));
    4557             :                                         }
    4558          17 :                                 } else if (len == ZSTR_LEN(loc) && !memcmp(ZSTR_VAL(loc), retval, len)) {
    4559          15 :                                         RETURN_STR(loc);
    4560             :                                 }
    4561             :                                 zend_string_release(loc);
    4562             :                         }
    4563          20 :                         RETURN_STRING(retval);
    4564             :                 }
    4565          20 :                 if (loc) {
    4566             :                         zend_string_release(loc);
    4567             :                 }
    4568             : 
    4569          40 :                 if (Z_TYPE(args[0]) == IS_ARRAY) {
    4570           3 :                         idx++;
    4571             :                 } else {
    4572          17 :                         if (++i >= num_args) break;
    4573             :                 }
    4574          19 :         }
    4575             : 
    4576             : #endif
    4577           3 :         RETURN_FALSE;
    4578             : }
    4579             : /* }}} */
    4580             : 
    4581             : /* {{{ proto void parse_str(string encoded_string [, array result])
    4582             :    Parses GET/POST/COOKIE data and sets global variables */
    4583          30 : PHP_FUNCTION(parse_str)
    4584             : {
    4585             :         char *arg;
    4586          30 :         zval *arrayArg = NULL;
    4587          30 :         char *res = NULL;
    4588             :         size_t arglen;
    4589             : 
    4590          30 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|z/", &arg, &arglen, &arrayArg) == FAILURE) {
    4591           2 :                 return;
    4592             :         }
    4593             : 
    4594          28 :         res = estrndup(arg, arglen);
    4595             : 
    4596          28 :         if (arrayArg == NULL) {
    4597             :                 zval tmp;
    4598          14 :                 zend_array *symbol_table = zend_rebuild_symbol_table();
    4599             : 
    4600          14 :                 ZVAL_ARR(&tmp, symbol_table);
    4601          14 :                 sapi_module.treat_data(PARSE_STRING, res, &tmp);
    4602             :         } else  {
    4603             :                 zval ret;
    4604             : 
    4605             :                 /* Clear out the array that was passed in. */
    4606          14 :                 zval_dtor(arrayArg);
    4607          14 :                 array_init(&ret);
    4608          14 :                 sapi_module.treat_data(PARSE_STRING, res, &ret);
    4609          14 :                 ZVAL_COPY_VALUE(arrayArg, &ret);
    4610             :         }
    4611             : }
    4612             : /* }}} */
    4613             : 
    4614             : #define PHP_TAG_BUF_SIZE 1023
    4615             : 
    4616             : /* {{{ php_tag_find
    4617             :  *
    4618             :  * Check if tag is in a set of tags
    4619             :  *
    4620             :  * states:
    4621             :  *
    4622             :  * 0 start tag
    4623             :  * 1 first non-whitespace char seen
    4624             :  */
    4625         567 : int php_tag_find(char *tag, size_t len, const char *set) {
    4626             :         char c, *n, *t;
    4627         567 :         int state=0, done=0;
    4628             :         char *norm;
    4629             : 
    4630         567 :         if (len <= 0) {
    4631           0 :                 return 0;
    4632             :         }
    4633             : 
    4634         567 :         norm = emalloc(len+1);
    4635             : 
    4636         567 :         n = norm;
    4637         567 :         t = tag;
    4638         567 :         c = tolower(*t);
    4639             :         /*
    4640             :            normalize the tag removing leading and trailing whitespace
    4641             :            and turn any <a whatever...> into just <a> and any </tag>
    4642             :            into <tag>
    4643             :         */
    4644        3954 :         while (!done) {
    4645        2820 :                 switch (c) {
    4646             :                         case '<':
    4647         566 :                                 *(n++) = c;
    4648         566 :                                 break;
    4649             :                         case '>':
    4650         536 :                                 done =1;
    4651         536 :                                 break;
    4652             :                         default:
    4653        1718 :                                 if (!isspace((int)c)) {
    4654        1685 :                                         if (state == 0) {
    4655         566 :                                                 state=1;
    4656             :                                         }
    4657        1685 :                                         if (c != '/') {
    4658        1418 :                                                 *(n++) = c;
    4659             :                                         }
    4660             :                                 } else {
    4661          33 :                                         if (state == 1)
    4662          31 :                                                 done=1;
    4663             :                                 }
    4664             :                                 break;
    4665             :                 }
    4666        2820 :                 c = tolower(*(++t));
    4667             :         }
    4668         567 :         *(n++) = '>';
    4669         567 :         *n = '\0';
    4670         567 :         if (strstr(set, norm)) {
    4671         152 :                 done=1;
    4672             :         } else {
    4673         415 :                 done=0;
    4674             :         }
    4675         567 :         efree(norm);
    4676         567 :         return done;
    4677             : }
    4678             : /* }}} */
    4679             : 
    4680         237 : PHPAPI size_t php_strip_tags(char *rbuf, size_t len, int *stateptr, const char *allow, size_t allow_len) /* {{{ */
    4681             : {
    4682         237 :         return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0);
    4683             : }
    4684             : /* }}} */
    4685             : 
    4686             : /* {{{ php_strip_tags
    4687             : 
    4688             :         A simple little state-machine to strip out html and php tags
    4689             : 
    4690             :         State 0 is the output state, State 1 means we are inside a
    4691             :         normal html tag and state 2 means we are inside a php tag.
    4692             : 
    4693             :         The state variable is passed in to allow a function like fgetss
    4694             :         to maintain state across calls to the function.
    4695             : 
    4696             :         lc holds the last significant character read and br is a bracket
    4697             :         counter.
    4698             : 
    4699             :         When an allow string is passed in we keep track of the string
    4700             :         in state 1 and when the tag is closed check it against the
    4701             :         allow string to see if we should allow it.
    4702             : 
    4703             :         swm: Added ability to strip <?xml tags without assuming it PHP
    4704             :         code.
    4705             : */
    4706         742 : 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)
    4707             : {
    4708             :         char *tbuf, *buf, *p, *tp, *rp, c, lc;
    4709         742 :         int br, depth=0, in_q = 0;
    4710         742 :         int state = 0;
    4711         742 :         size_t pos, i = 0;
    4712         742 :         char *allow_free = NULL;
    4713             :         const char *allow_actual;
    4714         742 :         char is_xml = 0;
    4715             : 
    4716         742 :         if (stateptr)
    4717         237 :                 state = *stateptr;
    4718             : 
    4719         742 :         buf = estrndup(rbuf, len);
    4720         742 :         c = *buf;
    4721         742 :         lc = '\0';
    4722         742 :         p = buf;
    4723         742 :         rp = rbuf;
    4724         742 :         br = 0;
    4725         742 :         if (allow) {
    4726         286 :                 allow_free = zend_str_tolower_dup_ex(allow, allow_len);
    4727         286 :                 allow_actual = allow_free ? allow_free : allow;
    4728         286 :                 tbuf = emalloc(PHP_TAG_BUF_SIZE + 1);
    4729         286 :                 tp = tbuf;
    4730             :         } else {
    4731         456 :                 tbuf = tp = NULL;
    4732             :         }
    4733             : 
    4734      136691 :         while (i < len) {
    4735      135207 :                 switch (c) {
    4736             :                         case '\0':
    4737           2 :                                 break;
    4738             :                         case '<':
    4739        1026 :                                 if (in_q) {
    4740           3 :                                         break;
    4741             :                                 }
    4742        1023 :                                 if (isspace(*(p + 1)) && !allow_tag_spaces) {
    4743           6 :                                         goto reg_char;
    4744             :                                 }
    4745        1017 :                                 if (state == 0) {
    4746         992 :                                         lc = '<';
    4747         992 :                                         state = 1;
    4748         992 :                                         if (allow) {
    4749         675 :                                                 if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4750           0 :                                                         pos = tp - tbuf;
    4751           0 :                                                         tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4752           0 :                                                         tp = tbuf + pos;
    4753             :                                                 }
    4754         675 :                                                 *(tp++) = '<';
    4755             :                                         }
    4756          25 :                                 } else if (state == 1) {
    4757          20 :                                         depth++;
    4758             :                                 }
    4759        1017 :                                 break;
    4760             : 
    4761             :                         case '(':
    4762         133 :                                 if (state == 2) {
    4763           3 :                                         if (lc != '"' && lc != '\'') {
    4764           3 :                                                 lc = '(';
    4765           3 :                                                 br++;
    4766             :                                         }
    4767         131 :                                 } else if (allow && state == 1) {
    4768           1 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4769           0 :                                                 pos = tp - tbuf;
    4770           0 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4771           0 :                                                 tp = tbuf + pos;
    4772             :                                         }
    4773           1 :                                         *(tp++) = c;
    4774         129 :                                 } else if (state == 0) {
    4775         128 :                                         *(rp++) = c;
    4776             :                                 }
    4777         133 :                                 break;
    4778             : 
    4779             :                         case ')':
    4780         133 :                                 if (state == 2) {
    4781           3 :                                         if (lc != '"' && lc != '\'') {
    4782           3 :                                                 lc = ')';
    4783           3 :                                                 br--;
    4784             :                                         }
    4785         131 :                                 } else if (allow && state == 1) {
    4786           1 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4787           0 :                                                 pos = tp - tbuf;
    4788           0 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4789           0 :                                                 tp = tbuf + pos;
    4790             :                                         }
    4791           1 :                                         *(tp++) = c;
    4792         129 :                                 } else if (state == 0) {
    4793         128 :                                         *(rp++) = c;
    4794             :                                 }
    4795         133 :                                 break;
    4796             : 
    4797             :                         case '>':
    4798        4523 :                                 if (depth) {
    4799          20 :                                         depth--;
    4800          20 :                                         break;
    4801             :                                 }
    4802             : 
    4803        4503 :                                 if (in_q) {
    4804           4 :                                         break;
    4805             :                                 }
    4806             : 
    4807        4499 :                                 switch (state) {
    4808             :                                         case 1: /* HTML/XML */
    4809         850 :                                                 lc = '>';
    4810         850 :                                                 if (is_xml && *(p -1) == '-') {
    4811           0 :                                                         break;
    4812             :                                                 }
    4813         850 :                                                 in_q = state = is_xml = 0;
    4814         850 :                                                 if (allow) {
    4815         567 :                                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4816           1 :                                                                 pos = tp - tbuf;
    4817           1 :                                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4818           1 :                                                                 tp = tbuf + pos;
    4819             :                                                         }
    4820         567 :                                                         *(tp++) = '>';
    4821         567 :                                                         *tp='\0';
    4822         567 :                                                         if (php_tag_find(tbuf, tp-tbuf, allow_actual)) {
    4823         152 :                                                                 memcpy(rp, tbuf, tp-tbuf);
    4824         152 :                                                                 rp += tp-tbuf;
    4825             :                                                         }
    4826         567 :                                                         tp = tbuf;
    4827             :                                                 }
    4828         850 :                                                 break;
    4829             : 
    4830             :                                         case 2: /* PHP */
    4831         103 :                                                 if (!br && lc != '\"' && *(p-1) == '?') {
    4832          94 :                                                         in_q = state = 0;
    4833          94 :                                                         tp = tbuf;
    4834             :                                                 }
    4835         103 :                                                 break;
    4836             : 
    4837             :                                         case 3:
    4838           1 :                                                 in_q = state = 0;
    4839           1 :                                                 tp = tbuf;
    4840           1 :                                                 break;
    4841             : 
    4842             :                                         case 4: /* JavaScript/CSS/etc... */
    4843          37 :                                                 if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') {
    4844          36 :                                                         in_q = state = 0;
    4845          36 :                                                         tp = tbuf;
    4846             :                                                 }
    4847          37 :                                                 break;
    4848             : 
    4849             :                                         default:
    4850        3508 :                                                 *(rp++) = c;
    4851             :                                                 break;
    4852             :                                 }
    4853        4499 :                                 break;
    4854             : 
    4855             :                         case '"':
    4856             :                         case '\'':
    4857        1250 :                                 if (state == 4) {
    4858             :                                         /* Inside <!-- comment --> */
    4859           1 :                                         break;
    4860        1313 :                                 } else if (state == 2 && *(p-1) != '\\') {
    4861          64 :                                         if (lc == c) {
    4862          32 :                                                 lc = '\0';
    4863          32 :                                         } else if (lc != '\\') {
    4864          32 :                                                 lc = c;
    4865             :                                         }
    4866        1185 :                                 } else if (state == 0) {
    4867        1006 :                                         *(rp++) = c;
    4868         179 :                                 } else if (allow && state == 1) {
    4869          43 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4870           1 :                                                 pos = tp - tbuf;
    4871           1 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4872           1 :                                                 tp = tbuf + pos;
    4873             :                                         }
    4874          43 :                                         *(tp++) = c;
    4875             :                                 }
    4876        1249 :                                 if (state && p != buf && (state == 1 || *(p-1) != '\\') && (!in_q || *p == in_q)) {
    4877         238 :                                         if (in_q) {
    4878         118 :                                                 in_q = 0;
    4879             :                                         } else {
    4880         120 :                                                 in_q = *p;
    4881             :                                         }
    4882             :                                 }
    4883        1249 :                                 break;
    4884             : 
    4885             :                         case '!':
    4886             :                                 /* JavaScript & Other HTML scripting languages */
    4887         109 :                                 if (state == 1 && *(p-1) == '<') {
    4888          40 :                                         state = 3;
    4889          40 :                                         lc = c;
    4890             :                                 } else {
    4891          29 :                                         if (state == 0) {
    4892          20 :                                                 *(rp++) = c;
    4893           9 :                                         } else if (allow && state == 1) {
    4894           6 :                                                 if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4895           0 :                                                         pos = tp - tbuf;
    4896           0 :                                                         tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4897           0 :                                                         tp = tbuf + pos;
    4898             :                                                 }
    4899           6 :                                                 *(tp++) = c;
    4900             :                                         }
    4901             :                                 }
    4902          69 :                                 break;
    4903             : 
    4904             :                         case '-':
    4905        1263 :                                 if (state == 3 && p >= buf + 2 && *(p-1) == '-' && *(p-2) == '!') {
    4906          36 :                                         state = 4;
    4907             :                                 } else {
    4908             :                                         goto reg_char;
    4909             :                                 }
    4910          36 :                                 break;
    4911             : 
    4912             :                         case '?':
    4913             : 
    4914         210 :                                 if (state == 1 && *(p-1) == '<') {
    4915          97 :                                         br=0;
    4916          97 :                                         state=2;
    4917          97 :                                         break;
    4918             :                                 }
    4919             : 
    4920             :                         case 'E':
    4921             :                         case 'e':
    4922             :                                 /* !DOCTYPE exception */
    4923       10210 :                                 if (state==3 && p > buf+6
    4924           6 :                                                      && tolower(*(p-1)) == 'p'
    4925           6 :                                                  && tolower(*(p-2)) == 'y'
    4926           6 :                                                      && tolower(*(p-3)) == 't'
    4927           6 :                                                      && tolower(*(p-4)) == 'c'
    4928           6 :                                                      && tolower(*(p-5)) == 'o'
    4929           6 :                                                      && tolower(*(p-6)) == 'd') {
    4930           3 :                                         state = 1;
    4931           3 :                                         break;
    4932             :                                 }
    4933             :                                 /* fall-through */
    4934             : 
    4935             :                         case 'l':
    4936             :                         case 'L':
    4937             : 
    4938             :                                 /* swm: If we encounter '<?xml' then we shouldn't be in
    4939             :                                  * state == 2 (PHP). Switch back to HTML.
    4940             :                                  */
    4941             : 
    4942       15596 :                                 if (state == 2 && p > buf+4 && strncasecmp(p-4, "<?xm", 4) == 0) {
    4943           2 :                                         state = 1; is_xml=1;
    4944           2 :                                         break;
    4945             :                                 }
    4946             : 
    4947             :                                 /* fall-through */
    4948             :                         default:
    4949             : reg_char:
    4950      127939 :                                 if (state == 0) {
    4951      116729 :                                         *(rp++) = c;
    4952       11210 :                                 } else if (allow && state == 1) {
    4953        4175 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4954        1041 :                                                 pos = tp - tbuf;
    4955        1041 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4956        1041 :                                                 tp = tbuf + pos;
    4957             :                                         }
    4958        4175 :                                         *(tp++) = c;
    4959             :                                 }
    4960             :                                 break;
    4961             :                 }
    4962      135207 :                 c = *(++p);
    4963      135207 :                 i++;
    4964             :         }
    4965         742 :         if (rp < rbuf + len) {
    4966         274 :                 *rp = '\0';
    4967             :         }
    4968         742 :         efree(buf);
    4969         742 :         if (allow) {
    4970         286 :                 efree(tbuf);
    4971         286 :                 if (allow_free) {
    4972          10 :                         efree(allow_free);
    4973             :                 }
    4974             :         }
    4975         742 :         if (stateptr)
    4976         237 :                 *stateptr = state;
    4977             : 
    4978         742 :         return (size_t)(rp - rbuf);
    4979             : }
    4980             : /* }}} */
    4981             : 
    4982             : /* {{{ proto array str_getcsv(string input[, string delimiter[, string enclosure[, string escape]]])
    4983             : Parse a CSV string into an array */
    4984          16 : PHP_FUNCTION(str_getcsv)
    4985             : {
    4986             :         zend_string *str;
    4987          16 :         char delim = ',', enc = '"', esc = '\\';
    4988          16 :         char *delim_str = NULL, *enc_str = NULL, *esc_str = NULL;
    4989          16 :         size_t delim_len = 0, enc_len = 0, esc_len = 0;
    4990             : 
    4991          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|sss", &str, &delim_str, &delim_len,
    4992             :                 &enc_str, &enc_len, &esc_str, &esc_len) == FAILURE) {
    4993           0 :                 return;
    4994             :         }
    4995             : 
    4996          16 :         delim = delim_len ? delim_str[0] : delim;
    4997          16 :         enc = enc_len ? enc_str[0] : enc;
    4998          16 :         esc = esc_len ? esc_str[0] : esc;
    4999             : 
    5000          16 :         php_fgetcsv(NULL, delim, enc, esc, ZSTR_LEN(str), ZSTR_VAL(str), return_value);
    5001             : }
    5002             : /* }}} */
    5003             : 
    5004             : /* {{{ proto string str_repeat(string input, int mult)
    5005             :    Returns the input string repeat mult times */
    5006      174435 : PHP_FUNCTION(str_repeat)
    5007             : {
    5008             :         zend_string             *input_str;             /* Input string */
    5009             :         zend_long               mult;                   /* Multiplier */
    5010             :         zend_string     *result;                /* Resulting string */
    5011             :         size_t          result_len;             /* Length of the resulting string */
    5012             : 
    5013      174435 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl", &input_str, &mult) == FAILURE) {
    5014          80 :                 return;
    5015             :         }
    5016             : 
    5017      174355 :         if (mult < 0) {
    5018           1 :                 php_error_docref(NULL, E_WARNING, "Second argument has to be greater than or equal to 0");
    5019           1 :                 return;
    5020             :         }
    5021             : 
    5022             :         /* Don't waste our time if it's empty */
    5023             :         /* ... or if the multiplier is zero */
    5024      174354 :         if (ZSTR_LEN(input_str) == 0 || mult == 0)
    5025          52 :                 RETURN_EMPTY_STRING();
    5026             : 
    5027             :         /* Initialize the result string */
    5028      348604 :         result = zend_string_safe_alloc(ZSTR_LEN(input_str), mult, 0, 0);
    5029      174302 :         result_len = ZSTR_LEN(input_str) * mult;
    5030             : 
    5031             :         /* Heavy optimization for situations where input string is 1 byte long */
    5032      174302 :         if (ZSTR_LEN(input_str) == 1) {
    5033      160677 :                 memset(ZSTR_VAL(result), *ZSTR_VAL(input_str), mult);
    5034             :         } else {
    5035             :                 char *s, *e, *ee;
    5036       13625 :                 ptrdiff_t l=0;
    5037       13625 :                 memcpy(ZSTR_VAL(result), ZSTR_VAL(input_str), ZSTR_LEN(input_str));
    5038       13625 :                 s = ZSTR_VAL(result);
    5039       13625 :                 e = ZSTR_VAL(result) + ZSTR_LEN(input_str);
    5040       13625 :                 ee = ZSTR_VAL(result) + result_len;
    5041             : 
    5042       40431 :                 while (e<ee) {
    5043       13181 :                         l = (e-s) < (ee-e) ? (e-s) : (ee-e);
    5044       13181 :                         memmove(e, s, l);
    5045       13181 :                         e += l;
    5046             :                 }
    5047             :         }
    5048             : 
    5049      174302 :         ZSTR_VAL(result)[result_len] = '\0';
    5050             : 
    5051      174302 :         RETURN_NEW_STR(result);
    5052             : }
    5053             : /* }}} */
    5054             : 
    5055             : /* {{{ proto mixed count_chars(string input [, int mode])
    5056             :    Returns info about what characters are used in input */
    5057          60 : PHP_FUNCTION(count_chars)
    5058             : {
    5059             :         zend_string *input;
    5060             :         int chars[256];
    5061          60 :         zend_long mymode=0;
    5062             :         unsigned char *buf;
    5063             :         int inx;
    5064             :         char retstr[256];
    5065          60 :         size_t retlen=0;
    5066          60 :         size_t tmp = 0;
    5067             : 
    5068          60 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &input, &mymode) == FAILURE) {
    5069          11 :                 return;
    5070             :         }
    5071             : 
    5072          49 :         if (mymode < 0 || mymode > 4) {
    5073           7 :                 php_error_docref(NULL, E_WARNING, "Unknown mode");
    5074           7 :                 RETURN_FALSE;
    5075             :         }
    5076             : 
    5077          42 :         buf = (unsigned char *) ZSTR_VAL(input);
    5078          42 :         memset((void*) chars, 0, sizeof(chars));
    5079             : 
    5080        1462 :         while (tmp < ZSTR_LEN(input)) {
    5081        1378 :                 chars[*buf]++;
    5082        1378 :                 buf++;
    5083        1378 :                 tmp++;
    5084             :         }
    5085             : 
    5086          42 :         if (mymode < 3) {
    5087          38 :                 array_init(return_value);
    5088             :         }
    5089             : 
    5090       10794 :         for (inx = 0; inx < 256; inx++) {
    5091       10752 :                 switch (mymode) {
    5092             :                         case 0:
    5093        2816 :                                 add_index_long(return_value, inx, chars[inx]);
    5094        2816 :                                 break;
    5095             :                         case 1:
    5096        6400 :                                 if (chars[inx] != 0) {
    5097         180 :                                         add_index_long(return_value, inx, chars[inx]);
    5098             :                                 }
    5099        6400 :                                 break;
    5100             :                         case 2:
    5101         512 :                                 if (chars[inx] == 0) {
    5102         475 :                                         add_index_long(return_value, inx, chars[inx]);
    5103             :                                 }
    5104         512 :                                 break;
    5105             :                         case 3:
    5106         512 :                                 if (chars[inx] != 0) {
    5107          37 :                                         retstr[retlen++] = inx;
    5108             :                                 }
    5109         512 :                                 break;
    5110             :                         case 4:
    5111         512 :                                 if (chars[inx] == 0) {
    5112         475 :                                         retstr[retlen++] = inx;
    5113             :                                 }
    5114             :                                 break;
    5115             :                 }
    5116             :         }
    5117             : 
    5118          42 :         if (mymode >= 3 && mymode <= 4) {
    5119           8 :                 RETURN_STRINGL(retstr, retlen);
    5120             :         }
    5121             : }
    5122             : /* }}} */
    5123             : 
    5124             : /* {{{ php_strnatcmp
    5125             :  */
    5126          54 : static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
    5127             : {
    5128             :         zend_string *s1, *s2;
    5129             : 
    5130          54 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &s1, &s2) == FAILURE) {
    5131           4 :                 return;
    5132             :         }
    5133             : 
    5134          50 :         RETURN_LONG(strnatcmp_ex(ZSTR_VAL(s1), ZSTR_LEN(s1),
    5135             :                                                          ZSTR_VAL(s2), ZSTR_LEN(s2),
    5136             :                                                          fold_case));
    5137             : }
    5138             : /* }}} */
    5139             : 
    5140           0 : PHPAPI int string_natural_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */
    5141             : {
    5142           0 :         zend_string *str1 = zval_get_string(op1);
    5143           0 :         zend_string *str2 = zval_get_string(op2);
    5144             : 
    5145           0 :         ZVAL_LONG(result, strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), case_insensitive));
    5146             : 
    5147             :         zend_string_release(str1);
    5148             :         zend_string_release(str2);
    5149           0 :         return SUCCESS;
    5150             : }
    5151             : /* }}} */
    5152             : 
    5153           0 : PHPAPI int string_natural_case_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
    5154             : {
    5155           0 :         return string_natural_compare_function_ex(result, op1, op2, 1);
    5156             : }
    5157             : /* }}} */
    5158             : 
    5159           0 : PHPAPI int string_natural_compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
    5160             : {
    5161           0 :         return string_natural_compare_function_ex(result, op1, op2, 0);
    5162             : }
    5163             : /* }}} */
    5164             : 
    5165             : /* {{{ proto int strnatcmp(string s1, string s2)
    5166             :    Returns the result of string comparison using 'natural' algorithm */
    5167          33 : PHP_FUNCTION(strnatcmp)
    5168             : {
    5169          33 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    5170          33 : }
    5171             : /* }}} */
    5172             : 
    5173             : /* {{{ proto array localeconv(void)
    5174             :    Returns numeric formatting information based on the current locale */
    5175          11 : PHP_FUNCTION(localeconv)
    5176             : {
    5177             :         zval grouping, mon_grouping;
    5178             :         int len, i;
    5179             : 
    5180             :         /* We don't need no stinkin' parameters... */
    5181          11 :         if (zend_parse_parameters_none() == FAILURE) {
    5182           0 :                 return;
    5183             :         }
    5184             : 
    5185          11 :         array_init(return_value);
    5186          11 :         array_init(&grouping);
    5187          11 :         array_init(&mon_grouping);
    5188             : 
    5189             : #ifdef HAVE_LOCALECONV
    5190             :         {
    5191             :                 struct lconv currlocdata;
    5192             : 
    5193          11 :                 localeconv_r( &currlocdata );
    5194             : 
    5195             :                 /* Grab the grouping data out of the array */
    5196          11 :                 len = (int)strlen(currlocdata.grouping);
    5197             : 
    5198          33 :                 for (i = 0; i < len; i++) {
    5199          22 :                         add_index_long(&grouping, i, currlocdata.grouping[i]);
    5200             :                 }
    5201             : 
    5202             :                 /* Grab the monetary grouping data out of the array */
    5203          11 :                 len = (int)strlen(currlocdata.mon_grouping);
    5204             : 
    5205          31 :                 for (i = 0; i < len; i++) {
    5206          20 :                         add_index_long(&mon_grouping, i, currlocdata.mon_grouping[i]);
    5207             :                 }
    5208             : 
    5209          11 :                 add_assoc_string(return_value, "decimal_point",     currlocdata.decimal_point);
    5210          11 :                 add_assoc_string(return_value, "thousands_sep",     currlocdata.thousands_sep);
    5211          11 :                 add_assoc_string(return_value, "int_curr_symbol",   currlocdata.int_curr_symbol);
    5212          11 :                 add_assoc_string(return_value, "currency_symbol",   currlocdata.currency_symbol);
    5213          11 :                 add_assoc_string(return_value, "mon_decimal_point", currlocdata.mon_decimal_point);
    5214          11 :                 add_assoc_string(return_value, "mon_thousands_sep", currlocdata.mon_thousands_sep);
    5215          11 :                 add_assoc_string(return_value, "positive_sign",     currlocdata.positive_sign);
    5216          11 :                 add_assoc_string(return_value, "negative_sign",     currlocdata.negative_sign);
    5217          11 :                 add_assoc_long(  return_value, "int_frac_digits",   currlocdata.int_frac_digits);
    5218          11 :                 add_assoc_long(  return_value, "frac_digits",       currlocdata.frac_digits);
    5219          11 :                 add_assoc_long(  return_value, "p_cs_precedes",     currlocdata.p_cs_precedes);
    5220          11 :                 add_assoc_long(  return_value, "p_sep_by_space",    currlocdata.p_sep_by_space);
    5221          11 :                 add_assoc_long(  return_value, "n_cs_precedes",     currlocdata.n_cs_precedes);
    5222          11 :                 add_assoc_long(  return_value, "n_sep_by_space",    currlocdata.n_sep_by_space);
    5223          11 :                 add_assoc_long(  return_value, "p_sign_posn",       currlocdata.p_sign_posn);
    5224          11 :                 add_assoc_long(  return_value, "n_sign_posn",       currlocdata.n_sign_posn);
    5225             :         }
    5226             : #else
    5227             :         /* Ok, it doesn't look like we have locale info floating around, so I guess it
    5228             :            wouldn't hurt to just go ahead and return the POSIX locale information?  */
    5229             : 
    5230             :         add_index_long(&grouping, 0, -1);
    5231             :         add_index_long(&mon_grouping, 0, -1);
    5232             : 
    5233             :         add_assoc_string(return_value, "decimal_point",     "\x2E");
    5234             :         add_assoc_string(return_value, "thousands_sep",     "");
    5235             :         add_assoc_string(return_value, "int_curr_symbol",   "");
    5236             :         add_assoc_string(return_value, "currency_symbol",   "");
    5237             :         add_assoc_string(return_value, "mon_decimal_point", "\x2E");
    5238             :         add_assoc_string(return_value, "mon_thousands_sep", "");
    5239             :         add_assoc_string(return_value, "positive_sign",     "");
    5240             :         add_assoc_string(return_value, "negative_sign",     "");
    5241             :         add_assoc_long(  return_value, "int_frac_digits",   CHAR_MAX);
    5242             :         add_assoc_long(  return_value, "frac_digits",       CHAR_MAX);
    5243             :         add_assoc_long(  return_value, "p_cs_precedes",     CHAR_MAX);
    5244             :         add_assoc_long(  return_value, "p_sep_by_space",    CHAR_MAX);
    5245             :         add_assoc_long(  return_value, "n_cs_precedes",     CHAR_MAX);
    5246             :         add_assoc_long(  return_value, "n_sep_by_space",    CHAR_MAX);
    5247             :         add_assoc_long(  return_value, "p_sign_posn",       CHAR_MAX);
    5248             :         add_assoc_long(  return_value, "n_sign_posn",       CHAR_MAX);
    5249             : #endif
    5250             : 
    5251          11 :         zend_hash_str_update(Z_ARRVAL_P(return_value), "grouping", sizeof("grouping")-1, &grouping);
    5252          11 :         zend_hash_str_update(Z_ARRVAL_P(return_value), "mon_grouping", sizeof("mon_grouping")-1, &mon_grouping);
    5253             : }
    5254             : /* }}} */
    5255             : 
    5256             : /* {{{ proto int strnatcasecmp(string s1, string s2)
    5257             :    Returns the result of case-insensitive string comparison using 'natural' algorithm */
    5258          21 : PHP_FUNCTION(strnatcasecmp)
    5259             : {
    5260          21 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    5261          21 : }
    5262             : /* }}} */
    5263             : 
    5264             : /* {{{ proto int substr_count(string haystack, string needle [, int offset [, int length]])
    5265             :    Returns the number of times a substring occurs in the string */
    5266          47 : PHP_FUNCTION(substr_count)
    5267             : {
    5268             :         char *haystack, *needle;
    5269          47 :         zend_long offset = 0, length = 0;
    5270          47 :         int ac = ZEND_NUM_ARGS();
    5271          47 :         int count = 0;
    5272             :         size_t haystack_len, needle_len;
    5273             :         char *p, *endp, cmp;
    5274             : 
    5275          47 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|ll", &haystack, &haystack_len, &needle, &needle_len, &offset, &length) == FAILURE) {
    5276           6 :                 return;
    5277             :         }
    5278             : 
    5279          41 :         if (needle_len == 0) {
    5280           2 :                 php_error_docref(NULL, E_WARNING, "Empty substring");
    5281           2 :                 RETURN_FALSE;
    5282             :         }
    5283             : 
    5284          39 :         p = haystack;
    5285          39 :         endp = p + haystack_len;
    5286             : 
    5287          39 :         if (offset < 0) {
    5288           1 :                 php_error_docref(NULL, E_WARNING, "Offset should be greater than or equal to 0");
    5289           1 :                 RETURN_FALSE;
    5290             :         }
    5291             : 
    5292          38 :         if ((size_t)offset > haystack_len) {
    5293           4 :                 php_error_docref(NULL, E_WARNING, "Offset value " ZEND_LONG_FMT " exceeds string length", offset);
    5294           4 :                 RETURN_FALSE;
    5295             :         }
    5296          34 :         p += offset;
    5297             : 
    5298          34 :         if (ac == 4) {
    5299             : 
    5300           6 :                 if (length <= 0) {
    5301           1 :                         php_error_docref(NULL, E_WARNING, "Length should be greater than 0");
    5302           1 :                         RETURN_FALSE;
    5303             :                 }
    5304           5 :                 if (length > (haystack_len - offset)) {
    5305           1 :                         php_error_docref(NULL, E_WARNING, "Length value " ZEND_LONG_FMT " exceeds string length", length);
    5306           1 :                         RETURN_FALSE;
    5307             :                 }
    5308           4 :                 endp = p + length;
    5309             :         }
    5310             : 
    5311          32 :         if (needle_len == 1) {
    5312          19 :                 cmp = needle[0];
    5313             : 
    5314          56 :                 while ((p = memchr(p, cmp, endp - p))) {
    5315          18 :                         count++;
    5316          18 :                         p++;
    5317             :                 }
    5318             :         } else {
    5319        1107 :                 while ((p = (char*)php_memnstr(p, needle, needle_len, endp))) {
    5320         534 :                         p += needle_len;
    5321         534 :                         count++;
    5322             :                 }
    5323             :         }
    5324             : 
    5325          32 :         RETURN_LONG(count);
    5326             : }
    5327             : /* }}} */
    5328             : 
    5329             : /* {{{ proto string str_pad(string input, int pad_length [, string pad_string [, int pad_type]])
    5330             :    Returns input string padded on the left or right to specified length with pad_string */
    5331         586 : PHP_FUNCTION(str_pad)
    5332             : {
    5333             :         /* Input arguments */
    5334             :         zend_string *input;                             /* Input string */
    5335             :         zend_long pad_length;                   /* Length to pad to */
    5336             : 
    5337             :         /* Helper variables */
    5338             :         size_t num_pad_chars;           /* Number of padding characters (total - input size) */
    5339         586 :         char *pad_str = " "; /* Pointer to padding string */
    5340         586 :         size_t pad_str_len = 1;
    5341         586 :         zend_long   pad_type_val = STR_PAD_RIGHT; /* The padding type value */
    5342         586 :         size_t     i, left_pad=0, right_pad=0;
    5343         586 :         zend_string *result = NULL;     /* Resulting string */
    5344             : 
    5345         586 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sl|sl", &input, &pad_length, &pad_str, &pad_str_len, &pad_type_val) == FAILURE) {
    5346          23 :                 return;
    5347             :         }
    5348             : 
    5349             :         /* If resulting string turns out to be shorter than input string,
    5350             :            we simply copy the input and return. */
    5351         563 :         if (pad_length < 0  || (size_t)pad_length <= ZSTR_LEN(input)) {
    5352         278 :                 RETURN_STRINGL(ZSTR_VAL(input), ZSTR_LEN(input));
    5353             :         }
    5354             : 
    5355         424 :         if (pad_str_len == 0) {
    5356           8 :                 php_error_docref(NULL, E_WARNING, "Padding string cannot be empty");
    5357           8 :                 return;
    5358             :         }
    5359             : 
    5360         416 :         if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) {
    5361           7 :                 php_error_docref(NULL, E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH");
    5362           7 :                 return;
    5363             :         }
    5364             : 
    5365         409 :         num_pad_chars = pad_length - ZSTR_LEN(input);
    5366         409 :         if (num_pad_chars >= INT_MAX) {
    5367           0 :                 php_error_docref(NULL, E_WARNING, "Padding length is too long");
    5368           0 :                 return;
    5369             :         }
    5370             : 
    5371         818 :         result = zend_string_alloc(ZSTR_LEN(input) + num_pad_chars, 0);
    5372         409 :         ZSTR_LEN(result) = 0;
    5373             : 
    5374             :         /* We need to figure out the left/right padding lengths. */
    5375         409 :         switch (pad_type_val) {
    5376             :                 case STR_PAD_RIGHT:
    5377         326 :                         left_pad = 0;
    5378         326 :                         right_pad = num_pad_chars;
    5379         326 :                         break;
    5380             : 
    5381             :                 case STR_PAD_LEFT:
    5382          49 :                         left_pad = num_pad_chars;
    5383          49 :                         right_pad = 0;
    5384          49 :                         break;
    5385             : 
    5386             :                 case STR_PAD_BOTH:
    5387          34 :                         left_pad = num_pad_chars / 2;
    5388          34 :                         right_pad = num_pad_chars - left_pad;
    5389             :                         break;
    5390             :         }
    5391             : 
    5392             :         /* First we pad on the left. */
    5393         956 :         for (i = 0; i < left_pad; i++)
    5394         547 :                 ZSTR_VAL(result)[ZSTR_LEN(result)++] = pad_str[i % pad_str_len];
    5395             : 
    5396             :         /* Then we copy the input string. */
    5397         409 :         memcpy(ZSTR_VAL(result) + ZSTR_LEN(result), ZSTR_VAL(input), ZSTR_LEN(input));
    5398         409 :         ZSTR_LEN(result) += ZSTR_LEN(input);
    5399             : 
    5400             :         /* Finally, we pad on the right. */
    5401     6303132 :         for (i = 0; i < right_pad; i++)
    5402     6302723 :                 ZSTR_VAL(result)[ZSTR_LEN(result)++] = pad_str[i % pad_str_len];
    5403             : 
    5404         409 :         ZSTR_VAL(result)[ZSTR_LEN(result)] = '\0';
    5405             : 
    5406         409 :         RETURN_NEW_STR(result);
    5407             : }
    5408             : /* }}} */
    5409             : 
    5410             : /* {{{ proto mixed sscanf(string str, string format [, string ...])
    5411             :    Implements an ANSI C compatible sscanf */
    5412          81 : PHP_FUNCTION(sscanf)
    5413             : {
    5414          81 :         zval *args = NULL;
    5415             :         char *str, *format;
    5416             :         size_t str_len, format_len;
    5417          81 :         int result, num_args = 0;
    5418             : 
    5419          81 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss*", &str, &str_len, &format, &format_len,
    5420             :                 &args, &num_args) == FAILURE) {
    5421          10 :                 return;
    5422             :         }
    5423             : 
    5424          71 :         result = php_sscanf_internal(str, format, num_args, args, 0, return_value);
    5425             : 
    5426          71 :         if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
    5427           0 :                 WRONG_PARAM_COUNT;
    5428             :         }
    5429             : }
    5430             : /* }}} */
    5431             : 
    5432             : static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    5433             : static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
    5434             : 
    5435             : /* {{{ proto string str_rot13(string str)
    5436             :    Perform the rot13 transform on a string */
    5437          29 : PHP_FUNCTION(str_rot13)
    5438             : {
    5439             :         zend_string *arg;
    5440             : 
    5441          29 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
    5442           5 :                 return;
    5443             :         }
    5444             : 
    5445          24 :         if (ZSTR_LEN(arg) == 0) {
    5446           0 :                 RETURN_EMPTY_STRING();
    5447             :         } else {
    5448          24 :                 RETURN_STR(php_strtr_ex(arg, rot13_from, rot13_to, 52));
    5449             :         }
    5450             : }
    5451             : /* }}} */
    5452             : 
    5453       91009 : static void php_string_shuffle(char *str, zend_long len) /* {{{ */
    5454             : {
    5455             :         zend_long n_elems, rnd_idx, n_left;
    5456             :         char temp;
    5457             :         /* The implementation is stolen from array_data_shuffle       */
    5458             :         /* Thus the characteristics of the randomization are the same */
    5459       91009 :         n_elems = len;
    5460             : 
    5461       91009 :         if (n_elems <= 1) {
    5462           0 :                 return;
    5463             :         }
    5464             : 
    5465       91009 :         n_left = n_elems;
    5466             : 
    5467      455116 :         while (--n_left) {
    5468      273098 :                 rnd_idx = php_rand();
    5469      273098 :                 RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    5470      273098 :                 if (rnd_idx != n_left) {
    5471      174405 :                         temp = str[n_left];
    5472      174405 :                         str[n_left] = str[rnd_idx];
    5473      174405 :                         str[rnd_idx] = temp;
    5474             :                 }
    5475             :         }
    5476             : }
    5477             : /* }}} */
    5478             : 
    5479             : /* {{{ proto void str_shuffle(string str)
    5480             :    Shuffles string. One permutation of all possible is created */
    5481       91025 : PHP_FUNCTION(str_shuffle)
    5482             : {
    5483             :         zend_string *arg;
    5484             : 
    5485       91025 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
    5486           6 :                 return;
    5487             :         }
    5488             : 
    5489      182038 :         RETVAL_STRINGL(ZSTR_VAL(arg), ZSTR_LEN(arg));
    5490       91019 :         if (Z_STRLEN_P(return_value) > 1) {
    5491       91009 :                 php_string_shuffle(Z_STRVAL_P(return_value), (zend_long) Z_STRLEN_P(return_value));
    5492             :         }
    5493             : }
    5494             : /* }}} */
    5495             : 
    5496             : /* {{{ proto mixed str_word_count(string str, [int format [, string charlist]])
    5497             :         Counts the number of words inside a string. If format of 1 is specified,
    5498             :         then the function will return an array containing all the words
    5499             :         found inside the string. If format of 2 is specified, then the function
    5500             :         will return an associated array where the position of the word is the key
    5501             :         and the word itself is the value.
    5502             : 
    5503             :         For the purpose of this function, 'word' is defined as a locale dependent
    5504             :         string containing alphabetic characters, which also may contain, but not start
    5505             :         with "'" and "-" characters.
    5506             : */
    5507          35 : PHP_FUNCTION(str_word_count)
    5508             : {
    5509             :         zend_string *str;
    5510          35 :         char *char_list = NULL, *p, *e, *s, ch[256];
    5511          35 :         size_t char_list_len = 0, word_count = 0;
    5512          35 :         zend_long type = 0;
    5513             : 
    5514          35 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|ls", &str, &type, &char_list, &char_list_len) == FAILURE) {
    5515           8 :                 return;
    5516             :         }
    5517             : 
    5518          27 :         switch(type) {
    5519             :                 case 1:
    5520             :                 case 2:
    5521          15 :                         array_init(return_value);
    5522          15 :                         if (!ZSTR_LEN(str)) {
    5523           0 :                                 return;
    5524             :                         }
    5525          15 :                         break;
    5526             :                 case 0:
    5527           6 :                         if (!ZSTR_LEN(str)) {
    5528           1 :                                 RETURN_LONG(0);
    5529             :                         }
    5530             :                         /* nothing to be done */
    5531           5 :                         break;
    5532             :                 default:
    5533           6 :                         php_error_docref(NULL, E_WARNING, "Invalid format value " ZEND_LONG_FMT, type);
    5534           6 :                         RETURN_FALSE;
    5535             :         }
    5536             : 
    5537          20 :         if (char_list) {
    5538          15 :                 php_charmask((unsigned char *)char_list, char_list_len, ch);
    5539             :         }
    5540             : 
    5541          20 :         p = ZSTR_VAL(str);
    5542          20 :         e = ZSTR_VAL(str) + ZSTR_LEN(str);
    5543             : 
    5544             :         /* first character cannot be ' or -, unless explicitly allowed by the user */
    5545          20 :         if ((*p == '\'' && (!char_list || !ch['\''])) || (*p == '-' && (!char_list || !ch['-']))) {
    5546           2 :                 p++;
    5547             :         }
    5548             :         /* last character cannot be -, unless explicitly allowed by the user */
    5549          20 :         if (*(e - 1) == '-' && (!char_list || !ch['-'])) {
    5550           1 :                 e--;
    5551             :         }
    5552             : 
    5553         187 :         while (p < e) {
    5554         147 :                 s = p;
    5555         576 :                 while (p < e && (isalpha((unsigned char)*p) || (char_list && ch[(unsigned char)*p]) || *p == '\'' || *p == '-')) {
    5556         282 :                         p++;
    5557             :                 }
    5558         147 :                 if (p > s) {
    5559          93 :                         switch (type)
    5560             :                         {
    5561             :                                 case 1:
    5562          29 :                                         add_next_index_stringl(return_value, s, p - s);
    5563          29 :                                         break;
    5564             :                                 case 2:
    5565          35 :                                         add_index_stringl(return_value, (s - ZSTR_VAL(str)), s, p - s);
    5566          35 :                                         break;
    5567             :                                 default:
    5568          29 :                                         word_count++;
    5569             :                                         break;
    5570             :                         }
    5571             :                 }
    5572         147 :                 p++;
    5573             :         }
    5574             : 
    5575          20 :         if (!type) {
    5576           5 :                 RETURN_LONG(word_count);
    5577             :         }
    5578             : }
    5579             : 
    5580             : /* }}} */
    5581             : 
    5582             : #if HAVE_STRFMON
    5583             : /* {{{ proto string money_format(string format , float value)
    5584             :    Convert monetary value(s) to string */
    5585          71 : PHP_FUNCTION(money_format)
    5586             : {
    5587          71 :         size_t format_len = 0;
    5588             :         char *format, *p, *e;
    5589             :         double value;
    5590          71 :         zend_bool check = 0;
    5591             :         zend_string *str;
    5592             :         ssize_t res_len;
    5593             : 
    5594          71 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sd", &format, &format_len, &value) == FAILURE) {
    5595          17 :                 return;
    5596             :         }
    5597             : 
    5598          54 :         p = format;
    5599          54 :         e = p + format_len;
    5600         141 :         while ((p = memchr(p, '%', (e - p)))) {
    5601          34 :                 if (*(p + 1) == '%') {
    5602           0 :                         p += 2;
    5603          34 :                 } else if (!check) {
    5604          33 :                         check = 1;
    5605          33 :                         p++;
    5606             :                 } else {
    5607           1 :                         php_error_docref(NULL, E_WARNING, "Only a single %%i or %%n token can be used");
    5608           1 :                         RETURN_FALSE;
    5609             :                 }
    5610             :         }
    5611             : 
    5612         106 :         str = zend_string_safe_alloc(format_len, 1, 1024, 0);
    5613          53 :         if ((res_len = strfmon(ZSTR_VAL(str), ZSTR_LEN(str), format, value)) < 0) {
    5614             :                 zend_string_free(str);
    5615           0 :                 RETURN_FALSE;
    5616             :         }
    5617          53 :         ZSTR_LEN(str) = (size_t)res_len;
    5618          53 :         ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
    5619             : 
    5620         106 :         RETURN_NEW_STR(zend_string_truncate(str, ZSTR_LEN(str), 0));
    5621             : }
    5622             : /* }}} */
    5623             : #endif
    5624             : 
    5625             : /* {{{ proto array str_split(string str [, int split_length])
    5626             :    Convert a string to an array. If split_length is specified, break the string down into chunks each split_length characters long. */
    5627         190 : PHP_FUNCTION(str_split)
    5628             : {
    5629             :         zend_string *str;
    5630         190 :         zend_long split_length = 1;
    5631             :         char *p;
    5632             :         size_t n_reg_segments;
    5633             : 
    5634         190 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &str, &split_length) == FAILURE) {
    5635          19 :                 return;
    5636             :         }
    5637             : 
    5638         171 :         if (split_length <= 0) {
    5639          15 :                 php_error_docref(NULL, E_WARNING, "The length of each segment must be greater than zero");
    5640          15 :                 RETURN_FALSE;
    5641             :         }
    5642             : 
    5643             : 
    5644         156 :         if (0 == ZSTR_LEN(str) || (size_t)split_length >= ZSTR_LEN(str)) {
    5645          29 :                 array_init_size(return_value, 1);
    5646          29 :                 add_next_index_stringl(return_value, ZSTR_VAL(str), ZSTR_LEN(str));
    5647          29 :                 return;
    5648             :         }
    5649             : 
    5650         127 :         array_init_size(return_value, (uint32_t)(((ZSTR_LEN(str) - 1) / split_length) + 1));
    5651             : 
    5652         127 :         n_reg_segments = ZSTR_LEN(str) / split_length;
    5653         127 :         p = ZSTR_VAL(str);
    5654             : 
    5655       22191 :         while (n_reg_segments-- > 0) {
    5656       21937 :                 add_next_index_stringl(return_value, p, split_length);
    5657       21937 :                 p += split_length;
    5658             :         }
    5659             : 
    5660         127 :         if (p != (ZSTR_VAL(str) + ZSTR_LEN(str))) {
    5661          31 :                 add_next_index_stringl(return_value, p, (ZSTR_VAL(str) + ZSTR_LEN(str) - p));
    5662             :         }
    5663             : }
    5664             : /* }}} */
    5665             : 
    5666             : /* {{{ proto array strpbrk(string haystack, string char_list)
    5667             :    Search a string for any of a set of characters */
    5668          20 : PHP_FUNCTION(strpbrk)
    5669             : {
    5670             :         zend_string *haystack, *char_list;
    5671             :         char *haystack_ptr, *cl_ptr;
    5672             : 
    5673          20 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &haystack, &char_list) == FAILURE) {
    5674           4 :                 RETURN_FALSE;
    5675             :         }
    5676             : 
    5677          16 :         if (!ZSTR_LEN(char_list)) {
    5678           1 :                 php_error_docref(NULL, E_WARNING, "The character list cannot be empty");
    5679           1 :                 RETURN_FALSE;
    5680             :         }
    5681             : 
    5682          96 :         for (haystack_ptr = ZSTR_VAL(haystack); haystack_ptr < (ZSTR_VAL(haystack) + ZSTR_LEN(haystack)); ++haystack_ptr) {
    5683         228 :                 for (cl_ptr = ZSTR_VAL(char_list); cl_ptr < (ZSTR_VAL(char_list) + ZSTR_LEN(char_list)); ++cl_ptr) {
    5684         147 :                         if (*cl_ptr == *haystack_ptr) {
    5685          20 :                                 RETURN_STRINGL(haystack_ptr, (ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - haystack_ptr));
    5686             :                         }
    5687             :                 }
    5688             :         }
    5689             : 
    5690           5 :         RETURN_FALSE;
    5691             : }
    5692             : /* }}} */
    5693             : 
    5694             : /* {{{ proto int substr_compare(string main_str, string str, int offset [, int length [, bool case_sensitivity]])
    5695             :    Binary safe optionally case insensitive comparison of 2 strings from an offset, up to length characters */
    5696          50 : PHP_FUNCTION(substr_compare)
    5697             : {
    5698             :         zend_string *s1, *s2;
    5699          50 :         zend_long offset, len=0;
    5700          50 :         zend_bool cs=0;
    5701             :         size_t cmp_len;
    5702             : 
    5703          50 :         if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSl|lb", &s1, &s2, &offset, &len, &cs) == FAILURE) {
    5704           2 :                 RETURN_FALSE;
    5705             :         }
    5706             : 
    5707          48 :         if (ZEND_NUM_ARGS() >= 4 && len <= 0) {
    5708           4 :                 if (len == 0) {
    5709           2 :                         RETURN_LONG(0L);
    5710             :                 } else {
    5711           2 :                         php_error_docref(NULL, E_WARNING, "The length must be greater than or equal to zero");
    5712           2 :                         RETURN_FALSE;
    5713             :                 }
    5714             :         }
    5715             : 
    5716          44 :         if (offset < 0) {
    5717           2 :                 offset = ZSTR_LEN(s1) + offset;
    5718           2 :                 offset = (offset < 0) ? 0 : offset;
    5719             :         }
    5720             : 
    5721          44 :         if ((size_t)offset >= ZSTR_LEN(s1)) {
    5722           2 :                 php_error_docref(NULL, E_WARNING, "The start position cannot exceed initial string length");
    5723           2 :                 RETURN_FALSE;
    5724             :         }
    5725             : 
    5726          42 :         cmp_len = (size_t) (len ? len : MAX(ZSTR_LEN(s2), (ZSTR_LEN(s1) - offset)));
    5727             : 
    5728          42 :         if (!cs) {
    5729          41 :                 RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1) + offset, (ZSTR_LEN(s1) - offset), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len));
    5730             :         } else {
    5731           1 :                 RETURN_LONG(zend_binary_strncasecmp_l(ZSTR_VAL(s1) + offset, (ZSTR_LEN(s1) - offset), ZSTR_VAL(s2), ZSTR_LEN(s2), cmp_len));
    5732             :         }
    5733             : }
    5734             : /* }}} */
    5735             : 
    5736             : /*
    5737             :  * Local variables:
    5738             :  * tab-width: 4
    5739             :  * c-basic-offset: 4
    5740             :  * End:
    5741             :  * vim600: noet sw=4 ts=4 fdm=marker
    5742             :  * vim<600: noet sw=4 ts=4
    5743             :  */

Generated by: LCOV version 1.10

Generated at Sat, 25 Jun 2016 07:09:07 +0000 (3 days ago)

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