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: 2403 2553 94.1 %
Date: 2014-07-21 Functions: 118 119 99.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Tue, 22 Jul 2014 01:33:20 +0000 (3 days ago)

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