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

Generated by: LCOV version 1.10

Generated at Sun, 20 Apr 2014 03:52:18 +0000 (4 days ago)

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