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

Generated by: LCOV version 1.10

Generated at Wed, 22 Oct 2014 07:24:59 +0000 (2 days ago)

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