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: 2429 2579 94.2 %
Date: 2014-12-15 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       20225 : void register_string_constants(INIT_FUNC_ARGS)
      88             : {
      89       20225 :         REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
      90       20225 :         REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
      91       20225 :         REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
      92       20225 :         REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
      93       20225 :         REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
      94       20225 :         REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
      95       20225 :         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       20225 :         REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
     106             : #endif
     107             : 
     108             : #ifdef HAVE_LOCALE_H
     109       20225 :         REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT);
     110       20225 :         REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT);
     111       20225 :         REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT);
     112       20225 :         REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT);
     113       20225 :         REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT);
     114       20225 :         REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT);
     115             : # ifdef LC_MESSAGES
     116       20225 :         REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
     117             : # endif
     118             : #endif
     119             : 
     120       20225 : }
     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       20225 : 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       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
     369       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
     370       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
     371       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
     372       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
     373       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
     374       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
     375             : #endif
     376             : #ifdef DAY_1
     377       20225 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
     378       20225 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
     379       20225 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
     380       20225 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
     381       20225 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
     382       20225 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
     383       20225 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
     384             : #endif
     385             : #ifdef ABMON_1
     386       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
     387       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
     388       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
     389       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
     390       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
     391       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
     392       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
     393       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
     394       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
     395       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
     396       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
     397       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
     398             : #endif
     399             : #ifdef MON_1
     400       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_1);
     401       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_2);
     402       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_3);
     403       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_4);
     404       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_5);
     405       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_6);
     406       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_7);
     407       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_8);
     408       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_9);
     409       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_10);
     410       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_11);
     411       20225 :         REGISTER_NL_LANGINFO_CONSTANT(MON_12);
     412             : #endif
     413             : #ifdef AM_STR
     414       20225 :         REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
     415             : #endif
     416             : #ifdef PM_STR
     417       20225 :         REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
     418             : #endif
     419             : #ifdef D_T_FMT
     420       20225 :         REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
     421             : #endif
     422             : #ifdef D_FMT
     423       20225 :         REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
     424             : #endif
     425             : #ifdef T_FMT
     426       20225 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
     427             : #endif
     428             : #ifdef T_FMT_AMPM
     429       20225 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
     430             : #endif
     431             : #ifdef ERA
     432       20225 :         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       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
     439             : #endif
     440             : #ifdef ERA_D_FMT
     441       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
     442             : #endif
     443             : #ifdef ERA_T_FMT
     444       20225 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
     445             : #endif
     446             : #ifdef ALT_DIGITS
     447       20225 :         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       20225 :         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       20225 :         REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
     502             : #endif
     503             : #ifdef THOUSANDS_SEP
     504             :         REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
     505             : #endif
     506             : #ifdef THOUSEP
     507       20225 :         REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
     508             : #endif
     509             : #ifdef GROUPING
     510             :         REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
     511             : #endif
     512             : #ifdef YESEXPR
     513       20225 :         REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
     514             : #endif
     515             : #ifdef NOEXPR
     516       20225 :         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       20225 :         REGISTER_NL_LANGINFO_CONSTANT(CODESET);
     526             : #endif
     527             : #undef REGISTER_NL_LANGINFO_CONSTANT
     528       20225 :         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      883048 : static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC)
     743             : {
     744             :         unsigned char *end;
     745             :         unsigned char c;
     746      883048 :         int result = SUCCESS;
     747             : 
     748      883048 :         memset(mask, 0, 256);
     749     6173562 :         for (end = input+len; input < end; input++) {
     750     5290514 :                 c=*input;
     751     5290571 :                 if ((input+3 < end) && input[1] == '.' && input[2] == '.'
     752          31 :                                 && input[3] >= c) {
     753          26 :                         memset(mask+c, 1, input[3] - c + 1);
     754          26 :                         input+=3;
     755     5290488 :                 } 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     5290474 :                         mask[c]=1;
     779             :                 }
     780             :         }
     781      883048 :         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      881141 : 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      881141 :         int trimmed = 0;
     795             :         char mask[256];
     796             : 
     797      881141 :         if (what) {
     798         242 :                 php_charmask((unsigned char*)what, what_len, mask TSRMLS_CC);
     799             :         } else {
     800      880899 :                 php_charmask((unsigned char*)" \n\r\t\v\0", 6, mask TSRMLS_CC);
     801             :         }
     802             : 
     803      881141 :         if (mode & 1) {
     804     1772712 :                 for (i = 0; i < len; i++) {
     805      755829 :                         if (mask[(unsigned char)c[i]]) {
     806        5514 :                                 trimmed++;
     807             :                         } else {
     808      750315 :                                 break;
     809             :                         }
     810             :                 }
     811      880842 :                 len -= trimmed;
     812      880842 :                 c += trimmed;
     813             :         }
     814      881141 :         if (mode & 2) {
     815     1820614 :                 for (i = len - 1; i >= 0; i--) {
     816      797841 :                         if (mask[(unsigned char)c[i]]) {
     817       48239 :                                 len--;
     818             :                         } else {
     819      749602 :                                 break;
     820             :                         }
     821             :                 }
     822             :         }
     823             : 
     824      881141 :         if (return_value) {
     825      881105 :                 RETVAL_STRINGL(c, len, 1);
     826             :         } else {
     827          36 :                 return estrndup(c, len);
     828             :         }
     829      881105 :         return "";
     830             : }
     831             : /* }}} */
     832             : 
     833             : /* {{{ php_do_trim
     834             :  * Base for trim(), rtrim() and ltrim() functions.
     835             :  */
     836      860932 : static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
     837             : {
     838             :         char *str;
     839      860932 :         char *what = NULL;
     840      860932 :         int str_len, what_len = 0;
     841             : 
     842      860932 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &what, &what_len) == FAILURE) {
     843          57 :                 return;
     844             :         }
     845             : 
     846      860875 :         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      841519 : PHP_FUNCTION(trim)
     853             : {
     854      841519 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
     855      841519 : }
     856             : /* }}} */
     857             : 
     858             : /* {{{ proto string rtrim(string str [, string character_mask])
     859             :    Removes trailing whitespace */
     860         328 : PHP_FUNCTION(rtrim)
     861             : {
     862         328 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
     863         328 : }
     864             : /* }}} */
     865             : 
     866             : /* {{{ proto string ltrim(string str [, string character_mask])
     867             :    Strips whitespace from the beginning of a string */
     868       19085 : PHP_FUNCTION(ltrim)
     869             : {
     870       19085 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     871       19085 : }
     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      497594 : PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit)
    1016             : {
    1017             :         char *p1, *p2, *endp;
    1018             : 
    1019      497594 :         endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
    1020             : 
    1021      497594 :         p1 = Z_STRVAL_P(str);
    1022      497594 :         p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
    1023             : 
    1024      497594 :         if (p2 == NULL) {
    1025          98 :                 add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
    1026             :         } else {
    1027             :                 do {
    1028      508683 :                         add_next_index_stringl(return_value, p1, p2 - p1, 1);
    1029      508683 :                         p1 = p2 + Z_STRLEN_P(delim);
    1030      508683 :                 } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
    1031      508683 :                                  --limit > 1);
    1032             : 
    1033      497496 :                 if (p1 <= endp)
    1034      497496 :                         add_next_index_stringl(return_value, p1, endp-p1, 1);
    1035             :         }
    1036      497594 : }
    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      497709 : PHP_FUNCTION(explode)
    1087             : {
    1088             :         char *str, *delim;
    1089      497709 :         int str_len = 0, delim_len = 0;
    1090      497709 :         long limit = LONG_MAX; /* No limit */
    1091             :         zval zdelim, zstr;
    1092             : 
    1093      497709 :         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      497686 :         if (delim_len == 0) {
    1098          28 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
    1099          28 :                 RETURN_FALSE;
    1100             :         }
    1101             : 
    1102      497658 :         array_init(return_value);
    1103             : 
    1104      497658 :         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      497646 :         ZVAL_STRINGL(&zstr, str, str_len, 0);
    1112      497646 :         ZVAL_STRINGL(&zdelim, delim, delim_len, 0);
    1113      497646 :         if (limit > 1) {
    1114      497594 :                 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       91012 : PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC)
    1130             : {
    1131             :         zval         **tmp;
    1132             :         HashPosition   pos;
    1133       91012 :         smart_str      implstr = {0};
    1134       91012 :         int            numelems, i = 0;
    1135             :         zval tmp_val;
    1136             :         int str_len;
    1137             : 
    1138       91012 :         numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
    1139             : 
    1140       91012 :         if (numelems == 0) {
    1141          47 :                 RETURN_EMPTY_STRING();
    1142             :         }
    1143             : 
    1144       90965 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos);
    1145             : 
    1146      546843 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) {
    1147      364913 :                 switch ((*tmp)->type) {
    1148             :                         case IS_STRING:
    1149        3831 :                                 smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
    1150        3831 :                                 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      364913 :                 if (++i != numelems) {
    1198      273948 :                         smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim));
    1199             :                 }
    1200      364913 :                 zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
    1201             :         }
    1202       90965 :         smart_str_0(&implstr);
    1203             : 
    1204       90965 :         if (implstr.len) {
    1205       90960 :                 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       91046 : PHP_FUNCTION(implode)
    1216             : {
    1217       91046 :         zval **arg1 = NULL, **arg2 = NULL, *delim, *arr;
    1218             : 
    1219       91046 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &arg1, &arg2) == FAILURE) {
    1220           4 :                 return;
    1221             :         }
    1222             : 
    1223       91042 :         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       91034 :                 if (Z_TYPE_PP(arg1) == IS_ARRAY) {
    1237          36 :                         arr = *arg1;
    1238          86 :                         convert_to_string_ex(arg2);
    1239          36 :                         delim = *arg2;
    1240       90998 :                 } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {
    1241       90971 :                         arr = *arg2;
    1242       91113 :                         convert_to_string_ex(arg1);
    1243       90971 :                         delim = *arg1;
    1244             :                 } else {
    1245          27 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid arguments passed");
    1246          27 :                         return;
    1247             :                 }
    1248             :         }
    1249             : 
    1250       91012 :         php_implode(delim, arr, return_value TSRMLS_CC);
    1251             : 
    1252       91012 :         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      243339 : PHPAPI char *php_strtolower(char *s, size_t len)
    1381             : {
    1382             :         unsigned char *c, *e;
    1383             : 
    1384      243339 :         c = (unsigned char *)s;
    1385      243339 :         e = c+len;
    1386             : 
    1387     8161471 :         while (c < e) {
    1388     7674793 :                 *c = tolower(*c);
    1389     7674793 :                 c++;
    1390             :         }
    1391      243339 :         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       15307 : 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       15307 :         char *ret = NULL, *c, *comp, *cend;
    1417             :         size_t inc_len, cnt;
    1418             :         int state;
    1419             : 
    1420       15307 :         c = comp = cend = (char*)s;
    1421       15307 :         cnt = len;
    1422       15307 :         state = 0;
    1423      896059 :         while (cnt > 0) {
    1424      865445 :                 inc_len = (*c == '\0' ? 1: php_mblen(c, cnt));
    1425             : 
    1426      865445 :                 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      865445 :                                 if (*c == '/') {
    1439             : #endif
    1440      100296 :                                         if (state == 1) {
    1441       86312 :                                                 state = 0;
    1442       86312 :                                                 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      765149 :                                         if (state == 0) {
    1459      101383 :                                                 comp = c;
    1460      101383 :                                                 state = 1;
    1461             :                                         }
    1462             :                                 }
    1463      865445 :                                 break;
    1464             :                         default:
    1465           0 :                                 if (state == 0) {
    1466           0 :                                         comp = c;
    1467           0 :                                         state = 1;
    1468             :                                 }
    1469             :                                 break;
    1470             :                 }
    1471      865445 :                 c += inc_len;
    1472      865445 :                 cnt -= inc_len;
    1473             :         }
    1474             : 
    1475             : quit_loop:
    1476       15307 :         if (state == 1) {
    1477       15071 :                 cend = c;
    1478             :         }
    1479       29009 :         if (suffix != NULL && sufflen < (uint)(cend - comp) &&
    1480       13702 :                         memcmp(cend - sufflen, suffix, sufflen) == 0) {
    1481       13617 :                 cend -= sufflen;
    1482             :         }
    1483             : 
    1484       15307 :         len = cend - comp;
    1485             : 
    1486       15307 :         if (p_ret) {
    1487       15307 :                 ret = emalloc(len + 1);
    1488       15307 :                 memcpy(ret, comp, len);
    1489       15307 :                 ret[len] = '\0';
    1490       15307 :                 *p_ret = ret;
    1491             :         }
    1492       15307 :         if (p_len) {
    1493       15271 :                 *p_len = len;
    1494             :         }
    1495       15307 : }
    1496             : /* }}} */
    1497             : 
    1498             : /* {{{ proto string basename(string path [, string suffix])
    1499             :    Returns the filename component of the path */
    1500       14067 : PHP_FUNCTION(basename)
    1501             : {
    1502       14067 :         char *string, *suffix = NULL, *ret;
    1503       14067 :         int   string_len, suffix_len = 0;
    1504             :         size_t ret_len;
    1505             : 
    1506       14067 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &string, &string_len, &suffix, &suffix_len) == FAILURE) {
    1507          30 :                 return;
    1508             :         }
    1509             : 
    1510       14037 :         php_basename(string, string_len, suffix, suffix_len, &ret, &ret_len TSRMLS_CC);
    1511       14037 :         RETURN_STRINGL(ret, (int)ret_len, 0);
    1512             : }
    1513             : /* }}} */
    1514             : 
    1515             : /* {{{ php_dirname
    1516             :    Returns directory name component of path */
    1517       25053 : PHPAPI size_t php_dirname(char *path, size_t len)
    1518             : {
    1519       25053 :         return zend_dirname(path, len);
    1520             : }
    1521             : /* }}} */
    1522             : 
    1523             : /* {{{ proto string dirname(string path)
    1524             :    Returns the directory name component of the path */
    1525       24602 : PHP_FUNCTION(dirname)
    1526             : {
    1527             :         char *str;
    1528             :         char *ret;
    1529             :         int str_len;
    1530             :         size_t ret_len;
    1531             : 
    1532       24602 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
    1533           9 :                 return;
    1534             :         }
    1535             : 
    1536       24593 :         ret = estrndup(str, str_len);
    1537       24593 :         ret_len = php_dirname(ret, str_len);
    1538             : 
    1539       24593 :         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        8630 : PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
    1630             : {
    1631        8630 :         php_strtolower(s, s_len);
    1632        8630 :         php_strtolower(t, t_len);
    1633        8630 :         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        8564 : PHP_FUNCTION(stristr)
    1712             : {
    1713             :         zval *needle;
    1714             :         char *haystack;
    1715             :         int haystack_len;
    1716        8564 :         char *found = NULL;
    1717             :         int  found_offset;
    1718             :         char *haystack_dup;
    1719             :         char needle_char[2];
    1720        8564 :         zend_bool part = 0;
    1721             : 
    1722        8564 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) {
    1723          11 :                 return;
    1724             :         }
    1725             : 
    1726        8553 :         haystack_dup = estrndup(haystack, haystack_len);
    1727             : 
    1728        8553 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1729             :                 char *orig_needle;
    1730        8530 :                 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        8526 :                 orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
    1736        8526 :                 found = php_stristr(haystack_dup, orig_needle,  haystack_len, Z_STRLEN_P(needle));
    1737        8526 :                 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        8544 :         if (found) {
    1749        1599 :                 found_offset = found - haystack_dup;
    1750        1599 :                 if (part) {
    1751           4 :                         RETVAL_STRINGL(haystack, found_offset, 1);
    1752             :                 } else {
    1753        1595 :                         RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1);
    1754             :                 }
    1755             :         } else {
    1756        6945 :                 RETVAL_FALSE;
    1757             :         }
    1758             : 
    1759        8544 :         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      880611 : PHP_FUNCTION(strpos)
    1814             : {
    1815             :         zval *needle;
    1816             :         char *haystack;
    1817      880611 :         char *found = NULL;
    1818             :         char  needle_char[2];
    1819      880611 :         long  offset = 0;
    1820             :         int   haystack_len;
    1821             : 
    1822      880611 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
    1823          11 :                 return;
    1824             :         }
    1825             : 
    1826      880600 :         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      880591 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1832      880578 :                 if (!Z_STRLEN_P(needle)) {
    1833           6 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle");
    1834           6 :                         RETURN_FALSE;
    1835             :                 }
    1836             : 
    1837     3522288 :                 found = php_memnstr(haystack + offset,
    1838      880572 :                                         Z_STRVAL_P(needle),
    1839      880572 :                                         Z_STRLEN_P(needle),
    1840      880572 :                                         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      880585 :         if (found) {
    1854      418013 :                 RETURN_LONG(found - haystack);
    1855             :         } else {
    1856      462572 :                 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      470595 : PHP_FUNCTION(substr)
    2235             : {
    2236             :         char *str;
    2237      470595 :         long l = 0, f;
    2238             :         int str_len;
    2239      470595 :         int argc = ZEND_NUM_ARGS();
    2240             : 
    2241      470595 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &str, &str_len, &f, &l) == FAILURE) {
    2242           6 :                 return;
    2243             :         }
    2244             : 
    2245      470589 :         if (argc > 2) {
    2246      426774 :                 if ((l < 0 && -l > str_len)) {
    2247           8 :                         RETURN_FALSE;
    2248      426766 :                 } else if (l > str_len) {
    2249         296 :                         l = str_len;
    2250             :                 }
    2251             :         } else {
    2252       43815 :                 l = str_len;
    2253             :         }
    2254             : 
    2255      470581 :         if (f > str_len) {
    2256          14 :                 RETURN_FALSE;
    2257      470567 :         } else if (f < 0 && -f > str_len) {
    2258        1409 :                 f = 0;
    2259             :         }
    2260             : 
    2261      470567 :         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      470565 :         if (f < 0) {
    2269       41237 :                 f = str_len + f;
    2270       41237 :                 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      470565 :         if (l < 0) {
    2279          90 :                 l = (str_len - f) + l;
    2280          90 :                 if (l < 0) {
    2281           5 :                         l = 0;
    2282             :                 }
    2283             :         }
    2284             : 
    2285      470565 :         if (f >= str_len) {
    2286         205 :                 RETURN_FALSE;
    2287             :         }
    2288             : 
    2289      470360 :         if ((f + l) > str_len) {
    2290       42852 :                 l = str_len - f;
    2291             :         }
    2292             : 
    2293      470360 :         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      659937 : PHP_FUNCTION(chr)
    2662             : {
    2663             :         long c;
    2664             :         char temp[2];
    2665             : 
    2666      659937 :         if (ZEND_NUM_ARGS() != 1) {
    2667           4 :                 WRONG_PARAM_COUNT;
    2668             :         }
    2669             : 
    2670      659933 :         if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &c) == FAILURE) {
    2671          15 :                 c = 0;
    2672             :         }
    2673             : 
    2674      659933 :         temp[0] = (char)c;
    2675      659933 :         temp[1] = '\0';
    2676             : 
    2677      659933 :         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         115 : PHP_FUNCTION(ucwords)
    2744             : {
    2745         115 :         char *str, *delims = " \t\r\n\f\v";
    2746             :         register char *r, *r_end;
    2747         115 :         int str_len, delims_len = 6;
    2748             :         char mask[256];
    2749             : 
    2750         115 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &delims, &delims_len) == FAILURE) {
    2751           8 :                 return;
    2752             :         }
    2753             : 
    2754         107 :         if (!str_len) {
    2755          10 :                 RETURN_EMPTY_STRING();
    2756             :         }
    2757             : 
    2758          97 :         php_charmask((unsigned char *)delims, delims_len, mask TSRMLS_CC);
    2759             : 
    2760          97 :         ZVAL_STRINGL(return_value, str, str_len, 1);
    2761          97 :         r = Z_STRVAL_P(return_value);
    2762             : 
    2763          97 :         *r = toupper((unsigned char) *r);
    2764        2021 :         for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) {
    2765        1827 :                 if (mask[(unsigned char)*r++]) {
    2766         208 :                         *r = toupper((unsigned char) *r);
    2767             :                 }
    2768             :         }
    2769             : }
    2770             : /* }}} */
    2771             : 
    2772             : /* {{{ php_strtr
    2773             :  */
    2774         142 : PHPAPI char *php_strtr(char *str, int len, char *str_from, char *str_to, int trlen)
    2775             : {
    2776             :         int i;
    2777             :         unsigned char xlat[256];
    2778             : 
    2779         142 :         if ((trlen < 1) || (len < 1)) {
    2780          12 :                 return str;
    2781             :         }
    2782             : 
    2783         130 :         for (i = 0; i < 256; xlat[i] = i, i++);
    2784             : 
    2785        3125 :         for (i = 0; i < trlen; i++) {
    2786        2995 :                 xlat[(unsigned char) str_from[i]] = str_to[i];
    2787             :         }
    2788             : 
    2789       83402 :         for (i = 0; i < len; i++) {
    2790       83272 :                 str[i] = xlat[(unsigned char) str[i]];
    2791             :         }
    2792             : 
    2793         130 :         return str;
    2794             : }
    2795             : /* }}} */
    2796             : 
    2797             : /* {{{ Definitions for php_strtr_array */
    2798             : typedef size_t STRLEN;  /* STRLEN should be unsigned */
    2799             : typedef uint16_t HASH;
    2800             : typedef struct {
    2801             :         HASH                    table_mask;
    2802             :         STRLEN                  entries[1];
    2803             : } SHIFT_TAB;
    2804             : typedef struct {
    2805             :         HASH                    table_mask;
    2806             :         int                             entries[1];
    2807             : } HASH_TAB;
    2808             : typedef struct {
    2809             :         const char      *s;
    2810             :         STRLEN          l;
    2811             : } STR;
    2812             : typedef struct _pat_and_repl {
    2813             :         STR                     pat;
    2814             :         STR                     repl;
    2815             : } PATNREPL;
    2816             : 
    2817             : #define S(a) ((a)->s)
    2818             : #define L(a) ((a)->l)
    2819             : 
    2820             : #define SHIFT_TAB_BITS  13
    2821             : #define HASH_TAB_BITS   10 /* should be less than sizeof(HASH) * 8 */
    2822             : #define SHIFT_TAB_SIZE  (1U << SHIFT_TAB_BITS)
    2823             : #define HASH_TAB_SIZE   (1U << HASH_TAB_BITS)
    2824             : 
    2825             : typedef struct {
    2826             :         int                             B;                      /* size of suffixes */
    2827             :         int                             Bp;                     /* size of prefixes */
    2828             :         STRLEN                  m;                      /* minimum pattern length */
    2829             :         int                             patnum;         /* number of patterns */
    2830             :         SHIFT_TAB               *shift;         /* table mapping hash to allowed shift */
    2831             :         HASH_TAB                *hash;          /* table mapping hash to int (pair of pointers) */
    2832             :         HASH                    *prefix;        /* array of hashes of prefixes by pattern suffix hash order */
    2833             :         PATNREPL                *patterns;      /* array of prefixes by pattern suffix hash order */
    2834             : } PPRES;
    2835             : /* }}} */
    2836             : 
    2837             : /* {{{ php_strtr_hash */
    2838        1532 : static inline HASH php_strtr_hash(const char *str, int len)
    2839             : {
    2840        1532 :         HASH    res = 0;
    2841             :         int             i;
    2842        3080 :         for (i = 0; i < len; i++) {
    2843        1548 :                 res = res * 33 + (unsigned char)str[i];
    2844             :         }
    2845             : 
    2846        1532 :         return res;
    2847             : }
    2848             : /* }}} */
    2849             : /* {{{ php_strtr_populate_shift */
    2850          39 : static inline void php_strtr_populate_shift(PATNREPL *patterns, int patnum, int B, STRLEN m, SHIFT_TAB *shift)
    2851             : {
    2852             :         int             i;
    2853             :         STRLEN  j,
    2854             :                         max_shift;
    2855             : 
    2856          39 :         max_shift = m - B + 1;
    2857      319527 :         for (i = 0; i < SHIFT_TAB_SIZE; i++) {
    2858      319488 :                 shift->entries[i] = max_shift;
    2859             :         }
    2860         138 :         for (i = 0; i < patnum; i++) {
    2861         198 :                 for (j = 0; j < m - B + 1; j++) {
    2862          99 :                         HASH h = php_strtr_hash(&S(&patterns[i].pat)[j], B) & shift->table_mask;
    2863             :                         assert((long long) m - (long long) j - B >= 0);
    2864          99 :                         shift->entries[h] = MIN(shift->entries[h], m - j - B);
    2865             :                 }
    2866             :         }
    2867          39 : }
    2868             : /* }}} */
    2869             : /* {{{ php_strtr_compare_hash_suffix */
    2870          94 : static int php_strtr_compare_hash_suffix(const void *a, const void *b, void *ctx_g)
    2871             : {
    2872          94 :         const PPRES             *res = ctx_g;
    2873          94 :         const PATNREPL  *pnr_a = a,
    2874          94 :                                         *pnr_b = b;
    2875         188 :         HASH                    hash_a = php_strtr_hash(&S(&pnr_a->pat)[res->m - res->B], res->B)
    2876         282 :                                                                 & res->hash->table_mask,
    2877         188 :                                         hash_b = php_strtr_hash(&S(&pnr_b->pat)[res->m - res->B], res->B)
    2878         282 :                                                                 & res->hash->table_mask;
    2879             :         /* TODO: don't recalculate the hashes all the time */
    2880          94 :         if (hash_a > hash_b) {
    2881          42 :                 return 1;
    2882          52 :         } else if (hash_a < hash_b) {
    2883          38 :                 return -1;
    2884             :         } else {
    2885             :                 /* longer patterns must be sorted first */
    2886          14 :                 if (L(&pnr_a->pat) > L(&pnr_b->pat)) {
    2887           0 :                         return -1;
    2888          14 :                 } else if (L(&pnr_a->pat) < L(&pnr_b->pat)) {
    2889          14 :                         return 1;
    2890             :                 } else {
    2891           0 :                         return 0;
    2892             :                 }
    2893             :         }
    2894             : }
    2895             : /* }}} */
    2896             : /* {{{ Sorting (no zend_qsort_r in this PHP version) */
    2897             : #define HS_LEFT(i)              ((i) * 2 + 1)
    2898             : #define HS_RIGHT(i)     ((i) * 2 + 2)
    2899             : #define HS_PARENT(i)    (((i) - 1) / 2);
    2900             : #define HS_OFF(data, i) ((void *)(&((data)->arr)[i]))
    2901             : #define HS_CMP_CALL(data, i1, i2) \
    2902             :                 (php_strtr_compare_hash_suffix(HS_OFF((data), (i1)), HS_OFF((data), (i2)), (data)->res))
    2903             : struct hs_data {
    2904             :         PATNREPL        *arr;
    2905             :         size_t          nel;
    2906             :         size_t          heapel;
    2907             :         PPRES           *res;
    2908             : };
    2909         116 : static inline void php_strtr_swap(PATNREPL *a, PATNREPL *b)
    2910             : {
    2911         116 :         PATNREPL tmp = *a;
    2912         116 :         *a = *b;
    2913         116 :         *b = tmp;
    2914         116 : }
    2915         154 : static inline void php_strtr_fix_heap(struct hs_data *data, size_t i)
    2916             : {
    2917         154 :         size_t  li =    HS_LEFT(i),
    2918         154 :                         ri =    HS_RIGHT(i),
    2919             :                         largei;
    2920         210 :         if (li < data->heapel && HS_CMP_CALL(data, li, i) > 0) {
    2921          56 :                 largei = li;
    2922             :         } else {
    2923          98 :                 largei = i;
    2924             :         }
    2925         154 :         if (ri < data->heapel && HS_CMP_CALL(data, ri, largei) > 0) {
    2926           0 :                 largei = ri;
    2927             :         }
    2928         154 :         if (largei != i) {
    2929          56 :                 php_strtr_swap(HS_OFF(data, i), HS_OFF(data, largei));
    2930          56 :                 php_strtr_fix_heap(data, largei);
    2931             :         }
    2932         154 : }
    2933          39 : static inline void php_strtr_build_heap(struct hs_data *data)
    2934             : {
    2935             :         size_t i;
    2936          77 :         for (i = data->nel / 2; i > 0; i--) {
    2937          38 :                 php_strtr_fix_heap(data, i - 1);
    2938             :         }
    2939          39 : }
    2940          39 : static inline void php_strtr_heapsort(PATNREPL *arr, size_t nel, PPRES *res)
    2941             : {
    2942          39 :         struct hs_data data = { arr, nel, nel, res };
    2943             :         size_t i;
    2944          39 :         php_strtr_build_heap(&data);
    2945          99 :         for (i = nel; i > 1; i--) {
    2946          60 :                 php_strtr_swap(arr, HS_OFF(&data, i - 1));
    2947          60 :                 data.heapel--;
    2948          60 :                 php_strtr_fix_heap(&data, 0);
    2949             :         }
    2950          39 : }
    2951             : /* }}} */
    2952             : /* {{{ php_strtr_free_strp */
    2953          21 : static void php_strtr_free_strp(void *strp)
    2954             : {
    2955          21 :         STR_FREE(*(char**)strp);
    2956          21 : }
    2957             : /* }}} */
    2958             : /* {{{ php_strtr_array_prepare_repls */
    2959          39 : static PATNREPL *php_strtr_array_prepare_repls(int slen, HashTable *pats, zend_llist **allocs, int *outsize)
    2960             : {
    2961             :         PATNREPL                *patterns;
    2962             :         HashPosition    hpos;
    2963             :         zval                    **entry;
    2964          39 :         int                             num_pats = zend_hash_num_elements(pats),
    2965             :                                         i;
    2966             : 
    2967          39 :         patterns = safe_emalloc(num_pats, sizeof(*patterns), 0);
    2968          39 :         *allocs = emalloc(sizeof **allocs);
    2969          39 :         zend_llist_init(*allocs, sizeof(void*), &php_strtr_free_strp, 0);
    2970             : 
    2971         189 :         for (i = 0, zend_hash_internal_pointer_reset_ex(pats, &hpos);
    2972         150 :                         zend_hash_get_current_data_ex(pats, (void **)&entry, &hpos) == SUCCESS;
    2973         111 :                         zend_hash_move_forward_ex(pats, &hpos)) {
    2974             :                 char    *string_key;
    2975             :                 uint    string_key_len;
    2976             :                 ulong   num_key;
    2977         111 :                 zval    *tzv = NULL;
    2978             : 
    2979         111 :                 switch (zend_hash_get_current_key_ex(pats, &string_key, &string_key_len, &num_key, 0, &hpos)) {
    2980             :                 case HASH_KEY_IS_LONG:
    2981          11 :                         string_key_len = 1 + zend_spprintf(&string_key, 0, "%ld", (long)num_key);
    2982          11 :                         zend_llist_add_element(*allocs, &string_key);
    2983             :                         /* break missing intentionally */
    2984             : 
    2985             :                 case HASH_KEY_IS_STRING:
    2986         111 :                         string_key_len--; /* exclude final '\0' */
    2987         111 :                         if (string_key_len == 0) { /* empty string given as pattern */
    2988           0 :                                 efree(patterns);
    2989           0 :                                 zend_llist_destroy(*allocs);
    2990           0 :                                 efree(*allocs);
    2991           0 :                                 *allocs = NULL;
    2992           0 :                                 return NULL;
    2993             :                         }
    2994         111 :                         if (string_key_len > slen) { /* this pattern can never match */
    2995          12 :                                 continue;
    2996             :                         }
    2997             : 
    2998          99 :                         if (Z_TYPE_PP(entry) != IS_STRING) {
    2999          10 :                                 tzv = *entry;
    3000          10 :                                 zval_addref_p(tzv);
    3001          40 :                                 SEPARATE_ZVAL(&tzv);
    3002          10 :                                 convert_to_string(tzv);
    3003          10 :                                 entry = &tzv;
    3004          10 :                                 zend_llist_add_element(*allocs, &Z_STRVAL_PP(entry));
    3005             :                         }
    3006             : 
    3007          99 :                         S(&patterns[i].pat) = string_key;
    3008          99 :                         L(&patterns[i].pat) = string_key_len;
    3009          99 :                         S(&patterns[i].repl) = Z_STRVAL_PP(entry);
    3010          99 :                         L(&patterns[i].repl) = Z_STRLEN_PP(entry);
    3011          99 :                         i++;
    3012             : 
    3013          99 :                         if (tzv) {
    3014          10 :                                 efree(tzv);
    3015             :                         }
    3016             :                 }
    3017             :         }
    3018             : 
    3019          39 :         *outsize = i;
    3020          39 :         return patterns;
    3021             : }
    3022             : /* }}} */
    3023             : 
    3024             : /* {{{ PPRES *php_strtr_array_prepare(STR *text, PATNREPL *patterns, int patnum, int B, int Bp) */
    3025          39 : static PPRES *php_strtr_array_prepare(STR *text, PATNREPL *patterns, int patnum, int B, int Bp)
    3026             : {
    3027             :         int             i;
    3028          39 :         PPRES   *res = emalloc(sizeof *res);
    3029             : 
    3030          39 :         res->m = (STRLEN)-1;
    3031         138 :         for (i = 0; i < patnum; i++) {
    3032          99 :                 if (L(&patterns[i].pat) < res->m) {
    3033          42 :                         res->m = L(&patterns[i].pat);
    3034             :                 }
    3035             :         }
    3036             :         assert(res->m > 0);
    3037          39 :         res->B       = B             = MIN(B, res->m);
    3038          39 :         res->Bp      = Bp    = MIN(Bp, res->m);
    3039             : 
    3040          39 :         res->shift = safe_emalloc(SHIFT_TAB_SIZE, sizeof(*res->shift->entries), sizeof(*res->shift));
    3041          39 :         res->shift->table_mask = SHIFT_TAB_SIZE - 1;
    3042          39 :         php_strtr_populate_shift(patterns, patnum, B, res->m, res->shift);
    3043             : 
    3044          39 :         res->hash = safe_emalloc(HASH_TAB_SIZE, sizeof(*res->hash->entries), sizeof(*res->hash));
    3045          39 :         res->hash->table_mask = HASH_TAB_SIZE - 1;
    3046             : 
    3047          39 :         res->patterns = safe_emalloc(patnum, sizeof(*res->patterns), 0);
    3048          39 :         memcpy(res->patterns, patterns, sizeof(*patterns) * patnum);
    3049          39 :         php_strtr_heapsort(res->patterns, patnum, res);
    3050             : 
    3051          39 :         res->prefix = safe_emalloc(patnum, sizeof(*res->prefix), 0);
    3052         138 :         for (i = 0; i < patnum; i++) {
    3053          99 :                 res->prefix[i] = php_strtr_hash(S(&res->patterns[i].pat), Bp);
    3054             :         }
    3055             : 
    3056             :         /* Initialize the rest of ->hash */
    3057       39975 :         for (i = 0; i < HASH_TAB_SIZE; i++) {
    3058       39936 :                 res->hash->entries[i] = -1;
    3059             :         }
    3060             :         {
    3061          39 :                 HASH last_h = -1; /* assumes not all bits are used in res->hash */
    3062             :                 /* res->patterns is already ordered by hash.
    3063             :                  * Make res->hash->entries[h] de index of the first pattern in
    3064             :                  * res->patterns that has hash h */
    3065         138 :                 for (i = 0; i < patnum; i++) {
    3066         198 :                         HASH h = php_strtr_hash(&S(&res->patterns[i].pat)[res->m - res->B], res->B)
    3067         297 :                                                 & res->hash->table_mask;
    3068          99 :                         if (h != last_h) {
    3069          86 :                                 res->hash->entries[h] = i;
    3070          86 :                                 last_h = h;
    3071             :                         }
    3072             :                 }
    3073             :         }
    3074          39 :         res->hash->entries[HASH_TAB_SIZE] = patnum; /* OK, we effectively allocated SIZE+1 */
    3075       39975 :         for (i = HASH_TAB_SIZE - 1; i >= 0; i--) {
    3076       39936 :                 if (res->hash->entries[i] == -1) {
    3077       39850 :                         res->hash->entries[i] = res->hash->entries[i + 1];
    3078             :                 }
    3079             :         }
    3080             : 
    3081          39 :         res->patnum  = patnum;
    3082             : 
    3083          39 :         return res;
    3084             : }
    3085             : /* }}} */
    3086             : /* {{{ php_strtr_array_destroy_ppres(PPRES *d) */
    3087          39 : static void php_strtr_array_destroy_ppres(PPRES *d)
    3088             : {
    3089          39 :         efree(d->shift);
    3090          39 :         efree(d->hash);
    3091          39 :         efree(d->prefix);
    3092          39 :         efree(d->patterns);
    3093          39 :         efree(d);
    3094          39 : }
    3095             : /* }}} */
    3096             : 
    3097             : /* {{{ php_strtr_array_do_repl(STR *text, PPRES *d, zval *return_value) */
    3098          39 : static void php_strtr_array_do_repl(STR *text, PPRES *d, zval *return_value)
    3099             : {
    3100          39 :         STRLEN          pos = 0,
    3101          39 :                                 nextwpos = 0,
    3102          39 :                                 lastpos = L(text) - d->m;
    3103          39 :         smart_str       result = {0};
    3104             : 
    3105        1029 :         while (pos <= lastpos) {
    3106         951 :                 HASH    h               = php_strtr_hash(&S(text)[pos + d->m - d->B], d->B) & d->shift->table_mask;
    3107         951 :                 STRLEN  shift   = d->shift->entries[h];
    3108             : 
    3109         951 :                 if (shift > 0) {
    3110         855 :                         pos += shift;
    3111             :                 } else {
    3112          96 :                         HASH    h2                              = h & d->hash->table_mask,
    3113          96 :                                         prefix_h                = php_strtr_hash(&S(text)[pos], d->Bp);
    3114             : 
    3115          96 :                         int             offset_start    = d->hash->entries[h2],
    3116          96 :                                         offset_end              = d->hash->entries[h2 + 1], /* exclusive */
    3117          96 :                                         i                               = 0;
    3118             : 
    3119         106 :                         for (i = offset_start; i < offset_end; i++) {
    3120             :                                 PATNREPL *pnr;
    3121         102 :                                 if (d->prefix[i] != prefix_h)
    3122           0 :                                         continue;
    3123             : 
    3124         102 :                                 pnr = &d->patterns[i];
    3125         203 :                                 if (L(&pnr->pat) > L(text) - pos ||
    3126         101 :                                                 memcmp(S(&pnr->pat), &S(text)[pos], L(&pnr->pat)) != 0)
    3127          10 :                                         continue;
    3128             : 
    3129          92 :                                 smart_str_appendl(&result, &S(text)[nextwpos], pos - nextwpos);
    3130          92 :                                 smart_str_appendl(&result, S(&pnr->repl), L(&pnr->repl));
    3131          92 :                                 pos += L(&pnr->pat);
    3132          92 :                                 nextwpos = pos;
    3133          92 :                                 goto end_outer_loop;
    3134             :                         }
    3135             : 
    3136           4 :                         pos++;
    3137             : end_outer_loop: ;
    3138             :                 }
    3139             :         }
    3140             : 
    3141          39 :         smart_str_appendl(&result, &S(text)[nextwpos], L(text) - nextwpos);
    3142             : 
    3143          39 :         if (result.c != NULL) {
    3144          39 :                 smart_str_0(&result);
    3145          39 :                 RETVAL_STRINGL(result.c, result.len, 0);
    3146             :         } else {
    3147           0 :                 RETURN_EMPTY_STRING();
    3148             :         }
    3149             : }
    3150             : /* }}} */
    3151             : 
    3152             : /* {{{ php_strtr_array */
    3153          41 : static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *pats)
    3154             : {
    3155             :         PPRES           *data;
    3156             :         STR                     text;
    3157             :         PATNREPL        *patterns;
    3158             :         int                     patterns_len;
    3159             :         zend_llist      *allocs;
    3160             : 
    3161          41 :         if (zend_hash_num_elements(pats) == 0) {
    3162           2 :                 RETURN_STRINGL(str, slen, 1);
    3163             :         }
    3164             : 
    3165          39 :         S(&text) = str;
    3166          39 :         L(&text) = slen;
    3167             : 
    3168          39 :         patterns = php_strtr_array_prepare_repls(slen, pats, &allocs, &patterns_len);
    3169          39 :         if (patterns == NULL) {
    3170           0 :                 RETURN_FALSE;
    3171             :         }
    3172          39 :         data = php_strtr_array_prepare(&text, patterns, patterns_len, 2, 2);
    3173          39 :         efree(patterns);
    3174          39 :         php_strtr_array_do_repl(&text, data, return_value);
    3175          39 :         php_strtr_array_destroy_ppres(data);
    3176          39 :         zend_llist_destroy(allocs);
    3177          39 :         efree(allocs);
    3178             : }
    3179             : /* }}} */
    3180             : 
    3181             : /* {{{ proto string strtr(string str, string from[, string to])
    3182             :    Translates characters in str using given translation tables */
    3183         211 : PHP_FUNCTION(strtr)
    3184             : {
    3185             :         zval **from;
    3186         211 :         char *str, *to = NULL;
    3187         211 :         int str_len, to_len = 0;
    3188         211 :         int ac = ZEND_NUM_ARGS();
    3189             : 
    3190         211 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &str, &str_len, &from, &to, &to_len) == FAILURE) {
    3191          23 :                 return;
    3192             :         }
    3193             : 
    3194         188 :         if (ac == 2 && Z_TYPE_PP(from) != IS_ARRAY) {
    3195          31 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument is not an array");
    3196          31 :                 RETURN_FALSE;
    3197             :         }
    3198             : 
    3199             :         /* shortcut for empty string */
    3200         157 :         if (str_len == 0) {
    3201          27 :                 RETURN_EMPTY_STRING();
    3202             :         }
    3203             : 
    3204         130 :         if (ac == 2) {
    3205          41 :                 php_strtr_array(return_value, str, str_len, HASH_OF(*from));
    3206             :         } else {
    3207         225 :                 convert_to_string_ex(from);
    3208             : 
    3209          89 :                 ZVAL_STRINGL(return_value, str, str_len, 1);
    3210             : 
    3211         178 :                 php_strtr(Z_STRVAL_P(return_value),
    3212             :                                   Z_STRLEN_P(return_value),
    3213          89 :                                   Z_STRVAL_PP(from),
    3214             :                                   to,
    3215          89 :                                   MIN(Z_STRLEN_PP(from),
    3216             :                                   to_len));
    3217             :         }
    3218             : }
    3219             : /* }}} */
    3220             : 
    3221             : /* {{{ proto string strrev(string str)
    3222             :    Reverse a string */
    3223         101 : PHP_FUNCTION(strrev)
    3224             : {
    3225             :         char *str;
    3226             :         char *e, *n, *p;
    3227             :         int  str_len;
    3228             : 
    3229         101 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
    3230           8 :                 return;
    3231             :         }
    3232             : 
    3233          93 :         n = emalloc(str_len+1);
    3234          93 :         p = n;
    3235             : 
    3236          93 :         e = str + str_len;
    3237             : 
    3238        4301 :         while (--e>=str) {
    3239        4115 :                 *p++ = *e;
    3240             :         }
    3241             : 
    3242          93 :         *p = '\0';
    3243             : 
    3244          93 :         RETVAL_STRINGL(n, str_len, 0);
    3245             : }
    3246             : /* }}} */
    3247             : 
    3248             : /* {{{ php_similar_str
    3249             :  */
    3250          10 : static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
    3251             : {
    3252             :         char *p, *q;
    3253          10 :         char *end1 = (char *) txt1 + len1;
    3254          10 :         char *end2 = (char *) txt2 + len2;
    3255             :         int l;
    3256             : 
    3257          10 :         *max = 0;
    3258         104 :         for (p = (char *) txt1; p < end1; p++) {
    3259         602 :                 for (q = (char *) txt2; q < end2; q++) {
    3260         508 :                         for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
    3261         508 :                         if (l > *max) {
    3262           6 :                                 *max = l;
    3263           6 :                                 *pos1 = p - txt1;
    3264           6 :                                 *pos2 = q - txt2;
    3265             :                         }
    3266             :                 }
    3267             :         }
    3268          10 : }
    3269             : /* }}} */
    3270             : 
    3271             : /* {{{ php_similar_char
    3272             :  */
    3273          10 : static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2)
    3274             : {
    3275             :         int sum;
    3276          10 :         int pos1 = 0, pos2 = 0, max;
    3277             : 
    3278          10 :         php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
    3279          10 :         if ((sum = max)) {
    3280           6 :                 if (pos1 && pos2) {
    3281           0 :                         sum += php_similar_char(txt1, pos1,
    3282             :                                                                         txt2, pos2);
    3283             :                 }
    3284           6 :                 if ((pos1 + max < len1) && (pos2 + max < len2)) {
    3285           6 :                         sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
    3286           6 :                                                                         txt2 + pos2 + max, len2 - pos2 - max);
    3287             :                 }
    3288             :         }
    3289             : 
    3290          10 :         return sum;
    3291             : }
    3292             : /* }}} */
    3293             : 
    3294             : /* {{{ proto int similar_text(string str1, string str2 [, float percent])
    3295             :    Calculates the similarity between two strings */
    3296          10 : PHP_FUNCTION(similar_text)
    3297             : {
    3298             :         char *t1, *t2;
    3299          10 :         zval **percent = NULL;
    3300          10 :         int ac = ZEND_NUM_ARGS();
    3301             :         int sim;
    3302             :         int t1_len, t2_len;
    3303             : 
    3304          10 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Z", &t1, &t1_len, &t2, &t2_len, &percent) == FAILURE) {
    3305           2 :                 return;
    3306             :         }
    3307             : 
    3308           8 :         if (ac > 2) {
    3309           6 :                 convert_to_double_ex(percent);
    3310             :         }
    3311             : 
    3312           8 :         if (t1_len + t2_len == 0) {
    3313           0 :                 if (ac > 2) {
    3314           0 :                         Z_DVAL_PP(percent) = 0;
    3315             :                 }
    3316             : 
    3317           0 :                 RETURN_LONG(0);
    3318             :         }
    3319             : 
    3320           8 :         sim = php_similar_char(t1, t1_len, t2, t2_len);
    3321             : 
    3322           8 :         if (ac > 2) {
    3323           4 :                 Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len);
    3324             :         }
    3325             : 
    3326           8 :         RETURN_LONG(sim);
    3327             : }
    3328             : /* }}} */
    3329             : 
    3330             : /* {{{ php_stripslashes
    3331             :  *
    3332             :  * be careful, this edits the string in-place */
    3333         103 : PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC)
    3334             : {
    3335             :         char *s, *t;
    3336             :         int l;
    3337             : 
    3338         103 :         if (len != NULL) {
    3339         103 :                 l = *len;
    3340             :         } else {
    3341           0 :                 l = strlen(str);
    3342             :         }
    3343         103 :         s = str;
    3344         103 :         t = str;
    3345             : 
    3346        1609 :         while (l > 0) {
    3347        1403 :                 if (*t == '\\') {
    3348         116 :                         t++;                            /* skip the slash */
    3349         116 :                         if (len != NULL) {
    3350         116 :                                 (*len)--;
    3351             :                         }
    3352         116 :                         l--;
    3353         116 :                         if (l > 0) {
    3354         116 :                                 if (*t == '0') {
    3355          15 :                                         *s++='\0';
    3356          15 :                                         t++;
    3357             :                                 } else {
    3358         101 :                                         *s++ = *t++;    /* preserve the next character */
    3359             :                                 }
    3360         116 :                                 l--;
    3361             :                         }
    3362             :                 } else {
    3363        1287 :                         *s++ = *t++;
    3364        1287 :                         l--;
    3365             :                 }
    3366             :         }
    3367         103 :         if (s != t) {
    3368          67 :                 *s = '\0';
    3369             :         }
    3370         103 : }
    3371             : /* }}} */
    3372             : 
    3373             : /* {{{ proto string addcslashes(string str, string charlist)
    3374             :    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...) */
    3375          44 : PHP_FUNCTION(addcslashes)
    3376             : {
    3377             :         char *str, *what;
    3378             :         int str_len, what_len;
    3379             : 
    3380          44 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &str, &str_len, &what, &what_len) == FAILURE) {
    3381           4 :                 return;
    3382             :         }
    3383             : 
    3384          40 :         if (str_len == 0) {
    3385           6 :                 RETURN_EMPTY_STRING();
    3386             :         }
    3387             : 
    3388          34 :         if (what_len == 0) {
    3389           5 :                 RETURN_STRINGL(str, str_len, 1);
    3390             :         }
    3391             : 
    3392          29 :         Z_STRVAL_P(return_value) = php_addcslashes(str, str_len, &Z_STRLEN_P(return_value), 0, what, what_len TSRMLS_CC);
    3393          29 :         RETURN_STRINGL(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), 0);
    3394             : }
    3395             : /* }}} */
    3396             : 
    3397             : /* {{{ proto string addslashes(string str)
    3398             :    Escapes single quote, double quotes and backslash characters in a string with backslashes */
    3399      394879 : PHP_FUNCTION(addslashes)
    3400             : {
    3401             :         char *str;
    3402             :         int  str_len;
    3403             : 
    3404      394879 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
    3405           8 :                 return;
    3406             :         }
    3407             : 
    3408      394871 :         if (str_len == 0) {
    3409      112149 :                 RETURN_EMPTY_STRING();
    3410             :         }
    3411             : 
    3412      282722 :         RETURN_STRING(php_addslashes(str,
    3413             :                                      str_len,
    3414             :                                      &Z_STRLEN_P(return_value), 0
    3415             :                                      TSRMLS_CC), 0);
    3416             : }
    3417             : /* }}} */
    3418             : 
    3419             : /* {{{ proto string stripcslashes(string str)
    3420             :    Strips backslashes from a string. Uses C-style conventions */
    3421          35 : PHP_FUNCTION(stripcslashes)
    3422             : {
    3423             :         char *str;
    3424             :         int  str_len;
    3425             : 
    3426          35 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
    3427           8 :                 return;
    3428             :         }
    3429             : 
    3430          27 :         ZVAL_STRINGL(return_value, str, str_len, 1);
    3431          27 :         php_stripcslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value));
    3432             : }
    3433             : /* }}} */
    3434             : 
    3435             : /* {{{ proto string stripslashes(string str)
    3436             :    Strips backslashes from a string */
    3437         111 : PHP_FUNCTION(stripslashes)
    3438             : {
    3439             :         char *str;
    3440             :         int  str_len;
    3441             : 
    3442         111 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
    3443           8 :                 return;
    3444             :         }
    3445             : 
    3446         103 :         ZVAL_STRINGL(return_value, str, str_len, 1);
    3447         103 :         php_stripslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC);
    3448             : }
    3449             : /* }}} */
    3450             : 
    3451             : #ifndef HAVE_STRERROR
    3452             : /* {{{ php_strerror
    3453             :  */
    3454             : char *php_strerror(int errnum)
    3455             : {
    3456             :         extern int sys_nerr;
    3457             :         extern char *sys_errlist[];
    3458             :         TSRMLS_FETCH();
    3459             : 
    3460             :         if ((unsigned int) errnum < sys_nerr) {
    3461             :                 return(sys_errlist[errnum]);
    3462             :         }
    3463             : 
    3464             :         (void) snprintf(BG(str_ebuf), sizeof(php_basic_globals.str_ebuf), "Unknown error: %d", errnum);
    3465             :         return(BG(str_ebuf));
    3466             : }
    3467             : /* }}} */
    3468             : #endif
    3469             : 
    3470             : /* {{{ php_stripcslashes
    3471             :  */
    3472          27 : PHPAPI void php_stripcslashes(char *str, int *len)
    3473             : {
    3474             :         char *source, *target, *end;
    3475          27 :         int  nlen = *len, i;
    3476             :         char numtmp[4];
    3477             : 
    3478         134 :         for (source=str, end=str+nlen, target=str; source < end; source++) {
    3479         142 :                 if (*source == '\\' && source+1 < end) {
    3480          35 :                         source++;
    3481          35 :                         switch (*source) {
    3482           2 :                                 case 'n':  *target++='\n'; nlen--; break;
    3483           2 :                                 case 'r':  *target++='\r'; nlen--; break;
    3484           0 :                                 case 'a':  *target++='\a'; nlen--; break;
    3485           0 :                                 case 't':  *target++='\t'; nlen--; break;
    3486           0 :                                 case 'v':  *target++='\v'; nlen--; break;
    3487           0 :                                 case 'b':  *target++='\b'; nlen--; break;
    3488           0 :                                 case 'f':  *target++='\f'; nlen--; break;
    3489           0 :                                 case '\\': *target++='\\'; nlen--; break;
    3490             :                                 case 'x':
    3491          11 :                                         if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3492          11 :                                                 numtmp[0] = *++source;
    3493          22 :                                                 if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3494          11 :                                                         numtmp[1] = *++source;
    3495          11 :                                                         numtmp[2] = '\0';
    3496          11 :                                                         nlen-=3;
    3497             :                                                 } else {
    3498           0 :                                                         numtmp[1] = '\0';
    3499           0 :                                                         nlen-=2;
    3500             :                                                 }
    3501          11 :                                                 *target++=(char)strtol(numtmp, NULL, 16);
    3502          11 :                                                 break;
    3503             :                                         }
    3504             :                                         /* break is left intentionally */
    3505             :                                 default:
    3506          20 :                                         i=0;
    3507          73 :                                         while (source < end && *source >= '0' && *source <= '7' && i<3) {
    3508          33 :                                                 numtmp[i++] = *source++;
    3509             :                                         }
    3510          20 :                                         if (i) {
    3511          11 :                                                 numtmp[i]='\0';
    3512          11 :                                                 *target++=(char)strtol(numtmp, NULL, 8);
    3513          11 :                                                 nlen-=i;
    3514          11 :                                                 source--;
    3515             :                                         } else {
    3516           9 :                                                 *target++=*source;
    3517           9 :                                                 nlen--;
    3518             :                                         }
    3519             :                         }
    3520             :                 } else {
    3521          72 :                         *target++=*source;
    3522             :                 }
    3523             :         }
    3524             : 
    3525          27 :         if (nlen != 0) {
    3526          18 :                 *target='\0';
    3527             :         }
    3528             : 
    3529          27 :         *len = nlen;
    3530          27 : }
    3531             : /* }}} */
    3532             : 
    3533             : /* {{{ php_addcslashes
    3534             :  */
    3535        1795 : PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int should_free, char *what, int wlength TSRMLS_DC)
    3536             : {
    3537             :         char flags[256];
    3538        1795 :         char *new_str = safe_emalloc(4, (length?length:(length=strlen(str))), 1);
    3539             :         char *source, *target;
    3540             :         char *end;
    3541             :         char c;
    3542             :         int  newlen;
    3543             : 
    3544        1795 :         if (!wlength) {
    3545           0 :                 wlength = strlen(what);
    3546             :         }
    3547             : 
    3548        1795 :         php_charmask((unsigned char *)what, wlength, flags TSRMLS_CC);
    3549             : 
    3550       20608 :         for (source = (char*)str, end = source + length, target = new_str; source < end; source++) {
    3551       18813 :                 c = *source;
    3552       18813 :                 if (flags[(unsigned char)c]) {
    3553         161 :                         if ((unsigned char) c < 32 || (unsigned char) c > 126) {
    3554          16 :                                 *target++ = '\\';
    3555          16 :                                 switch (c) {
    3556           2 :                                         case '\n': *target++ = 'n'; break;
    3557           2 :                                         case '\t': *target++ = 't'; break;
    3558           2 :                                         case '\r': *target++ = 'r'; break;
    3559           0 :                                         case '\a': *target++ = 'a'; break;
    3560           2 :                                         case '\v': *target++ = 'v'; break;
    3561           0 :                                         case '\b': *target++ = 'b'; break;
    3562           2 :                                         case '\f': *target++ = 'f'; break;
    3563           6 :                                         default: target += sprintf(target, "%03o", (unsigned char) c);
    3564             :                                 }
    3565          16 :                                 continue;
    3566             :                         }
    3567         145 :                         *target++ = '\\';
    3568             :                 }
    3569       18797 :                 *target++ = c;
    3570             :         }
    3571        1795 :         *target = 0;
    3572        1795 :         newlen = target - new_str;
    3573        1795 :         if (target - new_str < length * 4) {
    3574        1746 :                 new_str = erealloc(new_str, newlen + 1);
    3575             :         }
    3576        1795 :         if (new_length) {
    3577        1795 :                 *new_length = newlen;
    3578             :         }
    3579        1795 :         if (should_free) {
    3580           0 :                 STR_FREE((char*)str);
    3581             :         }
    3582        1795 :         return new_str;
    3583             : }
    3584             : /* }}} */
    3585             : 
    3586             : /* {{{ php_addslashes
    3587             :  */
    3588      282750 : PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC)
    3589             : {
    3590             :         /* maximum string length, worst case situation */
    3591             :         char *new_str;
    3592             :         char *source, *target;
    3593             :         char *end;
    3594             :         int local_new_length;
    3595             : 
    3596      282750 :         if (!new_length) {
    3597           8 :                 new_length = &local_new_length;
    3598             :         }
    3599      282750 :         if (!str) {
    3600           0 :                 *new_length = 0;
    3601           0 :                 return str;
    3602             :         }
    3603      282750 :         new_str = (char *) safe_emalloc(2, (length ? length : (length = strlen(str))), 1);
    3604      282750 :         source = str;
    3605      282750 :         end = source + length;
    3606      282750 :         target = new_str;
    3607             : 
    3608     1492067 :         while (source < end) {
    3609      926567 :                 switch (*source) {
    3610             :                         case '\0':
    3611          29 :                                 *target++ = '\\';
    3612          29 :                                 *target++ = '0';
    3613          29 :                                 break;
    3614             :                         case '\'':
    3615             :                         case '\"':
    3616             :                         case '\\':
    3617         224 :                                 *target++ = '\\';
    3618             :                                 /* break is missing *intentionally* */
    3619             :                         default:
    3620      926538 :                                 *target++ = *source;
    3621             :                                 break;
    3622             :                 }
    3623             : 
    3624      926567 :                 source++;
    3625             :         }
    3626             : 
    3627      282750 :         *target = 0;
    3628      282750 :         *new_length = target - new_str;
    3629      282750 :         if (should_free) {
    3630           0 :                 STR_FREE(str);
    3631             :         }
    3632      282750 :         new_str = (char *) erealloc(new_str, *new_length + 1);
    3633      282750 :         return new_str;
    3634             : }
    3635             : /* }}} */
    3636             : 
    3637             : #define _HEB_BLOCK_TYPE_ENG 1
    3638             : #define _HEB_BLOCK_TYPE_HEB 2
    3639             : #define isheb(c)      (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0)
    3640             : #define _isblank(c)   (((((unsigned char) c) == ' '  || ((unsigned char) c) == '\t')) ? 1 : 0)
    3641             : #define _isnewline(c) (((((unsigned char) c) == '\n' || ((unsigned char) c) == '\r')) ? 1 : 0)
    3642             : 
    3643             : /* {{{ php_char_to_str_ex
    3644             :  */
    3645        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)
    3646             : {
    3647        6336 :         int char_count = 0;
    3648        6336 :         int replaced = 0;
    3649        6336 :         char *source, *target, *tmp, *source_end=str+len, *tmp_end = NULL;
    3650             : 
    3651        6336 :         if (case_sensitivity) {
    3652        6326 :                 char *p = str, *e = p + len;
    3653       21676 :                 while ((p = memchr(p, from, (e - p)))) {
    3654        9024 :                         char_count++;
    3655        9024 :                         p++;
    3656             :                 }
    3657             :         } else {
    3658         327 :                 for (source = str; source < source_end; source++) {
    3659         317 :                         if (tolower(*source) == tolower(from)) {
    3660          29 :                                 char_count++;
    3661             :                         }
    3662             :                 }
    3663             :         }
    3664             : 
    3665        6336 :         if (char_count == 0 && case_sensitivity) {
    3666        1252 :                 ZVAL_STRINGL(result, str, len, 1);
    3667        1252 :                 return 0;
    3668             :         }
    3669             : 
    3670        5084 :         Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
    3671        5084 :         Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1);
    3672        5084 :         Z_TYPE_P(result) = IS_STRING;
    3673             : 
    3674        5084 :         if (case_sensitivity) {
    3675        5074 :                 char *p = str, *e = p + len, *s = str;
    3676       19172 :                 while ((p = memchr(p, from, (e - p)))) {
    3677        9024 :                         memcpy(target, s, (p - s));
    3678        9024 :                         target += p - s;
    3679        9024 :                         memcpy(target, to, to_len);
    3680        9024 :                         target += to_len;
    3681        9024 :                         p++;
    3682        9024 :                         s = p;
    3683        9024 :                         if (replace_count) {
    3684         266 :                                 *replace_count += 1;
    3685             :                         }
    3686             :                 }
    3687        5074 :                 if (s < e) {
    3688        1285 :                         memcpy(target, s, (e - s));
    3689        1285 :                         target += e - s;
    3690             :                 }
    3691             :         } else {
    3692         327 :                 for (source = str; source < source_end; source++) {
    3693         317 :                         if (tolower(*source) == tolower(from)) {
    3694          29 :                                 replaced = 1;
    3695          29 :                                 if (replace_count) {
    3696           0 :                                         *replace_count += 1;
    3697             :                                 }
    3698         117 :                                 for (tmp = to, tmp_end = tmp+to_len; tmp < tmp_end; tmp++) {
    3699          88 :                                         *target = *tmp;
    3700          88 :                                         target++;
    3701             :                                 }
    3702             :                         } else {
    3703         288 :                                 *target = *source;
    3704         288 :                                 target++;
    3705             :                         }
    3706             :                 }
    3707             :         }
    3708        5084 :         *target = 0;
    3709        5084 :         return replaced;
    3710             : }
    3711             : /* }}} */
    3712             : 
    3713             : /* {{{ php_char_to_str
    3714             :  */
    3715          34 : PHPAPI int php_char_to_str(char *str, uint len, char from, char *to, int to_len, zval *result)
    3716             : {
    3717          34 :         return php_char_to_str_ex(str, len, from, to, to_len, result, 1, NULL);
    3718             : }
    3719             : /* }}} */
    3720             : 
    3721             : /* {{{ php_str_to_str_ex
    3722             :  */
    3723      164905 : PHPAPI char *php_str_to_str_ex(char *haystack, int length,
    3724             :         char *needle, int needle_len, char *str, int str_len, int *_new_length, int case_sensitivity, int *replace_count)
    3725             : {
    3726             :         char *new_str;
    3727             : 
    3728      164905 :         if (needle_len < length) {
    3729      162197 :                 char *end, *haystack_dup = NULL, *needle_dup = NULL;
    3730             :                 char *e, *s, *p, *r;
    3731             : 
    3732      162197 :                 if (needle_len == str_len) {
    3733       23585 :                         new_str = estrndup(haystack, length);
    3734       23585 :                         *_new_length = length;
    3735             : 
    3736       23585 :                         if (case_sensitivity) {
    3737       23583 :                                 end = new_str + length;
    3738       23821 :                                 for (p = new_str; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3739         238 :                                         memcpy(r, str, str_len);
    3740         238 :                                         if (replace_count) {
    3741           9 :                                                 (*replace_count)++;
    3742             :                                         }
    3743             :                                 }
    3744             :                         } else {
    3745           2 :                                 haystack_dup = estrndup(haystack, length);
    3746           2 :                                 needle_dup = estrndup(needle, needle_len);
    3747           2 :                                 php_strtolower(haystack_dup, length);
    3748           2 :                                 php_strtolower(needle_dup, needle_len);
    3749           2 :                                 end = haystack_dup + length;
    3750          16 :                                 for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
    3751          14 :                                         memcpy(new_str + (r - haystack_dup), str, str_len);
    3752          14 :                                         if (replace_count) {
    3753           7 :                                                 (*replace_count)++;
    3754             :                                         }
    3755             :                                 }
    3756           2 :                                 efree(haystack_dup);
    3757           2 :                                 efree(needle_dup);
    3758             :                         }
    3759       23585 :                         return new_str;
    3760             :                 } else {
    3761      138612 :                         if (!case_sensitivity) {
    3762        1078 :                                 haystack_dup = estrndup(haystack, length);
    3763        1078 :                                 needle_dup = estrndup(needle, needle_len);
    3764        1078 :                                 php_strtolower(haystack_dup, length);
    3765        1078 :                                 php_strtolower(needle_dup, needle_len);
    3766             :                         }
    3767             : 
    3768      138612 :                         if (str_len < needle_len) {
    3769       82499 :                                 new_str = emalloc(length + 1);
    3770             :                         } else {
    3771       56113 :                                 int count = 0;
    3772             :                                 char *o, *n, *endp;
    3773             : 
    3774       56113 :                                 if (case_sensitivity) {
    3775       55085 :                                         o = haystack;
    3776       55085 :                                         n = needle;
    3777             :                                 } else {
    3778        1028 :                                         o = haystack_dup;
    3779        1028 :                                         n = needle_dup;
    3780             :                                 }
    3781       56113 :                                 endp = o + length;
    3782             : 
    3783      173457 :                                 while ((o = php_memnstr(o, n, needle_len, endp))) {
    3784       61231 :                                         o += needle_len;
    3785       61231 :                                         count++;
    3786             :                                 }
    3787       56113 :                                 if (count == 0) {
    3788             :                                         /* Needle doesn't occur, shortcircuit the actual replacement. */
    3789       46438 :                                         if (haystack_dup) {
    3790        1004 :                                                 efree(haystack_dup);
    3791             :                                         }
    3792       46438 :                                         if (needle_dup) {
    3793        1004 :                                                 efree(needle_dup);
    3794             :                                         }
    3795       46438 :                                         new_str = estrndup(haystack, length);
    3796       46438 :                                         if (_new_length) {
    3797       46438 :                                                 *_new_length = length;
    3798             :                                         }
    3799       46438 :                                         return new_str;
    3800             :                                 } else {
    3801        9675 :                                         new_str = safe_emalloc(count, str_len - needle_len, length + 1);
    3802             :                                 }
    3803             :                         }
    3804             : 
    3805       92174 :                         e = s = new_str;
    3806             : 
    3807       92174 :                         if (case_sensitivity) {
    3808       92100 :                                 end = haystack + length;
    3809      187377 :                                 for (p = haystack; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3810       95277 :                                         memcpy(e, p, r - p);
    3811       95277 :                                         e += r - p;
    3812       95277 :                                         memcpy(e, str, str_len);
    3813       95277 :                                         e += str_len;
    3814       95277 :                                         if (replace_count) {
    3815          66 :                                                 (*replace_count)++;
    3816             :                                         }
    3817             :                                 }
    3818             : 
    3819       92100 :                                 if (p < end) {
    3820       91204 :                                         memcpy(e, p, end - p);
    3821       91204 :                                         e += end - p;
    3822             :                                 }
    3823             :                         } else {
    3824          74 :                                 end = haystack_dup + length;
    3825             : 
    3826         246 :                                 for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
    3827         172 :                                         memcpy(e, haystack + (p - haystack_dup), r - p);
    3828         172 :                                         e += r - p;
    3829         172 :                                         memcpy(e, str, str_len);
    3830         172 :                                         e += str_len;
    3831         172 :                                         if (replace_count) {
    3832          21 :                                                 (*replace_count)++;
    3833             :                                         }
    3834             :                                 }
    3835             : 
    3836          74 :                                 if (p < end) {
    3837          31 :                                         memcpy(e, haystack + (p - haystack_dup), end - p);
    3838          31 :                                         e += end - p;
    3839             :                                 }
    3840             :                         }
    3841             : 
    3842       92174 :                         if (haystack_dup) {
    3843          74 :                                 efree(haystack_dup);
    3844             :                         }
    3845       92174 :                         if (needle_dup) {
    3846          74 :                                 efree(needle_dup);
    3847             :                         }
    3848             : 
    3849       92174 :                         *e = '\0';
    3850       92174 :                         *_new_length = e - s;
    3851             : 
    3852       92174 :                         new_str = erealloc(new_str, *_new_length + 1);
    3853       92174 :                         return new_str;
    3854             :                 }
    3855        2708 :         } else if (needle_len > length) {
    3856             : nothing_todo:
    3857        2639 :                 *_new_length = length;
    3858        2639 :                 new_str = estrndup(haystack, length);
    3859        2639 :                 return new_str;
    3860             :         } else {
    3861         893 :                 if (case_sensitivity && memcmp(haystack, needle, length)) {
    3862             :                         goto nothing_todo;
    3863         397 :                 } else if (!case_sensitivity) {
    3864             :                         char *l_haystack, *l_needle;
    3865             : 
    3866         370 :                         l_haystack = estrndup(haystack, length);
    3867         370 :                         l_needle = estrndup(needle, length);
    3868             : 
    3869         370 :                         php_strtolower(l_haystack, length);
    3870         370 :                         php_strtolower(l_needle, length);
    3871             : 
    3872         370 :                         if (memcmp(l_haystack, l_needle, length)) {
    3873         328 :                                 efree(l_haystack);
    3874         328 :                                 efree(l_needle);
    3875         328 :                                 goto nothing_todo;
    3876             :                         }
    3877          42 :                         efree(l_haystack);
    3878          42 :                         efree(l_needle);
    3879             :                 }
    3880             : 
    3881          69 :                 *_new_length = str_len;
    3882          69 :                 new_str = estrndup(str, str_len);
    3883             : 
    3884          69 :                 if (replace_count) {
    3885          16 :                         (*replace_count)++;
    3886             :                 }
    3887          69 :                 return new_str;
    3888             :         }
    3889             : 
    3890             : }
    3891             : /* }}} */
    3892             : 
    3893             : /* {{{ php_str_to_str
    3894             :  */
    3895           0 : PHPAPI char *php_str_to_str(char *haystack, int length,
    3896             :         char *needle, int needle_len, char *str, int str_len, int *_new_length)
    3897             : {
    3898           0 :         return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, _new_length, 1, NULL);
    3899             : }
    3900             : /* }}} */
    3901             : 
    3902             : /* {{{ php_str_replace_in_subject
    3903             :  */
    3904      152911 : static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int *replace_count)
    3905             : {
    3906             :         zval            **search_entry,
    3907      152911 :                                 **replace_entry = NULL,
    3908             :                                   temp_result;
    3909      152911 :         char            *replace_value = NULL;
    3910      152911 :         int                      replace_len = 0;
    3911             : 
    3912             :         /* Make sure we're dealing with strings. */
    3913      153373 :         convert_to_string_ex(subject);
    3914      152911 :         Z_TYPE_P(result) = IS_STRING;
    3915      152911 :         if (Z_STRLEN_PP(subject) == 0) {
    3916          99 :                 ZVAL_STRINGL(result, "", 0, 1);
    3917          99 :                 return;
    3918             :         }
    3919             : 
    3920             :         /* If search is an array */
    3921      152812 :         if (Z_TYPE_P(search) == IS_ARRAY) {
    3922             :                 /* Duplicate subject string for repeated replacement */
    3923       32840 :                 MAKE_COPY_ZVAL(subject, result);
    3924             : 
    3925       32840 :                 zend_hash_internal_pointer_reset(Z_ARRVAL_P(search));
    3926             : 
    3927       32840 :                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3928          26 :                         zend_hash_internal_pointer_reset(Z_ARRVAL_P(replace));
    3929             :                 } else {
    3930             :                         /* Set replacement value to the passed one */
    3931       32814 :                         replace_value = Z_STRVAL_P(replace);
    3932       32814 :                         replace_len = Z_STRLEN_P(replace);
    3933             :                 }
    3934             : 
    3935             :                 /* For each entry in the search array, get the entry */
    3936      115574 :                 while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) {
    3937             :                         /* Make sure we're dealing with strings. */
    3938       99792 :                         SEPARATE_ZVAL(search_entry);
    3939       49896 :                         convert_to_string(*search_entry);
    3940       49896 :                         if (Z_STRLEN_PP(search_entry) == 0) {
    3941           0 :                                 zend_hash_move_forward(Z_ARRVAL_P(search));
    3942           0 :                                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3943           0 :                                         zend_hash_move_forward(Z_ARRVAL_P(replace));
    3944             :                                 }
    3945           0 :                                 continue;
    3946             :                         }
    3947             : 
    3948             :                         /* If replace is an array. */
    3949       49896 :                         if (Z_TYPE_P(replace) == IS_ARRAY) {
    3950             :                                 /* Get current entry */
    3951          68 :                                 if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) {
    3952             :                                         /* Make sure we're dealing with strings. */
    3953          58 :                                         convert_to_string_ex(replace_entry);
    3954             : 
    3955             :                                         /* Set replacement value to the one we got from array */
    3956          58 :                                         replace_value = Z_STRVAL_PP(replace_entry);
    3957          58 :                                         replace_len = Z_STRLEN_PP(replace_entry);
    3958             : 
    3959          58 :                                         zend_hash_move_forward(Z_ARRVAL_P(replace));
    3960             :                                 } else {
    3961             :                                         /* We've run out of replacement strings, so use an empty one. */
    3962          10 :                                         replace_value = "";
    3963          10 :                                         replace_len = 0;
    3964             :                                 }
    3965             :                         }
    3966             : 
    3967       49896 :                         if (Z_STRLEN_PP(search_entry) == 1) {
    3968        5128 :                                 php_char_to_str_ex(Z_STRVAL_P(result),
    3969        2564 :                                                                 Z_STRLEN_P(result),
    3970        2564 :                                                                 Z_STRVAL_PP(search_entry)[0],
    3971             :                                                                 replace_value,
    3972             :                                                                 replace_len,
    3973             :                                                                 &temp_result,
    3974             :                                                                 case_sensitivity,
    3975             :                                                                 replace_count);
    3976       47332 :                         } else if (Z_STRLEN_PP(search_entry) > 1) {
    3977       94664 :                                 Z_STRVAL(temp_result) = php_str_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result),
    3978       94664 :                                                                                                                    Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry),
    3979             :                                                                                                                    replace_value, replace_len, &Z_STRLEN(temp_result), case_sensitivity, replace_count);
    3980             :                         }
    3981             : 
    3982       49896 :            str_efree(Z_STRVAL_P(result));
    3983       49896 :                         Z_STRVAL_P(result) = Z_STRVAL(temp_result);
    3984       49896 :                         Z_STRLEN_P(result) = Z_STRLEN(temp_result);
    3985             : 
    3986       49896 :                         if (Z_STRLEN_P(result) == 0) {
    3987           2 :                                 return;
    3988             :                         }
    3989             : 
    3990       49894 :                         zend_hash_move_forward(Z_ARRVAL_P(search));
    3991             :                 }
    3992             :         } else {
    3993      119972 :                 if (Z_STRLEN_P(search) == 1) {
    3994       11214 :                         php_char_to_str_ex(Z_STRVAL_PP(subject),
    3995        3738 :                                                         Z_STRLEN_PP(subject),
    3996        3738 :                                                         Z_STRVAL_P(search)[0],
    3997             :                                                         Z_STRVAL_P(replace),
    3998             :                                                         Z_STRLEN_P(replace),
    3999             :                                                         result,
    4000             :                                                         case_sensitivity,
    4001             :                                                         replace_count);
    4002      116234 :                 } else if (Z_STRLEN_P(search) > 1) {
    4003      116180 :                         Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject),
    4004             :                                                                                                         Z_STRVAL_P(search), Z_STRLEN_P(search),
    4005             :                                                                                                         Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), case_sensitivity, replace_count);
    4006             :                 } else {
    4007          54 :                         MAKE_COPY_ZVAL(subject, result);
    4008             :                 }
    4009             :         }
    4010             : }
    4011             : /* }}} */
    4012             : 
    4013             : /* {{{ php_str_replace_common
    4014             :  */
    4015      152657 : static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
    4016             : {
    4017      152657 :         zval **subject, **search, **replace, **subject_entry, **zcount = NULL;
    4018             :         zval *result;
    4019             :         char *string_key;
    4020             :         uint string_key_len;
    4021             :         ulong num_key;
    4022      152657 :         int count = 0;
    4023      152657 :         int argc = ZEND_NUM_ARGS();
    4024             : 
    4025      152657 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &search, &replace, &subject, &zcount) == FAILURE) {
    4026          15 :                 return;
    4027             :         }
    4028             : 
    4029      305700 :         SEPARATE_ZVAL(search);
    4030      305298 :         SEPARATE_ZVAL(replace);
    4031      608284 :         SEPARATE_ZVAL(subject);
    4032             : 
    4033             :         /* Make sure we're dealing with strings and do the replacement. */
    4034      152642 :         if (Z_TYPE_PP(search) != IS_ARRAY) {
    4035      119911 :                 convert_to_string_ex(search);
    4036      119845 :                 convert_to_string_ex(replace);
    4037       32821 :         } else if (Z_TYPE_PP(replace) != IS_ARRAY) {
    4038       32804 :                 convert_to_string_ex(replace);
    4039             :         }
    4040             : 
    4041             :         /* if subject is an array */
    4042      152642 :         if (Z_TYPE_PP(subject) == IS_ARRAY) {
    4043          45 :                 array_init(return_value);
    4044          45 :                 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject));
    4045             : 
    4046             :                 /* For each subject entry, convert it to string, then perform replacement
    4047             :                    and add the result to the return_value array. */
    4048         432 :                 while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) {
    4049         656 :                         if (Z_TYPE_PP(subject_entry) != IS_ARRAY && Z_TYPE_PP(subject_entry) != IS_OBJECT) {
    4050         314 :                                 MAKE_STD_ZVAL(result);
    4051        1200 :                                 SEPARATE_ZVAL(subject_entry);
    4052         314 :                                 php_str_replace_in_subject(*search, *replace, subject_entry, result, case_sensitivity, (argc > 3) ? &count : NULL);
    4053             :                         } else {
    4054          28 :                                 ALLOC_ZVAL(result);
    4055          28 :                                 Z_ADDREF_P(*subject_entry);
    4056          84 :                                 COPY_PZVAL_TO_ZVAL(*result, *subject_entry);
    4057             :                         }
    4058             :                         /* Add to return array */
    4059         342 :                         switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), &string_key,
    4060         342 :                                                                                                 &string_key_len, &num_key, 0, NULL)) {
    4061             :                                 case HASH_KEY_IS_STRING:
    4062           4 :                                         add_assoc_zval_ex(return_value, string_key, string_key_len, result);
    4063           4 :                                         break;
    4064             : 
    4065             :                                 case HASH_KEY_IS_LONG:
    4066         338 :                                         add_index_zval(return_value, num_key, result);
    4067             :                                         break;
    4068             :                         }
    4069             : 
    4070         342 :                         zend_hash_move_forward(Z_ARRVAL_PP(subject));
    4071             :                 }
    4072             :         } else {        /* if subject is not an array */
    4073      152597 :                 php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? &count : NULL);
    4074             :         }
    4075      152642 :         if (argc > 3) {
    4076         135 :                 zval_dtor(*zcount);
    4077         135 :                 ZVAL_LONG(*zcount, count);
    4078             :         }
    4079             : }
    4080             : /* }}} */
    4081             : 
    4082             : /* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count])
    4083             :    Replaces all occurrences of search in haystack with replace */
    4084      152552 : PHP_FUNCTION(str_replace)
    4085             : {
    4086      152552 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4087      152552 : }
    4088             : /* }}} */
    4089             : 
    4090             : /* {{{ proto mixed str_ireplace(mixed search, mixed replace, mixed subject [, int &replace_count])
    4091             :    Replaces all occurrences of search in haystack with replace / case-insensitive */
    4092         105 : PHP_FUNCTION(str_ireplace)
    4093             : {
    4094         105 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4095         105 : }
    4096             : /* }}} */
    4097             : 
    4098             : /* {{{ php_hebrev
    4099             :  *
    4100             :  * Converts Logical Hebrew text (Hebrew Windows style) to Visual text
    4101             :  * Cheers/complaints/flames - Zeev Suraski <zeev@php.net>
    4102             :  */
    4103         106 : static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
    4104             : {
    4105             :         char *str;
    4106             :         char *heb_str, *tmp, *target, *broken_str;
    4107             :         int block_start, block_end, block_type, block_length, i;
    4108         106 :         long max_chars=0;
    4109             :         int begin, end, char_count, orig_begin;
    4110             :         int str_len;
    4111             : 
    4112         106 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &max_chars) == FAILURE) {
    4113          26 :                 return;
    4114             :         }
    4115             : 
    4116          80 :         if (str_len == 0) {
    4117          12 :                 RETURN_FALSE;
    4118             :         }
    4119             : 
    4120          68 :         tmp = str;
    4121          68 :         block_start=block_end=0;
    4122             : 
    4123          68 :         heb_str = (char *) emalloc(str_len+1);
    4124          68 :         target = heb_str+str_len;
    4125          68 :         *target = 0;
    4126          68 :         target--;
    4127             : 
    4128          68 :         block_length=0;
    4129             : 
    4130          68 :         if (isheb(*tmp)) {
    4131           0 :                 block_type = _HEB_BLOCK_TYPE_HEB;
    4132             :         } else {
    4133          68 :                 block_type = _HEB_BLOCK_TYPE_ENG;
    4134             :         }
    4135             : 
    4136             :         do {
    4137         288 :                 if (block_type == _HEB_BLOCK_TYPE_HEB) {
    4138         660 :                         while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) {
    4139         396 :                                 tmp++;
    4140         396 :                                 block_end++;
    4141         396 :                                 block_length++;
    4142             :                         }
    4143         528 :                         for (i = block_start; i<= block_end; i++) {
    4144         396 :                                 *target = str[i];
    4145         396 :                                 switch (*target) {
    4146             :                                         case '(':
    4147          22 :                                                 *target = ')';
    4148          22 :                                                 break;
    4149             :                                         case ')':
    4150          22 :                                                 *target = '(';
    4151          22 :                                                 break;
    4152             :                                         case '[':
    4153           0 :                                                 *target = ']';
    4154           0 :                                                 break;
    4155             :                                         case ']':
    4156           0 :                                                 *target = '[';
    4157           0 :                                                 break;
    4158             :                                         case '{':
    4159           0 :                                                 *target = '}';
    4160           0 :                                                 break;
    4161             :                                         case '}':
    4162           0 :                                                 *target = '{';
    4163           0 :                                                 break;
    4164             :                                         case '<':
    4165           0 :                                                 *target = '>';
    4166           0 :                                                 break;
    4167             :                                         case '>':
    4168          22 :                                                 *target = '<';
    4169          22 :                                                 break;
    4170             :                                         case '\\':
    4171           0 :                                                 *target = '/';
    4172           0 :                                                 break;
    4173             :                                         case '/':
    4174           0 :                                                 *target = '\\';
    4175             :                                                 break;
    4176             :                                         default:
    4177             :                                                 break;
    4178             :                                 }
    4179         396 :                                 target--;
    4180             :                         }
    4181         132 :                         block_type = _HEB_BLOCK_TYPE_ENG;
    4182             :                 } else {
    4183        7164 :                         while (!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end < str_len-1) {
    4184        6852 :                                 tmp++;
    4185        6852 :                                 block_end++;
    4186        6852 :                                 block_length++;
    4187             :                         }
    4188         466 :                         while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
    4189         154 :                                 tmp--;
    4190         154 :                                 block_end--;
    4191             :                         }
    4192        6922 :                         for (i = block_end; i >= block_start; i--) {
    4193        6766 :                                 *target = str[i];
    4194        6766 :                                 target--;
    4195             :                         }
    4196         156 :                         block_type = _HEB_BLOCK_TYPE_HEB;
    4197             :                 }
    4198         288 :                 block_start=block_end+1;
    4199         288 :         } while (block_end < str_len-1);
    4200             : 
    4201             : 
    4202          68 :         broken_str = (char *) emalloc(str_len+1);
    4203          68 :         begin=end=str_len-1;
    4204          68 :         target = broken_str;
    4205             : 
    4206             :         while (1) {
    4207        1483 :                 char_count=0;
    4208        8747 :                 while ((!max_chars || char_count < max_chars) && begin > 0) {
    4209        5915 :                         char_count++;
    4210        5915 :                         begin--;
    4211        5915 :                         if (begin <= 0 || _isnewline(heb_str[begin])) {
    4212         268 :                                 while (begin > 0 && _isnewline(heb_str[begin-1])) {
    4213           0 :                                         begin--;
    4214           0 :                                         char_count++;
    4215             :                                 }
    4216         134 :                                 break;
    4217             :                         }
    4218             :                 }
    4219        1483 :                 if (char_count == max_chars) { /* try to avoid breaking words */
    4220         712 :                         int new_char_count=char_count, new_begin=begin;
    4221             : 
    4222        2398 :                         while (new_char_count > 0) {
    4223        1160 :                                 if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
    4224             :                                         break;
    4225             :                                 }
    4226         974 :                                 new_begin++;
    4227         974 :                                 new_char_count--;
    4228             :                         }
    4229         712 :                         if (new_char_count > 0) {
    4230         186 :                                 begin=new_begin;
    4231             :                         }
    4232             :                 }
    4233        1483 :                 orig_begin=begin;
    4234             : 
    4235        1483 :                 if (_isblank(heb_str[begin])) {
    4236         267 :                         heb_str[begin]='\n';
    4237             :                 }
    4238        3371 :                 while (begin <= end && _isnewline(heb_str[begin])) { /* skip leading newlines */
    4239         405 :                         begin++;
    4240             :                 }
    4241        8240 :                 for (i = begin; i <= end; i++) { /* copy content */
    4242        6757 :                         *target = heb_str[i];
    4243        6757 :                         target++;
    4244             :                 }
    4245        1888 :                 for (i = orig_begin; i <= end && _isnewline(heb_str[i]); i++) {
    4246         405 :                         *target = heb_str[i];
    4247         405 :                         target++;
    4248             :                 }
    4249        1483 :                 begin=orig_begin;
    4250             : 
    4251        1483 :                 if (begin <= 0) {
    4252          68 :                         *target = 0;
    4253          68 :                         break;
    4254             :                 }
    4255        1415 :                 begin--;
    4256        1415 :                 end=begin;
    4257        1415 :         }
    4258          68 :         efree(heb_str);
    4259             : 
    4260          68 :         if (convert_newlines) {
    4261          34 :                 php_char_to_str(broken_str, str_len,'\n', "<br />\n", 7, return_value);
    4262          34 :                 efree(broken_str);
    4263             :         } else {
    4264          34 :                 Z_STRVAL_P(return_value) = broken_str;
    4265          34 :                 Z_STRLEN_P(return_value) = str_len;
    4266          34 :                 Z_TYPE_P(return_value) = IS_STRING;
    4267             :         }
    4268             : }
    4269             : /* }}} */
    4270             : 
    4271             : /* {{{ proto string hebrev(string str [, int max_chars_per_line])
    4272             :    Converts logical Hebrew text to visual text */
    4273          53 : PHP_FUNCTION(hebrev)
    4274             : {
    4275          53 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4276          53 : }
    4277             : /* }}} */
    4278             : 
    4279             : /* {{{ proto string hebrevc(string str [, int max_chars_per_line])
    4280             :    Converts logical Hebrew text to visual text with newline conversion */
    4281          53 : PHP_FUNCTION(hebrevc)
    4282             : {
    4283          53 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4284          53 : }
    4285             : /* }}} */
    4286             : 
    4287             : /* {{{ proto string nl2br(string str [, bool is_xhtml])
    4288             :    Converts newlines to HTML line breaks */
    4289          60 : PHP_FUNCTION(nl2br)
    4290             : {
    4291             :         /* in brief this inserts <br /> or <br> before matched regexp \n\r?|\r\n? */
    4292             :         char            *tmp, *str;
    4293             :         int             new_length;
    4294             :         char            *end, *target;
    4295          60 :         int             repl_cnt = 0;
    4296             :         int             str_len;
    4297          60 :         zend_bool       is_xhtml = 1;
    4298             : 
    4299          60 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &str, &str_len, &is_xhtml) == FAILURE) {
    4300           8 :                 return;
    4301             :         }
    4302             : 
    4303          52 :         tmp = str;
    4304          52 :         end = str + str_len;
    4305             : 
    4306             :         /* it is really faster to scan twice and allocate mem once instead of scanning once
    4307             :            and constantly reallocing */
    4308         513 :         while (tmp < end) {
    4309         409 :                 if (*tmp == '\r') {
    4310          33 :                         if (*(tmp+1) == '\n') {
    4311          14 :                                 tmp++;
    4312             :                         }
    4313          33 :                         repl_cnt++;
    4314         376 :                 } else if (*tmp == '\n') {
    4315          46 :                         if (*(tmp+1) == '\r') {
    4316          13 :                                 tmp++;
    4317             :                         }
    4318          46 :                         repl_cnt++;
    4319             :                 }
    4320             : 
    4321         409 :                 tmp++;
    4322             :         }
    4323             : 
    4324          52 :         if (repl_cnt == 0) {
    4325          29 :                 RETURN_STRINGL(str, str_len, 1);
    4326             :         }
    4327             : 
    4328             :         {
    4329          23 :                 size_t repl_len = is_xhtml ? (sizeof("<br />") - 1) : (sizeof("<br>") - 1);
    4330             : 
    4331          23 :                 new_length = str_len + repl_cnt * repl_len;
    4332          23 :                 tmp = target = safe_emalloc(repl_cnt, repl_len, str_len + 1);
    4333             :         }
    4334             : 
    4335         303 :         while (str < end) {
    4336         257 :                 switch (*str) {
    4337             :                         case '\r':
    4338             :                         case '\n':
    4339          79 :                                 *target++ = '<';
    4340          79 :                                 *target++ = 'b';
    4341          79 :                                 *target++ = 'r';
    4342             : 
    4343          79 :                                 if (is_xhtml) {
    4344          79 :                                         *target++ = ' ';
    4345          79 :                                         *target++ = '/';
    4346             :                                 }
    4347             : 
    4348          79 :                                 *target++ = '>';
    4349             : 
    4350          79 :                                 if ((*str == '\r' && *(str+1) == '\n') || (*str == '\n' && *(str+1) == '\r')) {
    4351          27 :                                         *target++ = *str++;
    4352             :                                 }
    4353             :                                 /* lack of a break; is intentional */
    4354             :                         default:
    4355         257 :                                 *target++ = *str;
    4356             :                 }
    4357             : 
    4358         257 :                 str++;
    4359             :         }
    4360             : 
    4361          23 :         *target = '\0';
    4362             : 
    4363          23 :         RETURN_STRINGL(tmp, new_length, 0);
    4364             : }
    4365             : /* }}} */
    4366             : 
    4367             : /* {{{ proto string strip_tags(string str [, string allowable_tags])
    4368             :    Strips HTML and PHP tags from a string */
    4369         205 : PHP_FUNCTION(strip_tags)
    4370             : {
    4371             :         char *buf;
    4372             :         char *str;
    4373         205 :         zval **allow=NULL;
    4374         205 :         char *allowed_tags=NULL;
    4375         205 :         int allowed_tags_len=0;
    4376             :         int str_len;
    4377             :         size_t retval_len;
    4378             : 
    4379         205 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|Z", &str, &str_len, &allow) == FAILURE) {
    4380          14 :                 return;
    4381             :         }
    4382             : 
    4383             :         /* To maintain a certain BC, we allow anything for the second parameter and return original string */
    4384         191 :         if (allow != NULL) {
    4385         315 :                 convert_to_string_ex(allow);
    4386         113 :                 allowed_tags = Z_STRVAL_PP(allow);
    4387         113 :                 allowed_tags_len = Z_STRLEN_PP(allow);
    4388             :         }
    4389             : 
    4390         191 :         buf = estrndup(str, str_len);
    4391         191 :         retval_len = php_strip_tags_ex(buf, str_len, NULL, allowed_tags, allowed_tags_len, 0);
    4392         191 :         RETURN_STRINGL(buf, retval_len, 0);
    4393             : }
    4394             : /* }}} */
    4395             : 
    4396             : /* {{{ proto string setlocale(mixed category, string locale [, string ...])
    4397             :    Set locale information */
    4398         999 : PHP_FUNCTION(setlocale)
    4399             : {
    4400         999 :         zval ***args = NULL;
    4401             :         zval **pcategory, **plocale;
    4402         999 :         int num_args, cat, i = 0;
    4403             :         char *loc, *retval;
    4404             : 
    4405         999 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z+", &pcategory, &args, &num_args) == FAILURE) {
    4406           2 :                 return;
    4407             :         }
    4408             : 
    4409             : #ifdef HAVE_SETLOCALE
    4410         997 :         if (Z_TYPE_PP(pcategory) == IS_LONG) {
    4411         996 :                 convert_to_long_ex(pcategory);
    4412         996 :                 cat = Z_LVAL_PP(pcategory);
    4413             :         } else {
    4414             :                 /* FIXME: The following behaviour should be removed. */
    4415             :                 char *category;
    4416             : 
    4417           1 :                 php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "Passing locale category name as string is deprecated. Use the LC_* -constants instead");
    4418             : 
    4419           1 :                 convert_to_string_ex(pcategory);
    4420           1 :                 category = Z_STRVAL_PP(pcategory);
    4421             : 
    4422           1 :                 if (!strcasecmp("LC_ALL", category)) {
    4423           0 :                         cat = LC_ALL;
    4424           1 :                 } else if (!strcasecmp("LC_COLLATE", category)) {
    4425           0 :                         cat = LC_COLLATE;
    4426           1 :                 } else if (!strcasecmp("LC_CTYPE", category)) {
    4427           0 :                         cat = LC_CTYPE;
    4428             : #ifdef LC_MESSAGES
    4429           1 :                 } else if (!strcasecmp("LC_MESSAGES", category)) {
    4430           0 :                         cat = LC_MESSAGES;
    4431             : #endif
    4432           1 :                 } else if (!strcasecmp("LC_MONETARY", category)) {
    4433           0 :                         cat = LC_MONETARY;
    4434           1 :                 } else if (!strcasecmp("LC_NUMERIC", category)) {
    4435           0 :                         cat = LC_NUMERIC;
    4436           1 :                 } else if (!strcasecmp("LC_TIME", category)) {
    4437           0 :                         cat = LC_TIME;
    4438             :                 } else {
    4439           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);
    4440             : 
    4441           1 :                         if (args) {
    4442           1 :                                 efree(args);
    4443             :                         }
    4444           1 :                         RETURN_FALSE;
    4445             :                 }
    4446             :         }
    4447             : 
    4448         996 :         if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
    4449           2 :                 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(args[0]));
    4450             :         }
    4451             : 
    4452             :         while (1) {
    4453        1015 :                 if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
    4454           5 :                         if (!zend_hash_num_elements(Z_ARRVAL_PP(args[0]))) {
    4455           0 :                                 break;
    4456             :                         }
    4457           5 :                         zend_hash_get_current_data(Z_ARRVAL_PP(args[0]), (void **)&plocale);
    4458             :                 } else {
    4459        1010 :                         plocale = args[i];
    4460             :                 }
    4461             : 
    4462        1039 :                 convert_to_string_ex(plocale);
    4463             : 
    4464        1015 :                 if (!strcmp ("0", Z_STRVAL_PP(plocale))) {
    4465           7 :                         loc = NULL;
    4466             :                 } else {
    4467        1008 :                         loc = Z_STRVAL_PP(plocale);
    4468        1008 :                         if (Z_STRLEN_PP(plocale) >= 255) {
    4469           0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Specified locale name is too long");
    4470           0 :                                 break;
    4471             :                         }
    4472             :                 }
    4473             : 
    4474        1015 :                 retval = php_my_setlocale(cat, loc);
    4475             :                 zend_update_current_locale();
    4476        1015 :                 if (retval) {
    4477             :                         /* Remember if locale was changed */
    4478         994 :                         if (loc) {
    4479         987 :                                 STR_FREE(BG(locale_string));
    4480         987 :                                 BG(locale_string) = estrdup(retval);
    4481             :                         }
    4482             : 
    4483         994 :                         if (args) {
    4484         994 :                                 efree(args);
    4485             :                         }
    4486         994 :                         RETURN_STRING(retval, 1);
    4487             :                 }
    4488             : 
    4489          21 :                 if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
    4490           4 :                         if (zend_hash_move_forward(Z_ARRVAL_PP(args[0])) == FAILURE) break;
    4491             :                 } else {
    4492          17 :                         if (++i >= num_args) break;
    4493             :                 }
    4494          19 :         }
    4495             : 
    4496             : #endif
    4497           2 :         if (args) {
    4498           2 :                 efree(args);
    4499             :         }
    4500           2 :         RETURN_FALSE;
    4501             : }
    4502             : /* }}} */
    4503             : 
    4504             : /* {{{ proto void parse_str(string encoded_string [, array result])
    4505             :    Parses GET/POST/COOKIE data and sets global variables */
    4506          30 : PHP_FUNCTION(parse_str)
    4507             : {
    4508             :         char *arg;
    4509          30 :         zval *arrayArg = NULL;
    4510          30 :         char *res = NULL;
    4511             :         int arglen;
    4512             : 
    4513          30 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &arg, &arglen, &arrayArg) == FAILURE) {
    4514           2 :                 return;
    4515             :         }
    4516             : 
    4517          28 :         res = estrndup(arg, arglen);
    4518             : 
    4519          28 :         if (arrayArg == NULL) {
    4520             :                 zval tmp;
    4521             : 
    4522          14 :                 if (!EG(active_symbol_table)) {
    4523           0 :                         zend_rebuild_symbol_table(TSRMLS_C);
    4524             :                 }
    4525          14 :                 Z_ARRVAL(tmp) = EG(active_symbol_table);
    4526          14 :                 sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
    4527             :         } else  {
    4528             :                 zval ret;
    4529             : 
    4530          14 :                 array_init(&ret);
    4531          14 :                 sapi_module.treat_data(PARSE_STRING, res, &ret TSRMLS_CC);
    4532             :                 /* Clear out the array that was passed in. */
    4533          14 :                 zval_dtor(arrayArg);
    4534          14 :                 ZVAL_COPY_VALUE(arrayArg, &ret);
    4535             :         }
    4536             : }
    4537             : /* }}} */
    4538             : 
    4539             : #define PHP_TAG_BUF_SIZE 1023
    4540             : 
    4541             : /* {{{ php_tag_find
    4542             :  *
    4543             :  * Check if tag is in a set of tags
    4544             :  *
    4545             :  * states:
    4546             :  *
    4547             :  * 0 start tag
    4548             :  * 1 first non-whitespace char seen
    4549             :  */
    4550         555 : int php_tag_find(char *tag, int len, char *set) {
    4551             :         char c, *n, *t;
    4552         555 :         int state=0, done=0;
    4553             :         char *norm;
    4554             : 
    4555         555 :         if (len <= 0) {
    4556           0 :                 return 0;
    4557             :         }
    4558             : 
    4559         555 :         norm = emalloc(len+1);
    4560             : 
    4561         555 :         n = norm;
    4562         555 :         t = tag;
    4563         555 :         c = tolower(*t);
    4564             :         /*
    4565             :            normalize the tag removing leading and trailing whitespace
    4566             :            and turn any <a whatever...> into just <a> and any </tag>
    4567             :            into <tag>
    4568             :         */
    4569        3856 :         while (!done) {
    4570        2746 :                 switch (c) {
    4571             :                         case '<':
    4572         554 :                                 *(n++) = c;
    4573         554 :                                 break;
    4574             :                         case '>':
    4575         527 :                                 done =1;
    4576         527 :                                 break;
    4577             :                         default:
    4578        1665 :                                 if (!isspace((int)c)) {
    4579        1635 :                                         if (state == 0) {
    4580         554 :                                                 state=1;
    4581             :                                         }
    4582        1635 :                                         if (c != '/') {
    4583        1374 :                                                 *(n++) = c;
    4584             :                                         }
    4585             :                                 } else {
    4586          30 :                                         if (state == 1)
    4587          28 :                                                 done=1;
    4588             :                                 }
    4589             :                                 break;
    4590             :                 }
    4591        2746 :                 c = tolower(*(++t));
    4592             :         }
    4593         555 :         *(n++) = '>';
    4594         555 :         *n = '\0';
    4595         555 :         if (strstr(set, norm)) {
    4596         150 :                 done=1;
    4597             :         } else {
    4598         405 :                 done=0;
    4599             :         }
    4600         555 :         efree(norm);
    4601         555 :         return done;
    4602             : }
    4603             : /* }}} */
    4604             : 
    4605         232 : PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, int allow_len) /* {{{ */
    4606             : {
    4607         232 :         return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0);
    4608             : }
    4609             : /* }}} */
    4610             : 
    4611             : /* {{{ php_strip_tags
    4612             : 
    4613             :         A simple little state-machine to strip out html and php tags
    4614             : 
    4615             :         State 0 is the output state, State 1 means we are inside a
    4616             :         normal html tag and state 2 means we are inside a php tag.
    4617             : 
    4618             :         The state variable is passed in to allow a function like fgetss
    4619             :         to maintain state across calls to the function.
    4620             : 
    4621             :         lc holds the last significant character read and br is a bracket
    4622             :         counter.
    4623             : 
    4624             :         When an allow string is passed in we keep track of the string
    4625             :         in state 1 and when the tag is closed check it against the
    4626             :         allow string to see if we should allow it.
    4627             : 
    4628             :         swm: Added ability to strip <?xml tags without assuming it PHP
    4629             :         code.
    4630             : */
    4631         728 : PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow, int allow_len, zend_bool allow_tag_spaces)
    4632             : {
    4633             :         char *tbuf, *buf, *p, *tp, *rp, c, lc;
    4634         728 :         int br, i=0, depth=0, in_q = 0;
    4635         728 :         int state = 0, pos;
    4636         728 :         char *allow_free = NULL;
    4637             : 
    4638         728 :         if (stateptr)
    4639         232 :                 state = *stateptr;
    4640             : 
    4641         728 :         buf = estrndup(rbuf, len);
    4642         728 :         c = *buf;
    4643         728 :         lc = '\0';
    4644         728 :         p = buf;
    4645         728 :         rp = rbuf;
    4646         728 :         br = 0;
    4647         728 :         if (allow) {
    4648         522 :                 if (IS_INTERNED(allow)) {
    4649         241 :                         allow_free = allow = zend_str_tolower_dup(allow, allow_len);
    4650             :                 } else {
    4651          40 :                         allow_free = NULL;
    4652          40 :                         php_strtolower(allow, allow_len);
    4653             :                 }
    4654         281 :                 tbuf = emalloc(PHP_TAG_BUF_SIZE + 1);
    4655         281 :                 tp = tbuf;
    4656             :         } else {
    4657         447 :                 tbuf = tp = NULL;
    4658             :         }
    4659             : 
    4660      209965 :         while (i < len) {
    4661      208509 :                 switch (c) {
    4662             :                         case '\0':
    4663           2 :                                 break;
    4664             :                         case '<':
    4665        1049 :                                 if (in_q) {
    4666           3 :                                         break;
    4667             :                                 }
    4668        1046 :                                 if (isspace(*(p + 1)) && !allow_tag_spaces) {
    4669           6 :                                         goto reg_char;
    4670             :                                 }
    4671        1040 :                                 if (state == 0) {
    4672        1015 :                                         lc = '<';
    4673        1015 :                                         state = 1;
    4674        1015 :                                         if (allow) {
    4675         663 :                                                 if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4676           0 :                                                         pos = tp - tbuf;
    4677           0 :                                                         tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4678           0 :                                                         tp = tbuf + pos;
    4679             :                                                 }
    4680         663 :                                                 *(tp++) = '<';
    4681             :                                         }
    4682          25 :                                 } else if (state == 1) {
    4683          20 :                                         depth++;
    4684             :                                 }
    4685        1040 :                                 break;
    4686             : 
    4687             :                         case '(':
    4688         178 :                                 if (state == 2) {
    4689           0 :                                         if (lc != '"' && lc != '\'') {
    4690           0 :                                                 lc = '(';
    4691           0 :                                                 br++;
    4692             :                                         }
    4693         179 :                                 } else if (allow && state == 1) {
    4694           1 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4695           0 :                                                 pos = tp - tbuf;
    4696           0 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4697           0 :                                                 tp = tbuf + pos;
    4698             :                                         }
    4699           1 :                                         *(tp++) = c;
    4700         177 :                                 } else if (state == 0) {
    4701         176 :                                         *(rp++) = c;
    4702             :                                 }
    4703         178 :                                 break;
    4704             : 
    4705             :                         case ')':
    4706         178 :                                 if (state == 2) {
    4707           0 :                                         if (lc != '"' && lc != '\'') {
    4708           0 :                                                 lc = ')';
    4709           0 :                                                 br--;
    4710             :                                         }
    4711         179 :                                 } else if (allow && state == 1) {
    4712           1 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4713           0 :                                                 pos = tp - tbuf;
    4714           0 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4715           0 :                                                 tp = tbuf + pos;
    4716             :                                         }
    4717           1 :                                         *(tp++) = c;
    4718         177 :                                 } else if (state == 0) {
    4719         176 :                                         *(rp++) = c;
    4720             :                                 }
    4721         178 :                                 break;
    4722             : 
    4723             :                         case '>':
    4724        6757 :                                 if (depth) {
    4725          20 :                                         depth--;
    4726          20 :                                         break;
    4727             :                                 }
    4728             : 
    4729        6737 :                                 if (in_q) {
    4730           4 :                                         break;
    4731             :                                 }
    4732             : 
    4733        6733 :                                 switch (state) {
    4734             :                                         case 1: /* HTML/XML */
    4735         876 :                                                 lc = '>';
    4736         876 :                                                 in_q = state = 0;
    4737         876 :                                                 if (allow) {
    4738         555 :                                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4739           1 :                                                                 pos = tp - tbuf;
    4740           1 :                                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4741           1 :                                                                 tp = tbuf + pos;
    4742             :                                                         }
    4743         555 :                                                         *(tp++) = '>';
    4744         555 :                                                         *tp='\0';
    4745         555 :                                                         if (php_tag_find(tbuf, tp-tbuf, allow)) {
    4746         150 :                                                                 memcpy(rp, tbuf, tp-tbuf);
    4747         150 :                                                                 rp += tp-tbuf;
    4748             :                                                         }
    4749         555 :                                                         tp = tbuf;
    4750             :                                                 }
    4751         876 :                                                 break;
    4752             : 
    4753             :                                         case 2: /* PHP */
    4754          97 :                                                 if (!br && lc != '\"' && *(p-1) == '?') {
    4755          91 :                                                         in_q = state = 0;
    4756          91 :                                                         tp = tbuf;
    4757             :                                                 }
    4758          97 :                                                 break;
    4759             : 
    4760             :                                         case 3:
    4761           1 :                                                 in_q = state = 0;
    4762           1 :                                                 tp = tbuf;
    4763           1 :                                                 break;
    4764             : 
    4765             :                                         case 4: /* JavaScript/CSS/etc... */
    4766          37 :                                                 if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') {
    4767          36 :                                                         in_q = state = 0;
    4768          36 :                                                         tp = tbuf;
    4769             :                                                 }
    4770          37 :                                                 break;
    4771             : 
    4772             :                                         default:
    4773        5722 :                                                 *(rp++) = c;
    4774             :                                                 break;
    4775             :                                 }
    4776        6733 :                                 break;
    4777             : 
    4778             :                         case '"':
    4779             :                         case '\'':
    4780        1979 :                                 if (state == 4) {
    4781             :                                         /* Inside <!-- comment --> */
    4782           1 :                                         break;
    4783        2042 :                                 } else if (state == 2 && *(p-1) != '\\') {
    4784          64 :                                         if (lc == c) {
    4785          32 :                                                 lc = '\0';
    4786          32 :                                         } else if (lc != '\\') {
    4787          32 :                                                 lc = c;
    4788             :                                         }
    4789        1914 :                                 } else if (state == 0) {
    4790        1701 :                                         *(rp++) = c;
    4791         213 :                                 } else if (allow && state == 1) {
    4792          37 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4793           1 :                                                 pos = tp - tbuf;
    4794           1 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4795           1 :                                                 tp = tbuf + pos;
    4796             :                                         }
    4797          37 :                                         *(tp++) = c;
    4798             :                                 }
    4799        1978 :                                 if (state && p != buf && (state == 1 || *(p-1) != '\\') && (!in_q || *p == in_q)) {
    4800         272 :                                         if (in_q) {
    4801         135 :                                                 in_q = 0;
    4802             :                                         } else {
    4803         137 :                                                 in_q = *p;
    4804             :                                         }
    4805             :                                 }
    4806        1978 :                                 break;
    4807             : 
    4808             :                         case '!':
    4809             :                                 /* JavaScript & Other HTML scripting languages */
    4810         109 :                                 if (state == 1 && *(p-1) == '<') {
    4811          40 :                                         state = 3;
    4812          40 :                                         lc = c;
    4813             :                                 } else {
    4814          29 :                                         if (state == 0) {
    4815          20 :                                                 *(rp++) = c;
    4816           9 :                                         } else if (allow && state == 1) {
    4817           6 :                                                 if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4818           0 :                                                         pos = tp - tbuf;
    4819           0 :                                                         tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4820           0 :                                                         tp = tbuf + pos;
    4821             :                                                 }
    4822           6 :                                                 *(tp++) = c;
    4823             :                                         }
    4824             :                                 }
    4825          69 :                                 break;
    4826             : 
    4827             :                         case '-':
    4828        2043 :                                 if (state == 3 && p >= buf + 2 && *(p-1) == '-' && *(p-2) == '!') {
    4829          36 :                                         state = 4;
    4830             :                                 } else {
    4831             :                                         goto reg_char;
    4832             :                                 }
    4833          36 :                                 break;
    4834             : 
    4835             :                         case '?':
    4836             : 
    4837         204 :                                 if (state == 1 && *(p-1) == '<') {
    4838          94 :                                         br=0;
    4839          94 :                                         state=2;
    4840          94 :                                         break;
    4841             :                                 }
    4842             : 
    4843             :                         case 'E':
    4844             :                         case 'e':
    4845             :                                 /* !DOCTYPE exception */
    4846       16010 :                                 if (state==3 && p > buf+6
    4847           6 :                                                      && tolower(*(p-1)) == 'p'
    4848           6 :                                                  && tolower(*(p-2)) == 'y'
    4849           6 :                                                      && tolower(*(p-3)) == 't'
    4850           6 :                                                      && tolower(*(p-4)) == 'c'
    4851           6 :                                                      && tolower(*(p-5)) == 'o'
    4852           6 :                                                      && tolower(*(p-6)) == 'd') {
    4853           3 :                                         state = 1;
    4854           3 :                                         break;
    4855             :                                 }
    4856             :                                 /* fall-through */
    4857             : 
    4858             :                         case 'l':
    4859             :                         case 'L':
    4860             : 
    4861             :                                 /* swm: If we encounter '<?xml' then we shouldn't be in
    4862             :                                  * state == 2 (PHP). Switch back to HTML.
    4863             :                                  */
    4864             : 
    4865       24589 :                                 if (state == 2 && p > buf+2 && strncasecmp(p-2, "xm", 2) == 0) {
    4866           2 :                                         state = 1;
    4867           2 :                                         break;
    4868             :                                 }
    4869             : 
    4870             :                                 /* fall-through */
    4871             :                         default:
    4872             : reg_char:
    4873      198168 :                                 if (state == 0) {
    4874      186532 :                                         *(rp++) = c;
    4875       11636 :                                 } else if (allow && state == 1) {
    4876        4073 :                                         if (tp - tbuf >= PHP_TAG_BUF_SIZE) {
    4877        1041 :                                                 pos = tp - tbuf;
    4878        1041 :                                                 tbuf = erealloc(tbuf, (tp - tbuf) + PHP_TAG_BUF_SIZE + 1);
    4879        1041 :                                                 tp = tbuf + pos;
    4880             :                                         }
    4881        4073 :                                         *(tp++) = c;
    4882             :                                 }
    4883             :                                 break;
    4884             :                 }
    4885      208509 :                 c = *(++p);
    4886      208509 :                 i++;
    4887             :         }
    4888         728 :         if (rp < rbuf + len) {
    4889         267 :                 *rp = '\0';
    4890             :         }
    4891         728 :         efree(buf);
    4892         728 :         if (allow) {
    4893         281 :                 efree(tbuf);
    4894         281 :                 if (allow_free) {
    4895         241 :                         efree(allow_free);
    4896             :                 }
    4897             :         }
    4898         728 :         if (stateptr)
    4899         232 :                 *stateptr = state;
    4900             : 
    4901         728 :         return (size_t)(rp - rbuf);
    4902             : }
    4903             : /* }}} */
    4904             : 
    4905             : /* {{{ proto array str_getcsv(string input[, string delimiter[, string enclosure[, string escape]]])
    4906             : Parse a CSV string into an array */
    4907          16 : PHP_FUNCTION(str_getcsv)
    4908             : {
    4909          16 :         char *str, delim = ',', enc = '"', esc = '\\';
    4910          16 :         char *delim_str = NULL, *enc_str = NULL, *esc_str = NULL;
    4911          16 :         int str_len = 0, delim_len = 0, enc_len = 0, esc_len = 0;
    4912             : 
    4913          16 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &str, &str_len, &delim_str, &delim_len,
    4914             :                 &enc_str, &enc_len, &esc_str, &esc_len) == FAILURE) {
    4915           0 :                 return;
    4916             :         }
    4917             : 
    4918          16 :         delim = delim_len ? delim_str[0] : delim;
    4919          16 :         enc = enc_len ? enc_str[0] : enc;
    4920          16 :         esc = esc_len ? esc_str[0] : esc;
    4921             : 
    4922          16 :         php_fgetcsv(NULL, delim, enc, esc, str_len, str, return_value TSRMLS_CC);
    4923             : }
    4924             : /* }}} */
    4925             : 
    4926             : /* {{{ proto string str_repeat(string input, int mult)
    4927             :    Returns the input string repeat mult times */
    4928      174207 : PHP_FUNCTION(str_repeat)
    4929             : {
    4930             :         char            *input_str;             /* Input string */
    4931             :         int             input_len;
    4932             :         long            mult;                   /* Multiplier */
    4933             :         char            *result;                /* Resulting string */
    4934             :         size_t          result_len;             /* Length of the resulting string */
    4935             : 
    4936      174207 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &input_str, &input_len, &mult) == FAILURE) {
    4937          80 :                 return;
    4938             :         }
    4939             : 
    4940      174127 :         if (mult < 0) {
    4941           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be greater than or equal to 0");
    4942           1 :                 return;
    4943             :         }
    4944             : 
    4945             :         /* Don't waste our time if it's empty */
    4946             :         /* ... or if the multiplier is zero */
    4947      174126 :         if (input_len == 0 || mult == 0)
    4948          52 :                 RETURN_EMPTY_STRING();
    4949             : 
    4950             :         /* Initialize the result string */
    4951      174074 :         result_len = input_len * mult;
    4952      174074 :         result = (char *)safe_emalloc(input_len, mult, 1);
    4953             : 
    4954             :         /* Heavy optimization for situations where input string is 1 byte long */
    4955      174074 :         if (input_len == 1) {
    4956      160450 :                 memset(result, *(input_str), mult);
    4957             :         } else {
    4958             :                 char *s, *e, *ee;
    4959       13624 :                 int l=0;
    4960       13624 :                 memcpy(result, input_str, input_len);
    4961       13624 :                 s = result;
    4962       13624 :                 e = result + input_len;
    4963       13624 :                 ee = result + result_len;
    4964             : 
    4965       40400 :                 while (e<ee) {
    4966       13152 :                         l = (e-s) < (ee-e) ? (e-s) : (ee-e);
    4967       13152 :                         memmove(e, s, l);
    4968       13152 :                         e += l;
    4969             :                 }
    4970             :         }
    4971             : 
    4972      174074 :         result[result_len] = '\0';
    4973             : 
    4974      174074 :         RETURN_STRINGL(result, result_len, 0);
    4975             : }
    4976             : /* }}} */
    4977             : 
    4978             : /* {{{ proto mixed count_chars(string input [, int mode])
    4979             :    Returns info about what characters are used in input */
    4980          60 : PHP_FUNCTION(count_chars)
    4981             : {
    4982             :         char *input;
    4983             :         int chars[256];
    4984          60 :         long mymode=0;
    4985             :         unsigned char *buf;
    4986             :         int len, inx;
    4987             :         char retstr[256];
    4988          60 :         int retlen=0;
    4989             : 
    4990          60 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &input, &len, &mymode) == FAILURE) {
    4991          11 :                 return;
    4992             :         }
    4993             : 
    4994          49 :         if (mymode < 0 || mymode > 4) {
    4995           7 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown mode");
    4996           7 :                 RETURN_FALSE;
    4997             :         }
    4998             : 
    4999          42 :         buf = (unsigned char *) input;
    5000          42 :         memset((void*) chars, 0, sizeof(chars));
    5001             : 
    5002        1462 :         while (len > 0) {
    5003        1378 :                 chars[*buf]++;
    5004        1378 :                 buf++;
    5005        1378 :                 len--;
    5006             :         }
    5007             : 
    5008          42 :         if (mymode < 3) {
    5009          38 :                 array_init(return_value);
    5010             :         }
    5011             : 
    5012       10794 :         for (inx = 0; inx < 256; inx++) {
    5013       10752 :                 switch (mymode) {
    5014             :                         case 0:
    5015        2816 :                                 add_index_long(return_value, inx, chars[inx]);
    5016        2816 :                                 break;
    5017             :                         case 1:
    5018        6400 :                                 if (chars[inx] != 0) {
    5019         180 :                                         add_index_long(return_value, inx, chars[inx]);
    5020             :                                 }
    5021        6400 :                                 break;
    5022             :                         case 2:
    5023         512 :                                 if (chars[inx] == 0) {
    5024         475 :                                         add_index_long(return_value, inx, chars[inx]);
    5025             :                                 }
    5026         512 :                                 break;
    5027             :                         case 3:
    5028         512 :                                 if (chars[inx] != 0) {
    5029          37 :                                         retstr[retlen++] = inx;
    5030             :                                 }
    5031         512 :                                 break;
    5032             :                         case 4:
    5033         512 :                                 if (chars[inx] == 0) {
    5034         475 :                                         retstr[retlen++] = inx;
    5035             :                                 }
    5036             :                                 break;
    5037             :                 }
    5038             :         }
    5039             : 
    5040          42 :         if (mymode >= 3 && mymode <= 4) {
    5041           4 :                 RETURN_STRINGL(retstr, retlen, 1);
    5042             :         }
    5043             : }
    5044             : /* }}} */
    5045             : 
    5046             : /* {{{ php_strnatcmp
    5047             :  */
    5048          57 : static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
    5049             : {
    5050             :         char *s1, *s2;
    5051             :         int s1_len, s2_len;
    5052             : 
    5053          57 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &s1, &s1_len, &s2, &s2_len) == FAILURE) {
    5054           4 :                 return;
    5055             :         }
    5056             : 
    5057          53 :         RETURN_LONG(strnatcmp_ex(s1, s1_len,
    5058             :                                                          s2, s2_len,
    5059             :                                                          fold_case));
    5060             : }
    5061             : /* }}} */
    5062             : 
    5063         229 : PHPAPI int string_natural_compare_function_ex(zval *result, zval *op1, zval *op2, zend_bool case_insensitive TSRMLS_DC) /* {{{ */
    5064             : {
    5065             :         zval op1_copy, op2_copy;
    5066         229 :         int use_copy1 = 0, use_copy2 = 0;
    5067             : 
    5068         229 :         if (Z_TYPE_P(op1) != IS_STRING) {
    5069           0 :                 zend_make_printable_zval(op1, &op1_copy, &use_copy1);
    5070             :         }
    5071         229 :         if (Z_TYPE_P(op2) != IS_STRING) {
    5072           0 :                 zend_make_printable_zval(op2, &op2_copy, &use_copy2);
    5073             :         }
    5074             : 
    5075         229 :         if (use_copy1) {
    5076           0 :                 op1 = &op1_copy;
    5077             :         }
    5078         229 :         if (use_copy2) {
    5079           0 :                 op2 = &op2_copy;
    5080             :         }
    5081             : 
    5082         229 :         ZVAL_LONG(result, strnatcmp_ex(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2), case_insensitive));
    5083             : 
    5084         229 :         if (use_copy1) {
    5085             :                 zval_dtor(op1);
    5086             :         }
    5087         229 :         if (use_copy2) {
    5088             :                 zval_dtor(op2);
    5089             :         }
    5090         229 :         return SUCCESS;
    5091             : }
    5092             : /* }}} */
    5093             : 
    5094         105 : PHPAPI int string_natural_case_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
    5095             : {
    5096         105 :         return string_natural_compare_function_ex(result, op1, op2, 1 TSRMLS_CC);
    5097             : }
    5098             : /* }}} */
    5099             : 
    5100         124 : PHPAPI int string_natural_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */
    5101             : {
    5102         124 :         return string_natural_compare_function_ex(result, op1, op2, 0 TSRMLS_CC);
    5103             : }
    5104             : /* }}} */
    5105             : 
    5106             : /* {{{ proto int strnatcmp(string s1, string s2)
    5107             :    Returns the result of string comparison using 'natural' algorithm */
    5108          36 : PHP_FUNCTION(strnatcmp)
    5109             : {
    5110          36 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    5111          36 : }
    5112             : /* }}} */
    5113             : 
    5114             : /* {{{ proto array localeconv(void)
    5115             :    Returns numeric formatting information based on the current locale */
    5116          11 : PHP_FUNCTION(localeconv)
    5117             : {
    5118             :         zval *grouping, *mon_grouping;
    5119             :         int len, i;
    5120             : 
    5121             :         /* We don't need no stinkin' parameters... */
    5122          11 :         if (zend_parse_parameters_none() == FAILURE) {
    5123           0 :                 return;
    5124             :         }
    5125             : 
    5126          11 :         MAKE_STD_ZVAL(grouping);
    5127          11 :         MAKE_STD_ZVAL(mon_grouping);
    5128             : 
    5129          11 :         array_init(return_value);
    5130          11 :         array_init(grouping);
    5131          11 :         array_init(mon_grouping);
    5132             : 
    5133             : #ifdef HAVE_LOCALECONV
    5134             :         {
    5135             :                 struct lconv currlocdata;
    5136             : 
    5137          11 :                 localeconv_r( &currlocdata );
    5138             : 
    5139             :                 /* Grab the grouping data out of the array */
    5140          11 :                 len = strlen(currlocdata.grouping);
    5141             : 
    5142          33 :                 for (i = 0; i < len; i++) {
    5143          22 :                         add_index_long(grouping, i, currlocdata.grouping[i]);
    5144             :                 }
    5145             : 
    5146             :                 /* Grab the monetary grouping data out of the array */
    5147          11 :                 len = strlen(currlocdata.mon_grouping);
    5148             : 
    5149          31 :                 for (i = 0; i < len; i++) {
    5150          20 :                         add_index_long(mon_grouping, i, currlocdata.mon_grouping[i]);
    5151             :                 }
    5152             : 
    5153          11 :                 add_assoc_string(return_value, "decimal_point",     currlocdata.decimal_point,     1);
    5154          11 :                 add_assoc_string(return_value, "thousands_sep",     currlocdata.thousands_sep,     1);
    5155          11 :                 add_assoc_string(return_value, "int_curr_symbol",   currlocdata.int_curr_symbol,   1);
    5156          11 :                 add_assoc_string(return_value, "currency_symbol",   currlocdata.currency_symbol,   1);
    5157          11 :                 add_assoc_string(return_value, "mon_decimal_point", currlocdata.mon_decimal_point, 1);
    5158          11 :                 add_assoc_string(return_value, "mon_thousands_sep", currlocdata.mon_thousands_sep, 1);
    5159          11 :                 add_assoc_string(return_value, "positive_sign",     currlocdata.positive_sign,     1);
    5160          11 :                 add_assoc_string(return_value, "negative_sign",     currlocdata.negative_sign,     1);
    5161          11 :                 add_assoc_long(  return_value, "int_frac_digits",   currlocdata.int_frac_digits     );
    5162          11 :                 add_assoc_long(  return_value, "frac_digits",       currlocdata.frac_digits         );
    5163          11 :                 add_assoc_long(  return_value, "p_cs_precedes",     currlocdata.p_cs_precedes       );
    5164          11 :                 add_assoc_long(  return_value, "p_sep_by_space",    currlocdata.p_sep_by_space      );
    5165          11 :                 add_assoc_long(  return_value, "n_cs_precedes",     currlocdata.n_cs_precedes       );
    5166          11 :                 add_assoc_long(  return_value, "n_sep_by_space",    currlocdata.n_sep_by_space      );
    5167          11 :                 add_assoc_long(  return_value, "p_sign_posn",       currlocdata.p_sign_posn         );
    5168          11 :                 add_assoc_long(  return_value, "n_sign_posn",       currlocdata.n_sign_posn         );
    5169             :         }
    5170             : #else
    5171             :         /* Ok, it doesn't look like we have locale info floating around, so I guess it
    5172             :            wouldn't hurt to just go ahead and return the POSIX locale information?  */
    5173             : 
    5174             :         add_index_long(grouping, 0, -1);
    5175             :         add_index_long(mon_grouping, 0, -1);
    5176             : 
    5177             :         add_assoc_string(return_value, "decimal_point",     "\x2E", 1);
    5178             :         add_assoc_string(return_value, "thousands_sep",     "",     1);
    5179             :         add_assoc_string(return_value, "int_curr_symbol",   "",     1);
    5180             :         add_assoc_string(return_value, "currency_symbol",   "",     1);
    5181             :         add_assoc_string(return_value, "mon_decimal_point", "\x2E", 1);
    5182             :         add_assoc_string(return_value, "mon_thousands_sep", "",     1);
    5183             :         add_assoc_string(return_value, "positive_sign",     "",     1);
    5184             :         add_assoc_string(return_value, "negative_sign",     "",     1);
    5185             :         add_assoc_long(  return_value, "int_frac_digits",   CHAR_MAX );
    5186             :         add_assoc_long(  return_value, "frac_digits",       CHAR_MAX );
    5187             :         add_assoc_long(  return_value, "p_cs_precedes",     CHAR_MAX );
    5188             :         add_assoc_long(  return_value, "p_sep_by_space",    CHAR_MAX );
    5189             :         add_assoc_long(  return_value, "n_cs_precedes",     CHAR_MAX );
    5190             :         add_assoc_long(  return_value, "n_sep_by_space",    CHAR_MAX );
    5191             :         add_assoc_long(  return_value, "p_sign_posn",       CHAR_MAX );
    5192             :         add_assoc_long(  return_value, "n_sign_posn",       CHAR_MAX );
    5193             : #endif
    5194             : 
    5195          11 :         zend_hash_update(Z_ARRVAL_P(return_value), "grouping", 9, &grouping, sizeof(zval *), NULL);
    5196          11 :         zend_hash_update(Z_ARRVAL_P(return_value), "mon_grouping", 13, &mon_grouping, sizeof(zval *), NULL);
    5197             : }
    5198             : /* }}} */
    5199             : 
    5200             : /* {{{ proto int strnatcasecmp(string s1, string s2)
    5201             :    Returns the result of case-insensitive string comparison using 'natural' algorithm */
    5202          21 : PHP_FUNCTION(strnatcasecmp)
    5203             : {
    5204          21 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    5205          21 : }
    5206             : /* }}} */
    5207             : 
    5208             : /* {{{ proto int substr_count(string haystack, string needle [, int offset [, int length]])
    5209             :    Returns the number of times a substring occurs in the string */
    5210          47 : PHP_FUNCTION(substr_count)
    5211             : {
    5212             :         char *haystack, *needle;
    5213          47 :         long offset = 0, length = 0;
    5214          47 :         int ac = ZEND_NUM_ARGS();
    5215          47 :         int count = 0;
    5216             :         int haystack_len, needle_len;
    5217             :         char *p, *endp, cmp;
    5218             : 
    5219          47 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &haystack, &haystack_len, &needle, &needle_len, &offset, &length) == FAILURE) {
    5220           6 :                 return;
    5221             :         }
    5222             : 
    5223          41 :         if (needle_len == 0) {
    5224           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring");
    5225           2 :                 RETURN_FALSE;
    5226             :         }
    5227             : 
    5228          39 :         p = haystack;
    5229          39 :         endp = p + haystack_len;
    5230             : 
    5231          39 :         if (offset < 0) {
    5232           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset should be greater than or equal to 0");
    5233           1 :                 RETURN_FALSE;
    5234             :         }
    5235             : 
    5236          38 :         if (offset > haystack_len) {
    5237           4 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length", offset);
    5238           4 :                 RETURN_FALSE;
    5239             :         }
    5240          34 :         p += offset;
    5241             : 
    5242          34 :         if (ac == 4) {
    5243             : 
    5244           6 :                 if (length <= 0) {
    5245           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length should be greater than 0");
    5246           1 :                         RETURN_FALSE;
    5247             :                 }
    5248           5 :                 if (length > (haystack_len - offset)) {
    5249           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length value %ld exceeds string length", length);
    5250           1 :                         RETURN_FALSE;
    5251             :                 }
    5252           4 :                 endp = p + length;
    5253             :         }
    5254             : 
    5255          32 :         if (needle_len == 1) {
    5256          19 :                 cmp = needle[0];
    5257             : 
    5258          56 :                 while ((p = memchr(p, cmp, endp - p))) {
    5259          18 :                         count++;
    5260          18 :                         p++;
    5261             :                 }
    5262             :         } else {
    5263         560 :                 while ((p = php_memnstr(p, needle, needle_len, endp))) {
    5264         534 :                         p += needle_len;
    5265         534 :                         count++;
    5266             :                 }
    5267             :         }
    5268             : 
    5269          32 :         RETURN_LONG(count);
    5270             : }
    5271             : /* }}} */
    5272             : 
    5273             : /* {{{ proto string str_pad(string input, int pad_length [, string pad_string [, int pad_type]])
    5274             :    Returns input string padded on the left or right to specified length with pad_string */
    5275         584 : PHP_FUNCTION(str_pad)
    5276             : {
    5277             :         /* Input arguments */
    5278             :         char *input;                            /* Input string */
    5279             :         int  input_len;
    5280             :         long pad_length;                        /* Length to pad to */
    5281             : 
    5282             :         /* Helper variables */
    5283             :         size_t     num_pad_chars;               /* Number of padding characters (total - input size) */
    5284         584 :         char  *result = NULL;           /* Resulting string */
    5285         584 :         int        result_len = 0;              /* Length of the resulting string */
    5286         584 :         char  *pad_str_val = " ";     /* Pointer to padding string */
    5287         584 :         int    pad_str_len = 1;         /* Length of the padding string */
    5288         584 :         long   pad_type_val = STR_PAD_RIGHT; /* The padding type value */
    5289         584 :         int        i, left_pad=0, right_pad=0;
    5290             : 
    5291         584 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|sl", &input, &input_len, &pad_length,
    5292             :                                                                                                                                   &pad_str_val, &pad_str_len, &pad_type_val) == FAILURE) {
    5293          23 :                 return;
    5294             :         }
    5295             : 
    5296             :         /* If resulting string turns out to be shorter than input string,
    5297             :            we simply copy the input and return. */
    5298         561 :         if (pad_length <= 0 || (pad_length - input_len) <= 0) {
    5299         138 :                 RETURN_STRINGL(input, input_len, 1);
    5300             :         }
    5301             : 
    5302         423 :         if (pad_str_len == 0) {
    5303           8 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding string cannot be empty");
    5304           8 :                 return;
    5305             :         }
    5306             : 
    5307         415 :         if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) {
    5308           7 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH");
    5309           7 :                 return;
    5310             :         }
    5311             : 
    5312         408 :         num_pad_chars = pad_length - input_len;
    5313         408 :         if (num_pad_chars >= INT_MAX) {
    5314           0 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding length is too long");
    5315           0 :                 return;
    5316             :         }
    5317         408 :         result = (char *)emalloc(input_len + num_pad_chars + 1);
    5318             : 
    5319             :         /* We need to figure out the left/right padding lengths. */
    5320         408 :         switch (pad_type_val) {
    5321             :                 case STR_PAD_RIGHT:
    5322         325 :                         left_pad = 0;
    5323         325 :                         right_pad = num_pad_chars;
    5324         325 :                         break;
    5325             : 
    5326             :                 case STR_PAD_LEFT:
    5327          48 :                         left_pad = num_pad_chars;
    5328          48 :                         right_pad = 0;
    5329          48 :                         break;
    5330             : 
    5331             :                 case STR_PAD_BOTH:
    5332          35 :                         left_pad = num_pad_chars / 2;
    5333          35 :                         right_pad = num_pad_chars - left_pad;
    5334             :                         break;
    5335             :         }
    5336             : 
    5337             :         /* First we pad on the left. */
    5338         950 :         for (i = 0; i < left_pad; i++)
    5339         542 :                 result[result_len++] = pad_str_val[i % pad_str_len];
    5340             : 
    5341             :         /* Then we copy the input string. */
    5342         408 :         memcpy(result + result_len, input, input_len);
    5343         408 :         result_len += input_len;
    5344             : 
    5345             :         /* Finally, we pad on the right. */
    5346     6302881 :         for (i = 0; i < right_pad; i++)
    5347     6302473 :                 result[result_len++] = pad_str_val[i % pad_str_len];
    5348             : 
    5349         408 :         result[result_len] = '\0';
    5350             : 
    5351         408 :         RETURN_STRINGL(result, result_len, 0);
    5352             : }
    5353             : /* }}} */
    5354             : 
    5355             : /* {{{ proto mixed sscanf(string str, string format [, string ...])
    5356             :    Implements an ANSI C compatible sscanf */
    5357          81 : PHP_FUNCTION(sscanf)
    5358             : {
    5359          81 :         zval ***args = NULL;
    5360             :         char *str, *format;
    5361          81 :         int str_len, format_len, result, num_args = 0;
    5362             : 
    5363          81 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss*", &str, &str_len, &format, &format_len,
    5364             :                 &args, &num_args) == FAILURE) {
    5365          10 :                 return;
    5366             :         }
    5367             : 
    5368          71 :         result = php_sscanf_internal(str, format, num_args, args, 0, &return_value TSRMLS_CC);
    5369             : 
    5370          71 :         if (args) {
    5371          23 :                 efree(args);
    5372             :         }
    5373             : 
    5374          71 :         if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
    5375           0 :                 WRONG_PARAM_COUNT;
    5376             :         }
    5377             : }
    5378             : /* }}} */
    5379             : 
    5380             : static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    5381             : static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
    5382             : 
    5383             : /* {{{ proto string str_rot13(string str)
    5384             :    Perform the rot13 transform on a string */
    5385          27 : PHP_FUNCTION(str_rot13)
    5386             : {
    5387             :         char *arg;
    5388             :         int arglen;
    5389             : 
    5390          27 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) {
    5391           5 :                 return;
    5392             :         }
    5393             : 
    5394          22 :         RETVAL_STRINGL(arg, arglen, 1);
    5395             : 
    5396          22 :         php_strtr(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), rot13_from, rot13_to, 52);
    5397             : }
    5398             : /* }}} */
    5399             : 
    5400       91009 : static void php_string_shuffle(char *str, long len TSRMLS_DC) /* {{{ */
    5401             : {
    5402             :         long n_elems, rnd_idx, n_left;
    5403             :         char temp;
    5404             :         /* The implementation is stolen from array_data_shuffle       */
    5405             :         /* Thus the characteristics of the randomization are the same */
    5406       91009 :         n_elems = len;
    5407             : 
    5408       91009 :         if (n_elems <= 1) {
    5409           0 :                 return;
    5410             :         }
    5411             : 
    5412       91009 :         n_left = n_elems;
    5413             : 
    5414      455116 :         while (--n_left) {
    5415      273098 :                 rnd_idx = php_rand(TSRMLS_C);
    5416      273098 :                 RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
    5417      273098 :                 if (rnd_idx != n_left) {
    5418      174618 :                         temp = str[n_left];
    5419      174618 :                         str[n_left] = str[rnd_idx];
    5420      174618 :                         str[rnd_idx] = temp;
    5421             :                 }
    5422             :         }
    5423             : }
    5424             : /* }}} */
    5425             : 
    5426             : /* {{{ proto void str_shuffle(string str)
    5427             :    Shuffles string. One permutation of all possible is created */
    5428       91025 : PHP_FUNCTION(str_shuffle)
    5429             : {
    5430             :         char *arg;
    5431             :         int arglen;
    5432             : 
    5433       91025 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) {
    5434           6 :                 return;
    5435             :         }
    5436             : 
    5437       91019 :         RETVAL_STRINGL(arg, arglen, 1);
    5438       91019 :         if (Z_STRLEN_P(return_value) > 1) {
    5439       91009 :                 php_string_shuffle(Z_STRVAL_P(return_value), (long) Z_STRLEN_P(return_value) TSRMLS_CC);
    5440             :         }
    5441             : }
    5442             : /* }}} */
    5443             : 
    5444             : /* {{{ proto mixed str_word_count(string str, [int format [, string charlist]])
    5445             :         Counts the number of words inside a string. If format of 1 is specified,
    5446             :         then the function will return an array containing all the words
    5447             :         found inside the string. If format of 2 is specified, then the function
    5448             :         will return an associated array where the position of the word is the key
    5449             :         and the word itself is the value.
    5450             : 
    5451             :         For the purpose of this function, 'word' is defined as a locale dependent
    5452             :         string containing alphabetic characters, which also may contain, but not start
    5453             :         with "'" and "-" characters.
    5454             : */
    5455          35 : PHP_FUNCTION(str_word_count)
    5456             : {
    5457          35 :         char *buf, *str, *char_list = NULL, *p, *e, *s, ch[256];
    5458          35 :         int str_len, char_list_len = 0, word_count = 0;
    5459          35 :         long type = 0;
    5460             : 
    5461          35 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, &type, &char_list, &char_list_len) == FAILURE) {
    5462           8 :                 return;
    5463             :         }
    5464             : 
    5465          27 :         switch(type) {
    5466             :                 case 1:
    5467             :                 case 2:
    5468          15 :                         array_init(return_value);
    5469          15 :                         if (!str_len) {
    5470           0 :                                 return;
    5471             :                         }
    5472          15 :                         break;
    5473             :                 case 0:
    5474           6 :                         if (!str_len) {
    5475           1 :                                 RETURN_LONG(0);
    5476             :                         }
    5477             :                         /* nothing to be done */
    5478           5 :                         break;
    5479             :                 default:
    5480           6 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid format value %ld", type);
    5481           6 :                         RETURN_FALSE;
    5482             :         }
    5483             : 
    5484          20 :         if (char_list) {
    5485          15 :                 php_charmask((unsigned char *)char_list, char_list_len, ch TSRMLS_CC);
    5486             :         }
    5487             : 
    5488          20 :         p = str;
    5489          20 :         e = str + str_len;
    5490             : 
    5491             :         /* first character cannot be ' or -, unless explicitly allowed by the user */
    5492          20 :         if ((*p == '\'' && (!char_list || !ch['\''])) || (*p == '-' && (!char_list || !ch['-']))) {
    5493           2 :                 p++;
    5494             :         }
    5495             :         /* last character cannot be -, unless explicitly allowed by the user */
    5496          20 :         if (*(e - 1) == '-' && (!char_list || !ch['-'])) {
    5497           1 :                 e--;
    5498             :         }
    5499             : 
    5500         187 :         while (p < e) {
    5501         147 :                 s = p;
    5502         576 :                 while (p < e && (isalpha((unsigned char)*p) || (char_list && ch[(unsigned char)*p]) || *p == '\'' || *p == '-')) {
    5503         282 :                         p++;
    5504             :                 }
    5505         147 :                 if (p > s) {
    5506          93 :                         switch (type)
    5507             :                         {
    5508             :                                 case 1:
    5509          29 :                                         buf = estrndup(s, (p-s));
    5510          29 :                                         add_next_index_stringl(return_value, buf, (p-s), 0);
    5511          29 :                                         break;
    5512             :                                 case 2:
    5513          35 :                                         buf = estrndup(s, (p-s));
    5514          35 :                                         add_index_stringl(return_value, (s - str), buf, p-s, 0);
    5515          35 :                                         break;
    5516             :                                 default:
    5517          29 :                                         word_count++;
    5518             :                                         break;
    5519             :                         }
    5520             :                 }
    5521         147 :                 p++;
    5522             :         }
    5523             : 
    5524          20 :         if (!type) {
    5525           5 :                 RETURN_LONG(word_count);
    5526             :         }
    5527             : }
    5528             : 
    5529             : /* }}} */
    5530             : 
    5531             : #if HAVE_STRFMON
    5532             : /* {{{ proto string money_format(string format , float value)
    5533             :    Convert monetary value(s) to string */
    5534          71 : PHP_FUNCTION(money_format)
    5535             : {
    5536          71 :         int format_len = 0, str_len;
    5537             :         char *format, *str, *p, *e;
    5538             :         double value;
    5539          71 :         zend_bool check = 0;
    5540             : 
    5541          71 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sd", &format, &format_len, &value) == FAILURE) {
    5542          17 :                 return;
    5543             :         }
    5544             : 
    5545          54 :         p = format;
    5546          54 :         e = p + format_len;
    5547         141 :         while ((p = memchr(p, '%', (e - p)))) {
    5548          34 :                 if (*(p + 1) == '%') {
    5549           0 :                         p += 2;
    5550          34 :                 } else if (!check) {
    5551          33 :                         check = 1;
    5552          33 :                         p++;
    5553             :                 } else {
    5554           1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only a single %%i or %%n token can be used");
    5555           1 :                         RETURN_FALSE;
    5556             :                 }
    5557             :         }
    5558             : 
    5559          53 :         str_len = format_len + 1024;
    5560          53 :         str = emalloc(str_len);
    5561          53 :         if ((str_len = strfmon(str, str_len, format, value)) < 0) {
    5562           0 :                 efree(str);
    5563           0 :                 RETURN_FALSE;
    5564             :         }
    5565          53 :         str[str_len] = 0;
    5566             : 
    5567          53 :         RETURN_STRINGL(erealloc(str, str_len + 1), str_len, 0);
    5568             : }
    5569             : /* }}} */
    5570             : #endif
    5571             : 
    5572             : /* {{{ proto array str_split(string str [, int split_length])
    5573             :    Convert a string to an array. If split_length is specified, break the string down into chunks each split_length characters long. */
    5574         190 : PHP_FUNCTION(str_split)
    5575             : {
    5576             :         char *str;
    5577             :         int str_len;
    5578         190 :         long split_length = 1;
    5579             :         char *p;
    5580             :         int n_reg_segments;
    5581             : 
    5582         190 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &split_length) == FAILURE) {
    5583          19 :                 return;
    5584             :         }
    5585             : 
    5586         171 :         if (split_length <= 0) {
    5587          15 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The length of each segment must be greater than zero");
    5588          15 :                 RETURN_FALSE;
    5589             :         }
    5590             : 
    5591         156 :         array_init_size(return_value, ((str_len - 1) / split_length) + 1);
    5592             : 
    5593         156 :         if (split_length >= str_len) {
    5594          29 :                 add_next_index_stringl(return_value, str, str_len, 1);
    5595          29 :                 return;
    5596             :         }
    5597             : 
    5598         127 :         n_reg_segments = str_len / split_length;
    5599         127 :         p = str;
    5600             : 
    5601       22191 :         while (n_reg_segments-- > 0) {
    5602       21937 :                 add_next_index_stringl(return_value, p, split_length, 1);
    5603       21937 :                 p += split_length;
    5604             :         }
    5605             : 
    5606         127 :         if (p != (str + str_len)) {
    5607          31 :                 add_next_index_stringl(return_value, p, (str + str_len - p), 1);
    5608             :         }
    5609             : }
    5610             : /* }}} */
    5611             : 
    5612             : /* {{{ proto array strpbrk(string haystack, string char_list)
    5613             :    Search a string for any of a set of characters */
    5614          20 : PHP_FUNCTION(strpbrk)
    5615             : {
    5616             :         char *haystack, *char_list;
    5617             :         int haystack_len, char_list_len;
    5618             :         char *haystack_ptr, *cl_ptr;
    5619             : 
    5620          20 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &haystack, &haystack_len, &char_list, &char_list_len) == FAILURE) {
    5621           4 :                 RETURN_FALSE;
    5622             :         }
    5623             : 
    5624          16 :         if (!char_list_len) {
    5625           1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The character list cannot be empty");
    5626           1 :                 RETURN_FALSE;
    5627             :         }
    5628             : 
    5629          96 :         for (haystack_ptr = haystack; haystack_ptr < (haystack + haystack_len); ++haystack_ptr) {
    5630         228 :                 for (cl_ptr = char_list; cl_ptr < (char_list + char_list_len); ++cl_ptr) {
    5631         147 :                         if (*cl_ptr == *haystack_ptr) {
    5632          10 :                                 RETURN_STRINGL(haystack_ptr, (haystack + haystack_len - haystack_ptr), 1);
    5633             :                         }
    5634             :                 }
    5635             :         }
    5636             : 
    5637           5 :         RETURN_FALSE;
    5638             : }
    5639             : /* }}} */
    5640             : 
    5641             : /* {{{ proto int substr_compare(string main_str, string str, int offset [, int length [, bool case_sensitivity]])
    5642             :    Binary safe optionally case insensitive comparison of 2 strings from an offset, up to length characters */
    5643          47 : PHP_FUNCTION(substr_compare)
    5644             : {
    5645             :         char *s1, *s2;
    5646             :         int s1_len, s2_len;
    5647          47 :         long offset, len=0;
    5648          47 :         zend_bool cs=0;
    5649             :         uint cmp_len;
    5650             : 
    5651          47 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssl|lb", &s1, &s1_len, &s2, &s2_len, &offset, &len, &cs) == FAILURE) {
    5652           2 :                 RETURN_FALSE;
    5653             :         }
    5654             : 
    5655          45 :         if (ZEND_NUM_ARGS() >= 4 && len <= 0) {
    5656           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The length must be greater than zero");
    5657           2 :                 RETURN_FALSE;
    5658             :         }
    5659             : 
    5660          43 :         if (offset < 0) {
    5661           1 :                 offset = s1_len + offset;
    5662           1 :                 offset = (offset < 0) ? 0 : offset;
    5663             :         }
    5664             : 
    5665          43 :         if (offset >= s1_len) {
    5666           2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The start position cannot exceed initial string length");
    5667           2 :                 RETURN_FALSE;
    5668             :         }
    5669             : 
    5670          41 :         cmp_len = (uint) (len ? len : MAX(s2_len, (s1_len - offset)));
    5671             : 
    5672          41 :         if (!cs) {
    5673          40 :                 RETURN_LONG(zend_binary_strncmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len));
    5674             :         } else {
    5675           1 :                 RETURN_LONG(zend_binary_strncasecmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len));
    5676             :         }
    5677             : }
    5678             : /* }}} */
    5679             : 
    5680             : /*
    5681             :  * Local variables:
    5682             :  * tab-width: 4
    5683             :  * c-basic-offset: 4
    5684             :  * End:
    5685             :  * vim600: noet sw=4 ts=4 fdm=marker
    5686             :  * vim<600: noet sw=4 ts=4
    5687             :  */

Generated by: LCOV version 1.10

Generated at Mon, 15 Dec 2014 17:02:52 +0000 (3 days ago)

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