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: 2442 2581 94.6 %
Date: 2015-03-28 Functions: 115 115 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 29 Mar 2015 03:46:00 +0000 (2 days ago)

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