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: 2422 2555 94.8 %
Date: 2015-01-26 Functions: 115 115 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 26 Jan 2015 14:46:55 +0000 (4 days ago)

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