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: 2303 2427 94.9 %
Date: 2014-12-13 Functions: 111 112 99.1 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 13 Dec 2014 06:16:23 +0000 (9 days ago)

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