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

Generated by: LCOV version 1.10

Generated at Sat, 27 Sep 2014 16:43:19 +0000 (4 days ago)

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