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

Generated by: LCOV version 1.10

Generated at Thu, 21 May 2015 19:59:05 +0000 (7 days ago)

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