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

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:26 +0000 (5 days ago)

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