PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LTP GCOV extension - code coverage report
Current view: directory - standard - string.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 2417
Code covered: 95.4 % Executed lines: 2306
Legend: not executed executed

       1                 : /*
       2                 :    +----------------------------------------------------------------------+
       3                 :    | PHP Version 5                                                        |
       4                 :    +----------------------------------------------------------------------+
       5                 :    | Copyright (c) 1997-2009 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: string.c 287916 2009-08-31 12:28:46Z iliaa $ */
      22                 : 
      23                 : /* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */
      24                 : 
      25                 : #include <stdio.h>
      26                 : #include "php.h"
      27                 : #include "reg.h"
      28                 : #include "php_rand.h"
      29                 : #include "php_string.h"
      30                 : #include "php_variables.h"
      31                 : #ifdef HAVE_LOCALE_H
      32                 : # include <locale.h>
      33                 : #endif
      34                 : #ifdef HAVE_LANGINFO_H
      35                 : # include <langinfo.h>
      36                 : #endif
      37                 : #ifdef HAVE_MONETARY_H
      38                 : # include <monetary.h>
      39                 : #endif
      40                 : #ifdef HAVE_LIBINTL
      41                 : # include <libintl.h> /* For LC_MESSAGES */
      42                 : #endif
      43                 : 
      44                 : #include <math.h>
      45                 : 
      46                 : #include "scanf.h"
      47                 : #include "zend_API.h"
      48                 : #include "zend_execute.h"
      49                 : #include "php_globals.h"
      50                 : #include "basic_functions.h"
      51                 : #include "php_smart_str.h"
      52                 : #ifdef ZTS
      53                 : #include "TSRM.h"
      54                 : #endif
      55                 : 
      56                 : #define STR_PAD_LEFT                    0
      57                 : #define STR_PAD_RIGHT                   1
      58                 : #define STR_PAD_BOTH                    2
      59                 : #define PHP_PATHINFO_DIRNAME    1
      60                 : #define PHP_PATHINFO_BASENAME   2
      61                 : #define PHP_PATHINFO_EXTENSION  4
      62                 : #define PHP_PATHINFO_FILENAME   8
      63                 : #define PHP_PATHINFO_ALL        (PHP_PATHINFO_DIRNAME | PHP_PATHINFO_BASENAME | PHP_PATHINFO_EXTENSION | PHP_PATHINFO_FILENAME)
      64                 : 
      65                 : #define STR_STRSPN                              0
      66                 : #define STR_STRCSPN                             1
      67                 : 
      68                 : /* {{{ register_string_constants
      69                 :  */
      70                 : void register_string_constants(INIT_FUNC_ARGS)
      71           13565 : {
      72           13565 :         REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
      73           13565 :         REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
      74           13565 :         REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
      75           13565 :         REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
      76           13565 :         REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
      77           13565 :         REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
      78           13565 :         REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT);
      79                 : 
      80                 : #ifdef HAVE_LOCALECONV
      81                 :         /* If last members of struct lconv equal CHAR_MAX, no grouping is done */       
      82                 : 
      83                 : /* This is bad, but since we are going to be hardcoding in the POSIX stuff anyway... */
      84                 : # ifndef HAVE_LIMITS_H
      85                 : # define CHAR_MAX 127
      86                 : # endif
      87                 : 
      88           13565 :         REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
      89                 : #endif
      90                 : 
      91                 : #ifdef HAVE_LOCALE_H
      92           13565 :         REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT);
      93           13565 :         REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT);
      94           13565 :         REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT);
      95           13565 :         REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT);
      96           13565 :         REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT);
      97           13565 :         REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT);
      98                 : # ifdef LC_MESSAGES
      99           13565 :         REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
     100                 : # endif
     101                 : #endif
     102                 :         
     103           13565 : }
     104                 : /* }}} */
     105                 : 
     106                 : int php_tag_find(char *tag, int len, char *set);
     107                 : 
     108                 : /* this is read-only, so it's ok */
     109                 : static char hexconvtab[] = "0123456789abcdef";
     110                 : 
     111                 : /* localeconv mutex */
     112                 : #ifdef ZTS
     113                 : static MUTEX_T locale_mutex = NULL;
     114                 : #endif
     115                 : 
     116                 : /* {{{ php_bin2hex
     117                 :  */
     118                 : static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *newlen)
     119            7343 : {
     120            7343 :         register unsigned char *result = NULL;
     121                 :         size_t i, j;
     122                 : 
     123            7343 :         result = (char *) safe_emalloc(oldlen * 2, sizeof(char), 1);
     124                 :         
     125           42278 :         for (i = j = 0; i < oldlen; i++) {
     126           34935 :                 result[j++] = hexconvtab[old[i] >> 4];
     127           34935 :                 result[j++] = hexconvtab[old[i] & 15];
     128                 :         }
     129            7343 :         result[j] = '\0';
     130                 : 
     131            7343 :         if (newlen) 
     132            7343 :                 *newlen = oldlen * 2 * sizeof(char);
     133                 : 
     134            7343 :         return result;
     135                 : }
     136                 : /* }}} */
     137                 : 
     138                 : #ifdef HAVE_LOCALECONV
     139                 : /* {{{ localeconv_r
     140                 :  * glibc's localeconv is not reentrant, so lets make it so ... sorta */
     141                 : PHPAPI struct lconv *localeconv_r(struct lconv *out)
     142              11 : {
     143                 :         struct lconv *res;
     144                 : 
     145                 : # ifdef ZTS
     146                 :         tsrm_mutex_lock( locale_mutex );
     147                 : # endif
     148                 : 
     149                 :         /* localeconv doesn't return an error condition */
     150              11 :         res = localeconv();
     151                 : 
     152              11 :         *out = *res;
     153                 : 
     154                 : # ifdef ZTS
     155                 :         tsrm_mutex_unlock( locale_mutex );
     156                 : # endif
     157                 : 
     158              11 :         return out;
     159                 : }
     160                 : /* }}} */
     161                 : 
     162                 : # ifdef ZTS
     163                 : /* {{{ PHP_MINIT_FUNCTION
     164                 :  */
     165                 : PHP_MINIT_FUNCTION(localeconv)
     166                 : {
     167                 :         locale_mutex = tsrm_mutex_alloc();
     168                 :         return SUCCESS;
     169                 : }
     170                 : /* }}} */
     171                 : 
     172                 : /* {{{ PHP_MSHUTDOWN_FUNCTION
     173                 :  */
     174                 : PHP_MSHUTDOWN_FUNCTION(localeconv)
     175                 : {
     176                 :         tsrm_mutex_free( locale_mutex );
     177                 :         locale_mutex = NULL;
     178                 :         return SUCCESS;
     179                 : }
     180                 : /* }}} */
     181                 : # endif
     182                 : #endif
     183                 : 
     184                 : /* {{{ proto string bin2hex(string data)
     185                 :    Converts the binary representation of data to hex */
     186                 : PHP_FUNCTION(bin2hex)
     187            7345 : {
     188                 :         zval **data;
     189                 :         char *result;
     190                 :         size_t newlen;
     191                 : 
     192            7345 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &data) == FAILURE) {
     193               2 :                 WRONG_PARAM_COUNT;
     194                 :         }
     195            7343 :         convert_to_string_ex(data);
     196                 : 
     197            7343 :         result = php_bin2hex(Z_STRVAL_PP(data), Z_STRLEN_PP(data), &newlen);
     198                 :         
     199            7343 :         if (!result) {
     200               0 :                 RETURN_FALSE;
     201                 :         }
     202                 : 
     203            7343 :         RETURN_STRINGL(result, newlen, 0);
     204                 : }
     205                 : /* }}} */
     206                 : 
     207                 : static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
     208           13045 : {
     209                 :         char *s11, *s22;
     210                 :         int len1, len2;
     211                 :         long start, len;
     212                 :         
     213           13045 :         start = 0;
     214           13045 :         len = 0;
     215           13045 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &s11, &len1,
     216                 :                                 &s22, &len2, &start, &len) == FAILURE) {
     217             144 :                 return;
     218                 :         }
     219                 :         
     220           12901 :         if (ZEND_NUM_ARGS() < 4) {
     221            4086 :                 len = len1;
     222                 :         }
     223                 :         
     224                 :         /* look at substr() function for more information */
     225                 :         
     226           12901 :         if (start < 0) {
     227            4336 :                 start += len1;
     228            4336 :                 if (start < 0) {
     229            2306 :                         start = 0;
     230                 :                 }
     231            8565 :         } else if (start > len1) {
     232            2662 :                 RETURN_FALSE;
     233                 :         }
     234                 :         
     235           10239 :         if (len < 0) {
     236            2227 :                 len += (len1 - start);
     237            2227 :                 if (len < 0) {
     238            1286 :                         len = 0;
     239                 :                 }
     240                 :         }
     241                 :         
     242           10239 :         if (len > len1 - start) {
     243            3429 :                 len = len1 - start;
     244                 :         }
     245                 : 
     246           10239 :         if(len == 0) {
     247            3625 :                 RETURN_LONG(0);
     248                 :         }
     249                 : 
     250            6614 :         if (behavior == STR_STRSPN) {
     251            3381 :                 RETURN_LONG(php_strspn(s11 + start /*str1_start*/,
     252                 :                                                 s22 /*str2_start*/,
     253                 :                                                 s11 + start + len /*str1_end*/,
     254                 :                                                 s22 + len2 /*str2_end*/));
     255            3233 :         } else if (behavior == STR_STRCSPN) {
     256            3233 :                 RETURN_LONG(php_strcspn(s11 + start /*str1_start*/,
     257                 :                                                 s22 /*str2_start*/,
     258                 :                                                 s11 + start + len /*str1_end*/,
     259                 :                                                 s22 + len2 /*str2_end*/));
     260                 :         }
     261                 :         
     262                 : }
     263                 : /* }}} */
     264                 : 
     265                 : /* {{{ proto int strspn(string str, string mask [, start [, len]])
     266                 :    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) */
     267                 : PHP_FUNCTION(strspn)
     268            6718 : {
     269            6718 :         php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN);
     270            6718 : }
     271                 : /* }}} */
     272                 : 
     273                 : /* {{{ proto int strcspn(string str, string mask [, start [, len]])
     274                 :    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) */
     275                 : PHP_FUNCTION(strcspn)
     276            6327 : {
     277            6327 :         php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN);
     278            6327 : }
     279                 : /* }}} */
     280                 : 
     281                 : /* {{{ PHP_MINIT_FUNCTION(nl_langinfo) */
     282                 : #if HAVE_NL_LANGINFO
     283                 : PHP_MINIT_FUNCTION(nl_langinfo)
     284           13565 : {
     285                 : #define REGISTER_NL_LANGINFO_CONSTANT(x)        REGISTER_LONG_CONSTANT(#x, x, CONST_CS | CONST_PERSISTENT)
     286                 : #ifdef ABDAY_1
     287           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
     288           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
     289           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
     290           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
     291           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
     292           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
     293           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
     294                 : #endif
     295                 : #ifdef DAY_1
     296           13565 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
     297           13565 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
     298           13565 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
     299           13565 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
     300           13565 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
     301           13565 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
     302           13565 :         REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
     303                 : #endif
     304                 : #ifdef ABMON_1
     305           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
     306           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
     307           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
     308           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
     309           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
     310           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
     311           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
     312           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
     313           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
     314           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
     315           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
     316           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
     317                 : #endif
     318                 : #ifdef MON_1
     319           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_1);
     320           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_2);
     321           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_3);
     322           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_4);
     323           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_5);
     324           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_6);
     325           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_7);
     326           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_8);
     327           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_9);
     328           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_10);
     329           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_11);
     330           13565 :         REGISTER_NL_LANGINFO_CONSTANT(MON_12);
     331                 : #endif
     332                 : #ifdef AM_STR
     333           13565 :         REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
     334                 : #endif
     335                 : #ifdef PM_STR
     336           13565 :         REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
     337                 : #endif
     338                 : #ifdef D_T_FMT
     339           13565 :         REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
     340                 : #endif
     341                 : #ifdef D_FMT
     342           13565 :         REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
     343                 : #endif
     344                 : #ifdef T_FMT
     345           13565 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
     346                 : #endif
     347                 : #ifdef T_FMT_AMPM
     348           13565 :         REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
     349                 : #endif
     350                 : #ifdef ERA
     351           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ERA);
     352                 : #endif
     353                 : #ifdef ERA_YEAR
     354                 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_YEAR);
     355                 : #endif
     356                 : #ifdef ERA_D_T_FMT
     357           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
     358                 : #endif
     359                 : #ifdef ERA_D_FMT
     360           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
     361                 : #endif
     362                 : #ifdef ERA_T_FMT
     363           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
     364                 : #endif
     365                 : #ifdef ALT_DIGITS
     366           13565 :         REGISTER_NL_LANGINFO_CONSTANT(ALT_DIGITS);
     367                 : #endif
     368                 : #ifdef INT_CURR_SYMBOL
     369                 :         REGISTER_NL_LANGINFO_CONSTANT(INT_CURR_SYMBOL);
     370                 : #endif
     371                 : #ifdef CURRENCY_SYMBOL
     372                 :         REGISTER_NL_LANGINFO_CONSTANT(CURRENCY_SYMBOL);
     373                 : #endif
     374                 : #ifdef CRNCYSTR
     375           13565 :         REGISTER_NL_LANGINFO_CONSTANT(CRNCYSTR);
     376                 : #endif
     377                 : #ifdef MON_DECIMAL_POINT
     378                 :         REGISTER_NL_LANGINFO_CONSTANT(MON_DECIMAL_POINT);
     379                 : #endif
     380                 : #ifdef MON_THOUSANDS_SEP
     381                 :         REGISTER_NL_LANGINFO_CONSTANT(MON_THOUSANDS_SEP);
     382                 : #endif
     383                 : #ifdef MON_GROUPING
     384                 :         REGISTER_NL_LANGINFO_CONSTANT(MON_GROUPING);
     385                 : #endif
     386                 : #ifdef POSITIVE_SIGN
     387                 :         REGISTER_NL_LANGINFO_CONSTANT(POSITIVE_SIGN);
     388                 : #endif
     389                 : #ifdef NEGATIVE_SIGN
     390                 :         REGISTER_NL_LANGINFO_CONSTANT(NEGATIVE_SIGN);
     391                 : #endif
     392                 : #ifdef INT_FRAC_DIGITS
     393                 :         REGISTER_NL_LANGINFO_CONSTANT(INT_FRAC_DIGITS);
     394                 : #endif
     395                 : #ifdef FRAC_DIGITS
     396                 :         REGISTER_NL_LANGINFO_CONSTANT(FRAC_DIGITS);
     397                 : #endif
     398                 : #ifdef P_CS_PRECEDES
     399                 :         REGISTER_NL_LANGINFO_CONSTANT(P_CS_PRECEDES);
     400                 : #endif
     401                 : #ifdef P_SEP_BY_SPACE
     402                 :         REGISTER_NL_LANGINFO_CONSTANT(P_SEP_BY_SPACE);
     403                 : #endif
     404                 : #ifdef N_CS_PRECEDES
     405                 :         REGISTER_NL_LANGINFO_CONSTANT(N_CS_PRECEDES);
     406                 : #endif
     407                 : #ifdef N_SEP_BY_SPACE
     408                 :         REGISTER_NL_LANGINFO_CONSTANT(N_SEP_BY_SPACE);
     409                 : #endif
     410                 : #ifdef P_SIGN_POSN
     411                 :         REGISTER_NL_LANGINFO_CONSTANT(P_SIGN_POSN);
     412                 : #endif
     413                 : #ifdef N_SIGN_POSN
     414                 :         REGISTER_NL_LANGINFO_CONSTANT(N_SIGN_POSN);
     415                 : #endif
     416                 : #ifdef DECIMAL_POINT
     417                 :         REGISTER_NL_LANGINFO_CONSTANT(DECIMAL_POINT);
     418                 : #endif
     419                 : #ifdef RADIXCHAR
     420           13565 :         REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
     421                 : #endif
     422                 : #ifdef THOUSANDS_SEP
     423                 :         REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
     424                 : #endif
     425                 : #ifdef THOUSEP
     426           13565 :         REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
     427                 : #endif
     428                 : #ifdef GROUPING
     429                 :         REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
     430                 : #endif
     431                 : #ifdef YESEXPR
     432           13565 :         REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
     433                 : #endif
     434                 : #ifdef NOEXPR
     435           13565 :         REGISTER_NL_LANGINFO_CONSTANT(NOEXPR);
     436                 : #endif
     437                 : #ifdef YESSTR
     438                 :         REGISTER_NL_LANGINFO_CONSTANT(YESSTR);
     439                 : #endif
     440                 : #ifdef NOSTR
     441                 :         REGISTER_NL_LANGINFO_CONSTANT(NOSTR);
     442                 : #endif
     443                 : #ifdef CODESET
     444           13565 :         REGISTER_NL_LANGINFO_CONSTANT(CODESET);
     445                 : #endif
     446                 : #undef REGISTER_NL_LANGINFO_CONSTANT
     447           13565 :         return SUCCESS;
     448                 : }
     449                 : /* }}} */
     450                 : 
     451                 : /* {{{ proto string nl_langinfo(int item)
     452                 :    Query language and locale information */
     453                 : PHP_FUNCTION(nl_langinfo)
     454              28 : {
     455                 :         long item;
     456                 :         char *value;
     457                 :         
     458              28 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &item) == FAILURE) {
     459               7 :                 return;
     460                 :         }
     461                 : 
     462              21 :         switch(item) { /* {{{ */
     463                 : #ifdef ABDAY_1
     464                 :                 case ABDAY_1:
     465                 :                 case ABDAY_2:
     466                 :                 case ABDAY_3:
     467                 :                 case ABDAY_4:
     468                 :                 case ABDAY_5:
     469                 :                 case ABDAY_6:
     470                 :                 case ABDAY_7:
     471                 : #endif
     472                 : #ifdef DAY_1
     473                 :                 case DAY_1:
     474                 :                 case DAY_2:
     475                 :                 case DAY_3:
     476                 :                 case DAY_4:
     477                 :                 case DAY_5:
     478                 :                 case DAY_6:
     479                 :                 case DAY_7:
     480                 : #endif
     481                 : #ifdef ABMON_1
     482                 :                 case ABMON_1:
     483                 :                 case ABMON_2:
     484                 :                 case ABMON_3:
     485                 :                 case ABMON_4:
     486                 :                 case ABMON_5:
     487                 :                 case ABMON_6:
     488                 :                 case ABMON_7:
     489                 :                 case ABMON_8:
     490                 :                 case ABMON_9:
     491                 :                 case ABMON_10:
     492                 :                 case ABMON_11:
     493                 :                 case ABMON_12:
     494                 : #endif
     495                 : #ifdef MON_1
     496                 :                 case MON_1:
     497                 :                 case MON_2:
     498                 :                 case MON_3:
     499                 :                 case MON_4:
     500                 :                 case MON_5:
     501                 :                 case MON_6:
     502                 :                 case MON_7:
     503                 :                 case MON_8:
     504                 :                 case MON_9:
     505                 :                 case MON_10:
     506                 :                 case MON_11:
     507                 :                 case MON_12:
     508                 : #endif
     509                 : #ifdef AM_STR
     510                 :                 case AM_STR:
     511                 : #endif
     512                 : #ifdef PM_STR
     513                 :                 case PM_STR:
     514                 : #endif
     515                 : #ifdef D_T_FMT
     516                 :                 case D_T_FMT:
     517                 : #endif
     518                 : #ifdef D_FMT
     519                 :                 case D_FMT:
     520                 : #endif
     521                 : #ifdef T_FMT
     522                 :                 case T_FMT:
     523                 : #endif
     524                 : #ifdef T_FMT_AMPM
     525                 :                 case T_FMT_AMPM:
     526                 : #endif
     527                 : #ifdef ERA
     528                 :                 case ERA:
     529                 : #endif
     530                 : #ifdef ERA_YEAR
     531                 :                 case ERA_YEAR:
     532                 : #endif
     533                 : #ifdef ERA_D_T_FMT
     534                 :                 case ERA_D_T_FMT:
     535                 : #endif
     536                 : #ifdef ERA_D_FMT
     537                 :                 case ERA_D_FMT:
     538                 : #endif
     539                 : #ifdef ERA_T_FMT
     540                 :                 case ERA_T_FMT:
     541                 : #endif
     542                 : #ifdef ALT_DIGITS
     543                 :                 case ALT_DIGITS:
     544                 : #endif
     545                 : #ifdef INT_CURR_SYMBOL
     546                 :                 case INT_CURR_SYMBOL:
     547                 : #endif
     548                 : #ifdef CURRENCY_SYMBOL
     549                 :                 case CURRENCY_SYMBOL:
     550                 : #endif
     551                 : #ifdef CRNCYSTR
     552                 :                 case CRNCYSTR:
     553                 : #endif
     554                 : #ifdef MON_DECIMAL_POINT
     555                 :                 case MON_DECIMAL_POINT:
     556                 : #endif
     557                 : #ifdef MON_THOUSANDS_SEP
     558                 :                 case MON_THOUSANDS_SEP:
     559                 : #endif
     560                 : #ifdef MON_GROUPING
     561                 :                 case MON_GROUPING:
     562                 : #endif
     563                 : #ifdef POSITIVE_SIGN
     564                 :                 case POSITIVE_SIGN:
     565                 : #endif
     566                 : #ifdef NEGATIVE_SIGN
     567                 :                 case NEGATIVE_SIGN:
     568                 : #endif
     569                 : #ifdef INT_FRAC_DIGITS
     570                 :                 case INT_FRAC_DIGITS:
     571                 : #endif
     572                 : #ifdef FRAC_DIGITS
     573                 :                 case FRAC_DIGITS:
     574                 : #endif
     575                 : #ifdef P_CS_PRECEDES
     576                 :                 case P_CS_PRECEDES:
     577                 : #endif
     578                 : #ifdef P_SEP_BY_SPACE
     579                 :                 case P_SEP_BY_SPACE:
     580                 : #endif
     581                 : #ifdef N_CS_PRECEDES
     582                 :                 case N_CS_PRECEDES:
     583                 : #endif
     584                 : #ifdef N_SEP_BY_SPACE
     585                 :                 case N_SEP_BY_SPACE:
     586                 : #endif
     587                 : #ifdef P_SIGN_POSN
     588                 :                 case P_SIGN_POSN:
     589                 : #endif
     590                 : #ifdef N_SIGN_POSN
     591                 :                 case N_SIGN_POSN:
     592                 : #endif
     593                 : #ifdef DECIMAL_POINT
     594                 :                 case DECIMAL_POINT:
     595                 : #elif defined(RADIXCHAR)
     596                 :                 case RADIXCHAR:
     597                 : #endif
     598                 : #ifdef THOUSANDS_SEP
     599                 :                 case THOUSANDS_SEP:
     600                 : #elif defined(THOUSEP)
     601                 :                 case THOUSEP:
     602                 : #endif
     603                 : #ifdef GROUPING
     604                 :                 case GROUPING:
     605                 : #endif
     606                 : #ifdef YESEXPR
     607                 :                 case YESEXPR:
     608                 : #endif
     609                 : #ifdef NOEXPR
     610                 :                 case NOEXPR:
     611                 : #endif
     612                 : #ifdef YESSTR
     613                 :                 case YESSTR:
     614                 : #endif
     615                 : #ifdef NOSTR
     616                 :                 case NOSTR:
     617                 : #endif
     618                 : #ifdef CODESET
     619                 :                 case CODESET:
     620                 : #endif
     621                 :                         break;
     622                 :                 default:
     623              16 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Item '%ld' is not valid", item);
     624              16 :                         RETURN_FALSE;
     625                 :         }
     626                 :         /* }}} */
     627                 : 
     628               5 :         value = nl_langinfo(item);
     629               5 :         if (value == NULL) {
     630               0 :                 RETURN_FALSE;
     631                 :         } else {
     632               5 :                 RETURN_STRING(value, 1);
     633                 :         }
     634                 : }
     635                 : #endif
     636                 : /* }}} */
     637                 : 
     638                 : #ifdef HAVE_STRCOLL
     639                 : /* {{{ proto int strcoll(string str1, string str2)
     640                 :    Compares two strings using the current locale */
     641                 : PHP_FUNCTION(strcoll)
     642               5 : {
     643                 :         zval **s1, **s2;
     644                 : 
     645               5 :         if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
     646               4 :                 WRONG_PARAM_COUNT;
     647                 :         }
     648               1 :         convert_to_string_ex(s1);
     649               1 :         convert_to_string_ex(s2);
     650                 : 
     651               1 :         RETURN_LONG(strcoll((const char *) Z_STRVAL_PP(s1), 
     652                 :                             (const char *) Z_STRVAL_PP(s2)));
     653                 : }
     654                 : /* }}} */
     655                 : #endif
     656                 : 
     657                 : /* {{{ php_charmask
     658                 :  * Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
     659                 :  * it needs to be incrementing.  
     660                 :  * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
     661                 :  */
     662                 : static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC)
     663          608984 : {
     664                 :         unsigned char *end;
     665                 :         unsigned char c;
     666          608984 :         int result = SUCCESS;
     667                 : 
     668          608984 :         memset(mask, 0, 256);
     669         4259988 :         for (end = input+len; input < end; input++) {
     670         3651004 :                 c=*input; 
     671         3651029 :                 if ((input+3 < end) && input[1] == '.' && input[2] == '.' 
     672                 :                                 && input[3] >= c) {
     673              25 :                         memset(mask+c, 1, input[3] - c + 1);
     674              25 :                         input+=3;
     675         3650979 :                 } else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
     676                 :                         /* Error, try to be as helpful as possible:
     677                 :                            (a range ending/starting with '.' won't be captured here) */
     678              14 :                         if (end-len >= input) { /* there was no 'left' char */
     679               3 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
     680               3 :                                 result = FAILURE;
     681               3 :                                 continue;
     682                 :                         }
     683              11 :                         if (input+2 >= end) { /* there is no 'right' char */
     684               3 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
     685               3 :                                 result = FAILURE;
     686               3 :                                 continue;
     687                 :                         }
     688               8 :                         if (input[-1] > input[2]) { /* wrong order */
     689               5 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
     690               5 :                                 result = FAILURE;
     691               5 :                                 continue;
     692                 :                         } 
     693                 :                         /* FIXME: better error (a..b..c is the only left possibility?) */
     694               3 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range");
     695               3 :                         result = FAILURE;
     696               3 :                         continue;
     697                 :                 } else {
     698         3650965 :                         mask[c]=1;
     699                 :                 }
     700                 :         }
     701          608984 :         return result;
     702                 : }
     703                 : /* }}} */
     704                 : 
     705                 : /* {{{ php_trim()
     706                 :  * mode 1 : trim left
     707                 :  * mode 2 : trim right
     708                 :  * mode 3 : trim left and right
     709                 :  * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
     710                 :  */
     711                 : PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC)
     712          608378 : {
     713                 :         register int i;
     714          608378 :         int trimmed = 0;
     715                 :         char mask[256];
     716                 : 
     717          608378 :         if (what) {
     718             278 :                 php_charmask(what, what_len, mask TSRMLS_CC);
     719                 :         } else {
     720          608100 :                 php_charmask(" \n\r\t\v\0", 6, mask TSRMLS_CC);
     721                 :         }
     722                 : 
     723          608378 :         if (mode & 1) {
     724          610888 :                 for (i = 0; i < len; i++) {
     725          523805 :                         if (mask[(unsigned char)c[i]]) {
     726            2716 :                                 trimmed++;
     727                 :                         } else {
     728          521089 :                                 break;
     729                 :                         }
     730                 :                 }
     731          608172 :                 len -= trimmed;
     732          608172 :                 c += trimmed;
     733                 :         }
     734          608378 :         if (mode & 2) {
     735          627853 :                 for (i = len - 1; i >= 0; i--) {
     736          553062 :                         if (mask[(unsigned char)c[i]]) {
     737           32408 :                                 len--;
     738                 :                         } else {
     739          520654 :                                 break;
     740                 :                         }
     741                 :                 }
     742                 :         }
     743                 : 
     744          608378 :         if (return_value) {
     745          608375 :                 RETVAL_STRINGL(c, len, 1);
     746                 :         } else {
     747               3 :                 return estrndup(c, len);
     748                 :         }
     749          608375 :         return "";
     750                 : }
     751                 : /* }}} */
     752                 : 
     753                 : /* {{{ php_do_trim
     754                 :  * Base for trim(), rtrim() and ltrim() functions.
     755                 :  */
     756                 : static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
     757          608389 : {
     758                 :         zval **str;
     759          608389 :         zval **what = NULL;
     760          608389 :         int    argc = ZEND_NUM_ARGS();
     761                 : 
     762          608389 :         if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &str, &what) == FAILURE) {
     763              15 :                 WRONG_PARAM_COUNT;
     764                 :         }
     765                 : 
     766          608374 :         convert_to_string_ex(str);
     767                 : 
     768          608374 :         if (argc > 1) {
     769             278 :                 convert_to_string_ex(what);
     770             278 :                 php_trim(Z_STRVAL_PP(str), Z_STRLEN_PP(str), Z_STRVAL_PP(what), Z_STRLEN_PP(what), return_value, mode TSRMLS_CC);
     771                 :         } else {
     772          608096 :                 php_trim(Z_STRVAL_PP(str), Z_STRLEN_PP(str), NULL, 0, return_value, mode TSRMLS_CC);
     773                 :         }
     774                 : }
     775                 : /* }}} */
     776                 : 
     777                 : /* {{{ proto string trim(string str [, string character_mask])
     778                 :    Strips whitespace from the beginning and end of a string */
     779                 : PHP_FUNCTION(trim)
     780          595240 : {
     781          595240 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
     782          595240 : }
     783                 : /* }}} */
     784                 : 
     785                 : /* {{{ proto string rtrim(string str [, string character_mask])
     786                 :    Removes trailing whitespace */
     787                 : PHP_FUNCTION(rtrim)
     788             212 : {
     789             212 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
     790             212 : }
     791                 : /* }}} */
     792                 : 
     793                 : /* {{{ proto string ltrim(string str [, string character_mask])
     794                 :    Strips whitespace from the beginning of a string */
     795                 : PHP_FUNCTION(ltrim)
     796           12937 : {
     797           12937 :         php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
     798           12937 : }
     799                 : /* }}} */
     800                 : 
     801                 : /* {{{ proto string wordwrap(string str [, int width [, string break [, boolean cut]]])
     802                 :    Wraps buffer to selected number of characters using string break char */
     803                 : PHP_FUNCTION(wordwrap)
     804             357 : {
     805             357 :         const char *text, *breakchar = "\n";
     806                 :         char *newtext;
     807             357 :         int textlen, breakcharlen = 1, newtextlen, chk;
     808                 :         size_t alloced;
     809             357 :         long current = 0, laststart = 0, lastspace = 0;
     810             357 :         long linelength = 75;
     811             357 :         zend_bool docut = 0;
     812                 : 
     813             357 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lsb", &text, &textlen, &linelength, &breakchar, &breakcharlen, &docut) == FAILURE) {
     814             108 :                 return;
     815                 :         }
     816                 : 
     817             249 :         if (textlen == 0) {
     818              40 :                 RETURN_EMPTY_STRING();
     819                 :         }
     820                 : 
     821             209 :         if (breakcharlen == 0) {
     822              25 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Break string cannot be empty");
     823              25 :                 RETURN_FALSE;
     824                 :         }
     825                 : 
     826             184 :         if (linelength == 0 && docut) {
     827               8 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't force cut when width is zero");
     828               8 :                 RETURN_FALSE;
     829                 :         }
     830                 : 
     831                 :         /* Special case for a single-character break as it needs no
     832                 :            additional storage space */
     833             176 :         if (breakcharlen == 1 && !docut) {
     834              50 :                 newtext = estrndup(text, textlen);
     835                 : 
     836              50 :                 laststart = lastspace = 0;
     837            1009 :                 for (current = 0; current < textlen; current++) {
     838             959 :                         if (text[current] == breakchar[0]) {
     839               4 :                                 laststart = lastspace = current + 1;
     840             955 :                         } else if (text[current] == ' ') {
     841              72 :                                 if (current - laststart >= linelength) {
     842              30 :                                         newtext[current] = breakchar[0];
     843              30 :                                         laststart = current + 1;
     844                 :                                 }
     845              72 :                                 lastspace = current;
     846             883 :                         } else if (current - laststart >= linelength && laststart != lastspace) {
     847             220 :                                 newtext[lastspace] = breakchar[0];
     848             220 :                                 laststart = lastspace + 1;
     849                 :                         }
     850                 :                 }
     851                 : 
     852              50 :                 RETURN_STRINGL(newtext, textlen, 0);
     853                 :         } else {
     854                 :                 /* Multiple character line break or forced cut */
     855             126 :                 if (linelength > 0) {
     856             102 :                         chk = (int)(textlen/linelength + 1);
     857             102 :                         newtext = safe_emalloc(chk, breakcharlen, textlen + 1);
     858             102 :                         alloced = textlen + chk * breakcharlen + 1;
     859                 :                 } else {
     860              24 :                         chk = textlen;
     861              24 :                         alloced = textlen * (breakcharlen + 1) + 1;
     862              24 :                         newtext = safe_emalloc(textlen, (breakcharlen + 1), 1);
     863                 :                 }
     864                 : 
     865                 :                 /* now keep track of the actual new text length */
     866             126 :                 newtextlen = 0;
     867                 : 
     868             126 :                 laststart = lastspace = 0;
     869            2742 :                 for (current = 0; current < textlen; current++) {
     870            2616 :                         if (chk <= 0) {
     871               6 :                                 alloced += (int) (((textlen - current + 1)/linelength + 1) * breakcharlen) + 1;
     872               6 :                                 newtext = erealloc(newtext, alloced);
     873               6 :                                 chk = (int) ((textlen - current)/linelength) + 1;
     874                 :                         }
     875                 :                         /* when we hit an existing break, copy to new buffer, and
     876                 :                          * fix up laststart and lastspace */
     877            2630 :                         if (text[current] == breakchar[0]
     878                 :                                 && current + breakcharlen < textlen
     879                 :                                 && !strncmp(text+current, breakchar, breakcharlen)) {
     880              14 :                                 memcpy(newtext+newtextlen, text+laststart, current-laststart+breakcharlen);
     881              14 :                                 newtextlen += current-laststart+breakcharlen;
     882              14 :                                 current += breakcharlen - 1;
     883              14 :                                 laststart = lastspace = current + 1;
     884              14 :                                 chk--;
     885                 :                         }
     886                 :                         /* if it is a space, check if it is at the line boundary,
     887                 :                          * copy and insert a break, or just keep track of it */
     888            2602 :                         else if (text[current] == ' ') {
     889             214 :                                 if (current - laststart >= linelength) {
     890              85 :                                         memcpy(newtext+newtextlen, text+laststart, current-laststart);
     891              85 :                                         newtextlen += current - laststart;
     892              85 :                                         memcpy(newtext+newtextlen, breakchar, breakcharlen);
     893              85 :                                         newtextlen += breakcharlen;
     894              85 :                                         laststart = current + 1;
     895              85 :                                         chk--;
     896                 :                                 }
     897             214 :                                 lastspace = current;
     898                 :                         }
     899                 :                         /* if we are cutting, and we've accumulated enough
     900                 :                          * characters, and we haven't see a space for this line,
     901                 :                          * copy and insert a break. */
     902            2556 :                         else if (current - laststart >= linelength
     903                 :                                         && docut && laststart >= lastspace) {
     904             168 :                                 memcpy(newtext+newtextlen, text+laststart, current-laststart);
     905             168 :                                 newtextlen += current - laststart;
     906             168 :                                 memcpy(newtext+newtextlen, breakchar, breakcharlen);
     907             168 :                                 newtextlen += breakcharlen;
     908             168 :                                 laststart = lastspace = current;
     909             168 :                                 chk--;
     910                 :                         }
     911                 :                         /* if the current word puts us over the linelength, copy
     912                 :                          * back up until the last space, insert a break, and move
     913                 :                          * up the laststart */
     914            2220 :                         else if (current - laststart >= linelength
     915                 :                                         && laststart < lastspace) {
     916             107 :                                 memcpy(newtext+newtextlen, text+laststart, lastspace-laststart);
     917             107 :                                 newtextlen += lastspace - laststart;
     918             107 :                                 memcpy(newtext+newtextlen, breakchar, breakcharlen);
     919             107 :                                 newtextlen += breakcharlen;
     920             107 :                                 laststart = lastspace = lastspace + 1;
     921             107 :                                 chk--;
     922                 :                         }
     923                 :                 }
     924                 : 
     925                 :                 /* copy over any stragglers */
     926             126 :                 if (laststart != current) {
     927             126 :                         memcpy(newtext+newtextlen, text+laststart, current-laststart);
     928             126 :                         newtextlen += current - laststart;
     929                 :                 }
     930                 : 
     931             126 :                 newtext[newtextlen] = '\0';
     932                 :                 /* free unused memory */
     933             126 :                 newtext = erealloc(newtext, newtextlen+1);
     934                 : 
     935             126 :                 RETURN_STRINGL(newtext, newtextlen, 0);
     936                 :         }
     937                 : }
     938                 : /* }}} */
     939                 : 
     940                 : /* {{{ php_explode
     941                 :  */
     942                 : PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, int limit) 
     943          381841 : {
     944                 :         char *p1, *p2, *endp;
     945                 : 
     946          381841 :         endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
     947                 : 
     948          381841 :         p1 = Z_STRVAL_P(str);
     949          381841 :         p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
     950                 : 
     951          381841 :         if (p2 == NULL) {
     952              60 :                 add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
     953                 :         } else {
     954                 :                 do {
     955          395610 :                         add_next_index_stringl(return_value, p1, p2 - p1, 1);
     956          395610 :                         p1 = p2 + Z_STRLEN_P(delim);
     957                 :                 } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
     958          395610 :                                  (limit == -1 || --limit > 1));
     959                 : 
     960          381781 :                 if (p1 <= endp)
     961          381781 :                         add_next_index_stringl(return_value, p1, endp-p1, 1);
     962                 :         }
     963          381841 : }
     964                 : /* }}} */
     965                 : 
     966                 : /* {{{ php_explode_negative_limit
     967                 :  */
     968                 : PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, int limit) 
     969              22 : {
     970                 : #define EXPLODE_ALLOC_STEP 50
     971                 :         char *p1, *p2, *endp;
     972              22 :         int allocated = EXPLODE_ALLOC_STEP, found = 0, i = 0, to_return = 0;
     973              22 :         char **positions = safe_emalloc(allocated, sizeof(char *), 0);
     974                 :         
     975              22 :         endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
     976                 : 
     977              22 :         p1 = Z_STRVAL_P(str);
     978              22 :         p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
     979                 : 
     980              22 :         if (p2 == NULL) {
     981                 :                 /*
     982                 :                 do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0
     983                 :                 by doing nothing we return empty array
     984                 :                 */
     985                 :         } else {
     986              21 :                 positions[found++] = p1;
     987                 :                 do {
     988             114 :                         if (found >= allocated) {
     989               1 :                                 allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */
     990               1 :                                 positions = erealloc(positions, allocated*sizeof(char *));
     991                 :                         }
     992             114 :                         positions[found++] = p1 = p2 + Z_STRLEN_P(delim);
     993             114 :                 } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL);
     994                 :                 
     995              21 :                 to_return = limit + found;
     996                 :                 /* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
     997             116 :                 for (i = 0;i < to_return;i++) { /* this checks also for to_return > 0 */
     998              95 :                         add_next_index_stringl(return_value, positions[i], 
     999                 :                                         (positions[i+1] - Z_STRLEN_P(delim)) - positions[i],
    1000                 :                                         1
    1001                 :                                 );
    1002                 :                 }
    1003                 :         }
    1004              22 :         efree(positions);
    1005                 : #undef EXPLODE_ALLOC_STEP
    1006              22 : }
    1007                 : /* }}} */
    1008                 : 
    1009                 : /* {{{ proto array explode(string separator, string str [, int limit])
    1010                 :    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. */
    1011                 : PHP_FUNCTION(explode)
    1012          381941 : {
    1013          381941 :         zval **str, **delim, **zlimit = NULL;
    1014          381941 :         int limit = -1;
    1015          381941 :         int argc = ZEND_NUM_ARGS();
    1016                 : 
    1017          381941 :         if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &delim, &str, &zlimit) == FAILURE) {
    1018               4 :                 WRONG_PARAM_COUNT;
    1019                 :         }
    1020          381937 :         convert_to_string_ex(str);
    1021          381937 :         convert_to_string_ex(delim);
    1022                 : 
    1023          381937 :         if (argc > 2) {
    1024          281570 :                 convert_to_long_ex(zlimit);
    1025          281570 :                 limit = Z_LVAL_PP(zlimit);
    1026                 :         }
    1027                 : 
    1028          381937 :         if (! Z_STRLEN_PP(delim)) {
    1029              28 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
    1030              28 :                 RETURN_FALSE;
    1031                 :         }
    1032                 : 
    1033          381909 :         array_init(return_value);
    1034                 : 
    1035          381909 :         if (! Z_STRLEN_PP(str)) {
    1036              12 :                 if (limit >= 0 || argc == 2) {
    1037              11 :                         add_next_index_stringl(return_value, "", sizeof("") - 1, 1);
    1038                 :                 } 
    1039              12 :                 return;
    1040                 :         }
    1041                 : 
    1042                 : 
    1043          381931 :         if (limit == 0 || limit == 1) {
    1044              34 :                 add_index_stringl(return_value, 0, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
    1045          381885 :         } else if (limit < 0 && argc == 3) {
    1046              22 :                 php_explode_negative_limit(*delim, *str, return_value, limit);
    1047                 :         } else {
    1048          381841 :                 php_explode(*delim, *str, return_value, limit);
    1049                 :         }
    1050                 : }
    1051                 : /* }}} */
    1052                 : 
    1053                 : /* {{{ proto string join(array src, string glue)
    1054                 :    An alias for implode */
    1055                 : /* }}} */
    1056                 : 
    1057                 : /* {{{ php_implode
    1058                 :  */
    1059                 : PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC) 
    1060           90422 : {
    1061                 :         zval         **tmp;
    1062                 :         HashPosition   pos;
    1063           90422 :         smart_str      implstr = {0};
    1064           90422 :         int            numelems, i = 0;
    1065                 :         zval tmp_val;
    1066                 :         int str_len;
    1067                 : 
    1068           90422 :         numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
    1069                 : 
    1070           90422 :         if (numelems == 0) {
    1071              48 :                 RETURN_EMPTY_STRING();
    1072                 :         }
    1073                 : 
    1074           90374 :         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos);
    1075                 : 
    1076          542647 :         while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) {
    1077          361899 :                 switch ((*tmp)->type) {
    1078                 :                         case IS_STRING:
    1079            1152 :                                 smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
    1080            1152 :                                 break;
    1081                 : 
    1082                 :                         case IS_LONG: {
    1083                 :                                 char stmp[MAX_LENGTH_OF_LONG + 1];
    1084          360630 :                                 str_len = slprintf(stmp, sizeof(stmp), "%ld", Z_LVAL_PP(tmp));
    1085          360630 :                                 smart_str_appendl(&implstr, stmp, str_len);
    1086                 :                         }
    1087          360630 :                                 break;
    1088                 : 
    1089                 :                         case IS_BOOL:
    1090              47 :                                 if (Z_LVAL_PP(tmp) == 1) {
    1091              23 :                                         smart_str_appendl(&implstr, "1", sizeof("1")-1);
    1092                 :                                 }
    1093              47 :                                 break;
    1094                 :                         
    1095                 :                         case IS_NULL:
    1096              26 :                                 break;
    1097                 : 
    1098                 :                         case IS_DOUBLE: {
    1099                 :                                 char *stmp;
    1100              24 :                                 str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_PP(tmp));
    1101              24 :                                 smart_str_appendl(&implstr, stmp, str_len);
    1102              24 :                                 efree(stmp);
    1103                 :                         }
    1104              24 :                                 break;
    1105                 : 
    1106                 :                         case IS_OBJECT: {
    1107                 :                                 int copy;
    1108                 :                                 zval expr;
    1109               4 :                                 zend_make_printable_zval(*tmp, &expr, &copy);
    1110               4 :                                 smart_str_appendl(&implstr, Z_STRVAL(expr), Z_STRLEN(expr));
    1111               4 :                                 if (copy) {
    1112               4 :                                         zval_dtor(&expr);
    1113                 :                                 }
    1114                 :                         }
    1115               4 :                                 break;
    1116                 : 
    1117                 :                         default:
    1118              16 :                                 tmp_val = **tmp;
    1119              16 :                                 zval_copy_ctor(&tmp_val);
    1120              16 :                                 convert_to_string(&tmp_val);
    1121              16 :                                 smart_str_appendl(&implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
    1122              16 :                                 zval_dtor(&tmp_val);
    1123                 :                                 break;
    1124                 :                                 
    1125                 :                 }
    1126                 : 
    1127          361899 :                 if (++i != numelems) {
    1128          271525 :                         smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim));
    1129                 :                 }
    1130          361899 :                 zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
    1131                 :         }
    1132           90374 :         smart_str_0(&implstr);
    1133                 : 
    1134           90374 :         if (implstr.len) {
    1135           90369 :                 RETURN_STRINGL(implstr.c, implstr.len, 0);
    1136                 :         } else {
    1137               5 :                 smart_str_free(&implstr);
    1138               5 :                 RETURN_EMPTY_STRING();
    1139                 :         }
    1140                 : }
    1141                 : /* }}} */
    1142                 : 
    1143                 : /* {{{ proto string implode([string glue,] array pieces)
    1144                 :    Joins array elements placing glue string between items and return one string */
    1145                 : PHP_FUNCTION(implode)
    1146           90456 : {
    1147           90456 :         zval **arg1 = NULL, **arg2 = NULL, *delim, *arr;
    1148           90456 :         int argc = ZEND_NUM_ARGS();
    1149                 :         HashPosition pos;
    1150                 : 
    1151           90456 :         if (argc < 1 || argc > 2 ||
    1152                 :                 zend_get_parameters_ex(argc, &arg1, &arg2) == FAILURE) {
    1153               4 :                 WRONG_PARAM_COUNT;
    1154                 :         }
    1155                 : 
    1156           90452 :         if (argc == 1) {
    1157               8 :                 if (Z_TYPE_PP(arg1) != IS_ARRAY) {
    1158               3 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument must be an array");
    1159               3 :                         return;
    1160                 :                 }
    1161                 : 
    1162               5 :                 MAKE_STD_ZVAL(delim);
    1163                 : #define _IMPL_EMPTY ""
    1164               5 :                 ZVAL_STRINGL(delim, _IMPL_EMPTY, sizeof(_IMPL_EMPTY) - 1, 0);
    1165                 : 
    1166               5 :                 SEPARATE_ZVAL(arg1);
    1167               5 :                 arr = *arg1;
    1168                 :         } else {
    1169           90444 :                 if (Z_TYPE_PP(arg1) == IS_ARRAY) {
    1170              36 :                         arr = *arg1;
    1171              36 :                         convert_to_string_ex(arg2);
    1172              36 :                         delim = *arg2;
    1173           90408 :                 } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {
    1174           90381 :                         arr = *arg2;
    1175           90381 :                         convert_to_string_ex(arg1);
    1176           90381 :                         delim = *arg1;
    1177                 :                 } else {
    1178              27 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid arguments passed");
    1179              27 :                         return;
    1180                 :                 }
    1181                 :         }
    1182                 : 
    1183           90422 :         pos = Z_ARRVAL_P(arr)->pInternalPointer;
    1184                 :         
    1185           90422 :         php_implode(delim, arr, return_value TSRMLS_CC);
    1186                 : 
    1187           90422 :         Z_ARRVAL_P(arr)->pInternalPointer = pos;
    1188                 : 
    1189           90422 :         if (argc == 1) {
    1190               5 :                 FREE_ZVAL(delim);
    1191                 :         }
    1192                 : }
    1193                 : /* }}} */
    1194                 : 
    1195                 : #define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]    
    1196                 : 
    1197                 : /* {{{ proto string strtok([string str,] string token)
    1198                 :    Tokenize a string */
    1199                 : PHP_FUNCTION(strtok)
    1200             344 : {
    1201                 :         zval **args[2];
    1202                 :         zval **tok, **str;
    1203                 :         char *token;
    1204                 :         char *token_end;
    1205                 :         char *p;
    1206                 :         char *pe;
    1207             344 :         int skipped = 0;
    1208                 :         
    1209             344 :         if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
    1210               2 :                 WRONG_PARAM_COUNT;
    1211                 :         }
    1212                 :                 
    1213             342 :         switch (ZEND_NUM_ARGS()) {
    1214                 :                 case 1:
    1215             241 :                         tok = args[0];
    1216             241 :                         break;
    1217                 : 
    1218                 :                 default:
    1219                 :                 case 2:
    1220             101 :                         str = args[0];
    1221             101 :                         tok = args[1];
    1222             101 :                         convert_to_string_ex(str);
    1223                 : 
    1224             101 :                         zval_add_ref(str);
    1225             101 :                         if (BG(strtok_zval)) {
    1226              92 :                                 zval_ptr_dtor(&BG(strtok_zval));
    1227                 :                         }
    1228             101 :                         BG(strtok_zval) = *str;
    1229             101 :                         BG(strtok_last) = BG(strtok_string) = Z_STRVAL_PP(str);
    1230             101 :                         BG(strtok_len) = Z_STRLEN_PP(str);
    1231                 :                         break;
    1232                 :         }
    1233                 :         
    1234             342 :         p = BG(strtok_last); /* Where we start to search */
    1235             342 :         pe = BG(strtok_string) + BG(strtok_len);
    1236                 : 
    1237             342 :         if (!p || p >= pe) {
    1238             160 :                 RETURN_FALSE;
    1239                 :         }
    1240                 : 
    1241             182 :         convert_to_string_ex(tok);
    1242                 :         
    1243             182 :         token = Z_STRVAL_PP(tok);
    1244             182 :         token_end = token + Z_STRLEN_PP(tok);
    1245                 : 
    1246            1056 :         while (token < token_end) {
    1247             692 :                 STRTOK_TABLE(token++) = 1;
    1248                 :         }
    1249                 :         
    1250                 :         /* Skip leading delimiters */
    1251             451 :         while (STRTOK_TABLE(p)) {
    1252              99 :                 if (++p >= pe) {
    1253                 :                         /* no other chars left */
    1254              12 :                         BG(strtok_last) = NULL;
    1255              12 :                         RETVAL_FALSE;
    1256              12 :                         goto restore;
    1257                 :                 }
    1258              87 :                 skipped++;
    1259                 :         }
    1260                 :         
    1261                 :         /* We know at this place that *p is no delimiter, so skip it */ 
    1262            1590 :         while (++p < pe) {
    1263            1363 :                 if (STRTOK_TABLE(p)) {
    1264             113 :                         goto return_token;      
    1265                 :                 }
    1266                 :         }
    1267                 :         
    1268              57 :         if (p - BG(strtok_last)) {
    1269             170 : return_token:
    1270             170 :                 RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped, 1);
    1271             170 :                 BG(strtok_last) = p + 1;
    1272                 :         } else {
    1273               0 :                 RETVAL_FALSE;
    1274               0 :                 BG(strtok_last) = NULL;
    1275                 :         }
    1276                 : 
    1277                 :         /* Restore table -- usually faster then memset'ing the table on every invocation */
    1278             182 : restore:
    1279             182 :         token = Z_STRVAL_PP(tok);
    1280                 :         
    1281            1056 :         while (token < token_end) {
    1282             692 :                 STRTOK_TABLE(token++) = 0;
    1283                 :         }
    1284                 : }
    1285                 : /* }}} */
    1286                 : 
    1287                 : /* {{{ php_strtoupper
    1288                 :  */
    1289                 : PHPAPI char *php_strtoupper(char *s, size_t len)
    1290             517 : {
    1291                 :         unsigned char *c, *e;
    1292                 :         
    1293             517 :         c = s;
    1294             517 :         e = c+len;
    1295                 : 
    1296            4705 :         while (c < e) {
    1297            3671 :                 *c = toupper(*c);
    1298            3671 :                 c++;
    1299                 :         }
    1300             517 :         return s;
    1301                 : }
    1302                 : /* }}} */
    1303                 : 
    1304                 : /* {{{ proto string strtoupper(string str)
    1305                 :    Makes a string uppercase */
    1306                 : PHP_FUNCTION(strtoupper)
    1307             310 : {
    1308                 :         zval **arg;
    1309                 :         
    1310             310 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
    1311               0 :                 WRONG_PARAM_COUNT;
    1312                 :         }
    1313             310 :         convert_to_string_ex(arg);
    1314                 : 
    1315             310 :         RETVAL_ZVAL(*arg, 1, 0);
    1316             310 :         php_strtoupper(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
    1317                 : }
    1318                 : /* }}} */
    1319                 : 
    1320                 : /* {{{ php_strtolower
    1321                 :  */
    1322                 : PHPAPI char *php_strtolower(char *s, size_t len)
    1323          419749 : {
    1324                 :         unsigned char *c, *e;
    1325                 :         
    1326          419749 :         c = s;
    1327          419749 :         e = c+len;
    1328                 : 
    1329         7654202 :         while (c < e) {
    1330         6814704 :                 *c = tolower(*c);
    1331         6814704 :                 c++;
    1332                 :         }
    1333          419749 :         return s;
    1334                 : }
    1335                 : /* }}} */
    1336                 : 
    1337                 : /* {{{ proto string strtolower(string str)
    1338                 :    Makes a string lowercase */
    1339                 : PHP_FUNCTION(strtolower)
    1340          281502 : {
    1341                 :         zval **str;
    1342                 :         char *ret;
    1343                 :         
    1344          281502 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str)) {
    1345               0 :                 WRONG_PARAM_COUNT;
    1346                 :         }
    1347          281502 :         convert_to_string_ex(str);
    1348                 : 
    1349          281502 :         RETVAL_ZVAL(*str, 1, 0);
    1350          281502 :         ret = php_strtolower(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
    1351                 : }
    1352                 : /* }}} */
    1353                 : 
    1354                 : /* {{{ php_basename
    1355                 :  */
    1356                 : PHPAPI void php_basename(char *s, size_t len, char *suffix, size_t sufflen, char **p_ret, size_t *p_len TSRMLS_DC)
    1357           10509 : {
    1358           10509 :         char *ret = NULL, *c, *comp, *cend;
    1359                 :         size_t inc_len, cnt;
    1360                 :         int state;
    1361                 : 
    1362           10509 :         c = comp = cend = s;
    1363           10509 :         cnt = len;
    1364           10509 :         state = 0;
    1365          604659 :         while (cnt > 0) {
    1366          583641 :                 inc_len = (*c == '\0' ? 1: php_mblen(c, cnt));
    1367                 : 
    1368          583641 :                 switch (inc_len) {
    1369                 :                         case -2:
    1370                 :                         case -1:
    1371               0 :                                 inc_len = 1;
    1372               0 :                                 php_mblen(NULL, 0);
    1373               0 :                                 break;
    1374                 :                         case 0:
    1375               0 :                                 goto quit_loop;
    1376                 :                         case 1:
    1377                 : #if defined(PHP_WIN32) || defined(NETWARE)
    1378                 :                                 if (*c == '/' || *c == '\\') {
    1379                 : #else
    1380          583641 :                                 if (*c == '/') {
    1381                 : #endif
    1382           67294 :                                         if (state == 1) {
    1383           58013 :                                                 state = 0;
    1384           58013 :                                                 cend = c;
    1385                 :                                         }
    1386                 :                                 } else {
    1387          516347 :                                         if (state == 0) {
    1388           68286 :                                                 comp = c;
    1389           68286 :                                                 state = 1;
    1390                 :                                         }
    1391                 :                                 }
    1392          583641 :                                 break;
    1393                 :                         default:
    1394               0 :                                 if (state == 0) {
    1395               0 :                                         comp = c;
    1396               0 :                                         state = 1;
    1397                 :                                 }
    1398                 :                                 break;
    1399                 :                 }
    1400          583641 :                 c += inc_len;
    1401          583641 :                 cnt -= inc_len;
    1402                 :         }
    1403                 : 
    1404           10509 : quit_loop:
    1405           10509 :         if (state == 1) {
    1406           10273 :                 cend = c;
    1407                 :         }
    1408           10509 :         if (suffix != NULL && sufflen < (uint)(cend - comp) &&
    1409                 :                         memcmp(cend - sufflen, suffix, sufflen) == 0) {
    1410            8959 :                 cend -= sufflen;
    1411                 :         }
    1412                 : 
    1413           10509 :         len = cend - comp;
    1414                 : 
    1415           10509 :         if (p_ret) {
    1416           10509 :                 ret = emalloc(len + 1);
    1417           10509 :                 memcpy(ret, comp, len);
    1418           10509 :                 ret[len] = '\0';
    1419           10509 :                 *p_ret = ret;
    1420                 :         }
    1421           10509 :         if (p_len) {
    1422           10479 :                 *p_len = len;
    1423                 :         }
    1424           10509 : }
    1425                 : /* }}} */
    1426                 : 
    1427                 : /* {{{ proto string basename(string path [, string suffix])
    1428                 :    Returns the filename component of the path */
    1429                 : PHP_FUNCTION(basename)
    1430            9382 : {
    1431            9382 :         char *string, *suffix = NULL, *ret;
    1432            9382 :         int   string_len, suffix_len = 0;
    1433                 :         size_t ret_len;
    1434                 : 
    1435            9382 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &string, &string_len, &suffix, &suffix_len) == FAILURE) {
    1436              30 :                 return;
    1437                 :         }
    1438                 : 
    1439            9352 :         php_basename(string, string_len, suffix, suffix_len, &ret, &ret_len TSRMLS_CC);
    1440            9352 :         RETURN_STRINGL(ret, (int)ret_len, 0);
    1441                 : }
    1442                 : /* }}} */
    1443                 : 
    1444                 : /* {{{ php_dirname
    1445                 :    Returns directory name component of path */
    1446                 : PHPAPI size_t php_dirname(char *path, size_t len)
    1447           14092 : {
    1448           14092 :         register char *end = path + len - 1;
    1449           14092 :         unsigned int len_adjust = 0;
    1450                 : 
    1451                 : #ifdef PHP_WIN32
    1452                 :         /* Note that on Win32 CWD is per drive (heritage from CP/M).
    1453                 :          * This means dirname("c:foo") maps to "c:." or "c:" - which means CWD on C: drive.
    1454                 :          */
    1455                 :         if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
    1456                 :                 /* Skip over the drive spec (if any) so as not to change */
    1457                 :                 path += 2;
    1458                 :                 len_adjust += 2;
    1459                 :                 if (2 == len) {
    1460                 :                         /* Return "c:" on Win32 for dirname("c:").
    1461                 :                          * It would be more consistent to return "c:." 
    1462                 :                          * but that would require making the string *longer*.
    1463                 :                          */
    1464                 :                         return len;
    1465                 :                 }
    1466                 :         }
    1467                 : #elif defined(NETWARE)
    1468                 :         /*
    1469                 :          * Find the first occurence of : from the left 
    1470                 :          * move the path pointer to the position just after :
    1471                 :          * increment the len_adjust to the length of path till colon character(inclusive)
    1472                 :          * If there is no character beyond : simple return len
    1473                 :          */
    1474                 :         char *colonpos = NULL;
    1475                 :         colonpos = strchr(path, ':');
    1476                 :         if(colonpos != NULL) {
    1477                 :                 len_adjust = ((colonpos - path) + 1);
    1478                 :                 path += len_adjust;
    1479                 :                 if(len_adjust == len) {
    1480                 :                 return len;
    1481                 :                 }
    1482                 :         }
    1483                 : #endif
    1484                 : 
    1485           14092 :         if (len == 0) {
    1486                 :                 /* Illegal use of this function */
    1487              36 :                 return 0;
    1488                 :         }
    1489                 : 
    1490                 :         /* Strip trailing slashes */
    1491           28202 :         while (end >= path && IS_SLASH_P(end)) {
    1492              90 :                 end--;
    1493                 :         }
    1494           14056 :         if (end < path) {
    1495                 :                 /* The path only contained slashes */
    1496              11 :                 path[0] = DEFAULT_SLASH;
    1497              11 :                 path[1] = '\0';
    1498              11 :                 return 1 + len_adjust;
    1499                 :         }
    1500                 : 
    1501                 :         /* Strip filename */
    1502          318139 :         while (end >= path && !IS_SLASH_P(end)) {
    1503          290049 :                 end--;
    1504                 :         }
    1505           14045 :         if (end < path) {
    1506                 :                 /* No slash found, therefore return '.' */
    1507                 : #ifdef NETWARE
    1508                 :                 if(len_adjust == 0) {
    1509                 :                         path[0] = '.';
    1510                 :                         path[1] = '\0';
    1511                 :                         return 1; //only one character
    1512                 :                 } 
    1513                 :                 else {
    1514                 :                         path[0] = '\0';
    1515                 :                         return len_adjust;
    1516                 :                 }
    1517                 : #else
    1518             168 :                 path[0] = '.';
    1519             168 :                 path[1] = '\0';
    1520             168 :                 return 1 + len_adjust;
    1521                 : #endif
    1522                 :         }
    1523                 : 
    1524                 :         /* Strip slashes which came before the file name */
    1525           41646 :         while (end >= path && IS_SLASH_P(end)) {
    1526           13892 :                 end--;
    1527                 :         }
    1528           13877 :         if (end < path) {
    1529              23 :                 path[0] = DEFAULT_SLASH;
    1530              23 :                 path[1] = '\0';
    1531              23 :                 return 1 + len_adjust;
    1532                 :         }
    1533           13854 :         *(end+1) = '\0';
    1534                 : 
    1535           13854 :         return (size_t)(end + 1 - path) + len_adjust;
    1536                 : }
    1537                 : /* }}} */
    1538                 : 
    1539                 : /* {{{ proto string dirname(string path)
    1540                 :    Returns the directory name component of the path */
    1541                 : PHP_FUNCTION(dirname)
    1542           13663 : {
    1543                 :         zval **str;
    1544                 :         char *ret;
    1545                 :         size_t ret_len;
    1546                 : 
    1547           13663 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    1548               4 :                 WRONG_PARAM_COUNT;
    1549                 :         }
    1550           13659 :         convert_to_string_ex(str);
    1551                 : 
    1552           13659 :         ret = estrndup(Z_STRVAL_PP(str), Z_STRLEN_PP(str));
    1553           13659 :         ret_len = php_dirname(ret, Z_STRLEN_PP(str));
    1554                 : 
    1555           13659 :         RETURN_STRINGL(ret, ret_len, 0);
    1556                 : }
    1557                 : /* }}} */
    1558                 : 
    1559                 : /* {{{ proto array pathinfo(string path[, int options])
    1560                 :    Returns information about a certain string */
    1561                 : PHP_FUNCTION(pathinfo)
    1562             605 : {
    1563                 :         zval *tmp;
    1564             605 :         char *path, *ret = NULL;
    1565                 :         int path_len, have_basename;
    1566                 :         size_t ret_len;
    1567             605 :         long opt = PHP_PATHINFO_ALL;
    1568                 : 
    1569             605 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &path_len, &opt) == FAILURE) {
    1570              25 :                 return;
    1571                 :         }
    1572                 : 
    1573             580 :         have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
    1574                 :         
    1575             580 :         MAKE_STD_ZVAL(tmp);
    1576             580 :         array_init(tmp);
    1577                 :         
    1578             580 :         if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
    1579             247 :                 ret = estrndup(path, path_len);
    1580             247 :                 php_dirname(ret, path_len);
    1581             247 :                 if (*ret) {
    1582             224 :                         add_assoc_string(tmp, "dirname", ret, 1);
    1583                 :                 }
    1584             247 :                 efree(ret);
    1585             247 :                 ret = NULL;
    1586                 :         }
    1587                 :         
    1588             580 :         if (have_basename) {
    1589             227 :                 php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
    1590             227 :                 add_assoc_stringl(tmp, "basename", ret, ret_len, 0);
    1591                 :         }
    1592                 :         
    1593             580 :         if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
    1594                 :                 char *p;
    1595                 :                 int idx;
    1596                 : 
    1597             228 :                 if (!have_basename) {
    1598             110 :                         php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
    1599                 :                 }
    1600                 : 
    1601             228 :                 p = zend_memrchr(ret, '.', ret_len);
    1602                 : 
    1603             228 :                 if (p) {
    1604             122 :                         idx = p - ret;
    1605             122 :                         add_assoc_stringl(tmp, "extension", ret + idx + 1, ret_len - idx - 1, 1);
    1606                 :                 }
    1607                 :         }
    1608                 :         
    1609             580 :         if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
    1610                 :                 char *p;
    1611                 :                 int idx;
    1612                 : 
    1613                 :                 /* Have we alrady looked up the basename? */
    1614             231 :                 if (!have_basename && !ret) {
    1615             109 :                         php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
    1616                 :                 }
    1617                 : 
    1618             231 :                 p = zend_memrchr(ret, '.', ret_len);
    1619                 : 
    1620             231 :                 idx = p ? (p - ret) : ret_len;
    1621             231 :                 add_assoc_stringl(tmp, "filename", ret, idx, 1);
    1622                 :         }
    1623                 : 
    1624             580 :         if (!have_basename && ret) {
    1625             219 :                 efree(ret);
    1626                 :         }
    1627                 : 
    1628             580 :         if (opt == PHP_PATHINFO_ALL) {
    1629             113 :                 RETURN_ZVAL(tmp, 0, 1);
    1630                 :         } else {
    1631                 :                 zval **element;
    1632             467 :                 if (zend_hash_get_current_data(Z_ARRVAL_P(tmp), (void **) &element) == SUCCESS) {
    1633             392 :                         RETVAL_ZVAL(*element, 1, 0);
    1634                 :                 } else {
    1635              75 :                         ZVAL_EMPTY_STRING(return_value);
    1636                 :                 }
    1637                 :         }
    1638                 : 
    1639             467 :         zval_ptr_dtor(&tmp);
    1640                 : }
    1641                 : /* }}} */
    1642                 : 
    1643                 : /* {{{ php_stristr
    1644                 :    case insensitve strstr */
    1645                 : PHPAPI char *php_stristr(unsigned char *s, unsigned char *t, size_t s_len, size_t t_len)
    1646              86 : {
    1647              86 :         php_strtolower(s, s_len);
    1648              86 :         php_strtolower(t, t_len);
    1649              86 :         return php_memnstr(s, t, t_len, s + s_len);
    1650                 : }
    1651                 : /* }}} */
    1652                 : 
    1653                 : /* {{{ php_strspn
    1654                 :  */
    1655                 : PHPAPI size_t php_strspn(char *s1, char *s2, char *s1_end, char *s2_end)
    1656            3381 : {
    1657            3381 :         register const char *p = s1, *spanp;
    1658            3381 :         register char c = *p;
    1659                 : 
    1660            6573 : cont:
    1661           44080 :         for (spanp = s2; p != s1_end && spanp != s2_end;) {
    1662           34126 :                 if (*spanp++ == c) {
    1663            3192 :                         c = *(++p);
    1664            3192 :                         goto cont;
    1665                 :                 }
    1666                 :         }
    1667            3381 :         return (p - s1);
    1668                 : }
    1669                 : /* }}} */
    1670                 : 
    1671                 : /* {{{ php_strcspn
    1672                 :  */
    1673                 : PHPAPI size_t php_strcspn(char *s1, char *s2, char *s1_end, char *s2_end)
    1674            3233 : {
    1675                 :         register const char *p, *spanp;
    1676            3233 :         register char c = *s1;
    1677                 : 
    1678            3233 :         for (p = s1;;) {
    1679           24665 :                 spanp = s2;
    1680                 :                 do {
    1681           55603 :                         if (*spanp == c || p == s1_end) {
    1682            3233 :                                 return p - s1;
    1683                 :                         }
    1684           52370 :                 } while (spanp++ < (s2_end - 1));
    1685           21432 :                 c = *++p;
    1686           21432 :         }
    1687                 :         /* NOTREACHED */
    1688                 : }
    1689                 : /* }}} */
    1690                 : 
    1691                 : /* {{{ proto string stristr(string haystack, string needle)
    1692                 :    Finds first occurrence of a string within another, case insensitive */
    1693                 : PHP_FUNCTION(stristr)
    1694              96 : {
    1695                 :         zval **haystack, **needle;
    1696              96 :         char *found = NULL;
    1697                 :         int  found_offset;
    1698                 :         char *haystack_orig;
    1699                 :         char needle_char[2];
    1700                 :         
    1701              96 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) == FAILURE) {
    1702               5 :                 WRONG_PARAM_COUNT;
    1703                 :         }
    1704                 : 
    1705              91 :         SEPARATE_ZVAL(haystack);
    1706              91 :         SEPARATE_ZVAL(needle);
    1707                 :         
    1708              91 :         convert_to_string_ex(haystack);
    1709                 : 
    1710              91 :         haystack_orig = estrndup(Z_STRVAL_PP(haystack), Z_STRLEN_PP(haystack));
    1711                 : 
    1712              91 :         if (Z_TYPE_PP(needle) == IS_STRING) {
    1713              69 :                 if (!Z_STRLEN_PP(needle)) {
    1714               5 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
    1715               5 :                         efree(haystack_orig);
    1716               5 :                         RETURN_FALSE;
    1717                 :                 }
    1718                 : 
    1719              64 :                 found = php_stristr(Z_STRVAL_PP(haystack),
    1720                 :                                                         Z_STRVAL_PP(needle),
    1721                 :                                                         Z_STRLEN_PP(haystack),
    1722                 :                                                         Z_STRLEN_PP(needle));
    1723                 :         } else {
    1724              22 :                 convert_to_long_ex(needle);
    1725              22 :                 needle_char[0] = (char) Z_LVAL_PP(needle);
    1726              22 :                 needle_char[1] = 0;
    1727                 : 
    1728              22 :                 found = php_stristr(Z_STRVAL_PP(haystack),
    1729                 :                                                         needle_char,
    1730                 :                                                         Z_STRLEN_PP(haystack),
    1731                 :                                                         1);
    1732                 :         }
    1733                 : 
    1734              86 :         if (found) {
    1735              24 :                 found_offset = found - Z_STRVAL_PP(haystack);
    1736              24 :                 RETVAL_STRINGL(haystack_orig + found_offset, Z_STRLEN_PP(haystack) - found_offset, 1);
    1737                 :         } else {
    1738              62 :                 RETVAL_FALSE;
    1739                 :         }
    1740                 : 
    1741              86 :         efree(haystack_orig);
    1742                 : }
    1743                 : /* }}} */
    1744                 : 
    1745                 : /* {{{ proto string strstr(string haystack, string needle)
    1746                 :    Finds first occurrence of a string within another */
    1747                 : PHP_FUNCTION(strstr)
    1748            7715 : {
    1749                 :         zval **haystack, **needle;
    1750            7715 :         char *found = NULL;
    1751                 :         char needle_char[2];
    1752                 :         long found_offset;
    1753                 :         
    1754            7715 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) == FAILURE) {
    1755               4 :                 WRONG_PARAM_COUNT;
    1756                 :         }
    1757                 : 
    1758            7711 :         convert_to_string_ex(haystack);
    1759                 : 
    1760            7711 :         if (Z_TYPE_PP(needle) == IS_STRING) {
    1761            7696 :                 if (!Z_STRLEN_PP(needle)) {
    1762               5 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
    1763               5 :                         RETURN_FALSE;
    1764                 :                 }
    1765                 : 
    1766            7691 :                 found = php_memnstr(Z_STRVAL_PP(haystack), 
    1767                 :                                     Z_STRVAL_PP(needle),
    1768                 :                                     Z_STRLEN_PP(needle), 
    1769                 :                                     Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
    1770                 :         } else {
    1771              15 :                 convert_to_long_ex(needle);
    1772              15 :                 needle_char[0] = (char) Z_LVAL_PP(needle);
    1773              15 :                 needle_char[1] = 0;
    1774                 : 
    1775              15 :                 found = php_memnstr(Z_STRVAL_PP(haystack), 
    1776                 :                                                         needle_char,
    1777                 :                                                         1,
    1778                 :                                     Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
    1779                 :         }
    1780                 : 
    1781            7706 :         if (found) {
    1782            2850 :                 found_offset = found - Z_STRVAL_PP(haystack);
    1783            2850 :                 RETURN_STRINGL(found, Z_STRLEN_PP(haystack) - found_offset, 1);
    1784                 :         } else {
    1785            4856 :                 RETURN_FALSE;
    1786                 :         }
    1787                 : }
    1788                 : /* }}} */
    1789                 : 
    1790                 : /* {{{ proto string strchr(string haystack, string needle)
    1791                 :    An alias for strstr */
    1792                 : /* }}} */
    1793                 : 
    1794                 : /* {{{ proto int strpos(string haystack, string needle [, int offset])
    1795                 :    Finds position of first occurrence of a string within another */
    1796                 : PHP_FUNCTION(strpos)
    1797          601331 : {
    1798                 :         zval **haystack, **needle, **z_offset;
    1799          601331 :         char *found = NULL;
    1800                 :         char  needle_char[2];
    1801          601331 :         int   offset = 0;
    1802          601331 :         int   argc = ZEND_NUM_ARGS();
    1803                 : 
    1804          601331 :         if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &haystack, &needle, &z_offset) == FAILURE) {
    1805               4 :                 WRONG_PARAM_COUNT;
    1806                 :         }
    1807          601327 :         convert_to_string_ex(haystack);
    1808                 : 
    1809          601327 :         if (argc > 2) {
    1810            5576 :                 convert_to_long_ex(z_offset);
    1811            5576 :                 offset = Z_LVAL_PP(z_offset);
    1812                 :         }
    1813                 : 
    1814          601327 :         if (offset < 0 || offset > Z_STRLEN_PP(haystack)) {
    1815               9 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
    1816               9 :                 RETURN_FALSE;
    1817                 :         }
    1818                 : 
    1819          601318 :         if (Z_TYPE_PP(needle) == IS_STRING) {
    1820          601302 :                 if (!Z_STRLEN_PP(needle)) {
    1821               5 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
    1822               5 :                         RETURN_FALSE;
    1823                 :                 }
    1824                 : 
    1825          601297 :                 found = php_memnstr(Z_STRVAL_PP(haystack) + offset,
    1826                 :                                         Z_STRVAL_PP(needle),
    1827                 :                                         Z_STRLEN_PP(needle),
    1828                 :                                         Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
    1829                 :         } else {
    1830              16 :                 convert_to_long_ex(needle);
    1831              16 :                 needle_char[0] = (char) Z_LVAL_PP(needle);
    1832              16 :                 needle_char[1] = 0;
    1833                 : 
    1834              16 :                 found = php_memnstr(Z_STRVAL_PP(haystack) + offset,
    1835                 :                                                         needle_char,
    1836                 :                                                         1,
    1837                 :                                     Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
    1838                 :         }
    1839                 : 
    1840          601313 :         if (found) {
    1841          304265 :                 RETURN_LONG(found - Z_STRVAL_PP(haystack));
    1842                 :         } else {
    1843          297048 :                 RETURN_FALSE;
    1844                 :         }
    1845                 : }
    1846                 : /* }}} */
    1847                 : 
    1848                 : /* {{{ proto int stripos(string haystack, string needle [, int offset])
    1849                 :    Finds position of first occurrence of a string within another, case insensitive */
    1850                 : PHP_FUNCTION(stripos)
    1851             605 : {
    1852             605 :         char *found = NULL;
    1853                 :         char *haystack;
    1854                 :         int haystack_len;
    1855             605 :         long offset = 0;
    1856             605 :         char *needle_dup = NULL, *haystack_dup;
    1857                 :         char needle_char[2];
    1858                 :         zval *needle;
    1859                 : 
    1860             605 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
    1861              39 :                 return;
    1862                 :         }
    1863                 : 
    1864             566 :         if (offset < 0 || offset > haystack_len) {
    1865              22 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
    1866              22 :                 RETURN_FALSE;
    1867                 :         }
    1868                 : 
    1869             544 :         if (haystack_len == 0) {
    1870              30 :                 RETURN_FALSE;
    1871                 :         }
    1872                 : 
    1873             514 :         haystack_dup = estrndup(haystack, haystack_len);
    1874             514 :         php_strtolower(haystack_dup, haystack_len);
    1875                 : 
    1876             514 :         if (Z_TYPE_P(needle) == IS_STRING) {
    1877             436 :                 if (Z_STRLEN_P(needle) == 0 || Z_STRLEN_P(needle) > haystack_len) {
    1878              20 :                         efree(haystack_dup);
    1879              20 :                         RETURN_FALSE;
    1880                 :                 }
    1881                 : 
    1882             416 :                 needle_dup = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
    1883             416 :                 php_strtolower(needle_dup, Z_STRLEN_P(needle));
    1884             416 :                 found = php_memnstr(haystack_dup + offset, needle_dup, Z_STRLEN_P(needle), haystack_dup + haystack_len);
    1885                 :         } else {
    1886              78 :                 switch (Z_TYPE_P(needle)) {
    1887                 :                         case IS_LONG:
    1888                 :                         case IS_BOOL:
    1889              40 :                                 needle_char[0] = tolower((char) Z_LVAL_P(needle));
    1890              40 :                                 break;
    1891                 :                         case IS_DOUBLE:
    1892              17 :                                 needle_char[0] = tolower((char) Z_DVAL_P(needle));
    1893              17 :                                 break;
    1894                 :                         default:
    1895              21 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "needle is not a string or an integer");
    1896              21 :                                 efree(haystack_dup);
    1897              21 :                                 RETURN_FALSE;
    1898                 :                                 break;
    1899                 :                                         
    1900                 :                 }
    1901              57 :                 needle_char[1] = '\0';
    1902              57 :                 found = php_memnstr(haystack_dup + offset, 
    1903                 :                                                         needle_char, 
    1904                 :                                                         sizeof(needle_char) - 1, 
    1905                 :                                                         haystack_dup + haystack_len);
    1906                 :         }
    1907                 : 
    1908             473 :         efree(haystack_dup);
    1909             473 :         if (needle_dup) {
    1910             416 :                 efree(needle_dup);
    1911                 :         }
    1912                 : 
    1913             473 :         if (found) {
    1914             317 :                 RETURN_LONG(found - haystack_dup);
    1915                 :         } else {
    1916             156 :                 RETURN_FALSE;
    1917                 :         }
    1918                 : }
    1919                 : /* }}} */
    1920                 : 
    1921                 : /* {{{ proto int strrpos(string haystack, string needle [, int offset])
    1922                 :    Finds position of last occurrence of a string within another string */
    1923                 : PHP_FUNCTION(strrpos)
    1924             452 : {
    1925                 :         zval **zneedle;
    1926                 :         char *needle, *haystack;
    1927                 :         int needle_len, haystack_len;
    1928             452 :         long offset = 0;
    1929                 :         char *p, *e, ord_needle[2];
    1930                 : 
    1931             452 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
    1932              39 :                 RETURN_FALSE;
    1933                 :         }
    1934                 : 
    1935             413 :         if (Z_TYPE_PP(zneedle) == IS_STRING) {
    1936             316 :                 needle = Z_STRVAL_PP(zneedle);
    1937             316 :                 needle_len = Z_STRLEN_PP(zneedle);
    1938                 :         } else {
    1939              97 :                 convert_to_long_ex(zneedle);
    1940              97 :                 ord_needle[0] = (char)(Z_LVAL_PP(zneedle) & 0xFF);
    1941              97 :                 ord_needle[1] = '\0';
    1942              97 :                 needle = ord_needle;
    1943              97 :                 needle_len = 1;
    1944                 :         }
    1945                 : 
    1946             413 :         if ((haystack_len == 0) || (needle_len == 0)) {
    1947              44 :                 RETURN_FALSE;
    1948                 :         }
    1949                 : 
    1950             369 :         if (offset >= 0) {
    1951             357 :                 if (offset > haystack_len) {
    1952               6 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
    1953               6 :                         RETURN_FALSE;
    1954                 :                 }
    1955             351 :                 p = haystack + offset;
    1956             351 :                 e = haystack + haystack_len - needle_len;
    1957                 :         } else {
    1958              12 :                 if (-offset > haystack_len) {
    1959               4 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
    1960               4 :                         RETURN_FALSE;
    1961                 :                 }
    1962                 : 
    1963               8 :                 p = haystack;
    1964               8 :                 if (needle_len > -offset) {
    1965               3 :                         e = haystack + haystack_len - needle_len;
    1966                 :                 } else {
    1967               5 :                         e = haystack + haystack_len + offset;
    1968                 :                 }
    1969                 :         }
    1970                 : 
    1971             359 :         if (needle_len == 1) {
    1972                 :                 /* Single character search can shortcut memcmps */
    1973            4881 :                 while (e >= p) {
    1974            4592 :                         if (*e == *needle) {
    1975             107 :                                 RETURN_LONG(e - p + (offset > 0 ? offset : 0));
    1976                 :                         }
    1977            4485 :                         e--;
    1978                 :                 }
    1979              91 :                 RETURN_FALSE;
    1980                 :         }
    1981                 : 
    1982            2864 :         while (e >= p) {
    1983            2628 :                 if (memcmp(e, needle, needle_len) == 0) {
    1984              86 :                         RETURN_LONG(e - p + (offset > 0 ? offset : 0));
    1985                 :                 }
    1986            2542 :                 e--;
    1987                 :         }
    1988                 : 
    1989              75 :         RETURN_FALSE;
    1990                 : }
    1991                 : /* }}} */
    1992                 : 
    1993                 : /* {{{ proto int strripos(string haystack, string needle [, int offset])
    1994                 :    Finds position of last occurrence of a string within another string */
    1995                 : PHP_FUNCTION(strripos)
    1996             365 : {
    1997                 :         zval **zneedle;
    1998                 :         char *needle, *haystack;
    1999                 :         int needle_len, haystack_len;
    2000             365 :         long offset = 0;
    2001                 :         char *p, *e, ord_needle[2];
    2002                 :         char *needle_dup, *haystack_dup;
    2003                 : 
    2004             365 :         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
    2005               4 :                 RETURN_FALSE;
    2006                 :         }
    2007                 : 
    2008             361 :         if (Z_TYPE_PP(zneedle) == IS_STRING) {
    2009             321 :                 needle = Z_STRVAL_PP(zneedle);
    2010             321 :                 needle_len = Z_STRLEN_PP(zneedle);
    2011                 :         } else {
    2012              40 :                 convert_to_long_ex(zneedle);
    2013              40 :                 ord_needle[0] = (char)(Z_LVAL_PP(zneedle) & 0xFF);
    2014              40 :                 ord_needle[1] = '\0';
    2015              40 :                 needle = ord_needle;
    2016              40 :                 needle_len = 1;
    2017                 :         }
    2018                 : 
    2019             361 :         if ((haystack_len == 0) || (needle_len == 0)) {
    2020              12 :                 RETURN_FALSE;
    2021                 :         }
    2022                 : 
    2023             349 :         if (needle_len == 1) {
    2024                 :                 /* Single character search can shortcut memcmps 
    2025                 :                    Can also avoid tolower emallocs */
    2026             162 :                 if (offset >= 0) {
    2027             119 :                         if (offset > haystack_len) {
    2028               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
    2029               0 :                                 RETURN_FALSE;
    2030                 :                         }
    2031             119 :                         p = haystack + offset;
    2032             119 :                         e = haystack + haystack_len - 1;
    2033                 :                 } else {
    2034              43 :                         p = haystack;
    2035              43 :                         if (-offset > haystack_len || offset < -INT_MAX) {
    2036               5 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
    2037               5 :                                 RETURN_FALSE;
    2038                 :                         }
    2039              38 :                         e = haystack + haystack_len + offset;
    2040                 :                 }
    2041                 :                 /* Borrow that ord_needle buffer to avoid repeatedly tolower()ing needle */
    2042             157 :                 *ord_needle = tolower(*needle);
    2043            4076 :                 while (e >= p) {
    2044            3883 :                         if (tolower(*e) == *ord_needle) {
    2045             121 :                                 RETURN_LONG(e - p + (offset > 0 ? offset : 0));
    2046                 :                         }
    2047            3762 :                         e--;
    2048                 :                 }
    2049              36 :                 RETURN_FALSE;
    2050                 :         }
    2051                 : 
    2052             187 :         needle_dup = estrndup(needle, needle_len);
    2053             187 :         php_strtolower(needle_dup, needle_len);
    2054             187 :         haystack_dup = estrndup(haystack, haystack_len);
    2055             187 :         php_strtolower(haystack_dup, haystack_len);
    2056                 : 
    2057             187 :         if (offset >= 0) {
    2058             143 :                 if (offset > haystack_len) {
    2059               2 :                         efree(needle_dup);
    2060               2 :                         efree(haystack_dup);
    2061               2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
    2062               2 :                         RETURN_FALSE;
    2063                 :                 }
    2064             141 :                 p = haystack_dup + offset;
    2065             141 :                 e = haystack_dup + haystack_len - needle_len;
    2066                 :         } else {
    2067              44 :                 if (-offset > haystack_len || offset < -INT_MAX) {
    2068               3 :                         efree(needle_dup);
    2069               3 :                         efree(haystack_dup);
    2070               3 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
    2071               3 :                         RETURN_FALSE;
    2072                 :                 }
    2073              41 :                 p = haystack_dup;
    2074              41 :                 if (needle_len > -offset) {
    2075              36 :                         e = haystack_dup + haystack_len - needle_len;
    2076                 :                 } else {
    2077               5 :                         e = haystack_dup + haystack_len + offset;
    2078                 :                 }
    2079                 :         }
    2080                 : 
    2081            4357 :         while (e >= p) {
    2082            4125 :                 if (memcmp(e, needle_dup, needle_len) == 0) {
    2083             132 :                         efree(haystack_dup);
    2084             132 :                         efree(needle_dup);
    2085             132 :                         RETURN_LONG(e - p + (offset > 0 ? offset : 0));
    2086                 :                 }
    2087            3993 :                 e--;
    2088                 :         }
    2089                 : 
    2090              50 :         efree(haystack_dup);
    2091              50 :         efree(needle_dup);
    2092              50 :         RETURN_FALSE;
    2093                 : }
    2094                 : /* }}} */
    2095                 : 
    2096                 : /* {{{ proto string strrchr(string haystack, string needle)
    2097                 :    Finds the last occurrence of a character in a string within another */
    2098                 : PHP_FUNCTION(strrchr)
    2099             244 : {
    2100                 :         zval **haystack, **needle;
    2101             244 :         char *found = NULL;
    2102                 :         long found_offset;
    2103                 :         
    2104             244 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) ==
    2105                 :                 FAILURE) {
    2106               3 :                 WRONG_PARAM_COUNT;
    2107                 :         }
    2108             241 :         convert_to_string_ex(haystack);
    2109                 : 
    2110             241 :         if (Z_TYPE_PP(needle) == IS_STRING) {
    2111             173 :                 found = zend_memrchr(Z_STRVAL_PP(haystack), *Z_STRVAL_PP(needle), Z_STRLEN_PP(haystack));
    2112                 :         } else {
    2113              68 :                 convert_to_long_ex(needle);
    2114              68 :                 found = zend_memrchr(Z_STRVAL_PP(haystack), (char) Z_LVAL_PP(needle), Z_STRLEN_PP(haystack));
    2115                 :         }
    2116                 : 
    2117             241 :         if (found) {
    2118             148 :                 found_offset = found - Z_STRVAL_PP(haystack);
    2119             148 :                 RETURN_STRINGL(found, Z_STRLEN_PP(haystack) - found_offset, 1);
    2120                 :         } else {
    2121              93 :                 RETURN_FALSE;
    2122                 :         }
    2123                 : }
    2124                 : /* }}} */
    2125                 : 
    2126                 : /* {{{ php_chunk_split
    2127                 :  */
    2128                 : static char *php_chunk_split(char *src, int srclen, char *end, int endlen, int chunklen, int *destlen)
    2129             146 : {
    2130                 :         char *dest;
    2131                 :         char *p, *q;
    2132                 :         int chunks; /* complete chunks! */
    2133                 :         int restlen;
    2134                 :         int out_len; 
    2135                 : 
    2136             146 :         chunks = srclen / chunklen;
    2137             146 :         restlen = srclen - chunks * chunklen; /* srclen % chunklen */
    2138                 : 
    2139             146 :         if(chunks > INT_MAX - 1) {
    2140               0 :                 return NULL;
    2141                 :         }
    2142             146 :         out_len = chunks + 1;
    2143             146 :         if(endlen !=0 && out_len > INT_MAX/endlen) {
    2144               2 :                 return NULL;
    2145                 :         }
    2146             144 :         out_len *= endlen;
    2147             144 :         if(out_len > INT_MAX - srclen - 1) {
    2148               0 :                 return NULL;
    2149                 :         }
    2150             144 :         out_len += srclen + 1;
    2151                 : 
    2152             144 :         dest = safe_emalloc((int)out_len, sizeof(char), 0);
    2153                 : 
    2154            1499 :         for (p = src, q = dest; p < (src + srclen - chunklen + 1); ) {
    2155            1211 :                 memcpy(q, p, chunklen);
    2156            1211 :                 q += chunklen;
    2157            1211 :                 memcpy(q, end, endlen);
    2158            1211 :                 q += endlen;
    2159            1211 :                 p += chunklen;
    2160                 :         }
    2161                 : 
    2162             144 :         if (restlen) {
    2163             125 :                 memcpy(q, p, restlen);
    2164             125 :                 q += restlen;
    2165             125 :                 memcpy(q, end, endlen);
    2166             125 :                 q += endlen;
    2167                 :         }
    2168                 : 
    2169             144 :         *q = '\0';
    2170             144 :         if (destlen) {
    2171             144 :                 *destlen = q - dest;
    2172                 :         }
    2173                 : 
    2174             144 :         return(dest);
    2175                 : }
    2176                 : /* }}} */
    2177                 : 
    2178                 : /* {{{ proto string chunk_split(string str [, int chunklen [, string ending]])
    2179                 :    Returns split line */
    2180                 : PHP_FUNCTION(chunk_split) 
    2181             185 : {
    2182                 :         zval **p_str, **p_chunklen, **p_ending;
    2183                 :         char *result;
    2184             185 :         char *end    = "\r\n";
    2185             185 :         int endlen   = 2;
    2186             185 :         long chunklen = 76;
    2187                 :         int result_len;
    2188             185 :         int argc = ZEND_NUM_ARGS();
    2189                 : 
    2190             185 :         if (argc < 1 || argc > 3 ||       zend_get_parameters_ex(argc, &p_str, &p_chunklen, &p_ending) == FAILURE) {
    2191               2 :                 WRONG_PARAM_COUNT;
    2192                 :         }
    2193                 : 
    2194             183 :         convert_to_string_ex(p_str);
    2195                 : 
    2196             183 :         if (argc > 1) {
    2197             179 :                 convert_to_long_ex(p_chunklen);
    2198             179 :                 chunklen = Z_LVAL_PP(p_chunklen);
    2199                 :         }
    2200                 : 
    2201             183 :         if (argc > 2) {
    2202             169 :                 convert_to_string_ex(p_ending);
    2203             169 :                 end = Z_STRVAL_PP(p_ending);
    2204             169 :                 endlen = Z_STRLEN_PP(p_ending);
    2205                 :         }
    2206                 : 
    2207             183 :         if (chunklen <= 0) {
    2208              15 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Chunk length should be greater than zero");
    2209              15 :                 RETURN_FALSE;
    2210                 :         }
    2211                 : 
    2212             168 :         if (chunklen > Z_STRLEN_PP(p_str)) {
    2213                 :                 /* to maintain BC, we must return original string + ending */
    2214              22 :                 result_len = endlen + Z_STRLEN_PP(p_str);
    2215              22 :                 result = emalloc(result_len + 1);
    2216              22 :                 memcpy(result, Z_STRVAL_PP(p_str), Z_STRLEN_PP(p_str));
    2217              22 :                 memcpy(result + Z_STRLEN_PP(p_str), end, endlen);
    2218              22 :                 result[result_len] = '\0'; 
    2219              22 :                 RETURN_STRINGL(result, result_len, 0);  
    2220                 :         }
    2221                 : 
    2222             146 :         if (!Z_STRLEN_PP(p_str)) {
    2223               0 :                 RETURN_EMPTY_STRING();
    2224                 :         }
    2225                 : 
    2226             146 :         result = php_chunk_split(Z_STRVAL_PP(p_str), Z_STRLEN_PP(p_str), end, endlen, chunklen, &result_len);
    2227                 : 
    2228             146 :         if (result) {
    2229             144 :                 RETURN_STRINGL(result, result_len, 0);
    2230                 :         } else {
    2231               2 :                 RETURN_FALSE;
    2232                 :         }
    2233                 : }
    2234                 : /* }}} */
    2235                 : 
    2236                 : /* {{{ proto string substr(string str, int start [, int length])
    2237                 :    Returns part of a string */
    2238                 : PHP_FUNCTION(substr)
    2239          113189 : {
    2240                 :         zval **str, **from, **len;
    2241                 :         int l;
    2242                 :         int f;
    2243          113189 :         int argc = ZEND_NUM_ARGS();
    2244                 : 
    2245          113189 :         if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &str, &from, &len) == FAILURE) {
    2246               5 :                 WRONG_PARAM_COUNT;
    2247                 :         }
    2248                 : 
    2249          113184 :         convert_to_string_ex(str);
    2250          113184 :         convert_to_long_ex(from);
    2251                 : 
    2252          113184 :         if (argc > 2) {
    2253           22902 :                 convert_to_long_ex(len);
    2254           22902 :                 l = Z_LVAL_PP(len);
    2255           22902 :                 if ((l < 0 && -l > Z_STRLEN_PP(str))) {
    2256              10 :                         RETURN_FALSE;
    2257           22892 :                 } else if (l > Z_STRLEN_PP(str)) {
    2258             215 :                         l = Z_STRLEN_PP(str);
    2259                 :                 }
    2260                 :         } else {
    2261           90282 :                 l = Z_STRLEN_PP(str);
    2262                 :         }
    2263                 :         
    2264          113174 :         f = Z_LVAL_PP(from);
    2265          113174 :         if (f > Z_STRLEN_PP(str)) {
    2266            5520 :                 RETURN_FALSE;
    2267          107654 :         } else if (f < 0 && -f > Z_STRLEN_PP(str)) {
    2268           10250 :                 f = 0;
    2269                 :         }
    2270                 : 
    2271          107654 :         if (l < 0 && (l + Z_STRLEN_PP(str) - f) < 0) {
    2272               1 :                 RETURN_FALSE;
    2273                 :         }
    2274                 : 
    2275                 :         /* if "from" position is negative, count start position from the end
    2276                 :          * of the string
    2277                 :          */
    2278          107653 :         if (f < 0) {
    2279           80184 :                 f = Z_STRLEN_PP(str) + f;
    2280           80184 :                 if (f < 0) {
    2281               0 :                         f = 0;
    2282                 :                 }
    2283                 :         }
    2284                 : 
    2285                 :         /* if "length" position is negative, set it to the length
    2286                 :          * needed to stop that many chars from the end of the string
    2287                 :          */
    2288          107653 :         if (l < 0) {
    2289              47 :                 l = (Z_STRLEN_PP(str) - f) + l;
    2290              47 :                 if (l < 0) {
    2291               5 :                         l = 0;
    2292                 :                 }
    2293                 :         }
    2294                 : 
    2295          107653 :         if (f >= Z_STRLEN_PP(str)) {
    2296              24 :                 RETURN_FALSE;
    2297                 :         }
    2298                 : 
    2299          107629 :         if ((f + l) > Z_STRLEN_PP(str)) {
    2300           79295 :                 l = Z_STRLEN_PP(str) - f;
    2301                 :         }
    2302                 : 
    2303          107629 :         RETURN_STRINGL(Z_STRVAL_PP(str) + f, l, 1);
    2304                 : }
    2305                 : /* }}} */
    2306                 : 
    2307                 : /* {{{ proto mixed substr_replace(mixed str, mixed repl, mixed start [, mixed length])
    2308                 :    Replaces part of a string with another string */
    2309                 : PHP_FUNCTION(substr_replace)
    2310              54 : {
    2311                 :         zval **str;
    2312                 :         zval **from;
    2313              54 :         zval **len = NULL;
    2314                 :         zval **repl;
    2315                 :         char *result;
    2316                 :         int result_len;
    2317              54 :         int l = 0;
    2318                 :         int f;
    2319              54 :         int argc = ZEND_NUM_ARGS();
    2320                 : 
    2321                 :         HashPosition pos_str, pos_from, pos_repl, pos_len;
    2322              54 :         zval **tmp_str = NULL, **tmp_from = NULL, **tmp_repl = NULL, **tmp_len= NULL;
    2323                 : 
    2324                 : 
    2325              54 :         if (argc < 3 || argc > 4 || zend_get_parameters_ex(argc, &str, &repl, &from, &len) == FAILURE) {
    2326               3 :                 WRONG_PARAM_COUNT;
    2327                 :         }
    2328                 :         
    2329              51 :         if (Z_TYPE_PP(str) != IS_ARRAY) {
    2330              11 :                 convert_to_string_ex(str);
    2331                 :         }
    2332              51 :         if (Z_TYPE_PP(repl) != IS_ARRAY) {
    2333              30 :                 convert_to_string_ex(repl);
    2334                 :         }
    2335              51 :         if (Z_TYPE_PP(from) != IS_ARRAY) {
    2336              16 :                 convert_to_long_ex(from);
    2337                 :         }
    2338                 : 
    2339              51 :         if (argc > 3) {
    2340              42 :                 SEPARATE_ZVAL(len);
    2341              42 :                 if (Z_TYPE_PP(len) != IS_ARRAY) {
    2342              23 :                         convert_to_long_ex(len);
    2343              23 :                         l = Z_LVAL_PP(len);
    2344                 :                 }
    2345                 :         } else {
    2346               9 :                 if (Z_TYPE_PP(str) != IS_ARRAY) {
    2347               3 :                         l = Z_STRLEN_PP(str);
    2348                 :                 }
    2349                 :         }
    2350                 : 
    2351              51 :         if (Z_TYPE_PP(str) == IS_STRING) {
    2352              11 :                 if (
    2353                 :                         (argc == 3 && Z_TYPE_PP(from) == IS_ARRAY) || 
    2354                 :                         (argc == 4 && Z_TYPE_PP(from) != Z_TYPE_PP(len))
    2355                 :                 ) {
    2356               2 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should be of same type - numerical or array ");
    2357               2 :                         RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);          
    2358                 :                 }
    2359               9 :                 if (argc == 4 && Z_TYPE_PP(from) == IS_ARRAY) {
    2360               2 :                         if (zend_hash_num_elements(Z_ARRVAL_PP(from)) != zend_hash_num_elements(Z_ARRVAL_PP(len))) {
    2361               1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should have the same number of elements");
    2362               1 :                                 RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);          
    2363                 :                         }
    2364                 :                 }
    2365                 :         }
    2366                 :         
    2367              48 :         if (Z_TYPE_PP(str) != IS_ARRAY) {
    2368               8 :                 if (Z_TYPE_PP(from) != IS_ARRAY) {
    2369               7 :                         int repl_len = 0;
    2370                 : 
    2371               7 :                         f = Z_LVAL_PP(from);
    2372                 : 
    2373                 :                         /* if "from" position is negative, count start position from the end
    2374                 :                          * of the string
    2375                 :                          */
    2376               7 :                         if (f < 0) {
    2377               0 :                                 f = Z_STRLEN_PP(str) + f;
    2378               0 :                                 if (f < 0) {
    2379               0 :                                         f = 0;
    2380                 :                                 }
    2381               7 :                         } else if (f > Z_STRLEN_PP(str)) {
    2382               1 :                                 f = Z_STRLEN_PP(str);
    2383                 :                         }
    2384                 :                         /* if "length" position is negative, set it to the length
    2385                 :                          * needed to stop that many chars from the end of the string
    2386                 :                          */
    2387               7 :                         if (l < 0) {
    2388               1 :                                 l = (Z_STRLEN_PP(str) - f) + l;
    2389               1 :                                 if (l < 0) {
    2390               0 :                                         l = 0;
    2391                 :                                 }
    2392                 :                         }
    2393                 : 
    2394               7 :                         if (f > Z_STRLEN_PP(str) || (f < 0 && -f > Z_STRLEN_PP(str))) {
    2395               0 :                                 RETURN_FALSE;
    2396               7 :                         } else if (l > Z_STRLEN_PP(str) || (l < 0 && -l > Z_STRLEN_PP(str))) {
    2397               1 :                                 l = Z_STRLEN_PP(str);
    2398                 :                         }
    2399                 : 
    2400               7 :                         if ((f + l) > Z_STRLEN_PP(str)) {
    2401               3 :                                 l = Z_STRLEN_PP(str) - f;
    2402                 :                         }
    2403               7 :                         if (Z_TYPE_PP(repl) == IS_ARRAY) {
    2404               2 :                                 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl);
    2405               2 :                                 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
    2406               2 :                                         convert_to_string_ex(tmp_repl);
    2407               2 :                                         repl_len = Z_STRLEN_PP(tmp_repl);
    2408                 :                                 }
    2409                 :                         } else {
    2410               5 :                                 repl_len = Z_STRLEN_PP(repl);
    2411                 :                         }
    2412               7 :                         result_len = Z_STRLEN_PP(str) - l + repl_len;
    2413               7 :                         result = emalloc(result_len + 1);
    2414                 : 
    2415               7 :                         memcpy(result, Z_STRVAL_PP(str), f);
    2416               7 :                         if (repl_len) {
    2417               7 :                                 memcpy((result + f), (Z_TYPE_PP(repl) == IS_ARRAY ? Z_STRVAL_PP(tmp_repl) : Z_STRVAL_PP(repl)), repl_len);
    2418                 :                         }
    2419               7 :                         memcpy((result + f + repl_len), Z_STRVAL_PP(str) + f + l, Z_STRLEN_PP(str) - f - l);
    2420               7 :                         result[result_len] = '\0';
    2421               7 :                         RETURN_STRINGL(result, result_len, 0);
    2422                 :                 } else {
    2423               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Functionality of 'from' and 'len' as arrays is not implemented");
    2424               1 :                         RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);  
    2425                 :                 }
    2426                 :         } else { /* str is array of strings */
    2427              40 :                 array_init(return_value);
    2428                 : 
    2429              40 :                 if (Z_TYPE_PP(from) == IS_ARRAY) {
    2430              32 :                         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(from), &pos_from);
    2431                 :                 }
    2432                 : 
    2433              40 :                 if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
    2434              16 :                         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(len), &pos_len);
    2435                 :                 }
    2436                 : 
    2437              40 :                 if (Z_TYPE_PP(repl) == IS_ARRAY) {
    2438              19 :                         zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl);
    2439                 :                 }
    2440                 : 
    2441              40 :                 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(str), &pos_str);
    2442             151 :                 while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) {
    2443              71 :                         convert_to_string_ex(tmp_str);
    2444                 : 
    2445              71 :                         if (Z_TYPE_PP(from) == IS_ARRAY) {
    2446              56 :                                 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) {
    2447              50 :                                         convert_to_long_ex(tmp_from);
    2448                 : 
    2449              50 :                                         f = Z_LVAL_PP(tmp_from);
    2450              50 :                                         if (f < 0) {
    2451               0 :                                                 f = Z_STRLEN_PP(tmp_str) + f;
    2452               0 :                                                 if (f < 0) {
    2453               0 :                                                         f = 0;
    2454                 :                                                 }
    2455              50 :                                         } else if (f > Z_STRLEN_PP(tmp_str)) {
    2456               0 :                                                 f = Z_STRLEN_PP(tmp_str);
    2457                 :                                         }
    2458              50 :                                         zend_hash_move_forward_ex(Z_ARRVAL_PP(from), &pos_from);
    2459                 :                                 } else {
    2460               6 :                                         f = 0;
    2461                 :                                 }
    2462                 :                         } else {
    2463              15 :                                 f = Z_LVAL_PP(from);
    2464              15 :                                 if (f < 0) {
    2465               0 :                                         f = Z_STRLEN_PP(tmp_str) + f;
    2466               0 :                                         if (f < 0) {
    2467               0 :                                                 f = 0;
    2468                 :                                         }
    2469              15 :                                 } else if (f > Z_STRLEN_PP(tmp_str)) {
    2470               0 :                                         f = Z_STRLEN_PP(tmp_str);
    2471                 :                                 }
    2472                 :                         }
    2473                 : 
    2474             100 :                         if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
    2475              29 :                                 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(len), (void **) &tmp_len, &pos_len)) {
    2476              23 :                                         convert_to_long_ex(tmp_len);
    2477                 : 
    2478              23 :                                         l = Z_LVAL_PP(tmp_len);
    2479              23 :                                         zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len);
    2480                 :                                 } else {
    2481               6 :                                         l = Z_STRLEN_PP(tmp_str);
    2482                 :                                 }
    2483              42 :                         } else if (argc > 3) { 
    2484              36 :                                 l = Z_LVAL_PP(len);
    2485                 :                         } else {
    2486               6 :                                 l = Z_STRLEN_PP(tmp_str);
    2487                 :                         }
    2488                 : 
    2489              71 :                         if (l < 0) {
    2490              19 :                                 l = (Z_STRLEN_PP(tmp_str) - f) + l;
    2491              19 :                                 if (l < 0) {
    2492               0 :                                         l = 0;
    2493                 :                                 }
    2494                 :                         }
    2495                 : 
    2496              71 :                         if ((f + l) > Z_STRLEN_PP(tmp_str)) {
    2497              14 :                                 l = Z_STRLEN_PP(tmp_str) - f;
    2498                 :                         }
    2499                 : 
    2500              71 :                         result_len = Z_STRLEN_PP(tmp_str) - l;
    2501                 : 
    2502              71 :                         if (Z_TYPE_PP(repl) == IS_ARRAY) {
    2503              34 :                                 if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
    2504              19 :                                         convert_to_string_ex(tmp_repl);
    2505              19 :                                         result_len += Z_STRLEN_PP(tmp_repl);
    2506              19 :                                         zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);    
    2507              19 :                                         result = emalloc(result_len + 1);
    2508                 : 
    2509              19 :                                         memcpy(result, Z_STRVAL_PP(tmp_str), f);
    2510              19 :                                         memcpy((result + f), Z_STRVAL_PP(tmp_repl), Z_STRLEN_PP(tmp_repl));
    2511              19 :                                         memcpy((result + f + Z_STRLEN_PP(tmp_repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
    2512                 :                                 } else {
    2513              15 :                                         result = emalloc(result_len + 1);
    2514                 :         
    2515              15 :                                         memcpy(result, Z_STRVAL_PP(tmp_str), f);
    2516              15 :                                         memcpy((result + f), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
    2517                 :                                 }
    2518                 :                         } else {
    2519              37 :                                 result_len += Z_STRLEN_PP(repl);
    2520                 : 
    2521              37 :                                 result = emalloc(result_len + 1);
    2522                 : 
    2523              37 :                                 memcpy(result, Z_STRVAL_PP(tmp_str), f);
    2524              37 :                                 memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl));
    2525              37 :                                 memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
    2526                 :                         }
    2527                 : 
    2528              71 :                         result[result_len] = '\0';
    2529              71 :                         add_next_index_stringl(return_value, result, result_len, 0);
    2530                 : 
    2531              71 :                         zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str);
    2532                 :                 } /*while*/
    2533                 :         } /* if */
    2534                 : }
    2535                 : /* }}} */
    2536                 : 
    2537                 : /* {{{ proto string quotemeta(string str)
    2538                 :    Quotes meta characters */
    2539                 : PHP_FUNCTION(quotemeta)
    2540               6 : {
    2541                 :         zval **arg;
    2542                 :         char *str, *old;
    2543                 :         char *old_end;
    2544                 :         char *p, *q;
    2545                 :         char c;
    2546                 :         
    2547               6 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
    2548               2 :                 WRONG_PARAM_COUNT;
    2549                 :         }
    2550                 : 
    2551               4 :         convert_to_string_ex(arg);
    2552                 : 
    2553               4 :         old = Z_STRVAL_PP(arg);
    2554               4 :         old_end = Z_STRVAL_PP(arg) + Z_STRLEN_PP(arg);
    2555                 : 
    2556               4 :         if (old == old_end) {
    2557               0 :                 RETURN_FALSE;
    2558                 :         }
    2559                 :         
    2560               4 :         str = safe_emalloc(2, Z_STRLEN_PP(arg), 1);
    2561                 :         
    2562              60 :         for (p = old, q = str; p != old_end; p++) {
    2563              56 :                 c = *p;
    2564              56 :                 switch (c) {
    2565                 :                         case '.':
    2566                 :                         case '\\':
    2567                 :                         case '+':
    2568                 :                         case '*':
    2569                 :                         case '?':
    2570                 :                         case '[':
    2571                 :                         case '^':
    2572                 :                         case ']':
    2573                 :                         case '$':
    2574                 :                         case '(':
    2575                 :                         case ')':
    2576              24 :                                 *q++ = '\\';
    2577                 :                                 /* break is missing _intentionally_ */
    2578                 :                         default:
    2579              56 :                                 *q++ = c;
    2580                 :                 }
    2581                 :         }
    2582               4 :         *q = 0;
    2583                 : 
    2584               4 :         RETURN_STRINGL(erealloc(str, q - str + 1), q - str, 0);
    2585                 : }
    2586                 : /* }}} */
    2587                 : 
    2588                 : /* {{{ proto int ord(string character)
    2589                 :    Returns ASCII value of character */
    2590                 : PHP_FUNCTION(ord)
    2591            2182 : {
    2592                 :         zval **str;
    2593                 :         
    2594            2182 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    2595               4 :                 WRONG_PARAM_COUNT;
    2596                 :         }
    2597            2178 :         convert_to_string_ex(str);
    2598                 : 
    2599            2178 :         RETURN_LONG((unsigned char) Z_STRVAL_PP(str)[0]);
    2600                 : }
    2601                 : /* }}} */
    2602                 : 
    2603                 : /* {{{ proto string chr(int ascii)
    2604                 :    Converts ASCII code to a character */
    2605                 : PHP_FUNCTION(chr)
    2606          108270 : {
    2607                 :         zval **num;
    2608                 :         char temp[2];
    2609                 :         
    2610          108270 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
    2611               4 :                 WRONG_PARAM_COUNT;
    2612                 :         }
    2613          108266 :         convert_to_long_ex(num);
    2614                 :         
    2615          108266 :         temp[0] = (char) Z_LVAL_PP(num);
    2616          108266 :         temp[1] = 0;
    2617                 : 
    2618          108266 :         RETVAL_STRINGL(temp, 1, 1);
    2619                 : }
    2620                 : /* }}} */
    2621                 : 
    2622                 : /* {{{ proto string ucfirst(string str)
    2623                 :    Makes a string's first character uppercase */
    2624                 : PHP_FUNCTION(ucfirst)
    2625              63 : {
    2626                 :         zval **str;
    2627                 :         
    2628              63 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    2629               3 :                 WRONG_PARAM_COUNT;
    2630                 :         }
    2631              60 :         convert_to_string_ex(str);
    2632                 : 
    2633              60 :         if (!Z_STRLEN_PP(str)) {
    2634               4 :                 RETURN_EMPTY_STRING();
    2635                 :         }
    2636                 : 
    2637              56 :         ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
    2638              56 :         *Z_STRVAL_P(return_value) = toupper((unsigned char) *Z_STRVAL_P(return_value));
    2639                 : }
    2640                 : /* }}} */
    2641                 : 
    2642                 : /* {{{ proto string ucwords(string str)
    2643                 :    Uppercase the first character of every word in a string */
    2644                 : PHP_FUNCTION(ucwords)
    2645             111 : {
    2646                 :         zval **str;
    2647                 :         register char *r, *r_end;
    2648                 :         
    2649             111 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    2650               2 :                 WRONG_PARAM_COUNT;
    2651                 :         }
    2652             109 :         convert_to_string_ex(str);
    2653                 : 
    2654             109 :         if (!Z_STRLEN_PP(str)) {
    2655              10 :                 RETURN_EMPTY_STRING();
    2656                 :         }
    2657                 : 
    2658              99 :         ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
    2659              99 :         r = Z_STRVAL_P(return_value);
    2660                 : 
    2661              99 :         *r = toupper((unsigned char) *r);
    2662            1987 :         for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) {
    2663            1789 :                 if (isspace((int) *(unsigned char *)r++)) {
    2664             203 :                         *r = toupper((unsigned char) *r);
    2665                 :                 }
    2666                 :         }
    2667                 : }
    2668                 : /* }}} */
    2669                 : 
    2670                 : /* {{{ php_strtr
    2671                 :  */
    2672                 : PHPAPI char *php_strtr(char *str, int len, char *str_from, char *str_to, int trlen)
    2673             153 : {
    2674                 :         int i;
    2675                 :         unsigned char xlat[256];
    2676                 : 
    2677             153 :         if ((trlen < 1) || (len < 1)) {
    2678              12 :                 return str;
    2679                 :         }
    2680                 : 
    2681             141 :         for (i = 0; i < 256; xlat[i] = i, i++);
    2682                 : 
    2683            3064 :         for (i = 0; i < trlen; i++) {
    2684            2923 :                 xlat[(unsigned char) str_from[i]] = str_to[i];
    2685                 :         }
    2686                 : 
    2687           83434 :         for (i = 0; i < len; i++) {
    2688           83293 :                 str[i] = xlat[(unsigned char) str[i]];
    2689                 :         }
    2690                 : 
    2691             141 :         return str;
    2692                 : }
    2693                 : /* }}} */
    2694                 : 
    2695                 : /* {{{ php_strtr_array
    2696                 :  */
    2697                 : static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *hash)
    2698              45 : {
    2699                 :         zval **entry;
    2700                 :         char  *string_key;
    2701                 :         uint   string_key_len;
    2702                 :         zval **trans;
    2703                 :         zval   ctmp;
    2704                 :         ulong num_key;
    2705              45 :         int minlen = 128*1024;
    2706              45 :         int maxlen = 0, pos, len, found;
    2707                 :         char *key;
    2708                 :         HashPosition hpos;
    2709              45 :         smart_str result = {0};
    2710                 :         HashTable tmp_hash;
    2711                 :         
    2712              45 :         zend_hash_init(&tmp_hash, zend_hash_num_elements(hash), NULL, NULL, 0);
    2713              45 :         zend_hash_internal_pointer_reset_ex(hash, &hpos);
    2714             207 :         while (zend_hash_get_current_data_ex(hash, (void **)&entry, &hpos) == SUCCESS) {
    2715             117 :                 switch (zend_hash_get_current_key_ex(hash, &string_key, &string_key_len, &num_key, 0, &hpos)) {
    2716                 :                         case HASH_KEY_IS_STRING:
    2717             102 :                                 len = string_key_len-1;
    2718             102 :                                 if (len < 1) {
    2719               0 :                                         zend_hash_destroy(&tmp_hash);
    2720               0 :                                         RETURN_FALSE;
    2721                 :                                 }
    2722             102 :                                 zend_hash_add(&tmp_hash, string_key, string_key_len, entry, sizeof(zval*), NULL);
    2723             102 :                                 if (len > maxlen) {
    2724              69 :                                         maxlen = len;
    2725                 :                                 }
    2726             102 :                                 if (len < minlen) {
    2727              34 :                                         minlen = len;
    2728                 :                                 }
    2729             102 :                                 break; 
    2730                 :                         
    2731                 :                         case HASH_KEY_IS_LONG:
    2732              15 :                                 Z_TYPE(ctmp) = IS_LONG;
    2733              15 :                                 Z_LVAL(ctmp) = num_key;
    2734                 :                         
    2735              15 :                                 convert_to_string(&ctmp);
    2736              15 :                                 len = Z_STRLEN(ctmp);
    2737              15 :                                 zend_hash_add(&tmp_hash, Z_STRVAL(ctmp), len+1, entry, sizeof(zval*), NULL);
    2738              15 :                                 zval_dtor(&ctmp);
    2739                 : 
    2740              15 :                                 if (len > maxlen) {
    2741              13 :                                         maxlen = len;
    2742                 :                                 }
    2743              15 :                                 if (len < minlen) {
    2744              13 :                                         minlen = len;
    2745                 :                                 }
    2746                 :                                 break;
    2747                 :                 }
    2748             117 :                 zend_hash_move_forward_ex(hash, &hpos);
    2749                 :         }
    2750                 : 
    2751              45 :         key = emalloc(maxlen+1);
    2752              45 :         pos = 0;
    2753                 : 
    2754            1074 :         while (pos < slen) {
    2755             984 :                 if ((pos + maxlen) > slen) {
    2756              81 :                         maxlen = slen - pos;
    2757                 :                 }
    2758                 : 
    2759             984 :                 found = 0;
    2760             984 :                 memcpy(key, str+pos, maxlen);
    2761                 : 
    2762            3076 :                 for (len = maxlen; len >= minlen; len--) {
    2763            2184 :                         key[len] = 0;
    2764                 :                         
    2765            2184 :                         if (zend_hash_find(&tmp_hash, key, len+1, (void**)&trans) == SUCCESS) {
    2766                 :                                 char *tval;
    2767                 :                                 int tlen;
    2768                 :                                 zval tmp;
    2769                 : 
    2770              92 :                                 if (Z_TYPE_PP(trans) != IS_STRING) {
    2771               9 :                                         tmp = **trans;
    2772               9 :                                         zval_copy_ctor(&tmp);
    2773               9 :                                         convert_to_string(&tmp);
    2774               9 :                                         tval = Z_STRVAL(tmp);
    2775               9 :                                         tlen = Z_STRLEN(tmp);
    2776                 :                                 } else {
    2777              83 :                                         tval = Z_STRVAL_PP(trans);
    2778              83 :                                         tlen = Z_STRLEN_PP(trans);
    2779                 :                                 }
    2780                 : 
    2781              92 :                                 smart_str_appendl(&result, tval, tlen);
    2782              92 :                                 pos += len;
    2783              92 :                                 found = 1;
    2784                 : 
    2785              92 :                                 if (Z_TYPE_PP(trans) != IS_STRING) {
    2786               9 :                                         zval_dtor(&tmp);
    2787                 :                                 }
    2788              92 :                                 break;
    2789                 :                         } 
    2790                 :                 }
    2791                 : 
    2792             984 :                 if (! found) {
    2793             892 :                         smart_str_appendc(&result, str[pos++]);
    2794                 :                 }
    2795                 :         }
    2796                 : 
    2797              45 :         efree(key);
    2798              45 :         zend_hash_destroy(&tmp_hash);
    2799              45 :         smart_str_0(&result);
    2800              45 :         RETVAL_STRINGL(result.c, result.len, 0);
    2801                 : }
    2802                 : /* }}} */
    2803                 : 
    2804                 : /* {{{ proto string strtr(string str, string from[, string to])
    2805                 :    Translates characters in str using given translation tables */
    2806                 : PHP_FUNCTION(strtr)
    2807             210 : {                                                               
    2808                 :         zval **str, **from, **to;
    2809             210 :         int ac = ZEND_NUM_ARGS();
    2810                 : 
    2811             210 :         if (ac < 2 || ac > 3 || zend_get_parameters_ex(ac, &str, &from, &to) == FAILURE) {
    2812               3 :                 WRONG_PARAM_COUNT;
    2813                 :         }
    2814                 :         
    2815             207 :         if (ac == 2 && Z_TYPE_PP(from) != IS_ARRAY) {
    2816              32 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument is not an array");
    2817              32 :                 RETURN_FALSE;
    2818                 :         }
    2819                 : 
    2820             175 :         convert_to_string_ex(str);
    2821                 : 
    2822                 :         /* shortcut for empty string */
    2823             175 :         if (Z_STRLEN_PP(str) == 0) {
    2824              27 :                 RETURN_EMPTY_STRING();
    2825                 :         }
    2826                 : 
    2827             148 :         if (ac == 2) {
    2828              45 :                 php_strtr_array(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), HASH_OF(*from));
    2829                 :         } else {
    2830             103 :                 convert_to_string_ex(from);
    2831             103 :                 convert_to_string_ex(to);
    2832                 : 
    2833             103 :                 ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
    2834                 :                 
    2835             103 :                 php_strtr(Z_STRVAL_P(return_value),
    2836                 :                                   Z_STRLEN_P(return_value),
    2837                 :                                   Z_STRVAL_PP(from),
    2838                 :                                   Z_STRVAL_PP(to),
    2839                 :                                   MIN(Z_STRLEN_PP(from), 
    2840                 :                                   Z_STRLEN_PP(to)));
    2841                 :         }
    2842                 : }
    2843                 : /* }}} */
    2844                 : 
    2845                 : /* {{{ proto string strrev(string str)
    2846                 :    Reverse a string */
    2847                 : PHP_FUNCTION(strrev)
    2848             103 : {
    2849                 :         zval **str;
    2850                 :         char *s, *e, *n, *p;
    2851                 :         
    2852             103 :         if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    2853               2 :                 WRONG_PARAM_COUNT;
    2854                 :         }
    2855             101 :         convert_to_string_ex(str);
    2856                 :         
    2857             101 :         n = emalloc(Z_STRLEN_PP(str)+1);
    2858             101 :         p = n;
    2859                 :         
    2860             101 :         s = Z_STRVAL_PP(str);
    2861             101 :         e = s + Z_STRLEN_PP(str);
    2862                 :         
    2863            4363 :         while (--e>=s) {
    2864            4161 :                 *p++ = *e;
    2865                 :         }
    2866                 :         
    2867             101 :         *p = '\0';
    2868                 :         
    2869             101 :         RETVAL_STRINGL(n, Z_STRLEN_PP(str), 0);
    2870                 : }
    2871                 : /* }}} */
    2872                 : 
    2873                 : /* {{{ php_similar_str
    2874                 :  */
    2875                 : static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
    2876              10 : {
    2877                 :         char *p, *q;
    2878              10 :         char *end1 = (char *) txt1 + len1;
    2879              10 :         char *end2 = (char *) txt2 + len2;
    2880                 :         int l;
    2881                 :         
    2882              10 :         *max = 0;
    2883             104 :         for (p = (char *) txt1; p < end1; p++) {
    2884             602 :                 for (q = (char *) txt2; q < end2; q++) {
    2885             508 :                         for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
    2886             508 :                         if (l > *max) {
    2887               6 :                                 *max = l;
    2888               6 :                                 *pos1 = p - txt1;
    2889               6 :                                 *pos2 = q - txt2;
    2890                 :                         }
    2891                 :                 }
    2892                 :         }
    2893              10 : }
    2894                 : /* }}} */
    2895                 : 
    2896                 : /* {{{ php_similar_char
    2897                 :  */
    2898                 : static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2)
    2899              10 : {
    2900                 :         int sum;
    2901                 :         int pos1, pos2, max;
    2902                 : 
    2903              10 :         php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
    2904              10 :         if ((sum = max)) {
    2905               6 :                 if (pos1 && pos2) {
    2906               0 :                         sum += php_similar_char(txt1, pos1, 
    2907                 :                                                                         txt2, pos2);
    2908                 :                 }
    2909               6 :                 if ((pos1 + max < len1) && (pos2 + max < len2)) {
    2910               2 :                         sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max, 
    2911                 :                                                                         txt2 + pos2 + max, len2 - pos2 - max);
    2912                 :                 }
    2913                 :         }
    2914                 : 
    2915              10 :         return sum;
    2916                 : }
    2917                 : /* }}} */
    2918                 : 
    2919                 : /* {{{ proto int similar_text(string str1, string str2 [, float percent])
    2920                 :    Calculates the similarity between two strings */
    2921                 : PHP_FUNCTION(similar_text)
    2922              10 : {
    2923                 :         zval **t1, **t2, **percent;
    2924              10 :         int ac = ZEND_NUM_ARGS();
    2925                 :         int sim;
    2926                 :         
    2927              10 :         if (ac < 2 || ac > 3 || zend_get_parameters_ex(ac, &t1, &t2, &percent) == FAILURE) {
    2928               2 :                 WRONG_PARAM_COUNT;
    2929                 :         }       
    2930                 : 
    2931               8 :         convert_to_string_ex(t1);
    2932               8 :         convert_to_string_ex(t2);
    2933                 : 
    2934               8 :         if (ac > 2) {
    2935               4 :                 convert_to_double_ex(percent);
    2936                 :         }
    2937                 :         
    2938               8 :         if (Z_STRLEN_PP(t1) + Z_STRLEN_PP(t2) == 0) {
    2939               0 :                 if (ac > 2) {
    2940               0 :                         Z_DVAL_PP(percent) = 0;
    2941                 :                 }
    2942                 : 
    2943               0 :                 RETURN_LONG(0);
    2944                 :         }
    2945                 :         
    2946               8 :         sim = php_similar_char(Z_STRVAL_PP(t1), Z_STRLEN_PP(t1), Z_STRVAL_PP(t2), Z_STRLEN_PP(t2));     
    2947                 : 
    2948               8 :         if (ac > 2) {
    2949               4 :                 Z_DVAL_PP(percent) = sim * 200.0 / (Z_STRLEN_PP(t1) + Z_STRLEN_PP(t2));
    2950                 :         }
    2951                 : 
    2952               8 :         RETURN_LONG(sim);
    2953                 : }
    2954                 : /* }}} */
    2955                 : 
    2956                 : /* {{{ php_stripslashes
    2957                 :  *
    2958                 :  * be careful, this edits the string in-place */
    2959                 : PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC)
    2960             151 : {
    2961                 :         char *s, *t;
    2962                 :         int l;
    2963                 : 
    2964             151 :         if (len != NULL) {
    2965             151 :                 l = *len;
    2966                 :         } else {
    2967               0 :                 l = strlen(str);
    2968                 :         }
    2969             151 :         s = str;
    2970             151 :         t = str;
    2971                 : 
    2972             151 :         if (PG(magic_quotes_sybase)) {
    2973            1016 :                 while (l > 0) {
    2974             950 :                         if (*t == '\'') {
    2975              22 :                                 if ((l > 0) && (t[1] == '\'')) {
    2976              22 :                                         t++;
    2977              22 :                                         if (len != NULL) {
    2978              22 :                                                 (*len)--;
    2979                 :                                         }
    2980              22 :                                         l--;
    2981                 :                                 }
    2982              22 :                                 *s++ = *t++;
    2983             941 :                         } else if (*t == '\\' && t[1] == '0' && l > 0) {
    2984              13 :                                 *s++='\0';
    2985              13 :                                 t+=2;
    2986              13 :                                 if (len != NULL) {
    2987              13 :                                         (*len)--;
    2988                 :                                 }
    2989              13 :                                 l--;
    2990                 :                         } else {
    2991             915 :                                 *s++ = *t++;
    2992                 :                         }
    2993             950 :                         l--;
    2994                 :                 }
    2995              33 :                 *s = '\0';
    2996                 :                 
    2997              33 :                 return;
    2998                 :         }
    2999                 : 
    3000            1700 :         while (l > 0) {
    3001            1464 :                 if (*t == '\\') {
    3002             117 :                         t++;                            /* skip the slash */
    3003             117 :                         if (len != NULL) {
    3004             117 :                                 (*len)--;
    3005                 :                         }
    3006             117 :                         l--;
    3007             117 :                         if (l > 0) {
    3008             117 :                                 if (*t == '0') {
    3009              15 :                                         *s++='\0';
    3010              15 :                                         t++;
    3011                 :                                 } else {
    3012             102 :                                         *s++ = *t++;    /* preserve the next character */
    3013                 :                                 }
    3014             117 :                                 l--;
    3015                 :                         }
    3016                 :                 } else {
    3017            1347 :                         *s++ = *t++;
    3018            1347 :                         l--;
    3019                 :                 }
    3020                 :         }
    3021             118 :         if (s != t) {
    3022              68 :                 *s = '\0';
    3023                 :         }
    3024                 : }
    3025                 : /* }}} */
    3026                 : 
    3027                 : /* {{{ proto string addcslashes(string str, string charlist)
    3028                 :    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...) */
    3029                 : PHP_FUNCTION(addcslashes)
    3030              45 : {
    3031                 :         zval **str, **what;
    3032                 : 
    3033              45 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &str, &what) == FAILURE) {
    3034               3 :                 WRONG_PARAM_COUNT;
    3035                 :         }
    3036              42 :         convert_to_string_ex(str);
    3037              42 :         convert_to_string_ex(what);
    3038                 : 
    3039              42 :         if (Z_STRLEN_PP(str) == 0) {
    3040               6 :                 RETURN_EMPTY_STRING();
    3041                 :         }
    3042                 : 
    3043              36 :         if (Z_STRLEN_PP(what) == 0) {
    3044               5 :                 RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
    3045                 :         }
    3046                 : 
    3047              31 :         Z_STRVAL_P(return_value) = php_addcslashes(Z_STRVAL_PP(str), Z_STRLEN_PP(str), &Z_STRLEN_P(return_value), 0, Z_STRVAL_PP(what), Z_STRLEN_PP(what) TSRMLS_CC);
    3048              31 :         RETURN_STRINGL(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), 0);
    3049                 : }
    3050                 : /* }}} */
    3051                 : 
    3052                 : /* {{{ proto string addslashes(string str)
    3053                 :    Escapes single quote, double quotes and backslash characters in a string with backslashes */
    3054                 : PHP_FUNCTION(addslashes)
    3055          280856 : {
    3056                 :         zval **str;
    3057                 : 
    3058          280856 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    3059               2 :                 WRONG_PARAM_COUNT;
    3060                 :         }
    3061          280854 :         convert_to_string_ex(str);
    3062                 : 
    3063          280854 :         if (Z_STRLEN_PP(str) == 0) {
    3064           74617 :                 RETURN_EMPTY_STRING();
    3065                 :         }
    3066                 : 
    3067          206237 :         RETURN_STRING(php_addslashes(Z_STRVAL_PP(str),
    3068                 :                                      Z_STRLEN_PP(str), 
    3069                 :                                      &Z_STRLEN_P(return_value), 0 
    3070                 :                                      TSRMLS_CC), 0);
    3071                 : }
    3072                 : /* }}} */
    3073                 : 
    3074                 : /* {{{ proto string stripcslashes(string str)
    3075                 :    Strips backslashes from a string. Uses C-style conventions */
    3076                 : PHP_FUNCTION(stripcslashes)
    3077              35 : {
    3078                 :         zval **str;
    3079                 :         
    3080              35 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    3081               2 :                 WRONG_PARAM_COUNT;
    3082                 :         }
    3083              33 :         convert_to_string_ex(str);
    3084                 : 
    3085              33 :         ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
    3086              33 :         php_stripcslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value));
    3087                 : }
    3088                 : /* }}} */
    3089                 : 
    3090                 : /* {{{ proto string stripslashes(string str)
    3091                 :    Strips backslashes from a string */
    3092                 : PHP_FUNCTION(stripslashes)
    3093             144 : {
    3094                 :         zval **str;
    3095                 :         
    3096             144 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
    3097               2 :                 WRONG_PARAM_COUNT;
    3098                 :         }
    3099             142 :         convert_to_string_ex(str);
    3100                 : 
    3101             142 :         ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
    3102             142 :         php_stripslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC);
    3103                 : }
    3104                 : /* }}} */
    3105                 : 
    3106                 : #ifndef HAVE_STRERROR
    3107                 : /* {{{ php_strerror
    3108                 :  */
    3109                 : char *php_strerror(int errnum) 
    3110                 : {
    3111                 :         extern int sys_nerr;
    3112                 :         extern char *sys_errlist[];
    3113                 :         TSRMLS_FETCH();
    3114                 : 
    3115                 :         if ((unsigned int) errnum < sys_nerr) {
    3116                 :                 return(sys_errlist[errnum]);
    3117                 :         }
    3118                 : 
    3119                 :         (void) snprintf(BG(str_ebuf), sizeof(php_basic_globals.str_ebuf), "Unknown error: %d", errnum);
    3120                 :         return(BG(str_ebuf));
    3121                 : }
    3122                 : /* }}} */
    3123                 : #endif
    3124                 : 
    3125                 : /* {{{ php_stripcslashes
    3126                 :  */
    3127                 : PHPAPI void php_stripcslashes(char *str, int *len)
    3128              33 : {
    3129                 :         char *source, *target, *end;
    3130              33 :         int  nlen = *len, i;
    3131                 :         char numtmp[4];
    3132                 : 
    3133             179 :         for (source=str, end=str+nlen, target=str; source < end; source++) {
    3134             181 :                 if (*source == '\\' && source+1 < end) {
    3135              35 :                         source++;
    3136              35 :                         switch (*source) {
    3137               2 :                                 case 'n':  *target++='\n'; nlen--; break;
    3138               2 :                                 case 'r':  *target++='\r'; nlen--; break;
    3139               0 :                                 case 'a':  *target++='\a'; nlen--; break;
    3140               0 :                                 case 't':  *target++='\t'; nlen--; break;
    3141               0 :                                 case 'v':  *target++='\v'; nlen--; break;
    3142               0 :                                 case 'b':  *target++='\b'; nlen--; break;
    3143               0 :                                 case 'f':  *target++='\f'; nlen--; break;
    3144               0 :                                 case '\\': *target++='\\'; nlen--; break;
    3145                 :                                 case 'x':
    3146              11 :                                         if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3147              11 :                                                 numtmp[0] = *++source;
    3148              22 :                                                 if (source+1 < end && isxdigit((int)(*(source+1)))) {
    3149              11 :                                                         numtmp[1] = *++source;
    3150              11 :                                                         numtmp[2] = '\0';
    3151              11 :                                                         nlen-=3;
    3152                 :                                                 } else {
    3153               0 :                                                         numtmp[1] = '\0';
    3154               0 :                                                         nlen-=2;
    3155                 :                                                 }
    3156              11 :                                                 *target++=(char)strtol(numtmp, NULL, 16);
    3157              11 :                                                 break;
    3158                 :                                         }
    3159                 :                                         /* break is left intentionally */
    3160                 :                                 default: 
    3161              20 :                                         i=0; 
    3162              73 :                                         while (source < end && *source >= '0' && *source <= '7' && i<3) {
    3163              33 :                                                 numtmp[i++] = *source++;
    3164                 :                                         }
    3165              20 :                                         if (i) {
    3166              11 :                                                 numtmp[i]='\0';
    3167              11 :                                                 *target++=(char)strtol(numtmp, NULL, 8);
    3168              11 :                                                 nlen-=i;
    3169              11 :                                                 source--;
    3170                 :                                         } else {
    3171               9 :                                                 *target++=*source;
    3172               9 :                                                 nlen--;
    3173                 :                                         }
    3174                 :                         }
    3175                 :                 } else {
    3176             111 :                         *target++=*source;
    3177                 :                 }
    3178                 :         }
    3179                 : 
    3180              33 :         if (nlen != 0) {
    3181              24 :                 *target='\0';
    3182                 :         }
    3183                 : 
    3184              33 :         *len = nlen;
    3185              33 : }
    3186                 : /* }}} */
    3187                 :                         
    3188                 : /* {{{ php_addcslashes
    3189                 :  */
    3190                 : PHPAPI char *php_addcslashes(char *str, int length, int *new_length, int should_free, char *what, int wlength TSRMLS_DC)
    3191             591 : {
    3192                 :         char flags[256];
    3193             591 :         char *new_str = safe_emalloc(4, (length?length:(length=strlen(str))), 1);
    3194                 :         char *source, *target;
    3195                 :         char *end;
    3196                 :         char c;
    3197                 :         int  newlen;
    3198                 : 
    3199             591 :         if (!wlength) {
    3200               0 :                 wlength = strlen(what);
    3201                 :         }
    3202                 : 
    3203             591 :         php_charmask(what, wlength, flags TSRMLS_CC);
    3204                 : 
    3205            4318 :         for (source = str, end = source + length, target = new_str; source < end; source++) {
    3206            3727 :                 c = *source; 
    3207            3727 :                 if (flags[(unsigned char)c]) {
    3208             117 :                         if ((unsigned char) c < 32 || (unsigned char) c > 126) {
    3209              16 :                                 *target++ = '\\';
    3210              16 :                                 switch (c) {
    3211               2 :                                         case '\n': *target++ = 'n'; break;
    3212               2 :                                         case '\t': *target++ = 't'; break;
    3213               2 :                                         case '\r': *target++ = 'r'; break;
    3214               0 :                                         case '\a': *target++ = 'a'; break;
    3215               2 :                                         case '\v': *target++ = 'v'; break;
    3216               0 :                                         case '\b': *target++ = 'b'; break;
    3217               2 :                                         case '\f': *target++ = 'f'; break;
    3218               6 :                                         default: target += sprintf(target, "%03o", (unsigned char) c);
    3219                 :                                 }
    3220              16 :                                 continue;
    3221                 :                         } 
    3222             101 :                         *target++ = '\\';
    3223                 :                 }
    3224            3711 :                 *target++ = c;
    3225                 :         }
    3226             591 :         *target = 0;
    3227             591 :         newlen = target - new_str;
    3228             591 :         if (target - new_str < length * 4) {
    3229             566 :                 new_str = erealloc(new_str, newlen + 1);
    3230                 :         }
    3231             591 :         if (new_length) {
    3232             591 :                 *new_length = newlen;
    3233                 :         }
    3234             591 :         if (should_free) {
    3235               0 :                 STR_FREE(str);
    3236                 :         }
    3237             591 :         return new_str;
    3238                 : }
    3239                 : /* }}} */
    3240                 : 
    3241                 : /* {{{ php_addslashes
    3242                 :  */
    3243                 : PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC)
    3244          207340 : {
    3245          207340 :         return php_addslashes_ex(str, length, new_length, should_free, 0 TSRMLS_CC);
    3246                 : }
    3247                 : /* }}} */
    3248                 : 
    3249                 : /* {{{ php_addslashes_ex
    3250                 :  */
    3251                 : PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int should_free, int ignore_sybase TSRMLS_DC)
    3252          207348 : {
    3253                 :         /* maximum string length, worst case situation */
    3254                 :         char *new_str;
    3255                 :         char *source, *target;
    3256                 :         char *end;
    3257                 :         int local_new_length;
    3258                 :                 
    3259          207348 :         if (!new_length) {
    3260              18 :                 new_length = &local_new_length;
    3261                 :         }
    3262          207348 :         if (!str) {
    3263               0 :                 *new_length = 0;
    3264               0 :                 return str;
    3265                 :         }
    3266          207348 :         new_str = (char *) safe_emalloc(2, (length ? length : (length = strlen(str))), 1);
    3267          207348 :         source = str;
    3268          207348 :         end = source + length;
    3269          207348 :         target = new_str;
    3270                 :         
    3271          207409 :         if (!ignore_sybase && PG(magic_quotes_sybase)) {
    3272            1524 :                 while (source < end) {
    3273            1402 :                         switch (*source) {
    3274                 :                                 case '\0':
    3275              24 :                                         *target++ = '\\';
    3276              24 :                                         *target++ = '0';
    3277              24 :                                         break;
    3278                 :                                 case '\'':
    3279              42 :                                         *target++ = '\'';
    3280              42 :                                         *target++ = '\'';
    3281              42 :                                         break;
    3282                 :                                 default:
    3283            1336 :                                         *target++ = *source;
    3284                 :                                         break;
    3285                 :                         }
    3286            1402 :                         source++;
    3287                 :                 }
    3288                 :         } else {
    3289         1079759 :                 while (source < end) {
    3290          665185 :                         switch (*source) {
    3291                 :                                 case '\0':
    3292              36 :                                         *target++ = '\\';
    3293              36 :                                         *target++ = '0';
    3294              36 :                                         break;
    3295                 :                                 case '\'':
    3296                 :                                 case '\"':
    3297                 :                                 case '\\':
    3298             275 :                                         *target++ = '\\';
    3299                 :                                         /* break is missing *intentionally* */
    3300                 :                                 default:
    3301          665149 :                                         *target++ = *source;
    3302                 :                                         break;  
    3303                 :                         }
    3304                 :                 
    3305          665185 :                         source++;
    3306                 :                 }
    3307                 :         }
    3308                 :         
    3309          207348 :         *target = 0;
    3310          207348 :         *new_length = target - new_str;
    3311          207348 :         if (should_free) {
    3312               5 :                 STR_FREE(str);
    3313                 :         }
    3314          207348 :         new_str = (char *) erealloc(new_str, *new_length + 1);
    3315          207348 :         return new_str;
    3316                 : }
    3317                 : /* }}} */
    3318                 : 
    3319                 : #define _HEB_BLOCK_TYPE_ENG 1
    3320                 : #define _HEB_BLOCK_TYPE_HEB 2
    3321                 : #define isheb(c)      (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0)
    3322                 : #define _isblank(c)   (((((unsigned char) c) == ' '  || ((unsigned char) c) == '\t')) ? 1 : 0)
    3323                 : #define _isnewline(c) (((((unsigned char) c) == '\n' || ((unsigned char) c) == '\r')) ? 1 : 0)
    3324                 : 
    3325                 : /* {{{ php_char_to_str_ex
    3326                 :  */
    3327                 : 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)
    3328            4554 : {
    3329            4554 :         int char_count = 0;
    3330            4554 :         int replaced = 0;
    3331            4554 :         char *source, *target, *tmp, *source_end=str+len, *tmp_end = NULL;
    3332                 :                 
    3333            4554 :         if (case_sensitivity) {
    3334            4544 :                 char *p = str, *e = p + len;
    3335           16569 :                 while ((p = memchr(p, from, (e - p)))) {
    3336            7481 :                         char_count++;
    3337            7481 :                         p++;
    3338                 :                 }
    3339                 :         } else {
    3340             327 :                 for (source = str; source < source_end; source++) {
    3341             317 :                         if (tolower(*source) == tolower(from)) {
    3342              29 :                                 char_count++;
    3343                 :                         }
    3344                 :                 }
    3345                 :         }
    3346                 : 
    3347            4554 :         if (char_count == 0 && case_sensitivity) {
    3348             507 :                 ZVAL_STRINGL(result, str, len, 1);
    3349             507 :                 return 0;
    3350                 :         }
    3351                 :         
    3352            4047 :         Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
    3353            4047 :         Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1);
    3354            4047 :         Z_TYPE_P(result) = IS_STRING;
    3355                 : 
    3356            4047 :         if (case_sensitivity) {
    3357            4037 :                 char *p = str, *e = p + len, *s = str;
    3358           15555 :                 while ((p = memchr(p, from, (e - p)))) {
    3359            7481 :                         memcpy(target, s, (p - s));
    3360            7481 :                         target += p - s;
    3361            7481 :                         memcpy(target, to, to_len);
    3362            7481 :                         target += to_len;
    3363            7481 :                         p++;
    3364            7481 :                         s = p;
    3365            7481 :                         if (replace_count) {
    3366             266 :                                 *replace_count += 1;
    3367                 :                         }
    3368                 :                 }
    3369            4037 :                 if (s < e) {
    3370             474 :                         memcpy(target, s, (e - s));
    3371             474 :                         target += e - s;
    3372                 :                 }
    3373                 :         } else {
    3374             327 :                 for (source = str; source < source_end; source++) {
    3375             317 :                         if (tolower(*source) == tolower(from)) {
    3376              29 :                                 replaced = 1;
    3377              29 :                                 if (replace_count) {
    3378               0 :                                         *replace_count += 1;
    3379                 :                                 }
    3380             117 :                                 for (tmp = to, tmp_end = tmp+to_len; tmp < tmp_end; tmp++) {
    3381              88 :                                         *target = *tmp;
    3382              88 :                                         target++;
    3383                 :                                 }
    3384                 :                         } else {
    3385             288 :                                 *target = *source;
    3386             288 :                                 target++;
    3387                 :                         }
    3388                 :                 }
    3389                 :         }
    3390            4047 :         *target = 0;
    3391            4047 :         return replaced;
    3392                 : }
    3393                 : /* }}} */
    3394                 : 
    3395                 : /* {{{ php_char_to_str
    3396                 :  */
    3397                 : PHPAPI int php_char_to_str(char *str, uint len, char from, char *to, int to_len, zval *result)
    3398              45 : {
    3399              45 :         return php_char_to_str_ex(str, len, from, to, to_len, result, 1, NULL);
    3400                 : }
    3401                 : /* }}} */
    3402                 : 
    3403                 : /* {{{ php_str_to_str_ex
    3404                 :  */
    3405                 : PHPAPI char *php_str_to_str_ex(char *haystack, int length, 
    3406                 :         char *needle, int needle_len, char *str, int str_len, int *_new_length, int case_sensitivity, int *replace_count)
    3407          112166 : {
    3408                 :         char *new_str;
    3409                 : 
    3410          112166 :         if (needle_len < length) {
    3411          111455 :                 char *end, *haystack_dup = NULL, *needle_dup = NULL;
    3412                 :                 char *e, *s, *p, *r;
    3413                 : 
    3414          111455 :                 if (needle_len == str_len) {
    3415           16540 :                         new_str = estrndup(haystack, length);
    3416           16540 :                         *_new_length = length;
    3417                 : 
    3418           16540 :                         if (case_sensitivity) {
    3419           16538 :                                 end = new_str + length;
    3420           16704 :                                 for (p = new_str; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3421             166 :                                         memcpy(r, str, str_len);
    3422             166 :                                         if (replace_count) {
    3423               8 :                                                 (*replace_count)++;
    3424                 :                                         }
    3425                 :                                 }
    3426                 :                         } else {
    3427               2 :                                 haystack_dup = estrndup(haystack, length);
    3428               2 :                                 needle_dup = estrndup(needle, needle_len);
    3429               2 :                                 php_strtolower(haystack_dup, length);
    3430               2 :                                 php_strtolower(needle_dup, needle_len);
    3431               2 :                                 end = haystack_dup + length;
    3432              16 :                                 for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
    3433              14 :                                         memcpy(new_str + (r - haystack_dup), str, str_len);
    3434              14 :                                         if (replace_count) {
    3435               7 :                                                 (*replace_count)++;
    3436                 :                                         }
    3437                 :                                 }
    3438               2 :                                 efree(haystack_dup);
    3439               2 :                                 efree(needle_dup);
    3440                 :                         }
    3441           16540 :                         return new_str;
    3442                 :                 } else {
    3443           94915 :                         if (!case_sensitivity) {
    3444             473 :                                 haystack_dup = estrndup(haystack, length);
    3445             473 :                                 needle_dup = estrndup(needle, needle_len);
    3446             473 :                                 php_strtolower(haystack_dup, length);
    3447             473 :                                 php_strtolower(needle_dup, needle_len);
    3448                 :                         }
    3449                 : 
    3450           94915 :                         if (str_len < needle_len) {
    3451           55862 :                                 new_str = emalloc(length + 1);
    3452                 :                         } else {
    3453           39053 :                                 int count = 0;
    3454                 :                                 char *o, *n, *endp;
    3455                 : 
    3456           39053 :                                 if (case_sensitivity) {
    3457           38585 :                                         o = haystack;
    3458           38585 :                                         n = needle;
    3459                 :                                 } else {
    3460             468 :                                         o = haystack_dup;
    3461             468 :                                         n = needle_dup;
    3462                 :                                 }
    3463           39053 :                                 endp = o + length;
    3464                 : 
    3465          125429 :                                 while ((o = php_memnstr(o, n, needle_len, endp))) {
    3466           47323 :                                         o += needle_len;
    3467           47323 :                                         count++;
    3468                 :                                 }
    3469           39053 :                                 if (count == 0) {
    3470                 :                                         /* Needle doesn't occur, shortcircuit the actual replacement. */
    3471           32498 :                                         if (haystack_dup) {
    3472             447 :                                                 efree(haystack_dup);
    3473                 :                                         }
    3474           32498 :                                         if (needle_dup) {
    3475             447 :                                                 efree(needle_dup);
    3476                 :                                         }
    3477           32498 :                                         new_str = estrndup(haystack, length);
    3478           32498 :                                         if (_new_length) {
    3479           32498 :                                                 *_new_length = length;
    3480                 :                                         }
    3481           32498 :                                         return new_str;
    3482                 :                                 } else {
    3483            6555 :                                         new_str = safe_emalloc(count, str_len - needle_len, length + 1);
    3484                 :                                 }
    3485                 :                         }
    3486                 : 
    3487           62417 :                         e = s = new_str;
    3488                 : 
    3489           62417 :                         if (case_sensitivity) {
    3490           62391 :                                 end = haystack + length;
    3491          127933 :                                 for (p = haystack; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    3492           65542 :                                         memcpy(e, p, r - p);
    3493           65542 :                                         e += r - p;
    3494           65542 :                                         memcpy(e, str, str_len);
    3495           65542 :                                         e += str_len;
    3496           65542 :                                         if (replace_count) {
    3497              66 :                                                 (*replace_count)++;
    3498                 :                                         }
    3499                 :                                 }
    3500                 : 
    3501           62391 :                                 if (p < end) {
    3502           62390 :                                         memcpy(e, p, end - p);
    3503           62390 :                                         e += end - p;
    3504                 :                                 }
    3505                 :                         } else {
    3506              26 :                                 end = haystack_dup + length;
    3507                 : 
    3508             146 :                                 for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
    3509             120 :                                         memcpy(e, haystack + (p - haystack_dup), r - p);
    3510             120 :                                         e += r - p;
    3511             120 :                                         memcpy(e, str, str_len);
    3512             120 :                                         e += str_len;
    3513             120 :                                         if (replace_count) {
    3514              21 :                                                 (*replace_count)++;
    3515                 :                                         }
    3516                 :                                 }
    3517                 : 
    3518              26 :                                 if (p < end) {
    3519              23 :                                         memcpy(e, haystack + (p - haystack_dup), end - p);
    3520              23 :                                         e += end - p;
    3521                 :                                 }
    3522                 :                         }
    3523                 : 
    3524           62417 :                         if (haystack_dup) {
    3525              26 :                                 efree(haystack_dup);
    3526                 :                         }
    3527           62417 :                         if (needle_dup) {
    3528              26 :                                 efree(needle_dup);
    3529                 :                         }
    3530                 : 
    3531           62417 :                         *e = '\0';
    3532           62417 :                         *_new_length = e - s;
    3533                 : 
    3534           62417 :                         new_str = erealloc(new_str, *_new_length + 1);
    3535           62417 :                         return new_str;
    3536                 :                 }
    3537             711 :         } else if (needle_len > length) {
    3538             665 : nothing_todo:
    3539             665 :                 *_new_length = length;
    3540             665 :                 new_str = estrndup(haystack, length);
    3541             665 :                 return new_str;
    3542                 :         } else {
    3543             190 :                 if (case_sensitivity && memcmp(haystack, needle, length)) {
    3544                 :                         goto nothing_todo;
    3545             125 :                 } else if (!case_sensitivity) {
    3546                 :                         char *l_haystack, *l_needle;
    3547                 : 
    3548              88 :                         l_haystack = estrndup(haystack, length);
    3549              88 :                         l_needle = estrndup(needle, length);
    3550                 : 
    3551              88 :                         php_strtolower(l_haystack, length);
    3552              88 :                         php_strtolower(l_needle, length);
    3553                 : 
    3554              88 :                         if (memcmp(l_haystack, l_needle, length)) {
    3555              79 :                                 efree(l_haystack);
    3556              79 :                                 efree(l_needle);
    3557              79 :                                 goto nothing_todo;
    3558                 :                         }
    3559               9 :                         efree(l_haystack);
    3560               9 :                         efree(l_needle);
    3561                 :                 }
    3562                 : 
    3563              46 :                 *_new_length = str_len;
    3564              46 :                 new_str = estrndup(str, str_len);
    3565                 : 
    3566              46 :                 if (replace_count) {
    3567              16 :                         (*replace_count)++;
    3568                 :                 }
    3569              46 :                 return new_str;
    3570                 :         }
    3571                 : 
    3572                 : }
    3573                 : /* }}} */
    3574                 : 
    3575                 : /* {{{ php_str_to_str
    3576                 :  */
    3577                 : PHPAPI char *php_str_to_str(char *haystack, int length, 
    3578                 :         char *needle, int needle_len, char *str, int str_len, int *_new_length)
    3579              26 : {
    3580              26 :         return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, _new_length, 1, NULL);
    3581                 : } 
    3582                 : /* }}} */
    3583                 : 
    3584                 : /* {{{ php_str_replace_in_subject
    3585                 :  */
    3586                 : static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int *replace_count)
    3587          104802 : {
    3588                 :         zval            **search_entry,
    3589          104802 :                                 **replace_entry = NULL,
    3590                 :                                   temp_result;
    3591          104802 :         char            *replace_value = NULL;
    3592          104802 :         int                      replace_len = 0;
    3593                 : 
    3594                 :         /* Make sure we're dealing with strings. */     
    3595          104802 :         convert_to_string_ex(subject);
    3596          104802 :         Z_TYPE_P(result) = IS_STRING;
    3597          104802 :         if (Z_STRLEN_PP(subject) == 0) {
    3598              99 :                 ZVAL_STRINGL(result, "", 0, 1);
    3599              99 :                 return;
    3600                 :         }
    3601                 :         
    3602                 :         /* If search is an array */
    3603          104703 :         if (Z_TYPE_P(search) == IS_ARRAY) {
    3604                 :                 /* Duplicate subject string for repeated replacement */
    3605           22470 :                 *result = **subject;
    3606           22470 :                 zval_copy_ctor(result);
    3607           22470 :                 INIT_PZVAL(result);
    3608                 :                 
    3609           22470 :                 zend_hash_internal_pointer_reset(Z_ARRVAL_P(search));
    3610                 : 
    3611           22470 :                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3612              26 :                         zend_hash_internal_pointer_reset(Z_ARRVAL_P(replace));
    3613                 :                 } else {
    3614                 :                         /* Set replacement value to the passed one */
    3615           22444 :                         replace_value = Z_STRVAL_P(replace);
    3616           22444 :                         replace_len = Z_STRLEN_P(replace);
    3617                 :                 }
    3618                 : 
    3619                 :                 /* For each entry in the search array, get the entry */
    3620           78848 :                 while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) {
    3621                 :                         /* Make sure we're dealing with strings. */     
    3622           33910 :                         SEPARATE_ZVAL(search_entry);
    3623           33910 :                         convert_to_string(*search_entry);
    3624           33910 :                         if (Z_STRLEN_PP(search_entry) == 0) {
    3625               0 :                                 zend_hash_move_forward(Z_ARRVAL_P(search));
    3626               0 :                                 if (Z_TYPE_P(replace) == IS_ARRAY) {
    3627               0 :                                         zend_hash_move_forward(Z_ARRVAL_P(replace));
    3628                 :                                 }
    3629               0 :                                 continue;
    3630                 :                         }
    3631                 : 
    3632                 :                         /* If replace is an array. */
    3633           33910 :                         if (Z_TYPE_P(replace) == IS_ARRAY) {
    3634                 :                                 /* Get current entry */
    3635              68 :                                 if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) {
    3636                 :                                         /* Make sure we're dealing with strings. */     
    3637              58 :                                         convert_to_string_ex(replace_entry);
    3638                 :                                         
    3639                 :                                         /* Set replacement value to the one we got from array */
    3640              58 :                                         replace_value = Z_STRVAL_PP(replace_entry);
    3641              58 :                                         replace_len = Z_STRLEN_PP(replace_entry);
    3642                 : 
    3643              58 :                                         zend_hash_move_forward(Z_ARRVAL_P(replace));
    3644                 :                                 } else {
    3645                 :                                         /* We've run out of replacement strings, so use an empty one. */
    3646              10 :                                         replace_value = "";
    3647              10 :                                         replace_len = 0;
    3648                 :                                 }
    3649                 :                         }
    3650                 :                         
    3651           33910 :                         if (Z_STRLEN_PP(search_entry) == 1) {
    3652             840 :                                 php_char_to_str_ex(Z_STRVAL_P(result),
    3653                 :                                                                 Z_STRLEN_P(result),
    3654                 :                                                                 Z_STRVAL_PP(search_entry)[0],
    3655                 :                                                                 replace_value,
    3656                 :                                                                 replace_len,
    3657                 :                                                                 &temp_result,
    3658                 :                                                                 case_sensitivity,
    3659                 :                                                                 replace_count);
    3660           33070 :                         } else if (Z_STRLEN_PP(search_entry) > 1) {
    3661           33070 :                                 Z_STRVAL(temp_result) = php_str_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result),
    3662                 :                                                                                                                    Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry),
    3663                 :                                                                                                                    replace_value, replace_len, &Z_STRLEN(temp_result), case_sensitivity, replace_count);
    3664                 :                         }
    3665                 : 
    3666           33910 :                         efree(Z_STRVAL_P(result));
    3667           33910 :                         Z_STRVAL_P(result) = Z_STRVAL(temp_result);
    3668           33910 :                         Z_STRLEN_P(result) = Z_STRLEN(temp_result);
    3669                 : 
    3670           33910 :                         if (Z_STRLEN_P(result) == 0) {
    3671               2 :                                 return;
    3672                 :                         }
    3673                 : 
    3674           33908 :                         zend_hash_move_forward(Z_ARRVAL_P(search));
    3675                 :                 }
    3676                 :         } else {
    3677           82233 :                 if (Z_STRLEN_P(search) == 1) {
    3678            3669 :                         php_char_to_str_ex(Z_STRVAL_PP(subject),
    3679                 :                                                         Z_STRLEN_PP(subject),
    3680                 :                                                         Z_STRVAL_P(search)[0],
    3681                 :                                                         Z_STRVAL_P(replace),
    3682                 :                                                         Z_STRLEN_P(replace),
    3683                 :                                                         result,
    3684                 :                                                         case_sensitivity,
    3685                 :                                                         replace_count);
    3686           78564 :                 } else if (Z_STRLEN_P(search) > 1) {
    3687           78510 :                         Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject),
    3688                 :                                                                                                         Z_STRVAL_P(search), Z_STRLEN_P(search),
    3689                 :                                                                                                         Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), case_sensitivity, replace_count);
    3690                 :                 } else {
    3691              54 :                         *result = **subject;
    3692              54 :                         zval_copy_ctor(result);
    3693              54 :                         INIT_PZVAL(result);
    3694                 :                 }
    3695                 :         }
    3696                 : }
    3697                 : /* }}} */
    3698                 : 
    3699                 : /* {{{ php_str_replace_common
    3700                 :  */
    3701                 : static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
    3702          104548 : {
    3703                 :         zval **subject, **search, **replace, **subject_entry, **zcount;
    3704                 :         zval *result;
    3705                 :         char *string_key;
    3706                 :         uint string_key_len;
    3707                 :         ulong num_key;
    3708          104548 :         int count = 0;
    3709          104548 :         int argc = ZEND_NUM_ARGS();
    3710                 : 
    3711          104548 :         if (argc < 3 || argc > 4 ||
    3712                 :            zend_get_parameters_ex(argc, &search, &replace, &subject, &zcount) == FAILURE) {
    3713              15 :                 WRONG_PARAM_COUNT;
    3714                 :         }
    3715                 : 
    3716          104533 :         SEPARATE_ZVAL(search);
    3717          104533 :         SEPARATE_ZVAL(replace);
    3718          104533 :         SEPARATE_ZVAL(subject);
    3719                 : 
    3720                 :         /* Make sure we're dealing with strings and do the replacement. */
    3721          104533 :         if (Z_TYPE_PP(search) != IS_ARRAY) {
    3722           82082 :                 convert_to_string_ex(search);
    3723           82082 :                 convert_to_string_ex(replace);
    3724           22451 :         } else if (Z_TYPE_PP(replace) != IS_ARRAY) {
    3725           22434 :                 convert_to_string_ex(replace);
    3726                 :         }
    3727                 : 
    3728                 :         /* if subject is an array */
    3729          104533 :         if (Z_TYPE_PP(subject) == IS_ARRAY) {
    3730              45 :                 array_init(return_value);
    3731              45 :                 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject));
    3732                 : 
    3733                 :                 /* For each subject entry, convert it to string, then perform replacement
    3734                 :                    and add the result to the return_value array. */
    3735             432 :                 while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) {
    3736             656 :                         if (Z_TYPE_PP(subject_entry) != IS_ARRAY && Z_TYPE_PP(subject_entry) != IS_OBJECT) {
    3737             314 :                                 MAKE_STD_ZVAL(result);
    3738             314 :                                 SEPARATE_ZVAL(subject_entry);
    3739             314 :                                 php_str_replace_in_subject(*search, *replace, subject_entry, result, case_sensitivity, (argc > 3) ? &count : NULL);
    3740                 :                         } else {
    3741              28 :                                 ALLOC_ZVAL(result);
    3742              28 :                                 ZVAL_ADDREF(*subject_entry);
    3743              28 :                                 COPY_PZVAL_TO_ZVAL(*result, *subject_entry);
    3744                 :                         }
    3745                 :                         /* Add to return array */
    3746                 :                         switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), &string_key,
    3747             342 :                                                                                                 &string_key_len, &num_key, 0, NULL)) {
    3748                 :                                 case HASH_KEY_IS_STRING:
    3749               4 :                                         add_assoc_zval_ex(return_value, string_key, string_key_len, result);
    3750               4 :                                         break;
    3751                 : 
    3752                 :                                 case HASH_KEY_IS_LONG:
    3753             338 :                                         add_index_zval(return_value, num_key, result);
    3754                 :                                         break;
    3755                 :                         }
    3756                 :                 
    3757             342 :                         zend_hash_move_forward(Z_ARRVAL_PP(subject));
    3758                 :                 }
    3759                 :         } else {        /* if subject is not an array */
    3760          104488 :                 php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? &count : NULL);
    3761                 :         }       
    3762          104533 :         if (argc > 3) {
    3763             134 :                 zval_dtor(*zcount);
    3764             134 :                 ZVAL_LONG(*zcount, count);
    3765                 :         }
    3766                 : }
    3767                 : /* }}} */
    3768                 : 
    3769                 : /* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count])
    3770                 :    Replaces all occurrences of search in haystack with replace */
    3771                 : PHP_FUNCTION(str_replace)
    3772          104521 : {
    3773          104521 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    3774          104521 : }
    3775                 : /* }}} */
    3776                 : 
    3777                 : /* {{{ proto mixed str_ireplace(mixed search, mixed replace, mixed subject [, int &replace_count])
    3778                 :    Replaces all occurrences of search in haystack with replace / case-insensitive */
    3779                 : PHP_FUNCTION(str_ireplace)
    3780              27 : {
    3781              27 :         php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    3782              27 : }
    3783                 : /* }}} */
    3784                 : 
    3785                 : /* {{{ php_hebrev
    3786                 :  *
    3787                 :  * Converts Logical Hebrew text (Hebrew Windows style) to Visual text
    3788                 :  * Cheers/complaints/flames - Zeev Suraski <zeev@php.net>
    3789                 :  */
    3790                 : static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
    3791             106 : {
    3792                 :         zval **str, **max_chars_per_line;
    3793                 :         char *heb_str, *tmp, *target, *broken_str;
    3794                 :         int block_start, block_end, block_type, block_length, i;
    3795             106 :         long max_chars=0;
    3796                 :         int begin, end, char_count, orig_begin;
    3797                 : 
    3798                 :         
    3799             106 :         switch (ZEND_NUM_ARGS()) {
    3800                 :                 case 1:
    3801              46 :                         if (zend_get_parameters_ex(1, &str) == FAILURE) {
    3802               0 :                                 RETURN_FALSE;
    3803                 :                         }
    3804              46 :                         break;
    3805                 :                 case 2:
    3806              56 :                         if (zend_get_parameters_ex(2, &str, &max_chars_per_line) == FAILURE) {
    3807               0 :                                 RETURN_FALSE;
    3808                 :                         }
    3809              56 :                         convert_to_long_ex(max_chars_per_line);
    3810              56 :                         max_chars = Z_LVAL_PP(max_chars_per_line);
    3811              56 :                         break;
    3812                 :                 default:
    3813               4 :                         WRONG_PARAM_COUNT;
    3814                 :                         break;
    3815                 :         }
    3816                 :         
    3817             102 :         convert_to_string_ex(str);
    3818                 :         
    3819             102 :         if (Z_STRLEN_PP(str) == 0) {
    3820              12 :                 RETURN_FALSE;
    3821                 :         }
    3822                 : 
    3823              90 :         tmp = Z_STRVAL_PP(str);
    3824              90 :         block_start=block_end=0;
    3825                 : 
    3826              90 :         heb_str = (char *) emalloc(Z_STRLEN_PP(str)+1);
    3827              90 :         target = heb_str+Z_STRLEN_PP(str);
    3828              90 :         *target = 0;
    3829              90 :         target--;
    3830                 : 
    3831              90 :         block_length=0;
    3832                 : 
    3833              90 :         if (isheb(*tmp)) {
    3834               0 :                 block_type = _HEB_BLOCK_TYPE_HEB;
    3835                 :         } else {
    3836              90 :                 block_type = _HEB_BLOCK_TYPE_ENG;
    3837                 :         }
    3838                 :         
    3839                 :         do {
    3840             380 :                 if (block_type == _HEB_BLOCK_TYPE_HEB) {
    3841             870 :                         while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<Z_STRLEN_PP(str)-1) {
    3842             522 :                                 tmp++;
    3843             522 :                                 block_end++;
    3844             522 :                                 block_length++;
    3845                 :                         }
    3846             696 :                         for (i = block_start; i<= block_end; i++) {
    3847             522 :                                 *target = Z_STRVAL_PP(str)[i];
    3848             522 :                                 switch (*target) {
    3849                 :                                         case '(':
    3850              29 :                                                 *target = ')';
    3851              29 :                                                 break;
    3852                 :                                         case ')':
    3853              29 :                                                 *target = '(';
    3854              29 :                                                 break;
    3855                 :                                         case '[':
    3856               0 :                                                 *target = ']';
    3857               0 :                                                 break;
    3858                 :                                         case ']':
    3859               0 :                                                 *target = '[';
    3860               0 :                                                 break;
    3861                 :                                         case '{':
    3862               0 :                                                 *target = '}';
    3863               0 :                                                 break;
    3864                 :                                         case '}':
    3865               0 :                                                 *target = '{';
    3866               0 :                                                 break;
    3867                 :                                         case '<':
    3868               0 :                                                 *target = '>';
    3869               0 :                                                 break;
    3870                 :                                         case '>':
    3871              29 :                                                 *target = '<';
    3872              29 :                                                 break;
    3873                 :                                         case '\\':
    3874               0 :                                                 *target = '/';
    3875               0 :                                                 break;
    3876                 :                                         case '/':
    3877               0 :                                                 *target = '\\';
    3878                 :                                                 break;
    3879                 :                                         default:
    3880                 :                                                 break;
    3881                 :                                 }
    3882             522 :                                 target--;
    3883                 :                         }
    3884             174 :                         block_type = _HEB_BLOCK_TYPE_ENG;
    3885                 :                 } else {
    3886            9463 :                         while (!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end < Z_STRLEN_PP(str)-1) {
    3887            9051 :                                 tmp++;
    3888            9051 :                                 block_end++;
    3889            9051 :                                 block_length++;
    3890                 :                         }
    3891             615 :                         while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
    3892             203 :                                 tmp--;
    3893             203 :                                 block_end--;
    3894                 :                         }
    3895            9144 :                         for (i = block_end; i >= block_start; i--) {
    3896            8938 :                                 *target = Z_STRVAL_PP(str)[i];
    3897            8938 :                                 target--;
    3898                 :                         }
    3899             206 :                         block_type = _HEB_BLOCK_TYPE_HEB;
    3900                 :                 }
    3901             380 :                 block_start=block_end+1;
    3902             380 :         } while (block_end < Z_STRLEN_PP(str)-1);
    3903                 : 
    3904                 : 
    3905              90 :         broken_str = (char *) emalloc(Z_STRLEN_PP(str)+1);
    3906              90 :         begin=end=Z_STRLEN_PP(str)-1;
    3907              90 :         target = broken_str;
    3908                 :                 
    3909                 :         while (1) {
    3910            1981 :                 char_count=0;
    3911           11546 :                 while ((!max_chars || char_count < max_chars) && begin > 0) {
    3912            7759 :                         char_count++;
    3913            7759 :                         begin--;
    3914            7759 :                         if (begin <= 0 || _isnewline(heb_str[begin])) {
    3915             350 :                                 while (begin > 0 && _isnewline(heb_str[begin-1])) {
    3916               0 :                                         begin--;
    3917               0 :                                         char_count++;
    3918                 :                                 }
    3919             175 :                                 break;
    3920                 :                         }
    3921                 :                 }
    3922            1981 :                 if (char_count == max_chars) { /* try to avoid breaking words */
    3923            1165 :                         int new_char_count=char_count, new_begin=begin;
    3924                 :                         
    3925            3701 :                         while (new_char_count > 0) {
    3926            1635 :                                 if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
    3927                 :                                         break;
    3928                 :                                 }
    3929            1371 :                                 new_begin++;
    3930            1371 :                                 new_char_count--;
    3931                 :                         }
    3932            1165 :                         if (new_char_count > 0) {
    3933             264 :                                 char_count=new_char_count;
    3934             264 :                                 begin=new_begin;
    3935                 :                         }
    3936                 :                 }
    3937            1981 :                 orig_begin=begin;
    3938                 :                 
    3939            1981 :                 if (_isblank(heb_str[begin])) {
    3940             343 :                         heb_str[begin]='\n';
    3941                 :                 }
    3942            4482 :                 while (begin <= end && _isnewline(heb_str[begin])) { /* skip leading newlines */
    3943             520 :                         begin++;
    3944                 :                 }
    3945           10921 :                 for (i = begin; i <= end; i++) { /* copy content */
    3946            8940 :                         *target = heb_str[i];
    3947            8940 :                         target++;
    3948                 :                 }
    3949            2501 :                 for (i = orig_begin; i <= end && _isnewline(heb_str[i]); i++) {
    3950             520 :                         *target = heb_str[i];
    3951             520 :                         target++;
    3952                 :                 }
    3953            1981 :                 begin=orig_begin;
    3954                 : 
    3955            1981 :                 if (begin <= 0) {
    3956              90 :                         *target = 0;
    3957                 :                         break;
    3958                 :                 }
    3959            1891 :                 begin--;
    3960            1891 :                 end=begin;
    3961            1891 :         }
    3962              90 :         efree(heb_str);
    3963                 : 
    3964              90 :         if (convert_newlines) {
    3965              45 :                 php_char_to_str(broken_str, Z_STRLEN_PP(str),'\n', "<br />\n", 7, return_value);
    3966              45 :                 efree(broken_str);
    3967                 :         } else {
    3968              45 :                 Z_STRVAL_P(return_value) = broken_str;
    3969              45 :                 Z_STRLEN_P(return_value) = Z_STRLEN_PP(str);
    3970              45 :                 Z_TYPE_P(return_value) = IS_STRING;
    3971                 :         }
    3972                 : }
    3973                 : /* }}} */
    3974                 : 
    3975                 : /* {{{ proto string hebrev(string str [, int max_chars_per_line])
    3976                 :    Converts logical Hebrew text to visual text */
    3977                 : PHP_FUNCTION(hebrev)
    3978              53 : {
    3979              53 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    3980              53 : }
    3981                 : /* }}} */
    3982                 : 
    3983                 : /* {{{ proto string hebrevc(string str [, int max_chars_per_line])
    3984                 :    Converts logical Hebrew text to visual text with newline conversion */
    3985                 : PHP_FUNCTION(hebrevc)
    3986              53 : {
    3987              53 :         php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    3988              53 : }
    3989                 : /* }}} */
    3990                 : 
    3991                 : /* {{{ proto string nl2br(string str)
    3992                 :    Converts newlines to HTML line breaks */
    3993                 : PHP_FUNCTION(nl2br)
    3994              60 : {
    3995                 :         /* in brief this inserts <br /> before matched regexp \n\r?|\r\n? */
    3996                 :         zval    **zstr;
    3997                 :         char    *tmp, *str;
    3998                 :         int     new_length;
    3999                 :         char    *end, *target;
    4000              60 :         int     repl_cnt = 0;
    4001                 : 
    4002              60 :         if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zstr) == FAILURE) {
    4003               2 :                 WRONG_PARAM_COUNT;
    4004                 :         }
    4005                 :         
    4006              58 :         convert_to_string_ex(zstr);
    4007                 : 
    4008              58 :         str = Z_STRVAL_PP(zstr);
    4009              58 :         end = str + Z_STRLEN_PP(zstr);
    4010                 :         
    4011                 :         /* it is really faster to scan twice and allocate mem once insted scanning once
    4012                 :            and constantly reallocing */
    4013             570 :         while (str < end) {
    4014             454 :                 if (*str == '\r') {
    4015              33 :                         if (*(str+1) == '\n') {
    4016              14 :                                 str++;
    4017                 :                         }
    4018              33 :                         repl_cnt++;
    4019             421 :                 } else if (*str == '\n') {
    4020              46 :                         if (*(str+1) == '\r') {
    4021              13 :                                 str++;
    4022                 :                         }
    4023              46 :                         repl_cnt++;
    4024                 :                 }
    4025                 :                 
    4026             454 :                 str++;
    4027                 :         }
    4028                 :         
    4029              58 :         if (repl_cnt == 0) {
    4030              35 :                 RETURN_STRINGL(Z_STRVAL_PP(zstr), Z_STRLEN_PP(zstr), 1);
    4031                 :         }
    4032                 : 
    4033              23 :         new_length = Z_STRLEN_PP(zstr) + repl_cnt * (sizeof("<br />") - 1);
    4034              23 :         tmp = target = emalloc(new_length + 1);
    4035                 : 
    4036              23 :         str = Z_STRVAL_PP(zstr);
    4037                 : 
    4038             303 :         while (str < end) {
    4039             257 :                 switch (*str) {
    4040                 :                         case '\r':
    4041                 :                         case '\n':
    4042              79 :                                 *target++ = '<';
    4043              79 :                                 *target++ = 'b';
    4044              79 :                                 *target++ = 'r';
    4045              79 :                                 *target++ = ' ';
    4046              79 :                                 *target++ = '/';
    4047              79 :                                 *target++ = '>';
    4048                 :                                 
    4049              79 :                                 if ((*str == '\r' && *(str+1) == '\n') || (*str == '\n' && *(str+1) == '\r')) {
    4050              27 :                                         *target++ = *str++;
    4051                 :                                 }
    4052                 :                                 /* lack of a break; is intentional */
    4053                 :                         default:
    4054             257 :                                 *target++ = *str;
    4055                 :                 }
    4056                 :         
    4057             257 :                 str++;
    4058                 :         }
    4059                 :         
    4060              23 :         *target = '\0';
    4061                 : 
    4062              23 :         RETURN_STRINGL(tmp, new_length, 0);
    4063                 : }
    4064                 : /* }}} */
    4065                 : 
    4066                 : /* {{{ proto string strip_tags(string str [, string allowable_tags])
    4067                 :    Strips HTML and PHP tags from a string */
    4068                 : PHP_FUNCTION(strip_tags)
    4069             182 : {
    4070                 :         char *buf;
    4071             182 :         zval **str, **allow=NULL;
    4072             182 :         char *allowed_tags=NULL;
    4073             182 :         int allowed_tags_len=0;
    4074                 :         size_t retval_len;
    4075                 : 
    4076             182 :         switch (ZEND_NUM_ARGS()) {
    4077                 :                 case 1:
    4078              65 :                         if (zend_get_parameters_ex(1, &str) == FAILURE) {
    4079               0 :                                 RETURN_FALSE;
    4080                 :                         }
    4081              65 :                         break;
    4082                 :                 case 2:
    4083             115 :                         if (zend_get_parameters_ex(2, &str, &allow) == FAILURE) {
    4084               0 :                                 RETURN_FALSE;
    4085                 :                         }
    4086             115 :                         convert_to_string_ex(allow);
    4087             115 :                         allowed_tags = Z_STRVAL_PP(allow);
    4088             115 :                         allowed_tags_len = Z_STRLEN_PP(allow);
    4089             115 :                         break;
    4090                 :                 default:
    4091               2 :                         WRONG_PARAM_COUNT;
    4092                 :                         break;
    4093                 :         }
    4094             180 :         convert_to_string_ex(str);
    4095             180 :         buf = estrndup(Z_STRVAL_PP(str), Z_STRLEN_PP(str));
    4096             180 :         retval_len = php_strip_tags_ex(buf, Z_STRLEN_PP(str), NULL, allowed_tags, allowed_tags_len, 0);
    4097             180 :         RETURN_STRINGL(buf, retval_len, 0);
    4098                 : }
    4099                 : /* }}} */
    4100                 : 
    4101                 : /* {{{ proto string setlocale(mixed category, string locale [, string ...])
    4102                 :    Set locale information */
    4103                 : PHP_FUNCTION(setlocale)
    4104             879 : {
    4105             879 :         zval ***args = (zval ***) safe_emalloc(sizeof(zval **), ZEND_NUM_ARGS(), 0);
    4106                 :         zval **pcategory, **plocale;
    4107             879 :         int i, cat, n_args=ZEND_NUM_ARGS();
    4108                 :         char *loc, *retval;
    4109                 : 
    4110             879 :         if (zend_get_parameters_array_ex(n_args, args) == FAILURE || n_args < 2) {
    4111               2 :                 efree(args);
    4112               2 :                 WRONG_PARAM_COUNT;
    4113                 :         }
    4114                 : #ifdef HAVE_SETLOCALE
    4115             877 :         pcategory = args[0];
    4116             877 :         if (Z_TYPE_PP(pcategory) == IS_LONG) {
    4117             876 :                 convert_to_long_ex(pcategory);  
    4118             876 :                 cat = Z_LVAL_PP(pcategory);
    4119                 :         } else { /* FIXME: The following behaviour should be removed. */
    4120                 :                 char *category;
    4121               1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passing locale category name as string is deprecated. Use the LC_* -constants instead");
    4122               1 :                 convert_to_string_ex(pcategory);
    4123               1 :                 category = Z_STRVAL_P(*pcategory);
    4124                 : 
    4125               1 :                 if (!strcasecmp ("LC_ALL", category))
    4126               0 :                         cat = LC_ALL;
    4127               1 :                 else if (!strcasecmp ("LC_COLLATE", category))
    4128               0 :                         cat = LC_COLLATE;
    4129               1 :                 else if (!strcasecmp ("LC_CTYPE", category))
    4130               0 :                         cat = LC_CTYPE;
    4131                 : #ifdef LC_MESSAGES
    4132               1 :                 else if (!strcasecmp ("LC_MESSAGES", category))
    4133               0 :                         cat = LC_MESSAGES;
    4134                 : #endif
    4135               1 :                 else if (!strcasecmp ("LC_MONETARY", category))
    4136               0 :                         cat = LC_MONETARY;
    4137               1 :                 else if (!strcasecmp ("LC_NUMERIC", category))
    4138               0 :                         cat = LC_NUMERIC;
    4139               1 :                 else if (!strcasecmp ("LC_TIME", category))
    4140               0 :                         cat = LC_TIME;
    4141                 :                 else {
    4142               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);
    4143               1 :                         efree(args);
    4144               1 :                         RETURN_FALSE;
    4145                 :                 }
    4146                 :         }
    4147                 : 
    4148             876 :         if (Z_TYPE_PP(args[1]) == IS_ARRAY) {
    4149               2 :                 zend_hash_internal_pointer_reset(Z_ARRVAL_PP(args[1]));
    4150               2 :                 i=0; /* not needed in this case: only kill a compiler warning */
    4151                 :         } else {
    4152             874 :                 i=1;
    4153                 :         }
    4154                 :         while (1) {
    4155             895 :                 if (Z_TYPE_PP(args[1]) == IS_ARRAY) {
    4156               5 :                         if (!zend_hash_num_elements(Z_ARRVAL_PP(args[1]))) {
    4157               0 :                                 break;
    4158                 :                         }
    4159               5 :                         zend_hash_get_current_data(Z_ARRVAL_PP(args[1]),(void **)&plocale);
    4160                 :                 } else {
    4161             890 :                         plocale = args[i];
    4162                 :                 }
    4163                 : 
    4164             895 :                 convert_to_string_ex(plocale);
    4165                 :                 
    4166             895 :                 if (!strcmp ("0", Z_STRVAL_PP(plocale))) {
    4167               5 :                         loc = NULL;
    4168                 :                 } else {
    4169             890 :                         loc = Z_STRVAL_PP(plocale);
    4170             890 :                         if (Z_STRLEN_PP(plocale) >= 255) {
    4171               0 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Specified locale name is too long");
    4172               0 :                                 break;
    4173                 :                         }
    4174                 :                 }
    4175                 : 
    4176             895 :                 retval = setlocale (cat, loc);
    4177                 :                 zend_update_current_locale();
    4178             895 :                 if (retval) {
    4179                 :                         /* Remember if locale was changed */
    4180             872 :                         if (loc) {
    4181             867 :                                 STR_FREE(BG(locale_string));
    4182             867 :                                 BG(locale_string) = estrdup(retval);
    4183                 :                         }
    4184                 :                         
    4185             872 :                         efree(args);
    4186             872 :                         RETVAL_STRING(retval, 1);
    4187                 :                         
    4188             872 :                         return;
    4189                 :                 }
    4190                 :                 
    4191              23 :                 if (Z_TYPE_PP(args[1]) == IS_ARRAY) {
    4192               4 :                         if (zend_hash_move_forward(Z_ARRVAL_PP(args[1])) == FAILURE) break;
    4193                 :                 } else {
    4194              19 :                         if (++i >= n_args) break;
    4195                 :                 }
    4196              19 :         }
    4197                 : 
    4198                 : #endif
    4199               4 :         efree(args);
    4200                 : 
    4201               4 :         RETURN_FALSE;
    4202                 : }
    4203                 : /* }}} */
    4204                 : 
    4205                 : /* {{{ proto void parse_str(string encoded_string [, array result])
    4206                 :    Parses GET/POST/COOKIE data and sets global variables */
    4207                 : PHP_FUNCTION(parse_str)
    4208              32 : {
    4209                 :         zval **arg;
    4210                 :         zval **arrayArg;
    4211                 :         zval *sarg;
    4212              32 :         char *res = NULL;
    4213                 :         int argCount;
    4214                 : 
    4215              32 :         argCount = ZEND_NUM_ARGS();
    4216              32 :         if (argCount < 1 || argCount > 2 || zend_get_parameters_ex(argCount, &arg, &arrayArg) == FAILURE) {
    4217               2 :                 WRONG_PARAM_COUNT;
    4218                 :         }
    4219                 : 
    4220              30 :         convert_to_string_ex(arg);
    4221              30 :         sarg = *arg;
    4222              30 :         if (Z_STRVAL_P(sarg) && *Z_STRVAL_P(sarg)) {
    4223              30 :                 res = estrndup(Z_STRVAL_P(sarg), Z_STRLEN_P(sarg));
    4224                 :         }
    4225                 : 
    4226              30 :         if (argCount == 1) {
    4227                 :                 zval tmp;
    4228              15 :                 Z_ARRVAL(tmp) = EG(active_symbol_table);
    4229                 : 
    4230              15 :                 sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
    4231                 :         } else  {
    4232                 :                 /* Clear out the array that was passed in. */
    4233              15 :                 zval_dtor(*arrayArg);
    4234              15 :                 array_init(*arrayArg);
    4235                 :                 
    4236              15 :                 sapi_module.treat_data(PARSE_STRING, res, *arrayArg TSRMLS_CC);
    4237                 :         }
    4238                 : }
    4239                 : /* }}} */
    4240                 : 
    4241                 : #define PHP_TAG_BUF_SIZE 1023
    4242                 : 
    4243                 : /* {{{ php_tag_find
    4244                 :  *
    4245                 :  * Check if tag is in a set of tags 
    4246                 :  *
    4247                 :  * states:
    4248                 :  * 
    4249                 :  * 0 start tag
    4250                 :  * 1 first non-whitespace char seen
    4251                 :  */
    4252             541 : int php_tag_find(char *tag, int len, char *set) {
    4253                 :         char c, *n, *t;
    4254             541 :         int state=0, done=0;
    4255                 :         char *norm;
    4256                 : 
    4257             541 :         if (len <= 0) {
    4258               0 :                 return 0;
    4259                 :         }
    4260                 :         
    4261             541 :         norm = emalloc(len+1);
    4262                 : 
    4263             541 :         n = norm;
    4264             541 :         t = tag;
    4265             541 :         c = tolower(*t);
    4266                 :         /* 
    4267                 :            normalize the tag removing leading and trailing whitespace
    4268                 :            and turn any <a whatever...> into just <a> and any </tag>
    4269                 :            into <tag>
    4270                 :         */
    4271            3754 :         while (!done) {
    4272            2672 :                 switch (c) {
    4273                 :                         case '<':
    4274             540 :                                 *(n++) = c;
    4275             540 :                                 break;
    4276                 :                         case '>':
    4277             522 :                                 done =1;
    4278             522 :                                 break;
    4279                 :                         default:
    4280            1610 :                                 if (!isspace((int)c)) {
    4281            1589 :                                         if (state == 0) {
    4282             540 :                                                 state=1;
    4283             540 :                                                 if (c != '/')
    4284             282 :                                                         *(n++) = c;
    4285                 :                                         } else {
    4286            1049 :                                                 *(n++) = c;
    4287                 :                                         }
    4288                 :                                 } else {
    4289              21 :                                         if (state == 1)
    4290              19 :                                                 done=1;
    4291                 :                                 }
    4292                 :                                 break;
    4293                 :                 }
    4294            2672 :                 c = tolower(*(++t));
    4295                 :         }  
    4296             541 :         *(n++) = '>';
    4297             541 :         *n = '\0'; 
    4298             541 :         if (strstr(set, norm)) {
    4299             141 :                 done=1;
    4300                 :         } else {
    4301             400 :                 done=0;
    4302                 :         }
    4303             541 :         efree(norm);
    4304             541 :         return done;
    4305                 : }
    4306                 : /* }}} */
    4307                 : 
    4308                 : PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, int allow_len) /* {{{ */
    4309             230 : {
    4310             230 :         return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0);
    4311                 : }
    4312                 : /* }}} */
    4313                 : 
    4314                 : /* {{{ php_strip_tags
    4315                 :  
    4316                 :         A simple little state-machine to strip out html and php tags 
    4317                 :         
    4318                 :         State 0 is the output state, State 1 means we are inside a
    4319                 :         normal html tag and state 2 means we are inside a php tag.
    4320                 : 
    4321                 :         The state variable is passed in to allow a function like fgetss
    4322                 :         to maintain state across calls to the function.
    4323                 : 
    4324                 :         lc holds the last significant character read and br is a bracket
    4325                 :         counter.
    4326                 : 
    4327                 :         When an allow string is passed in we keep track of the string
    4328                 :         in state 1 and when the tag is closed check it against the
    4329                 :         allow string to see if we should allow it.
    4330                 : 
    4331                 :         swm: Added ability to strip <?xml tags without assuming it PHP
    4332                 :         code.
    4333                 : */
    4334                 : PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow, int allow_len, zend_bool allow_tag_spaces)
    4335             715 : {
    4336                 :         char *tbuf, *buf, *p, *tp, *rp, c, lc;
    4337             715 :         int br, i=0, depth=0, in_q = 0;
    4338             715 :         int state = 0;
    4339                 : 
    4340             715 :         if (stateptr)
    4341             230 :                 state = *stateptr;
    4342                 : 
    4343             715 :         buf = estrndup(rbuf, len);
    4344             715 :         c = *buf;
    4345             715 :         lc = '\0';
    4346             715 :         p = buf;
    4347             715 :         rp = rbuf;
    4348             715 :         br = 0;
    4349             715 :         if (allow) {
    4350             283 :                 php_strtolower(allow, allow_len);
    4351             283 :                 tbuf = emalloc(PHP_TAG_BUF_SIZE+1);
    4352             283 :                 tp = tbuf;
    4353                 :         } else {
    4354             432 :                 tbuf = tp = NULL;
    4355                 :         }
    4356                 : 
    4357           19714 :         while (i < len) {
    4358           18284 :                 switch (c) {
    4359                 :                         case '\0':
    4360               2 :                                 break;
    4361                 :                         case '<':
    4362             914 :                                 if (in_q) {
    4363               3 :                                         break;
    4364                 :                                 }
    4365             911 :                                 if (isspace(*(p + 1)) && !allow_tag_spaces) {
    4366               5 :                                         goto reg_char;
    4367                 :                                 }
    4368             906 :                                 if (state == 0) {
    4369             882 :                                         lc = '<';
    4370             882 :                                         state = 1;
    4371             882 :                                         if (allow) {
    4372             649 :                                                 tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
    4373             649 :                                                 *(tp++) = '<';
    4374                 :                                         }
    4375              24 :                                 } else if (state == 1) {
    4376              20 :                                         depth++;
    4377                 :                                 }
    4378             906 :                                 break;
    4379                 : 
    4380                 :                         case '(':
    4381              63 :                                 if (state == 2) {
    4382               0 :                                         if (lc != '"' && lc != '\'') {
    4383               0 :                                                 lc = '(';
    4384               0 :                                                 br++;
    4385                 :                                         }
    4386              64 :                                 } else if (allow && state == 1) {
    4387               1 :                                         tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
    4388               1 :                                         *(tp++) = c;
    4389              62 :                                 } else if (state == 0) {
    4390              61 :                                         *(rp++) = c;
    4391                 :                                 }
    4392              63 :                                 break;  
    4393                 : 
    4394                 :                         case ')':
    4395              63 :                                 if (state == 2) {
    4396               0 :                                         if (lc != '"' && lc != '\'') {
    4397               0 :                                                 lc = ')';
    4398               0 :                                                 br--;
    4399                 :                                         }
    4400              64 :                                 } else if (allow && state == 1) {
    4401               1 :                                         tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
    4402               1 :                                         *(tp++) = c;
    4403              62 :                                 } else if (state == 0) {
    4404              61 :                                         *(rp++) = c;
    4405                 :                                 }
    4406              63 :                                 break;  
    4407                 : 
    4408                 :                         case '>':
    4409             909 :                                 if (depth) {
    4410              20 :                                         depth--;
    4411              20 :                                         break;
    4412                 :                                 }
    4413                 : 
    4414             889 :                                 if (in_q) {
    4415               4 :                                         break;
    4416                 :                                 }
    4417                 : 
    4418             885 :                                 switch (state) {
    4419                 :                                         case 1: /* HTML/XML */
    4420             748 :                                                 lc = '>';
    4421             748 :                                                 in_q = state = 0;
    4422             748 :                                                 if (allow) {
    4423             541 :                                                         tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
    4424             541 :                                                         *(tp++) = '>';
    4425             541 :                                                         *tp='\0';
    4426             541 :                                                         if (php_tag_find(tbuf, tp-tbuf, allow)) {
    4427             141 :                                                                 memcpy(rp, tbuf, tp-tbuf);
    4428             141 :                                                                 rp += tp-tbuf;
    4429                 :                                                         }
    4430             541 :                                                         tp = tbuf;
    4431                 :                                                 }
    4432             748 :                                                 break;
    4433                 :                                                 
    4434                 :                                         case 2: /* PHP */
    4435              95 :                                                 if (!br && lc != '\"' && *(p-1) == '?') {
    4436              90 :                                                         in_q = state = 0;
    4437              90 :                                                         tp = tbuf;
    4438                 :                                                 }
    4439              95 :                                                 break;
    4440                 :                                                 
    4441                 :                                         case 3:
    4442               0 :                                                 in_q = state = 0;
    4443               0 :                                                 tp = tbuf;
    4444               0 :                                                 break;
    4445                 : 
    4446                 :                                         case 4: /* JavaScript/CSS/etc... */
    4447              35 :                                                 if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') {
    4448              34 :                                                         in_q = state = 0;
    4449              34 :                                                         tp = tbuf;
    4450                 :                                                 }
    4451              35 :                                                 break;
    4452                 : 
    4453                 :                                         default:
    4454               7 :                                                 *(rp++) = c;
    4455                 :                                                 break;
    4456                 :                                 }
    4457             885 :                                 break;
    4458                 : 
    4459                 :                         case '"':
    4460                 :                         case '\'':
    4461             229 :                                 if (state == 2 && *(p-1) != '\\') {
    4462              62 :                                         if (lc == c) {
    4463              31 :                                                 lc = '\0';
    4464              31 :                                         } else if (lc != '\\') {
    4465              31 :                                                 lc = c;
    4466                 :                                         }
    4467             105 :                                 } else if (state == 0) {
    4468              16 :                                         *(rp++) = c;
    4469              89 :                                 } else if (allow && state == 1) {
    4470              27 :                                         tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
    4471              27 :                                         *(tp++) = c;
    4472                 :                                 }
    4473             167 :                                 if (state && p != buf && *(p-1) != '\\' && (!in_q || *p == in_q)) {
    4474             144 :                                         if (in_q) {
    4475              71 :                                                 in_q = 0;
    4476                 :                                         } else {
    4477              73 :                                                 in_q = *p;
    4478                 :                                         }
    4479                 :                                 }
    4480             167 :                                 break;
    4481                 :                         
    4482                 :                         case '!': 
    4483                 :                                 /* JavaScript & Other HTML scripting languages */
    4484             100 :                                 if (state == 1 && *(p-1) == '<') { 
    4485              37 :                                         state = 3;
    4486              37 :                                         lc = c;
    4487                 :                                 } else {
    4488              26 :                                         if (state == 0) {
    4489              20 :                                                 *(rp++) = c;
    4490               6 :                                         } else if (allow && state == 1) {
    4491               6 :                                                 tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
    4492               6 :                                                 *(tp++) = c;
    4493                 :                                         }
    4494                 :                                 }
    4495              63 :                                 break;
    4496                 : 
    4497                 :                         case '-':
    4498             156 :                                 if (state == 3 && p >= buf + 2 && *(p-1) == '-' && *(p-2) == '!') {
    4499              34 :                                         state = 4;
    4500                 :                                 } else {
    4501                 :                                         goto reg_char;
    4502                 :                                 }
    4503              34 :                                 break;
    4504                 : 
    4505                 :                         case '?':
    4506                 : 
    4507             201 :                                 if (state == 1 && *(p-1) == '<') { 
    4508              92 :                                         br=0;
    4509              92 :                                         state=2;
    4510              92 :                                         break;
    4511                 :                                 }
    4512                 : 
    4513                 :                         case 'E':
    4514                 :                         case 'e':
    4515                 :                                 /* !DOCTYPE exception */
    4516            1060 :                                 if (state==3 && p > buf+6
    4517                 :                                                      && tolower(*(p-1)) == 'p'
    4518                 :                                                  && tolower(*(p-2)) == 'y'
    4519                 :                                                      && tolower(*(p-3)) == 't'
    4520                 :                                                      && tolower(*(p-4)) == 'c'
    4521                 :                                                      && tolower(*(p-5)) == 'o'
    4522                 :                                                      && tolower(*(p-6)) == 'd') {
    4523               3 :                                         state = 1;
    4524               3 :                                         break;
    4525                 :                                 }
    4526                 :                                 /* fall-through */
    4527                 : 
    4528                 :                         case 'l':
    4529                 :                         case 'L':
    4530                 : 
    4531                 :                                 /* swm: If we encounter '<?xml' then we shouldn't be in
    4532                 :                                  * state == 2 (PHP). Switch back to HTML.
    4533                 :                                  */
    4534                 : 
    4535            1832 :                                 if (state == 2 && p > buf+2 && strncasecmp(p-2, "xm", 2) == 0) {
    4536               2 :                                         state = 1;
    4537               2 :                                         break;
    4538                 :                                 }
    4539                 : 
    4540                 :                                 /* fall-through */
    4541                 :                         default:
    4542           15977 : reg_char:
    4543           15977 :                                 if (state == 0) {
    4544           10242 :                                         *(rp++) = c;
    4545            5735 :                                 } else if (allow && state == 1) {
    4546            1914 :                                         tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
    4547            1914 :                                         *(tp++) = c;
    4548                 :                                 } 
    4549                 :                                 break;
    4550                 :                 }
    4551           18284 :                 c = *(++p);
    4552           18284 :                 i++;
    4553                 :         }       
    4554             715 :         if (rp < rbuf + len) {
    4555             251 :                 *rp = '\0';
    4556                 :         }
    4557             715 :         efree(buf);
    4558             715 :         if (allow)
    4559             283 :                 efree(tbuf);
    4560             715 :         if (stateptr)
    4561             230 :                 *stateptr = state;
    4562                 : 
    4563             715 :         return (size_t)(rp - rbuf);
    4564                 : }
    4565                 : /* }}} */
    4566                 : 
    4567                 : /* {{{ proto string str_repeat(string input, int mult)
    4568                 :    Returns the input string repeat mult times */
    4569                 : PHP_FUNCTION(str_repeat)
    4570          146851 : {
    4571                 :         zval            **input_str;            /* Input string */
    4572                 :         zval            **mult;                 /* Multiplier */
    4573                 :         char            *result;                /* Resulting string */
    4574                 :         size_t          result_len;             /* Length of the resulting string */
    4575                 :         
    4576          146851 :         if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &input_str, &mult) == FAILURE) {
    4577               3 :                 WRONG_PARAM_COUNT;
    4578                 :         }
    4579                 :         
    4580                 :         /* Make sure we're dealing with proper types */
    4581          146848 :         convert_to_string_ex(input_str);
    4582          146848 :         convert_to_long_ex(mult);
    4583                 :         
    4584          146848 :         if (Z_LVAL_PP(mult) < 0) {
    4585               1 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be greater than or equal to 0");
    4586               1 :                 return;
    4587                 :         }
    4588                 : 
    4589                 :         /* Don't waste our time if it's empty */
    4590          146847 :         if (Z_STRLEN_PP(input_str) == 0)
    4591              30 :                 RETURN_STRINGL("", 0, 1);
    4592                 :         
    4593                 :         /* ... or if the multiplier is zero */
    4594          146817 :         if (Z_LVAL_PP(mult) == 0)
    4595              83 :                 RETURN_STRINGL("", 0, 1);
    4596                 :         
    4597                 :         /* Initialize the result string */      
    4598          146734 :         result_len = Z_STRLEN_PP(input_str) * Z_LVAL_PP(mult);
    4599          146734 :         result = (char *)safe_emalloc(Z_STRLEN_PP(input_str), Z_LVAL_PP(mult), 1);
    4600                 :         
    4601                 :         /* Heavy optimization for situations where input string is 1 byte long */
    4602          146734 :         if (Z_STRLEN_PP(input_str) == 1) {
    4603          145526 :                 memset(result, *(Z_STRVAL_PP(input_str)), Z_LVAL_PP(mult)); 
    4604                 :         } else {
    4605                 :                 char *s, *e, *ee;
    4606            1208 :                 int l=0;
    4607            1208 :                 memcpy(result, Z_STRVAL_PP(input_str), Z_STRLEN_PP(input_str));
    4608            1208 :                 s = result;
    4609            1208 :                 e = result + Z_STRLEN_PP(input_str);
    4610            1208 :                 ee = result + result_len;
    4611                 :                 
    4612           10986 :                 while (e<ee) {
    4613            8570 :                         l = (e-s) < (ee-e) ? (e-s) : (ee-e);
    4614            8570 :                         memmove(e, s, l);
    4615            8570 :                         e += l;
    4616                 :                 }
    4617                 :         }
    4618                 : 
    4619          146734 :         result[result_len] = '\0';
    4620                 :         
    4621          146734 :         RETURN_STRINGL(result, result_len, 0);
    4622                 : }
    4623                 : /* }}} */
    4624                 : 
    4625                 : /* {{{ proto mixed count_chars(string input [, int mode])
    4626                 :    Returns info about what characters are used in input */
    4627                 : PHP_FUNCTION(count_chars)
    4628              60 : {
    4629                 :         zval **input, **mode;
    4630                 :         int chars[256];
    4631              60 :         int ac=ZEND_NUM_ARGS();
    4632              60 :         int mymode=0;
    4633                 :         unsigned char *buf;
    4634                 :         int len, inx;
    4635                 :         char retstr[256];
    4636              60 :         int retlen=0;
    4637                 : 
    4638              60 :         if (ac < 1 || ac > 2 || zend_get_parameters_ex(ac, &input, &mode) == FAILURE) {
    4639               2 :                 WRONG_PARAM_COUNT;
    4640                 :         }
    4641                 :         
    4642              58 :         convert_to_string_ex(input);
    4643                 : 
    4644              58 :         if (ac == 2) {
    4645              57 :                 convert_to_long_ex(mode);
    4646              57 :                 mymode = Z_LVAL_PP(mode);
    4647                 :                 
    4648              57 :                 if (mymode < 0 || mymode > 4) {
    4649               7 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown mode");
    4650               7 :                         RETURN_FALSE;
    4651                 :                 }
    4652                 :         }
    4653                 :         
    4654              51 :         len = Z_STRLEN_PP(input);
    4655              51 :         buf = (unsigned char *) Z_STRVAL_PP(input);
    4656              51 :         memset((void*) chars, 0, sizeof(chars));
    4657                 : 
    4658            1769 :         while (len > 0) {
    4659            1667 :                 chars[*buf]++;
    4660            1667 :                 buf++;
    4661            1667 :                 len--;
    4662                 :         }
    4663                 : 
    4664              51 :         if (mymode < 3) {
    4665              47 :                 array_init(return_value);
    4666                 :         }
    4667                 : 
    4668           13107 :         for (inx = 0; inx < 256; inx++) {
    4669           13056 :                 switch (mymode) {
    4670                 :                         case 0:
    4671            3584 :                                 add_index_long(return_value, inx, chars[inx]);
    4672            3584 :                                 break;
    4673                 :                         case 1:
    4674            7936 :                                 if (chars[inx] != 0) {
    4675             240 :                                         add_index_long(return_value, inx, chars[inx]);
    4676                 :                                 }
    4677            7936 :                                 break;
    4678                 :                         case 2:
    4679             512 :                                 if (chars[inx] == 0) {
    4680             475 :                                         add_index_long(return_value, inx, chars[inx]);
    4681                 :                                 }
    4682             512 :                                 break;
    4683                 :                         case 3:
    4684             512 :                                 if (chars[inx] != 0) {
    4685              37 :                                         retstr[retlen++] = inx;
    4686                 :                                 }
    4687             512 :                                 break;
    4688                 :                         case 4:
    4689             512 :                                 if (chars[inx] == 0) {
    4690             475 :                                         retstr[retlen++] = inx;
    4691                 :                                 }
    4692                 :                                 break;
    4693                 :                 }
    4694                 :         }
    4695                 :         
    4696              51 :         if (mymode >= 3 && mymode <= 4) {
    4697               4 :                 RETURN_STRINGL(retstr, retlen, 1);
    4698                 :         }
    4699                 : }
    4700                 : /* }}} */
    4701                 : 
    4702                 : /* {{{ php_strnatcmp
    4703                 :  */
    4704                 : static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
    4705              48 : {
    4706                 :         zval **s1, **s2;
    4707                 : 
    4708              48 :         if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
    4709               4 :                 WRONG_PARAM_COUNT;
    4710                 :         }
    4711                 : 
    4712              44 :         convert_to_string_ex(s1);
    4713              44 :         convert_to_string_ex(s2);
    4714                 : 
    4715              44 :         RETURN_LONG(strnatcmp_ex(Z_STRVAL_PP(s1), Z_STRLEN_PP(s1),
    4716                 :                                                          Z_STRVAL_PP(s2), Z_STRLEN_PP(s2),
    4717                 :                                                          fold_case));
    4718                 : }
    4719                 : /* }}} */
    4720                 : 
    4721                 : /* {{{ proto int strnatcmp(string s1, string s2)
    4722                 :    Returns the result of string comparison using 'natural' algorithm */
    4723                 : PHP_FUNCTION(strnatcmp)
    4724              27 : {
    4725              27 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    4726              27 : }
    4727                 : /* }}} */
    4728                 : 
    4729                 : /* {{{ proto array localeconv(void)
    4730                 :    Returns numeric formatting information based on the current locale */
    4731                 : PHP_FUNCTION(localeconv)
    4732              11 : {
    4733                 :         zval *grouping, *mon_grouping;
    4734                 :         int len, i;
    4735                 : 
    4736                 :         /* We don't need no stinkin' parameters... */
    4737              11 :         if (ZEND_NUM_ARGS() > 0) {
    4738               0 :                 WRONG_PARAM_COUNT;
    4739                 :         }
    4740                 : 
    4741              11 :         MAKE_STD_ZVAL(grouping);
    4742              11 :         MAKE_STD_ZVAL(mon_grouping);
    4743                 : 
    4744              11 :         array_init(return_value);
    4745              11 :         array_init(grouping);
    4746              11 :         array_init(mon_grouping);
    4747                 : 
    4748                 : #ifdef HAVE_LOCALECONV
    4749                 :         {
    4750                 :                 struct lconv currlocdata;
    4751                 : 
    4752              11 :                 localeconv_r( &currlocdata );
    4753                 :    
    4754                 :                 /* Grab the grouping data out of the array */
    4755              11 :                 len = strlen(currlocdata.grouping);
    4756                 : 
    4757              33 :                 for (i = 0; i < len; i++) {
    4758              22 :                         add_index_long(grouping, i, currlocdata.grouping[i]);
    4759                 :                 }
    4760                 : 
    4761                 :                 /* Grab the monetary grouping data out of the array */
    4762              11 :                 len = strlen(currlocdata.mon_grouping);
    4763                 : 
    4764              31 :                 for (i = 0; i < len; i++) {
    4765              20 :                         add_index_long(mon_grouping, i, currlocdata.mon_grouping[i]);
    4766                 :                 }
    4767                 : 
    4768              11 :                 add_assoc_string(return_value, "decimal_point",     currlocdata.decimal_point,     1);
    4769              11 :                 add_assoc_string(return_value, "thousands_sep",     currlocdata.thousands_sep,     1);
    4770              11 :                 add_assoc_string(return_value, "int_curr_symbol",   currlocdata.int_curr_symbol,   1);
    4771              11 :                 add_assoc_string(return_value, "currency_symbol",   currlocdata.currency_symbol,   1);
    4772              11 :                 add_assoc_string(return_value, "mon_decimal_point", currlocdata.mon_decimal_point, 1);
    4773              11 :                 add_assoc_string(return_value, "mon_thousands_sep", currlocdata.mon_thousands_sep, 1);
    4774              11 :                 add_assoc_string(return_value, "positive_sign",     currlocdata.positive_sign,     1);
    4775              11 :                 add_assoc_string(return_value, "negative_sign",     currlocdata.negative_sign,     1);
    4776              11 :                 add_assoc_long(  return_value, "int_frac_digits",   currlocdata.int_frac_digits     );
    4777              11 :                 add_assoc_long(  return_value, "frac_digits",       currlocdata.frac_digits         );
    4778              11 :                 add_assoc_long(  return_value, "p_cs_precedes",     currlocdata.p_cs_precedes       );
    4779              11 :                 add_assoc_long(  return_value, "p_sep_by_space",    currlocdata.p_sep_by_space      );
    4780              11 :                 add_assoc_long(  return_value, "n_cs_precedes",     currlocdata.n_cs_precedes       );
    4781              11 :                 add_assoc_long(  return_value, "n_sep_by_space",    currlocdata.n_sep_by_space      );
    4782              11 :                 add_assoc_long(  return_value, "p_sign_posn",       currlocdata.p_sign_posn         );
    4783              11 :                 add_assoc_long(  return_value, "n_sign_posn",       currlocdata.n_sign_posn         );
    4784                 :         }
    4785                 : #else
    4786                 :         /* Ok, it doesn't look like we have locale info floating around, so I guess it
    4787                 :            wouldn't hurt to just go ahead and return the POSIX locale information?  */
    4788                 : 
    4789                 :         add_index_long(grouping, 0, -1);
    4790                 :         add_index_long(mon_grouping, 0, -1);
    4791                 : 
    4792                 :         add_assoc_string(return_value, "decimal_point",     "\x2E", 1);
    4793                 :         add_assoc_string(return_value, "thousands_sep",     "",     1);
    4794                 :         add_assoc_string(return_value, "int_curr_symbol",   "",     1);
    4795                 :         add_assoc_string(return_value, "currency_symbol",   "",     1);
    4796                 :         add_assoc_string(return_value, "mon_decimal_point", "\x2E", 1);
    4797                 :         add_assoc_string(return_value, "mon_thousands_sep", "",     1);
    4798                 :         add_assoc_string(return_value, "positive_sign",     "",     1);
    4799                 :         add_assoc_string(return_value, "negative_sign",     "",     1);
    4800                 :         add_assoc_long(  return_value, "int_frac_digits",   CHAR_MAX );
    4801                 :         add_assoc_long(  return_value, "frac_digits",       CHAR_MAX );
    4802                 :         add_assoc_long(  return_value, "p_cs_precedes",     CHAR_MAX );
    4803                 :         add_assoc_long(  return_value, "p_sep_by_space",    CHAR_MAX );
    4804                 :         add_assoc_long(  return_value, "n_cs_precedes",     CHAR_MAX );
    4805                 :         add_assoc_long(  return_value, "n_sep_by_space",    CHAR_MAX );
    4806                 :         add_assoc_long(  return_value, "p_sign_posn",       CHAR_MAX );
    4807                 :         add_assoc_long(  return_value, "n_sign_posn",       CHAR_MAX );
    4808                 : #endif
    4809                 : 
    4810              11 :         zend_hash_update(Z_ARRVAL_P(return_value), "grouping", 9, &grouping, sizeof(zval *), NULL);
    4811              11 :         zend_hash_update(Z_ARRVAL_P(return_value), "mon_grouping", 13, &mon_grouping, sizeof(zval *), NULL);
    4812                 : }
    4813                 : /* }}} */
    4814                 : 
    4815                 : /* {{{ proto int strnatcasecmp(string s1, string s2)
    4816                 :    Returns the result of case-insensitive string comparison using 'natural' algorithm */
    4817                 : PHP_FUNCTION(strnatcasecmp)
    4818              21 : {
    4819              21 :         php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    4820              21 : }
    4821                 : /* }}} */
    4822                 : 
    4823                 : /* {{{ proto int substr_count(string haystack, string needle [, int offset [, int length]])
    4824                 :    Returns the number of times a substring occurs in the string */
    4825                 : PHP_FUNCTION(substr_count)
    4826              47 : {
    4827                 :         zval **haystack, **needle, **offset, **length;
    4828              47 :         int ac = ZEND_NUM_ARGS();
    4829              47 :         int count = 0;
    4830                 :         char *p, *endp, cmp;
    4831                 : 
    4832              47 :         if (ac < 2 || ac > 4 || zend_get_parameters_ex(ac, &haystack, &needle, &offset, &length) == FAILURE) {
    4833               2 :                 WRONG_PARAM_COUNT;
    4834                 :         }
    4835                 : 
    4836              45 :         convert_to_string_ex(haystack);
    4837              45 :         convert_to_string_ex(needle);
    4838                 : 
    4839              45 :         if (Z_STRLEN_PP(needle) == 0) {
    4840               2 :                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring");
    4841               2 :                 RETURN_FALSE;
    4842                 :         }
    4843                 :         
    4844              43 :         p = Z_STRVAL_PP(haystack);
    4845              43 :         endp = p + Z_STRLEN_PP(haystack);
    4846                 :         
    4847              43 :         if (ac > 2) {
    4848              20 :                 convert_to_long_ex(offset);
    4849              20 :                 if (Z_LVAL_PP(offset) < 0) {
    4850               1 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset should be greater than or equal to 0");
    4851               1 :                         RETURN_FALSE;           
    4852                 :                 }
    4853                 : 
    4854              19 :                 if (Z_LVAL_PP(offset) > Z_STRLEN_PP(haystack)) {
    4855               4 :                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length", Z_LVAL_PP(offset));
    4856               4 :                         RETURN_FALSE;           
    4857                 :                 }
    4858              15 :                 p += Z_LVAL_PP(offset);
    4859                 : 
    4860              15 :                 if (ac == 4) {
    4861               8 :                         convert_to_long_ex(length);
    4862               8 :                         if (Z_LVAL_PP(length) <= 0) {
    4863               2 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length should be greater than 0");
    4864               2 :                                 RETURN_FALSE;           
    4865                 :                         }
    4866               6 :                         if (Z_LVAL_PP(length) > (Z_STRLEN_PP(haystack) - Z_LVAL_PP(offset))) {
    4867               1 :                                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length value %ld exceeds string length", Z_LVAL_PP(length));
    4868               1 :                                 RETURN_FALSE;
    4869                 :