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

Generated by: LCOV version 1.10

Generated at Sun, 18 Sep 2016 08:20:18 +0000 (6 days ago)

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