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

Generated by: LCOV version 1.10

Generated at Fri, 31 Jul 2015 08:58:59 +0000 (35 hours ago)

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