Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 6cd6a74c5a
Fetching contributors…

Cannot retrieve contributors at this time

5391 lines (4704 sloc) 129.59 kb
<
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2012 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Rasmus Lerdorf <rasmus@php.net> |
| Stig Sæther Bakken <ssb@php.net> |
| Zeev Suraski <zeev@zend.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
/* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */
#include <stdio.h>
#include "php.h"
#include "php_rand.h"
#include "php_string.h"
#include "php_variables.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#ifdef HAVE_LANGINFO_H
# include <langinfo.h>
#endif
#ifdef HAVE_MONETARY_H
# include <monetary.h>
#endif
/*
* This define is here because some versions of libintl redefine setlocale
* to point to libintl_setlocale. That's a ridiculous thing to do as far
* as I am concerned, but with this define and the subsequent undef we
* limit the damage to just the actual setlocale() call in this file
* without turning zif_setlocale into zif_libintl_setlocale. -Rasmus
*/
#define php_my_setlocale setlocale
#ifdef HAVE_LIBINTL
# include <libintl.h> /* For LC_MESSAGES */
#ifdef setlocale
# undef setlocale
#endif
#endif
#include "scanf.h"
#include "zend_API.h"
#include "zend_execute.h"
#include "php_globals.h"
#include "basic_functions.h"
#include "php_smart_str.h"
#ifdef ZTS
#include "TSRM.h"
#endif
/* For str_getcsv() support */
#include "ext/standard/file.h"
#define STR_PAD_LEFT 0
#define STR_PAD_RIGHT 1
#define STR_PAD_BOTH 2
#define PHP_PATHINFO_DIRNAME 1
#define PHP_PATHINFO_BASENAME 2
#define PHP_PATHINFO_EXTENSION 4
#define PHP_PATHINFO_FILENAME 8
#define PHP_PATHINFO_ALL (PHP_PATHINFO_DIRNAME | PHP_PATHINFO_BASENAME | PHP_PATHINFO_EXTENSION | PHP_PATHINFO_FILENAME)
#define STR_STRSPN 0
#define STR_STRCSPN 1
/* {{{ register_string_constants
*/
void register_string_constants(INIT_FUNC_ARGS)
{
REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT);
#ifdef HAVE_LOCALECONV
/* If last members of struct lconv equal CHAR_MAX, no grouping is done */
/* This is bad, but since we are going to be hardcoding in the POSIX stuff anyway... */
# ifndef HAVE_LIMITS_H
# define CHAR_MAX 127
# endif
REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef HAVE_LOCALE_H
REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT);
# ifdef LC_MESSAGES
REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
# endif
#endif
}
/* }}} */
int php_tag_find(char *tag, int len, char *set);
/* this is read-only, so it's ok */
static char hexconvtab[] = "0123456789abcdef";
/* localeconv mutex */
#ifdef ZTS
static MUTEX_T locale_mutex = NULL;
#endif
/* {{{ php_bin2hex
*/
static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *newlen)
{
register unsigned char *result = NULL;
size_t i, j;
result = (unsigned char *) safe_emalloc(oldlen, 2 * sizeof(char), 1);
for (i = j = 0; i < oldlen; i++) {
result[j++] = hexconvtab[old[i] >> 4];
result[j++] = hexconvtab[old[i] & 15];
}
result[j] = '\0';
if (newlen)
*newlen = oldlen * 2 * sizeof(char);
return (char *)result;
}
/* }}} */
/* {{{ php_hex2bin
*/
static char *php_hex2bin(const unsigned char *old, const size_t oldlen, size_t *newlen)
{
size_t target_length = oldlen >> 1;
register unsigned char *str = (unsigned char *)safe_emalloc(target_length, sizeof(char), 1);
size_t i, j;
for (i = j = 0; i < target_length; i++) {
char c = old[j++];
if (c >= '0' && c <= '9') {
str[i] = (c - '0') << 4;
} else if (c >= 'a' && c <= 'f') {
str[i] = (c - 'a' + 10) << 4;
} else if (c >= 'A' && c <= 'F') {
str[i] = (c - 'A' + 10) << 4;
} else {
efree(str);
return NULL;
}
c = old[j++];
if (c >= '0' && c <= '9') {
str[i] |= c - '0';
} else if (c >= 'a' && c <= 'f') {
str[i] |= c - 'a' + 10;
} else if (c >= 'A' && c <= 'F') {
str[i] |= c - 'A' + 10;
} else {
efree(str);
return NULL;
}
}
str[target_length] = '\0';
if (newlen)
*newlen = target_length;
return (char *)str;
}
/* }}} */
#ifdef HAVE_LOCALECONV
/* {{{ localeconv_r
* glibc's localeconv is not reentrant, so lets make it so ... sorta */
PHPAPI struct lconv *localeconv_r(struct lconv *out)
{
struct lconv *res;
# ifdef ZTS
tsrm_mutex_lock( locale_mutex );
# endif
/* localeconv doesn't return an error condition */
res = localeconv();
*out = *res;
# ifdef ZTS
tsrm_mutex_unlock( locale_mutex );
# endif
return out;
}
/* }}} */
# ifdef ZTS
/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(localeconv)
{
locale_mutex = tsrm_mutex_alloc();
return SUCCESS;
}
/* }}} */
/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(localeconv)
{
tsrm_mutex_free( locale_mutex );
locale_mutex = NULL;
return SUCCESS;
}
/* }}} */
# endif
#endif
/* {{{ proto string bin2hex(string data)
Converts the binary representation of data to hex */
PHP_FUNCTION(bin2hex)
{
char *result, *data;
size_t newlen;
int datalen;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &datalen) == FAILURE) {
return;
}
result = php_bin2hex((unsigned char *)data, datalen, &newlen);
if (!result) {
RETURN_FALSE;
}
RETURN_STRINGL(result, newlen, 0);
}
/* }}} */
/* {{{ proto string hex2bin(string data)
Converts the hex representation of data to binary */
PHP_FUNCTION(hex2bin)
{
char *result, *data;
size_t newlen;
int datalen;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &datalen) == FAILURE) {
return;
}
if (datalen % 2 != 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Hexadecimal input string must have an even length");
RETURN_FALSE;
}
result = php_hex2bin((unsigned char *)data, datalen, &newlen);
if (!result) {
RETURN_FALSE;
}
RETURN_STRINGL(result, newlen, 0);
}
/* }}} */
static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
{
char *s11, *s22;
int len1, len2;
long start = 0, len = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &s11, &len1,
&s22, &len2, &start, &len) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() < 4) {
len = len1;
}
/* look at substr() function for more information */
if (start < 0) {
start += len1;
if (start < 0) {
start = 0;
}
} else if (start > len1) {
RETURN_FALSE;
}
if (len < 0) {
len += (len1 - start);
if (len < 0) {
len = 0;
}
}
if (len > len1 - start) {
len = len1 - start;
}
if(len == 0) {
RETURN_LONG(0);
}
if (behavior == STR_STRSPN) {
RETURN_LONG(php_strspn(s11 + start /*str1_start*/,
s22 /*str2_start*/,
s11 + start + len /*str1_end*/,
s22 + len2 /*str2_end*/));
} else if (behavior == STR_STRCSPN) {
RETURN_LONG(php_strcspn(s11 + start /*str1_start*/,
s22 /*str2_start*/,
s11 + start + len /*str1_end*/,
s22 + len2 /*str2_end*/));
}
}
/* }}} */
/* {{{ proto int strspn(string str, string mask [, start [, len]])
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) */
PHP_FUNCTION(strspn)
{
php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN);
}
/* }}} */
/* {{{ proto int strcspn(string str, string mask [, start [, len]])
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) */
PHP_FUNCTION(strcspn)
{
php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN);
}
/* }}} */
/* {{{ PHP_MINIT_FUNCTION(nl_langinfo) */
#if HAVE_NL_LANGINFO
PHP_MINIT_FUNCTION(nl_langinfo)
{
#define REGISTER_NL_LANGINFO_CONSTANT(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS | CONST_PERSISTENT)
#ifdef ABDAY_1
REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
#endif
#ifdef DAY_1
REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
#endif
#ifdef ABMON_1
REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
#endif
#ifdef MON_1
REGISTER_NL_LANGINFO_CONSTANT(MON_1);
REGISTER_NL_LANGINFO_CONSTANT(MON_2);
REGISTER_NL_LANGINFO_CONSTANT(MON_3);
REGISTER_NL_LANGINFO_CONSTANT(MON_4);
REGISTER_NL_LANGINFO_CONSTANT(MON_5);
REGISTER_NL_LANGINFO_CONSTANT(MON_6);
REGISTER_NL_LANGINFO_CONSTANT(MON_7);
REGISTER_NL_LANGINFO_CONSTANT(MON_8);
REGISTER_NL_LANGINFO_CONSTANT(MON_9);
REGISTER_NL_LANGINFO_CONSTANT(MON_10);
REGISTER_NL_LANGINFO_CONSTANT(MON_11);
REGISTER_NL_LANGINFO_CONSTANT(MON_12);
#endif
#ifdef AM_STR
REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
#endif
#ifdef PM_STR
REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
#endif
#ifdef D_T_FMT
REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
#endif
#ifdef D_FMT
REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
#endif
#ifdef T_FMT
REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
#endif
#ifdef T_FMT_AMPM
REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
#endif
#ifdef ERA
REGISTER_NL_LANGINFO_CONSTANT(ERA);
#endif
#ifdef ERA_YEAR
REGISTER_NL_LANGINFO_CONSTANT(ERA_YEAR);
#endif
#ifdef ERA_D_T_FMT
REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
#endif
#ifdef ERA_D_FMT
REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
#endif
#ifdef ERA_T_FMT
REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
#endif
#ifdef ALT_DIGITS
REGISTER_NL_LANGINFO_CONSTANT(ALT_DIGITS);
#endif
#ifdef INT_CURR_SYMBOL
REGISTER_NL_LANGINFO_CONSTANT(INT_CURR_SYMBOL);
#endif
#ifdef CURRENCY_SYMBOL
REGISTER_NL_LANGINFO_CONSTANT(CURRENCY_SYMBOL);
#endif
#ifdef CRNCYSTR
REGISTER_NL_LANGINFO_CONSTANT(CRNCYSTR);
#endif
#ifdef MON_DECIMAL_POINT
REGISTER_NL_LANGINFO_CONSTANT(MON_DECIMAL_POINT);
#endif
#ifdef MON_THOUSANDS_SEP
REGISTER_NL_LANGINFO_CONSTANT(MON_THOUSANDS_SEP);
#endif
#ifdef MON_GROUPING
REGISTER_NL_LANGINFO_CONSTANT(MON_GROUPING);
#endif
#ifdef POSITIVE_SIGN
REGISTER_NL_LANGINFO_CONSTANT(POSITIVE_SIGN);
#endif
#ifdef NEGATIVE_SIGN
REGISTER_NL_LANGINFO_CONSTANT(NEGATIVE_SIGN);
#endif
#ifdef INT_FRAC_DIGITS
REGISTER_NL_LANGINFO_CONSTANT(INT_FRAC_DIGITS);
#endif
#ifdef FRAC_DIGITS
REGISTER_NL_LANGINFO_CONSTANT(FRAC_DIGITS);
#endif
#ifdef P_CS_PRECEDES
REGISTER_NL_LANGINFO_CONSTANT(P_CS_PRECEDES);
#endif
#ifdef P_SEP_BY_SPACE
REGISTER_NL_LANGINFO_CONSTANT(P_SEP_BY_SPACE);
#endif
#ifdef N_CS_PRECEDES
REGISTER_NL_LANGINFO_CONSTANT(N_CS_PRECEDES);
#endif
#ifdef N_SEP_BY_SPACE
REGISTER_NL_LANGINFO_CONSTANT(N_SEP_BY_SPACE);
#endif
#ifdef P_SIGN_POSN
REGISTER_NL_LANGINFO_CONSTANT(P_SIGN_POSN);
#endif
#ifdef N_SIGN_POSN
REGISTER_NL_LANGINFO_CONSTANT(N_SIGN_POSN);
#endif
#ifdef DECIMAL_POINT
REGISTER_NL_LANGINFO_CONSTANT(DECIMAL_POINT);
#endif
#ifdef RADIXCHAR
REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
#endif
#ifdef THOUSANDS_SEP
REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
#endif
#ifdef THOUSEP
REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
#endif
#ifdef GROUPING
REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
#endif
#ifdef YESEXPR
REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
#endif
#ifdef NOEXPR
REGISTER_NL_LANGINFO_CONSTANT(NOEXPR);
#endif
#ifdef YESSTR
REGISTER_NL_LANGINFO_CONSTANT(YESSTR);
#endif
#ifdef NOSTR
REGISTER_NL_LANGINFO_CONSTANT(NOSTR);
#endif
#ifdef CODESET
REGISTER_NL_LANGINFO_CONSTANT(CODESET);
#endif
#undef REGISTER_NL_LANGINFO_CONSTANT
return SUCCESS;
}
/* }}} */
/* {{{ proto string nl_langinfo(int item)
Query language and locale information */
PHP_FUNCTION(nl_langinfo)
{
long item;
char *value;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &item) == FAILURE) {
return;
}
switch(item) { /* {{{ */
#ifdef ABDAY_1
case ABDAY_1:
case ABDAY_2:
case ABDAY_3:
case ABDAY_4:
case ABDAY_5:
case ABDAY_6:
case ABDAY_7:
#endif
#ifdef DAY_1
case DAY_1:
case DAY_2:
case DAY_3:
case DAY_4:
case DAY_5:
case DAY_6:
case DAY_7:
#endif
#ifdef ABMON_1
case ABMON_1:
case ABMON_2:
case ABMON_3:
case ABMON_4:
case ABMON_5:
case ABMON_6:
case ABMON_7:
case ABMON_8:
case ABMON_9:
case ABMON_10:
case ABMON_11:
case ABMON_12:
#endif
#ifdef MON_1
case MON_1:
case MON_2:
case MON_3:
case MON_4:
case MON_5:
case MON_6:
case MON_7:
case MON_8:
case MON_9:
case MON_10:
case MON_11:
case MON_12:
#endif
#ifdef AM_STR
case AM_STR:
#endif
#ifdef PM_STR
case PM_STR:
#endif
#ifdef D_T_FMT
case D_T_FMT:
#endif
#ifdef D_FMT
case D_FMT:
#endif
#ifdef T_FMT
case T_FMT:
#endif
#ifdef T_FMT_AMPM
case T_FMT_AMPM:
#endif
#ifdef ERA
case ERA:
#endif
#ifdef ERA_YEAR
case ERA_YEAR:
#endif
#ifdef ERA_D_T_FMT
case ERA_D_T_FMT:
#endif
#ifdef ERA_D_FMT
case ERA_D_FMT:
#endif
#ifdef ERA_T_FMT
case ERA_T_FMT:
#endif
#ifdef ALT_DIGITS
case ALT_DIGITS:
#endif
#ifdef INT_CURR_SYMBOL
case INT_CURR_SYMBOL:
#endif
#ifdef CURRENCY_SYMBOL
case CURRENCY_SYMBOL:
#endif
#ifdef CRNCYSTR
case CRNCYSTR:
#endif
#ifdef MON_DECIMAL_POINT
case MON_DECIMAL_POINT:
#endif
#ifdef MON_THOUSANDS_SEP
case MON_THOUSANDS_SEP:
#endif
#ifdef MON_GROUPING
case MON_GROUPING:
#endif
#ifdef POSITIVE_SIGN
case POSITIVE_SIGN:
#endif
#ifdef NEGATIVE_SIGN
case NEGATIVE_SIGN:
#endif
#ifdef INT_FRAC_DIGITS
case INT_FRAC_DIGITS:
#endif
#ifdef FRAC_DIGITS
case FRAC_DIGITS:
#endif
#ifdef P_CS_PRECEDES
case P_CS_PRECEDES:
#endif
#ifdef P_SEP_BY_SPACE
case P_SEP_BY_SPACE:
#endif
#ifdef N_CS_PRECEDES
case N_CS_PRECEDES:
#endif
#ifdef N_SEP_BY_SPACE
case N_SEP_BY_SPACE:
#endif
#ifdef P_SIGN_POSN
case P_SIGN_POSN:
#endif
#ifdef N_SIGN_POSN
case N_SIGN_POSN:
#endif
#ifdef DECIMAL_POINT
case DECIMAL_POINT:
#elif defined(RADIXCHAR)
case RADIXCHAR:
#endif
#ifdef THOUSANDS_SEP
case THOUSANDS_SEP:
#elif defined(THOUSEP)
case THOUSEP:
#endif
#ifdef GROUPING
case GROUPING:
#endif
#ifdef YESEXPR
case YESEXPR:
#endif
#ifdef NOEXPR
case NOEXPR:
#endif
#ifdef YESSTR
case YESSTR:
#endif
#ifdef NOSTR
case NOSTR:
#endif
#ifdef CODESET
case CODESET:
#endif
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Item '%ld' is not valid", item);
RETURN_FALSE;
}
/* }}} */
value = nl_langinfo(item);
if (value == NULL) {
RETURN_FALSE;
} else {
RETURN_STRING(value, 1);
}
}
#endif
/* }}} */
#ifdef HAVE_STRCOLL
/* {{{ proto int strcoll(string str1, string str2)
Compares two strings using the current locale */
PHP_FUNCTION(strcoll)
{
char *s1, *s2;
int s1len, s2len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &s1, &s1len, &s2, &s2len) == FAILURE) {
return;
}
RETURN_LONG(strcoll((const char *) s1,
(const char *) s2));
}
/* }}} */
#endif
/* {{{ php_charmask
* Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
* it needs to be incrementing.
* Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
*/
static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC)
{
unsigned char *end;
unsigned char c;
int result = SUCCESS;
memset(mask, 0, 256);
for (end = input+len; input < end; input++) {
c=*input;
if ((input+3 < end) && input[1] == '.' && input[2] == '.'
&& input[3] >= c) {
memset(mask+c, 1, input[3] - c + 1);
input+=3;
} else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
/* Error, try to be as helpful as possible:
(a range ending/starting with '.' won't be captured here) */
if (end-len >= input) { /* there was no 'left' char */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
result = FAILURE;
continue;
}
if (input+2 >= end) { /* there is no 'right' char */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
result = FAILURE;
continue;
}
if (input[-1] > input[2]) { /* wrong order */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
result = FAILURE;
continue;
}
/* FIXME: better error (a..b..c is the only left possibility?) */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range");
result = FAILURE;
continue;
} else {
mask[c]=1;
}
}
return result;
}
/* }}} */
/* {{{ php_trim()
* mode 1 : trim left
* mode 2 : trim right
* mode 3 : trim left and right
* what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
*/
PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC)
{
register int i;
int trimmed = 0;
char mask[256];
if (what) {
php_charmask((unsigned char*)what, what_len, mask TSRMLS_CC);
} else {
php_charmask((unsigned char*)" \n\r\t\v\0", 6, mask TSRMLS_CC);
}
if (mode & 1) {
for (i = 0; i < len; i++) {
if (mask[(unsigned char)c[i]]) {
trimmed++;
} else {
break;
}
}
len -= trimmed;
c += trimmed;
}
if (mode & 2) {
for (i = len - 1; i >= 0; i--) {
if (mask[(unsigned char)c[i]]) {
len--;
} else {
break;
}
}
}
if (return_value) {
RETVAL_STRINGL(c, len, 1);
} else {
return estrndup(c, len);
}
return "";
}
/* }}} */
/* {{{ php_do_trim
* Base for trim(), rtrim() and ltrim() functions.
*/
static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
char *str;
char *what = NULL;
int str_len, what_len = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &what, &what_len) == FAILURE) {
return;
}
php_trim(str, str_len, what, what_len, return_value, mode TSRMLS_CC);
}
/* }}} */
/* {{{ proto string trim(string str [, string character_mask])
Strips whitespace from the beginning and end of a string */
PHP_FUNCTION(trim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
}
/* }}} */
/* {{{ proto string rtrim(string str [, string character_mask])
Removes trailing whitespace */
PHP_FUNCTION(rtrim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
}
/* }}} */
/* {{{ proto string ltrim(string str [, string character_mask])
Strips whitespace from the beginning of a string */
PHP_FUNCTION(ltrim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */
/* {{{ proto string wordwrap(string str [, int width [, string break [, boolean cut]]])
Wraps buffer to selected number of characters using string break char */
PHP_FUNCTION(wordwrap)
{
const char *text, *breakchar = "\n";
char *newtext;
int textlen, breakcharlen = 1, newtextlen, chk;
size_t alloced;
long current = 0, laststart = 0, lastspace = 0;
long linelength = 75;
zend_bool docut = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lsb", &text, &textlen, &linelength, &breakchar, &breakcharlen, &docut) == FAILURE) {
return;
}
if (textlen == 0) {
RETURN_EMPTY_STRING();
}
if (breakcharlen == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Break string cannot be empty");
RETURN_FALSE;
}
if (linelength == 0 && docut) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't force cut when width is zero");
RETURN_FALSE;
}
/* Special case for a single-character break as it needs no
additional storage space */
if (breakcharlen == 1 && !docut) {
newtext = estrndup(text, textlen);
laststart = lastspace = 0;
for (current = 0; current < textlen; current++) {
if (text[current] == breakchar[0]) {
laststart = lastspace = current + 1;
} else if (text[current] == ' ') {
if (current - laststart >= linelength) {
newtext[current] = breakchar[0];
laststart = current + 1;
}
lastspace = current;
} else if (current - laststart >= linelength && laststart != lastspace) {
newtext[lastspace] = breakchar[0];
laststart = lastspace + 1;
}
}
RETURN_STRINGL(newtext, textlen, 0);
} else {
/* Multiple character line break or forced cut */
if (linelength > 0) {
chk = (int)(textlen/linelength + 1);
newtext = safe_emalloc(chk, breakcharlen, textlen + 1);
alloced = textlen + chk * breakcharlen + 1;
} else {
chk = textlen;
alloced = textlen * (breakcharlen + 1) + 1;
newtext = safe_emalloc(textlen, (breakcharlen + 1), 1);
}
/* now keep track of the actual new text length */
newtextlen = 0;
laststart = lastspace = 0;
for (current = 0; current < textlen; current++) {
if (chk <= 0) {
alloced += (int) (((textlen - current + 1)/linelength + 1) * breakcharlen) + 1;
newtext = erealloc(newtext, alloced);
chk = (int) ((textlen - current)/linelength) + 1;
}
/* when we hit an existing break, copy to new buffer, and
* fix up laststart and lastspace */
if (text[current] == breakchar[0]
&& current + breakcharlen < textlen
&& !strncmp(text+current, breakchar, breakcharlen)) {
memcpy(newtext+newtextlen, text+laststart, current-laststart+breakcharlen);
newtextlen += current-laststart+breakcharlen;
current += breakcharlen - 1;
laststart = lastspace = current + 1;
chk--;
}
/* if it is a space, check if it is at the line boundary,
* copy and insert a break, or just keep track of it */
else if (text[current] == ' ') {
if (current - laststart >= linelength) {
memcpy(newtext+newtextlen, text+laststart, current-laststart);
newtextlen += current - laststart;
memcpy(newtext+newtextlen, breakchar, breakcharlen);
newtextlen += breakcharlen;
laststart = current + 1;
chk--;
}
lastspace = current;
}
/* if we are cutting, and we've accumulated enough
* characters, and we haven't see a space for this line,
* copy and insert a break. */
else if (current - laststart >= linelength
&& docut && laststart >= lastspace) {
memcpy(newtext+newtextlen, text+laststart, current-laststart);
newtextlen += current - laststart;
memcpy(newtext+newtextlen, breakchar, breakcharlen);
newtextlen += breakcharlen;
laststart = lastspace = current;
chk--;
}
/* if the current word puts us over the linelength, copy
* back up until the last space, insert a break, and move
* up the laststart */
else if (current - laststart >= linelength
&& laststart < lastspace) {
memcpy(newtext+newtextlen, text+laststart, lastspace-laststart);
newtextlen += lastspace - laststart;
memcpy(newtext+newtextlen, breakchar, breakcharlen);
newtextlen += breakcharlen;
laststart = lastspace = lastspace + 1;
chk--;
}
}
/* copy over any stragglers */
if (laststart != current) {
memcpy(newtext+newtextlen, text+laststart, current-laststart);
newtextlen += current - laststart;
}
newtext[newtextlen] = '\0';
/* free unused memory */
newtext = erealloc(newtext, newtextlen+1);
RETURN_STRINGL(newtext, newtextlen, 0);
}
}
/* }}} */
/* {{{ php_explode
*/
PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit)
{
char *p1, *p2, *endp;
endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
p1 = Z_STRVAL_P(str);
p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
if (p2 == NULL) {
add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
} else {
do {
add_next_index_stringl(return_value, p1, p2 - p1, 1);
p1 = p2 + Z_STRLEN_P(delim);
} while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
--limit > 1);
if (p1 <= endp)
add_next_index_stringl(return_value, p1, endp-p1, 1);
}
}
/* }}} */
/* {{{ php_explode_negative_limit
*/
PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, long limit)
{
#define EXPLODE_ALLOC_STEP 64
char *p1, *p2, *endp;
endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
p1 = Z_STRVAL_P(str);
p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
if (p2 == NULL) {
/*
do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0
by doing nothing we return empty array
*/
} else {
int allocated = EXPLODE_ALLOC_STEP, found = 0;
long i, to_return;
char **positions = emalloc(allocated * sizeof(char *));
positions[found++] = p1;
do {
if (found >= allocated) {
allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */
positions = erealloc(positions, allocated*sizeof(char *));
}
positions[found++] = p1 = p2 + Z_STRLEN_P(delim);
} while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL);
to_return = limit + found;
/* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
for (i = 0;i < to_return;i++) { /* this checks also for to_return > 0 */
add_next_index_stringl(return_value, positions[i],
(positions[i+1] - Z_STRLEN_P(delim)) - positions[i],
1
);
}
efree(positions);
}
#undef EXPLODE_ALLOC_STEP
}
/* }}} */
/* {{{ proto array explode(string separator, string str [, int limit])
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. */
PHP_FUNCTION(explode)
{
char *str, *delim;
int str_len = 0, delim_len = 0;
long limit = LONG_MAX; /* No limit */
zval zdelim, zstr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &delim, &delim_len, &str, &str_len, &limit) == FAILURE) {
return;
}
if (delim_len == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
array_init(return_value);
if (str_len == 0) {
if (limit >= 0) {
add_next_index_stringl(return_value, "", sizeof("") - 1, 1);
}
return;
}
ZVAL_STRINGL(&zstr, str, str_len, 0);
ZVAL_STRINGL(&zdelim, delim, delim_len, 0);
if (limit > 1) {
php_explode(&zdelim, &zstr, return_value, limit);
} else if (limit < 0) {
php_explode_negative_limit(&zdelim, &zstr, return_value, limit);
} else {
add_index_stringl(return_value, 0, str, str_len, 1);
}
}
/* }}} */
/* {{{ proto string join(array src, string glue)
An alias for implode */
/* }}} */
/* {{{ php_implode
*/
PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC)
{
zval **tmp;
HashPosition pos;
smart_str implstr = {0};
int numelems, i = 0;
zval tmp_val;
int str_len;
numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
if (numelems == 0) {
RETURN_EMPTY_STRING();
}
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos);
while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) {
switch ((*tmp)->type) {
case IS_STRING:
smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
break;
case IS_LONG: {
char stmp[MAX_LENGTH_OF_LONG + 1];
str_len = slprintf(stmp, sizeof(stmp), "%ld", Z_LVAL_PP(tmp));
smart_str_appendl(&implstr, stmp, str_len);
}
break;
case IS_BOOL:
if (Z_LVAL_PP(tmp) == 1) {
smart_str_appendl(&implstr, "1", sizeof("1")-1);
}
break;
case IS_NULL:
break;
case IS_DOUBLE: {
char *stmp;
str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_PP(tmp));
smart_str_appendl(&implstr, stmp, str_len);
efree(stmp);
}
break;
case IS_OBJECT: {
int copy;
zval expr;
zend_make_printable_zval(*tmp, &expr, &copy);
smart_str_appendl(&implstr, Z_STRVAL(expr), Z_STRLEN(expr));
if (copy) {
zval_dtor(&expr);
}
}
break;
default:
tmp_val = **tmp;
zval_copy_ctor(&tmp_val);
convert_to_string(&tmp_val);
smart_str_appendl(&implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
zval_dtor(&tmp_val);
break;
}
if (++i != numelems) {
smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim));
}
zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
}
smart_str_0(&implstr);
if (implstr.len) {
RETURN_STRINGL(implstr.c, implstr.len, 0);
} else {
smart_str_free(&implstr);
RETURN_EMPTY_STRING();
}
}
/* }}} */
/* {{{ proto string implode([string glue,] array pieces)
Joins array elements placing glue string between items and return one string */
PHP_FUNCTION(implode)
{
zval **arg1 = NULL, **arg2 = NULL, *delim, *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &arg1, &arg2) == FAILURE) {
return;
}
if (arg2 == NULL) {
if (Z_TYPE_PP(arg1) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument must be an array");
return;
}
MAKE_STD_ZVAL(delim);
#define _IMPL_EMPTY ""
ZVAL_STRINGL(delim, _IMPL_EMPTY, sizeof(_IMPL_EMPTY) - 1, 0);
SEPARATE_ZVAL(arg1);
arr = *arg1;
} else {
if (Z_TYPE_PP(arg1) == IS_ARRAY) {
arr = *arg1;
convert_to_string_ex(arg2);
delim = *arg2;
} else if (Z_TYPE_PP(arg2) == IS_ARRAY) {
arr = *arg2;
convert_to_string_ex(arg1);
delim = *arg1;
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid arguments passed");
return;
}
}
php_implode(delim, arr, return_value TSRMLS_CC);
if (arg2 == NULL) {
FREE_ZVAL(delim);
}
}
/* }}} */
#define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
/* {{{ proto string strtok([string str,] string token)
Tokenize a string */
PHP_FUNCTION(strtok)
{
char *str, *tok = NULL;
int str_len, tok_len = 0;
zval *zv;
char *token;
char *token_end;
char *p;
char *pe;
int skipped = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &tok, &tok_len) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() == 1) {
tok = str;
tok_len = str_len;
} else {
if (BG(strtok_zval)) {
zval_ptr_dtor(&BG(strtok_zval));
}
MAKE_STD_ZVAL(zv);
ZVAL_STRINGL(zv, str, str_len, 1);
BG(strtok_zval) = zv;
BG(strtok_last) = BG(strtok_string) = Z_STRVAL_P(zv);
BG(strtok_len) = str_len;
}
p = BG(strtok_last); /* Where we start to search */
pe = BG(strtok_string) + BG(strtok_len);
if (!p || p >= pe) {
RETURN_FALSE;
}
token = tok;
token_end = token + tok_len;
while (token < token_end) {
STRTOK_TABLE(token++) = 1;
}
/* Skip leading delimiters */
while (STRTOK_TABLE(p)) {
if (++p >= pe) {
/* no other chars left */
BG(strtok_last) = NULL;
RETVAL_FALSE;
goto restore;
}
skipped++;
}
/* We know at this place that *p is no delimiter, so skip it */
while (++p < pe) {
if (STRTOK_TABLE(p)) {
goto return_token;
}
}
if (p - BG(strtok_last)) {
return_token:
RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped, 1);
BG(strtok_last) = p + 1;
} else {
RETVAL_FALSE;
BG(strtok_last) = NULL;
}
/* Restore table -- usually faster then memset'ing the table on every invocation */
restore:
token = tok;
while (token < token_end) {
STRTOK_TABLE(token++) = 0;
}
}
/* }}} */
/* {{{ php_strtoupper
*/
PHPAPI char *php_strtoupper(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = (unsigned char *)c+len;
while (c < e) {
*c = toupper(*c);
c++;
}
return s;
}
/* }}} */
/* {{{ proto string strtoupper(string str)
Makes a string uppercase */
PHP_FUNCTION(strtoupper)
{
char *arg;
int arglen;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) {
return;
}
arg = estrndup(arg, arglen);
php_strtoupper(arg, arglen);
RETURN_STRINGL(arg, arglen, 0);
}
/* }}} */
/* {{{ php_strtolower
*/
PHPAPI char *php_strtolower(char *s, size_t len)
{
unsigned char *c, *e;
c = (unsigned char *)s;
e = c+len;
while (c < e) {
*c = tolower(*c);
c++;
}
return s;
}
/* }}} */
/* {{{ proto string strtolower(string str)
Makes a string lowercase */
PHP_FUNCTION(strtolower)
{
char *str;
int arglen;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &arglen) == FAILURE) {
return;
}
str = estrndup(str, arglen);
php_strtolower(str, arglen);
RETURN_STRINGL(str, arglen, 0);
}
/* }}} */
/* {{{ php_basename
*/
PHPAPI void php_basename(const char *s, size_t len, char *suffix, size_t sufflen, char **p_ret, size_t *p_len TSRMLS_DC)
{
char *ret = NULL, *c, *comp, *cend;
size_t inc_len, cnt;
int state;
c = comp = cend = (char*)s;
cnt = len;
state = 0;
while (cnt > 0) {
inc_len = (*c == '\0' ? 1: php_mblen(c, cnt));
switch (inc_len) {
case -2:
case -1:
inc_len = 1;
php_ignore_value(php_mblen(NULL, 0));
break;
case 0:
goto quit_loop;
case 1:
#if defined(PHP_WIN32) || defined(NETWARE)
if (*c == '/' || *c == '\\') {
#else
if (*c == '/') {
#endif
if (state == 1) {
state = 0;
cend = c;
}
} else {
if (state == 0) {
comp = c;
state = 1;
}
}
break;
default:
if (state == 0) {
comp = c;
state = 1;
}
break;
}
c += inc_len;
cnt -= inc_len;
}
quit_loop:
if (state == 1) {
cend = c;
}
if (suffix != NULL && sufflen < (uint)(cend - comp) &&
memcmp(cend - sufflen, suffix, sufflen) == 0) {
cend -= sufflen;
}
len = cend - comp;
if (p_ret) {
ret = emalloc(len + 1);
memcpy(ret, comp, len);
ret[len] = '\0';
*p_ret = ret;
}
if (p_len) {
*p_len = len;
}
}
/* }}} */
/* {{{ proto string basename(string path [, string suffix])
Returns the filename component of the path */
PHP_FUNCTION(basename)
{
char *string, *suffix = NULL, *ret;
int string_len, suffix_len = 0;
size_t ret_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &string, &string_len, &suffix, &suffix_len) == FAILURE) {
return;
}
php_basename(string, string_len, suffix, suffix_len, &ret, &ret_len TSRMLS_CC);
RETURN_STRINGL(ret, (int)ret_len, 0);
}
/* }}} */
/* {{{ php_dirname
Returns directory name component of path */
PHPAPI size_t php_dirname(char *path, size_t len)
{
return zend_dirname(path, len);
}
/* }}} */
/* {{{ proto string dirname(string path)
Returns the directory name component of the path */
PHP_FUNCTION(dirname)
{
char *str;
char *ret;
int str_len;
size_t ret_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
ret = estrndup(str, str_len);
ret_len = php_dirname(ret, str_len);
RETURN_STRINGL(ret, ret_len, 0);
}
/* }}} */
/* {{{ proto array pathinfo(string path[, int options])
Returns information about a certain string */
PHP_FUNCTION(pathinfo)
{
zval *tmp;
char *path, *ret = NULL;
int path_len, have_basename;
size_t ret_len;
long opt = PHP_PATHINFO_ALL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &path_len, &opt) == FAILURE) {
return;
}
have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
MAKE_STD_ZVAL(tmp);
array_init(tmp);
if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
ret = estrndup(path, path_len);
php_dirname(ret, path_len);
if (*ret) {
add_assoc_string(tmp, "dirname", ret, 1);
}
efree(ret);
ret = NULL;
}
if (have_basename) {
php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
add_assoc_stringl(tmp, "basename", ret, ret_len, 0);
}
if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
const char *p;
int idx;
if (!have_basename) {
php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
}
p = zend_memrchr(ret, '.', ret_len);
if (p) {
idx = p - ret;
add_assoc_stringl(tmp, "extension", ret + idx + 1, ret_len - idx - 1, 1);
}
}
if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
const char *p;
int idx;
/* Have we alrady looked up the basename? */
if (!have_basename && !ret) {
php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
}
p = zend_memrchr(ret, '.', ret_len);
idx = p ? (p - ret) : ret_len;
add_assoc_stringl(tmp, "filename", ret, idx, 1);
}
if (!have_basename && ret) {
efree(ret);
}
if (opt == PHP_PATHINFO_ALL) {
RETURN_ZVAL(tmp, 0, 1);
} else {
zval **element;
if (zend_hash_get_current_data(Z_ARRVAL_P(tmp), (void **) &element) == SUCCESS) {
RETVAL_ZVAL(*element, 1, 0);
} else {
ZVAL_EMPTY_STRING(return_value);
}
}
zval_ptr_dtor(&tmp);
}
/* }}} */
/* {{{ php_stristr
case insensitve strstr */
PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
{
php_strtolower(s, s_len);
php_strtolower(t, t_len);
return php_memnstr(s, t, t_len, s + s_len);
}
/* }}} */
/* {{{ php_strspn
*/
PHPAPI size_t php_strspn(char *s1, char *s2, char *s1_end, char *s2_end)
{
register const char *p = s1, *spanp;
register char c = *p;
cont:
for (spanp = s2; p != s1_end && spanp != s2_end;) {
if (*spanp++ == c) {
c = *(++p);
goto cont;
}
}
return (p - s1);
}
/* }}} */
/* {{{ php_strcspn
*/
PHPAPI size_t php_strcspn(char *s1, char *s2, char *s1_end, char *s2_end)
{
register const char *p, *spanp;
register char c = *s1;
for (p = s1;;) {
spanp = s2;
do {
if (*spanp == c || p == s1_end) {
return p - s1;
}
} while (spanp++ < (s2_end - 1));
c = *++p;
}
/* NOTREACHED */
}
/* }}} */
/* {{{ php_needle_char
*/
static int php_needle_char(zval *needle, char *target TSRMLS_DC)
{
switch (Z_TYPE_P(needle)) {
case IS_LONG:
case IS_BOOL:
*target = (char)Z_LVAL_P(needle);
return SUCCESS;
case IS_NULL:
*target = '\0';
return SUCCESS;
case IS_DOUBLE:
*target = (char)(int)Z_DVAL_P(needle);
return SUCCESS;
case IS_OBJECT:
{
zval holder = *needle;
zval_copy_ctor(&(holder));
convert_to_long(&(holder));
if(Z_TYPE(holder) != IS_LONG) {
return FAILURE;
}
*target = (char)Z_LVAL(holder);
return SUCCESS;
}
default: {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "needle is not a string or an integer");
return FAILURE;
}
}
}
/* }}} */
/* {{{ proto string stristr(string haystack, string needle[, bool part])
Finds first occurrence of a string within another, case insensitive */
PHP_FUNCTION(stristr)
{
zval *needle;
char *haystack;
int haystack_len;
char *found = NULL;
int found_offset;
char *haystack_dup;
char needle_char[2];
zend_bool part = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) {
return;
}
haystack_dup = estrndup(haystack, haystack_len);
if (Z_TYPE_P(needle) == IS_STRING) {
char *orig_needle;
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
efree(haystack_dup);
RETURN_FALSE;
}
orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
found = php_stristr(haystack_dup, orig_needle, haystack_len, Z_STRLEN_P(needle));
efree(orig_needle);
} else {
if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
efree(haystack_dup);
RETURN_FALSE;
}
needle_char[1] = 0;
found = php_stristr(haystack_dup, needle_char, haystack_len, 1);
}
if (found) {
found_offset = found - haystack_dup;
if (part) {
RETVAL_STRINGL(haystack, found_offset, 1);
} else {
RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1);
}
} else {
RETVAL_FALSE;
}
efree(haystack_dup);
}
/* }}} */
/* {{{ proto string strstr(string haystack, string needle[, bool part])
Finds first occurrence of a string within another */
PHP_FUNCTION(strstr)
{
zval *needle;
char *haystack;
int haystack_len;
char *found = NULL;
char needle_char[2];
long found_offset;
zend_bool part = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) {
return;
}
if (Z_TYPE_P(needle) == IS_STRING) {
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
found = php_memnstr(haystack, Z_STRVAL_P(needle), Z_STRLEN_P(needle), haystack + haystack_len);
} else {
if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
RETURN_FALSE;
}
needle_char[1] = 0;
found = php_memnstr(haystack, needle_char, 1, haystack + haystack_len);
}
if (found) {
found_offset = found - haystack;
if (part) {
RETURN_STRINGL(haystack, found_offset, 1);
} else {
RETURN_STRINGL(found, haystack_len - found_offset, 1);
}
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto string strchr(string haystack, string needle)
An alias for strstr */
/* }}} */
/* {{{ proto int strpos(string haystack, string needle [, int offset])
Finds position of first occurrence of a string within another */
PHP_FUNCTION(strpos)
{
zval *needle;
char *haystack;
char *found = NULL;
char needle_char[2];
long offset = 0;
int haystack_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
return;
}
if (offset < 0 || offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
RETURN_FALSE;
}
if (Z_TYPE_P(needle) == IS_STRING) {
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
found = php_memnstr(haystack + offset,
Z_STRVAL_P(needle),
Z_STRLEN_P(needle),
haystack + haystack_len);
} else {
if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
RETURN_FALSE;
}
needle_char[1] = 0;
found = php_memnstr(haystack + offset,
needle_char,
1,
haystack + haystack_len);
}
if (found) {
RETURN_LONG(found - haystack);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int stripos(string haystack, string needle [, int offset])
Finds position of first occurrence of a string within another, case insensitive */
PHP_FUNCTION(stripos)
{
char *found = NULL;
char *haystack;
int haystack_len;
long offset = 0;
char *needle_dup = NULL, *haystack_dup;
char needle_char[2];
zval *needle;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
return;
}
if (offset < 0 || offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
RETURN_FALSE;
}
if (haystack_len == 0) {
RETURN_FALSE;
}
haystack_dup = estrndup(haystack, haystack_len);
php_strtolower(haystack_dup, haystack_len);
if (Z_TYPE_P(needle) == IS_STRING) {
if (Z_STRLEN_P(needle) == 0 || Z_STRLEN_P(needle) > haystack_len) {
efree(haystack_dup);
RETURN_FALSE;
}
needle_dup = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
php_strtolower(needle_dup, Z_STRLEN_P(needle));
found = php_memnstr(haystack_dup + offset, needle_dup, Z_STRLEN_P(needle), haystack_dup + haystack_len);
} else {
if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
efree(haystack_dup);
RETURN_FALSE;
}
needle_char[0] = tolower(needle_char[0]);
needle_char[1] = '\0';
found = php_memnstr(haystack_dup + offset,
needle_char,
sizeof(needle_char) - 1,
haystack_dup + haystack_len);
}
efree(haystack_dup);
if (needle_dup) {
efree(needle_dup);
}
if (found) {
RETURN_LONG(found - haystack_dup);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto int strrpos(string haystack, string needle [, int offset])
Finds position of last occurrence of a string within another string */
PHP_FUNCTION(strrpos)
{
zval *zneedle;
char *needle, *haystack;
int needle_len, haystack_len;
long offset = 0;
char *p, *e, ord_needle[2];
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
RETURN_FALSE;
}
if (Z_TYPE_P(zneedle) == IS_STRING) {
needle = Z_STRVAL_P(zneedle);
needle_len = Z_STRLEN_P(zneedle);
} else {
if (php_needle_char(zneedle, ord_needle TSRMLS_CC) != SUCCESS) {
RETURN_FALSE;
}
ord_needle[1] = '\0';
needle = ord_needle;
needle_len = 1;
}
if ((haystack_len == 0) || (needle_len == 0)) {
RETURN_FALSE;
}
if (offset >= 0) {
if (offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack + offset;
e = haystack + haystack_len - needle_len;
} else {
if (offset < -INT_MAX || -offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack;
if (needle_len > -offset) {
e = haystack + haystack_len - needle_len;
} else {
e = haystack + haystack_len + offset;
}
}
if (needle_len == 1) {
/* Single character search can shortcut memcmps */
while (e >= p) {
if (*e == *needle) {
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
RETURN_FALSE;
}
while (e >= p) {
if (memcmp(e, needle, needle_len) == 0) {
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
RETURN_FALSE;
}
/* }}} */
/* {{{ proto int strripos(string haystack, string needle [, int offset])
Finds position of last occurrence of a string within another string */
PHP_FUNCTION(strripos)
{
zval *zneedle;
char *needle, *haystack;
int needle_len, haystack_len;
long offset = 0;
char *p, *e, ord_needle[2];
char *needle_dup, *haystack_dup;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
RETURN_FALSE;
}
if (Z_TYPE_P(zneedle) == IS_STRING) {
needle = Z_STRVAL_P(zneedle);
needle_len = Z_STRLEN_P(zneedle);
} else {
if (php_needle_char(zneedle, ord_needle TSRMLS_CC) != SUCCESS) {
RETURN_FALSE;
}
ord_needle[1] = '\0';
needle = ord_needle;
needle_len = 1;
}
if ((haystack_len == 0) || (needle_len == 0)) {
RETURN_FALSE;
}
if (needle_len == 1) {
/* Single character search can shortcut memcmps
Can also avoid tolower emallocs */
if (offset >= 0) {
if (offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack + offset;
e = haystack + haystack_len - 1;
} else {
p = haystack;
if (offset < -INT_MAX || -offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
e = haystack + haystack_len + offset;
}
/* Borrow that ord_needle buffer to avoid repeatedly tolower()ing needle */
*ord_needle = tolower(*needle);
while (e >= p) {
if (tolower(*e) == *ord_needle) {
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
RETURN_FALSE;
}
needle_dup = estrndup(needle, needle_len);
php_strtolower(needle_dup, needle_len);
haystack_dup = estrndup(haystack, haystack_len);
php_strtolower(haystack_dup, haystack_len);
if (offset >= 0) {
if (offset > haystack_len) {
efree(needle_dup);
efree(haystack_dup);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack_dup + offset;
e = haystack_dup + haystack_len - needle_len;
} else {
if (offset < -INT_MAX || -offset > haystack_len) {
efree(needle_dup);
efree(haystack_dup);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack_dup;
if (needle_len > -offset) {
e = haystack_dup + haystack_len - needle_len;
} else {
e = haystack_dup + haystack_len + offset;
}
}
while (e >= p) {
if (memcmp(e, needle_dup, needle_len) == 0) {
efree(haystack_dup);
efree(needle_dup);
RETURN_LONG(e - p + (offset > 0 ? offset : 0));
}
e--;
}
efree(haystack_dup);
efree(needle_dup);
RETURN_FALSE;
}
/* }}} */
/* {{{ proto string strrchr(string haystack, string needle)
Finds the last occurrence of a character in a string within another */
PHP_FUNCTION(strrchr)
{
zval *needle;
char *haystack;
const char *found = NULL;
long found_offset;
int haystack_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &haystack, &haystack_len, &needle) == FAILURE) {
return;
}
if (Z_TYPE_P(needle) == IS_STRING) {
found = zend_memrchr(haystack, *Z_STRVAL_P(needle), haystack_len);
} else {
char needle_chr;
if (php_needle_char(needle, &needle_chr TSRMLS_CC) != SUCCESS) {
RETURN_FALSE;
}
found = zend_memrchr(haystack, needle_chr, haystack_len);
}
if (found) {
found_offset = found - haystack;
RETURN_STRINGL(found, haystack_len - found_offset, 1);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ php_chunk_split
*/
static char *php_chunk_split(char *src, int srclen, char *end, int endlen, int chunklen, int *destlen)
{
char *dest;
char *p, *q;
int chunks; /* complete chunks! */
int restlen;
int out_len;
chunks = srclen / chunklen;
restlen = srclen - chunks * chunklen; /* srclen % chunklen */
if(chunks > INT_MAX - 1) {
return NULL;
}
out_len = chunks + 1;
if(endlen !=0 && out_len > INT_MAX/endlen) {
return NULL;
}
out_len *= endlen;
if(out_len > INT_MAX - srclen - 1) {
return NULL;
}
out_len += srclen + 1;
dest = safe_emalloc((int)out_len, sizeof(char), 0);
for (p = src, q = dest; p < (src + srclen - chunklen + 1); ) {
memcpy(q, p, chunklen);
q += chunklen;
memcpy(q, end, endlen);
q += endlen;
p += chunklen;
}
if (restlen) {
memcpy(q, p, restlen);
q += restlen;
memcpy(q, end, endlen);
q += endlen;
}
*q = '\0';
if (destlen) {
*destlen = q - dest;
}
return(dest);
}
/* }}} */
/* {{{ proto string chunk_split(string str [, int chunklen [, string ending]])
Returns split line */
PHP_FUNCTION(chunk_split)
{
char *str;
char *result;
char *end = "\r\n";
int endlen = 2;
long chunklen = 76;
int result_len;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, &chunklen, &end, &endlen) == FAILURE) {
return;
}
if (chunklen <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Chunk length should be greater than zero");
RETURN_FALSE;
}
if (chunklen > str_len) {
/* to maintain BC, we must return original string + ending */
result_len = endlen + str_len;
result = emalloc(result_len + 1);
memcpy(result, str, str_len);
memcpy(result + str_len, end, endlen);
result[result_len] = '\0';
RETURN_STRINGL(result, result_len, 0);
}
if (!str_len) {
RETURN_EMPTY_STRING();
}
result = php_chunk_split(str, str_len, end, endlen, chunklen, &result_len);
if (result) {
RETURN_STRINGL(result, result_len, 0);
} else {
RETURN_FALSE;
}
}
/* }}} */
/* {{{ proto string substr(string str, int start [, int length])
Returns part of a string */
PHP_FUNCTION(substr)
{
char *str;
long l = 0, f;
int str_len;
int argc = ZEND_NUM_ARGS();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &str, &str_len, &f, &l) == FAILURE) {
return;
}
if (argc > 2) {
if ((l < 0 && -l > str_len)) {
RETURN_FALSE;
} else if (l > str_len) {
l = str_len;
}
} else {
l = str_len;
}
if (f > str_len) {
RETURN_FALSE;
} else if (f < 0 && -f > str_len) {
f = 0;
}
if (l < 0 && (l + str_len - f) < 0) {
RETURN_FALSE;
}
/* if "from" position is negative, count start position from the end
* of the string
*/
if (f < 0) {
f = str_len + f;
if (f < 0) {
f = 0;
}
}
/* if "length" position is negative, set it to the length
* needed to stop that many chars from the end of the string
*/
if (l < 0) {
l = (str_len - f) + l;
if (l < 0) {
l = 0;
}
}
if (f >= str_len) {
RETURN_FALSE;
}
if ((f + l) > str_len) {
l = str_len - f;
}
RETURN_STRINGL(str + f, l, 1);
}
/* }}} */
/* {{{ proto mixed substr_replace(mixed str, mixed repl, mixed start [, mixed length])
Replaces part of a string with another string */
PHP_FUNCTION(substr_replace)
{
zval **str;
zval **from;
zval **len = NULL;
zval **repl;
char *result;
int result_len;
int l = 0;
int f;
int argc = ZEND_NUM_ARGS();
HashPosition pos_str, pos_from, pos_repl, pos_len;
zval **tmp_str = NULL, **tmp_from = NULL, **tmp_repl = NULL, **tmp_len= NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &str, &repl, &from, &len) == FAILURE) {
return;
}
if (Z_TYPE_PP(str) != IS_ARRAY) {
if (Z_ISREF_PP(str)) {
SEPARATE_ZVAL(str);
}
convert_to_string_ex(str);
}
if (Z_TYPE_PP(repl) != IS_ARRAY) {
if (Z_ISREF_PP(repl)) {
SEPARATE_ZVAL(repl);
}
convert_to_string_ex(repl);
}
if (Z_TYPE_PP(from) != IS_ARRAY) {
if (Z_ISREF_PP(from)) {
SEPARATE_ZVAL(from);
}
convert_to_long_ex(from);
}
if (argc > 3) {
SEPARATE_ZVAL(len);
if (Z_TYPE_PP(len) != IS_ARRAY) {
convert_to_long_ex(len);
l = Z_LVAL_PP(len);
}
} else {
if (Z_TYPE_PP(str) != IS_ARRAY) {
l = Z_STRLEN_PP(str);
}
}
if (Z_TYPE_PP(str) == IS_STRING) {
if (
(argc == 3 && Z_TYPE_PP(from) == IS_ARRAY) ||
(argc == 4 && Z_TYPE_PP(from) != Z_TYPE_PP(len))
) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should be of same type - numerical or array ");
RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
}
if (argc == 4 && Z_TYPE_PP(from) == IS_ARRAY) {
if (zend_hash_num_elements(Z_ARRVAL_PP(from)) != zend_hash_num_elements(Z_ARRVAL_PP(len))) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should have the same number of elements");
RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
}
}
}
if (Z_TYPE_PP(str) != IS_ARRAY) {
if (Z_TYPE_PP(from) != IS_ARRAY) {
int repl_len = 0;
f = Z_LVAL_PP(from);
/* if "from" position is negative, count start position from the end
* of the string
*/
if (f < 0) {
f = Z_STRLEN_PP(str) + f;
if (f < 0) {
f = 0;
}
} else if (f > Z_STRLEN_PP(str)) {
f = Z_STRLEN_PP(str);
}
/* if "length" position is negative, set it to the length
* needed to stop that many chars from the end of the string
*/
if (l < 0) {
l = (Z_STRLEN_PP(str) - f) + l;
if (l < 0) {
l = 0;
}
}
if (f > Z_STRLEN_PP(str) || (f < 0 && -f > Z_STRLEN_PP(str))) {
RETURN_FALSE;
} else if (l > Z_STRLEN_PP(str) || (l < 0 && -l > Z_STRLEN_PP(str))) {
l = Z_STRLEN_PP(str);
}
if ((f + l) > Z_STRLEN_PP(str)) {
l = Z_STRLEN_PP(str) - f;
}
if (Z_TYPE_PP(repl) == IS_ARRAY) {
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl);
if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
convert_to_string_ex(tmp_repl);
repl_len = Z_STRLEN_PP(tmp_repl);
}
} else {
repl_len = Z_STRLEN_PP(repl);
}
result_len = Z_STRLEN_PP(str) - l + repl_len;
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_PP(str), f);
if (repl_len) {
memcpy((result + f), (Z_TYPE_PP(repl) == IS_ARRAY ? Z_STRVAL_PP(tmp_repl) : Z_STRVAL_PP(repl)), repl_len);
}
memcpy((result + f + repl_len), Z_STRVAL_PP(str) + f + l, Z_STRLEN_PP(str) - f - l);
result[result_len] = '\0';
RETURN_STRINGL(result, result_len, 0);
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Functionality of 'from' and 'len' as arrays is not implemented");
RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
}
} else { /* str is array of strings */
char *str_index = NULL;
uint str_index_len;
ulong num_index;
array_init(return_value);
if (Z_TYPE_PP(from) == IS_ARRAY) {
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(from), &pos_from);
}
if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(len), &pos_len);
}
if (Z_TYPE_PP(repl) == IS_ARRAY) {
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl);
}
zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(str), &pos_str);
while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) {
zval *orig_str;
zval dummy;
ulong refcount;
int was_ref;
if(Z_TYPE_PP(tmp_str) != IS_STRING) {
dummy = **tmp_str;
orig_str = &dummy;
zval_copy_ctor(orig_str);
convert_to_string(orig_str);
} else {
orig_str = *tmp_str;
}
was_ref = Z_ISREF_P(orig_str);
Z_UNSET_ISREF_P(orig_str);
refcount = Z_REFCOUNT_P(orig_str);
if (Z_TYPE_PP(from) == IS_ARRAY) {
if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) {
if(Z_TYPE_PP(tmp_from) != IS_LONG) {
zval dummy = **tmp_from;
zval_copy_ctor(&dummy);
convert_to_long(&dummy);
f = Z_LVAL(dummy);
} else {
f = Z_LVAL_PP(tmp_from);
}
if (f < 0) {
f = Z_STRLEN_P(orig_str) + f;
if (f < 0) {
f = 0;
}
} else if (f > Z_STRLEN_P(orig_str)) {
f = Z_STRLEN_P(orig_str);
}
zend_hash_move_forward_ex(Z_ARRVAL_PP(from), &pos_from);
} else {
f = 0;
}
} else {
f = Z_LVAL_PP(from);
if (f < 0) {
f = Z_STRLEN_P(orig_str) + f;
if (f < 0) {
f = 0;
}
} else if (f > Z_STRLEN_P(orig_str)) {
f = Z_STRLEN_P(orig_str);
}
}
if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(len), (void **) &tmp_len, &pos_len)) {
if(Z_TYPE_PP(tmp_len) != IS_LONG) {
zval dummy = **tmp_len;
zval_copy_ctor(&dummy);
convert_to_long(&dummy);
l = Z_LVAL(dummy);
} else {
l = Z_LVAL_PP(tmp_len);
}
zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len);
} else {
l = Z_STRLEN_P(orig_str);
}
} else if (argc > 3) {
l = Z_LVAL_PP(len);
} else {
l = Z_STRLEN_P(orig_str);
}
if (l < 0) {
l = (Z_STRLEN_P(orig_str) - f) + l;
if (l < 0) {
l = 0;
}
}
if ((f + l) > Z_STRLEN_P(orig_str)) {
l = Z_STRLEN_P(orig_str) - f;
}
result_len = Z_STRLEN_P(orig_str) - l;
if (Z_TYPE_PP(repl) == IS_ARRAY) {
if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
zval *repl_str;
zval zrepl;
if(Z_TYPE_PP(tmp_repl) != IS_STRING) {
zrepl = **tmp_repl;
repl_str = &zrepl;
zval_copy_ctor(repl_str);
convert_to_string(repl_str);
} else {
repl_str = *tmp_repl;
}
if(Z_REFCOUNT_P(orig_str) != refcount) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument was modified while replacing");
if(Z_TYPE_PP(tmp_repl) != IS_STRING) {
zval_dtor(repl_str);
}
break;
}
result_len += Z_STRLEN_P(repl_str);
zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_P(orig_str), f);
memcpy((result + f), Z_STRVAL_P(repl_str), Z_STRLEN_P(repl_str));
memcpy((result + f + Z_STRLEN_P(repl_str)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
if(Z_TYPE_PP(tmp_repl) != IS_STRING) {
zval_dtor(repl_str);
}
} else {
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_P(orig_str), f);
memcpy((result + f), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
}
} else {
result_len += Z_STRLEN_PP(repl);
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_P(orig_str), f);
memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl));
memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
}
result[result_len] = '\0';
if (zend_hash_get_current_key_ex(Z_ARRVAL_PP(str), &str_index, &str_index_len, &num_index, 0, &pos_str) == HASH_KEY_IS_STRING) {
add_assoc_stringl_ex(return_value, str_index, str_index_len, result, result_len, 0);
} else {
add_index_stringl(return_value, num_index, result, result_len, 0);
}
if(Z_TYPE_PP(tmp_str) != IS_STRING) {
zval_dtor(orig_str);
} else {
Z_SET_ISREF_TO_P(orig_str, was_ref);
}
zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str);
} /*while*/
} /* if */
}
/* }}} */
/* {{{ proto string quotemeta(string str)
Quotes meta characters */
PHP_FUNCTION(quotemeta)
{
char *str, *old;
char *old_end;
char *p, *q;
char c;
int old_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &old, &old_len) == FAILURE) {
return;
}
old_end = old + old_len;
if (old == old_end) {
RETURN_FALSE;
}
str = safe_emalloc(2, old_len, 1);
for (p = old, q = str; p != old_end; p++) {
c = *p;
switch (c) {
case '.':
case '\\':
case '+':
case '*':
case '?':
case '[':
case '^':
case ']':
case '$':
case '(':
case ')':
*q++ = '\\';
/* break is missing _intentionally_ */
default:
*q++ = c;
}
}
*q = 0;
RETURN_STRINGL(erealloc(str, q - str + 1), q - str, 0);
}
/* }}} */
/* {{{ proto int ord(string character)
Returns ASCII value of character */
PHP_FUNCTION(ord)
{
char *str;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
RETURN_LONG((unsigned char) str[0]);
}
/* }}} */
/* {{{ proto string chr(int ascii)
Converts ASCII code to a character */
PHP_FUNCTION(chr)
{
long c;
char temp[2];
if (ZEND_NUM_ARGS() != 1) {
WRONG_PARAM_COUNT;
}
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &c) == FAILURE) {
c = 0;
}
temp[0] = (char)c;
temp[1] = '\0';
RETURN_STRINGL(temp, 1, 1);
}
/* }}} */
/* {{{ php_ucfirst
Uppercase the first character of the word in a native string */
static void php_ucfirst(char *str)
{
register char *r;
r = str;
*r = toupper((unsigned char) *r);
}
/* }}} */
/* {{{ proto string ucfirst(string str)
Makes a string's first character uppercase */
PHP_FUNCTION(ucfirst)
{
char *str;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
if (!str_len) {
RETURN_EMPTY_STRING();
}
ZVAL_STRINGL(return_value, str, str_len, 1);
php_ucfirst(Z_STRVAL_P(return_value));
}
/* }}} */
/* {{{
Lowercase the first character of the word in a native string */
static void php_lcfirst(char *str)
{
register char *r;
r = str;
*r = tolower((unsigned char) *r);
}
/* }}} */
/* {{{ proto string lcfirst(string str)
Make a string's first character lowercase */
PHP_FUNCTION(lcfirst)
{
char *str;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
if (!str_len) {
RETURN_EMPTY_STRING();
}
ZVAL_STRINGL(return_value, str, str_len, 1);
php_lcfirst(Z_STRVAL_P(return_value));
}
/* }}} */
/* {{{ proto string ucwords(string str)
Uppercase the first character of every word in a string */
PHP_FUNCTION(ucwords)
{
char *str;
register char *r, *r_end;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
if (!str_len) {
RETURN_EMPTY_STRING();
}
ZVAL_STRINGL(return_value, str, str_len, 1);
r = Z_STRVAL_P(return_value);
*r = toupper((unsigned char) *r);
for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) {
if (isspace((int) *(unsigned char *)r++)) {
*r = toupper((unsigned char) *r);
}
}
}
/* }}} */
/* {{{ php_strtr
*/
PHPAPI char *php_strtr(char *str, int len, char *str_from, char *str_to, int trlen)
{
int i;
unsigned char xlat[256];
if ((trlen < 1) || (len < 1)) {
return str;
}
for (i = 0; i < 256; xlat[i] = i, i++);
for (i = 0; i < trlen; i++) {
xlat[(unsigned char) str_from[i]] = str_to[i];
}
for (i = 0; i < len; i++) {
str[i] = xlat[(unsigned char) str[i]];
}
return str;
}
/* }}} */
/* {{{ php_strtr_array
*/
static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *hash)
{
zval **entry;
char *string_key;
uint string_key_len;
zval **trans;
zval ctmp;
ulong num_key;
int minlen = 128*1024;
int maxlen = 0, pos, len, found;
char *key;
HashPosition hpos;
smart_str result = {0};
HashTable tmp_hash;
zend_hash_init(&tmp_hash, zend_hash_num_elements(hash), NULL, NULL, 0);
zend_hash_internal_pointer_reset_ex(hash, &hpos);
while (zend_hash_get_current_data_ex(hash, (void **)&entry, &hpos) == SUCCESS) {
switch (zend_hash_get_current_key_ex(hash, &string_key, &string_key_len, &num_key, 0, &hpos)) {
case HASH_KEY_IS_STRING:
len = string_key_len-1;
if (len < 1) {
zend_hash_destroy(&tmp_hash);
RETURN_FALSE;
}
zend_hash_add(&tmp_hash, string_key, string_key_len, entry, sizeof(zval*), NULL);
if (len > maxlen) {
maxlen = len;
}
if (len < minlen) {
minlen = len;
}
break;
case HASH_KEY_IS_LONG:
Z_TYPE(ctmp) = IS_LONG;
Z_LVAL(ctmp) = num_key;
convert_to_string(&ctmp);
len = Z_STRLEN(ctmp);
zend_hash_add(&tmp_hash, Z_STRVAL(ctmp), len+1, entry, sizeof(zval*), NULL);
zval_dtor(&ctmp);
if (len > maxlen) {
maxlen = len;
}
if (len < minlen) {
minlen = len;
}
break;
}
zend_hash_move_forward_ex(hash, &hpos);
}
key = emalloc(maxlen+1);
pos = 0;
while (pos < slen) {
if ((pos + maxlen) > slen) {
maxlen = slen - pos;
}
found = 0;
memcpy(key, str+pos, maxlen);
for (len = maxlen; len >= minlen; len--) {
key[len] = 0;
if (zend_hash_find(&tmp_hash, key, len+1, (void**)&trans) == SUCCESS) {
char *tval;
int tlen;
zval tmp;
if (Z_TYPE_PP(trans) != IS_STRING) {
tmp = **trans;
zval_copy_ctor(&tmp);
convert_to_string(&tmp);
tval = Z_STRVAL(tmp);
tlen = Z_STRLEN(tmp);
} else {
tval = Z_STRVAL_PP(trans);
tlen = Z_STRLEN_PP(trans);
}
smart_str_appendl(&result, tval, tlen);
pos += len;
found = 1;
if (Z_TYPE_PP(trans) != IS_STRING) {
zval_dtor(&tmp);
}
break;
}
}
if (! found) {
smart_str_appendc(&result, str[pos++]);
}
}
efree(key);
zend_hash_destroy(&tmp_hash);
smart_str_0(&result);
RETVAL_STRINGL(result.c, result.len, 0);
}
/* }}} */
/* {{{ proto string strtr(string str, string from[, string to])
Translates characters in str using given translation tables */
PHP_FUNCTION(strtr)
{
zval **from;
char *str, *to = NULL;
int str_len, to_len = 0;
int ac = ZEND_NUM_ARGS();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &str, &str_len, &from, &to, &to_len) == FAILURE) {
return;
}
if (ac == 2 && Z_TYPE_PP(from) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument is not an array");
RETURN_FALSE;
}
/* shortcut for empty string */
if (str_len == 0) {
RETURN_EMPTY_STRING();
}
if (ac == 2) {
php_strtr_array(return_value, str, str_len, HASH_OF(*from));
} else {
convert_to_string_ex(from);
ZVAL_STRINGL(return_value, str, str_len, 1);
php_strtr(Z_STRVAL_P(return_value),
Z_STRLEN_P(return_value),
Z_STRVAL_PP(from),
to,
MIN(Z_STRLEN_PP(from),
to_len));
}
}
/* }}} */
/* {{{ proto string strrev(string str)
Reverse a string */
PHP_FUNCTION(strrev)
{
char *str;
char *e, *n, *p;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
n = emalloc(str_len+1);
p = n;
e = str + str_len;
while (--e>=str) {
*p++ = *e;
}
*p = '\0';
RETVAL_STRINGL(n, str_len, 0);
}
/* }}} */
/* {{{ php_similar_str
*/
static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
{
char *p, *q;
char *end1 = (char *) txt1 + len1;
char *end2 = (char *) txt2 + len2;
int l;
*max = 0;
for (p = (char *) txt1; p < end1; p++) {
for (q = (char *) txt2; q < end2; q++) {
for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
if (l > *max) {
*max = l;
*pos1 = p - txt1;
*pos2 = q - txt2;
}
}
}
}
/* }}} */
/* {{{ php_similar_char
*/
static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2)
{
int sum;
int pos1, pos2, max;
php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
if ((sum = max)) {
if (pos1 && pos2) {
sum += php_similar_char(txt1, pos1,
txt2, pos2);
}
if ((pos1 + max < len1) && (pos2 + max < len2)) {
sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
txt2 + pos2 + max, len2 - pos2 - max);
}
}
return sum;
}
/* }}} */
/* {{{ proto int similar_text(string str1, string str2 [, float percent])
Calculates the similarity between two strings */
PHP_FUNCTION(similar_text)
{
char *t1, *t2;
zval **percent = NULL;
int ac = ZEND_NUM_ARGS();
int sim;
int t1_len, t2_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Z", &t1, &t1_len, &t2, &t2_len, &percent) == FAILURE) {
return;
}
if (ac > 2) {
convert_to_double_ex(percent);
}
if (t1_len + t2_len == 0) {
if (ac > 2) {
Z_DVAL_PP(percent) = 0;
}
RETURN_LONG(0);
}
sim = php_similar_char(t1, t1_len, t2, t2_len);
if (ac > 2) {
Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len);
}
RETURN_LONG(sim);
}
/* }}} */
/* {{{ php_stripslashes
*
* be careful, this edits the string in-place */
PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC)
{
char *s, *t;
int l;
if (len != NULL) {
l = *len;
} else {
l = strlen(str);
}
s = str;
t = str;
while (l > 0) {
if (*t == '\\') {
t++; /* skip the slash */
if (len != NULL) {
(*len)--;
}
l--;
if (l > 0) {
if (*t == '0') {
*s++='\0';
t++;
} else {
*s++ = *t++; /* preserve the next character */
}
l--;
}
} else {
*s++ = *t++;
l--;
}
}
if (s != t) {
*s = '\0';
}
}
/* }}} */
/* {{{ proto string addcslashes(string str, string charlist)
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...) */
PHP_FUNCTION(addcslashes)
{
char *str, *what;
int str_len, what_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &str, &str_len, &what, &what_len) == FAILURE) {
return;
}
if (str_len == 0) {
RETURN_EMPTY_STRING();
}
if (what_len == 0) {
RETURN_STRINGL(str, str_len, 1);
}
Z_STRVAL_P(return_value) = php_addcslashes(str, str_len, &Z_STRLEN_P(return_value), 0, what, what_len TSRMLS_CC);
RETURN_STRINGL(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), 0);
}
/* }}} */
/* {{{ proto string addslashes(string str)
Escapes single quote, double quotes and backslash characters in a string with backslashes */
PHP_FUNCTION(addslashes)
{
char *str;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
if (str_len == 0) {
RETURN_EMPTY_STRING();
}
RETURN_STRING(php_addslashes(str,
str_len,
&Z_STRLEN_P(return_value), 0
TSRMLS_CC), 0);
}
/* }}} */
/* {{{ proto string stripcslashes(string str)
Strips backslashes from a string. Uses C-style conventions */
PHP_FUNCTION(stripcslashes)
{
char *str;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
ZVAL_STRINGL(return_value, str, str_len, 1);
php_stripcslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value));
}
/* }}} */
/* {{{ proto string stripslashes(string str)
Strips backslashes from a string */
PHP_FUNCTION(stripslashes)
{
char *str;
int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
return;
}
ZVAL_STRINGL(return_value, str, str_len, 1);
php_stripslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC);
}
/* }}} */
#ifndef HAVE_STRERROR
/* {{{ php_strerror
*/
char *php_strerror(int errnum)
{
extern int sys_nerr;
extern char *sys_errlist[];
TSRMLS_FETCH();
if ((unsigned int) errnum < sys_nerr) {
return(sys_errlist[errnum]);
}
(void) snprintf(BG(str_ebuf), sizeof(php_basic_globals.str_ebuf), "Unknown error: %d", errnum);
return(BG(str_ebuf));
}
/* }}} */
#endif
/* {{{ php_stripcslashes
*/
PHPAPI void php_stripcslashes(char *str, int *len)
{
char *source, *target, *end;
int nlen = *len, i;
char numtmp[4];
for (source=str, end=str+nlen, target=str; source < end; source++) {
if (*source == '\\' && source+1 < end) {
source++;
switch (*source) {
case 'n': *target++='\n'; nlen--; break;
case 'r': *target++='\r'; nlen--; break;
case 'a': *target++='\a'; nlen--; break;
case 't': *target++='\t'; nlen--; break;
case 'v': *target++='\v'; nlen--; break;
case 'b': *target++='\b'; nlen--; break;
case 'f': *target++='\f'; nlen--; break;
case '\\': *target++='\\'; nlen--; break;
case 'x':
if (source+1 < end && isxdigit((int)(*(source+1)))) {
numtmp[0] = *++source;
if (source+1 < end && isxdigit((int)(*(source+1)))) {
numtmp[1] = *++source;
numtmp[2] = '\0';
nlen-=3;
} else {
numtmp[1] = '\0';
nlen-=2;
}
*target++=(char)strtol(numtmp, NULL, 16);
break;
}
/* break is left intentionally */
default:
i=0;
while (source < end && *source >= '0' && *source <= '7' && i<3) {
numtmp[i++] = *source++;
}
if (i) {
numtmp[i]='\0';
*target++=(char)strtol(numtmp, NULL, 8);
nlen-=i;
source--;
} else {
*target++=*source;
nlen--;
}
}
} else {
*target++=*source;
}
}
if (nlen != 0) {
*target='\0';
}
*len = nlen;
}
/* }}} */
/* {{{ php_addcslashes
*/
PHPAPI char *php_addcslashes(const char *str, int length, int *new_length, int should_free, char *what, int wlength TSRMLS_DC)
{
char flags[256];
char *new_str = safe_emalloc(4, (length?length:(length=strlen(str))), 1);
char *source, *target;
char *end;
char c;
int newlen;
if (!wlength) {
wlength = strlen(what);
}
php_charmask((unsigned char *)what, wlength, flags TSRMLS_CC);
for (source = (char*)str, end = source + length, target = new_str; source < end; source++) {
c = *source;
if (flags[(unsigned char)c]) {
if ((unsigned char) c < 32 || (unsigned char) c > 126) {
*target++ = '\\';
switch (c) {
case '\n': *target++ = 'n'; break;
case '\t': *target++ = 't'; break;
case '\r': *target++ = 'r'; break;
case '\a': *target++ = 'a'; break;
case '\v': *target++ = 'v'; break;
case '\b': *target++ = 'b'; break;
case '\f': *target++ = 'f'; break;
default: target += sprintf(target, "%03o", (unsigned char) c);
}
continue;
}
*target++ = '\\';
}
*target++ = c;
}
*target = 0;
newlen = target - new_str;
if (target - new_str < length * 4) {
new_str = erealloc(new_str, newlen + 1);
}
if (new_length) {
*new_length = newlen;
}
if (should_free) {
STR_FREE((char*)str);
}
return new_str;
}
/* }}} */
/* {{{ php_addslashes
*/
PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC)
{
/* maximum string length, worst case situation */
char *new_str;
char *source, *target;
char *end;
int local_new_length;
if (!new_length) {
new_length = &local_new_length;
}
if (!str) {
*new_length = 0;
return str;
}
new_str = (char *) safe_emalloc(2, (length ? length : (length = strlen(str))), 1);
source = str;
end = source + length;
target = new_str;
while (source < end) {
switch (*source) {
case '\0':
*target++ = '\\';
*target++ = '0';
break;
case '\'':
case '\"':
case '\\':
*target++ = '\\';
/* break is missing *intentionally* */
default:
*target++ = *source;
break;
}
source++;
}
*target = 0;
*new_length = target - new_str;
if (should_free) {
STR_FREE(str);
}
new_str = (char *) erealloc(new_str, *new_length + 1);
return new_str;
}
/* }}} */
#define _HEB_BLOCK_TYPE_ENG 1
#define _HEB_BLOCK_TYPE_HEB 2
#define isheb(c) (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0)
#define _isblank(c) (((((unsigned char) c) == ' ' || ((unsigned char) c) == '\t')) ? 1 : 0)
#define _isnewline(c) (((((unsigned char) c) == '\n' || ((unsigned char) c) == '\r')) ? 1 : 0)
/* {{{ php_char_to_str_ex
*/
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)
{
int char_count = 0;
int replaced = 0;
char *source, *target, *tmp, *source_end=str+len, *tmp_end = NULL;
if (case_sensitivity) {
char *p = str, *e = p + len;
while ((p = memchr(p, from, (e - p)))) {
char_count++;
p++;
}
} else {
for (source = str; source < source_end; source++) {
if (tolower(*source) == tolower(from)) {
char_count++;
}
}
}
if (char_count == 0 && case_sensitivity) {
ZVAL_STRINGL(result, str, len, 1);
return 0;
}
Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1);
Z_TYPE_P(result) = IS_STRING;
if (case_sensitivity) {
char *p = str, *e = p + len, *s = str;
while ((p = memchr(p, from, (e - p)))) {
memcpy(target, s, (p - s));
target += p - s;
memcpy(target, to, to_len);
target += to_len;
p++;
s = p;
if (replace_count) {
*replace_count += 1;
}
}
if (s < e) {
memcpy(target, s, (e - s));
target += e - s;
}
} else {
for (source = str; source < source_end; source++) {
if (tolower(*source) == tolower(from)) {
replaced = 1;
if (replace_count) {
*replace_count += 1;
}
for (tmp = to, tmp_end = tmp+to_len; tmp < tmp_end; tmp++) {
*target = *tmp;
target++;
}
} else {
*target = *source;
target++;
}
}
}
*target = 0;
return replaced;
}
/* }}} */
/* {{{ php_char_to_str
*/
PHPAPI int php_char_to_str(char *str, uint len, char from, char *to, int to_len, zval *result)
{
return php_char_to_str_ex(str, len, from, to, to_len, result, 1, NULL);
}
/* }}} */
/* {{{ php_str_to_str_ex
*/
PHPAPI char *php_str_to_str_ex(char *haystack, int length,
char *needle, int needle_len, char *str, int str_len, int *_new_length, int case_sensitivity, int *replace_count)
{
char *new_str;
if (needle_len < length) {
char *end, *haystack_dup = NULL, *needle_dup = NULL;
char *e, *s, *p, *r;
if (needle_len == str_len) {
new_str = estrndup(haystack, length);
*_new_length = length;
if (case_sensitivity) {
end = new_str + length;
for (p = new_str; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
memcpy(r, str, str_len);
if (replace_count) {
(*replace_count)++;
}
}
} else {
haystack_dup = estrndup(haystack, length);
needle_dup = estrndup(needle, needle_len);
php_strtolower(haystack_dup, length);
php_strtolower(needle_dup, needle_len);
end = haystack_dup + length;
for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
memcpy(new_str + (r - haystack_dup), str, str_len);
if (replace_count) {
(*replace_count)++;
}
}
efree(haystack_dup);
efree(needle_dup);
}
return new_str;
} else {
if (!case_sensitivity) {
haystack_dup = estrndup(haystack, length);
needle_dup = estrndup(needle, needle_len);
php_strtolower(haystack_dup, length);
php_strtolower(needle_dup, needle_len);
}
if (str_len < needle_len) {
new_str = emalloc(length + 1);
} else {
int count = 0;
char *o, *n, *endp;
if (case_sensitivity) {
o = haystack;
n = needle;
} else {
o = haystack_dup;
n = needle_dup;
}
endp = o + length;
while ((o = php_memnstr(o, n, needle_len, endp))) {
o += needle_len;
count++;
}
if (count == 0) {
/* Needle doesn't occur, shortcircuit the actual replacement. */
if (haystack_dup) {
efree(haystack_dup);
}
if (needle_dup) {
efree(needle_dup);
}
new_str = estrndup(haystack, length);
if (_new_length) {
*_new_length = length;
}
return new_str;
} else {
new_str = safe_emalloc(count, str_len - needle_len, length + 1);
}
}
e = s = new_str;
if (case_sensitivity) {
end = haystack + length;
for (p = haystack; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
memcpy(e, p, r - p);
e += r - p;
memcpy(e, str, str_len);
e += str_len;
if (replace_count) {
(*replace_count)++;
}
}
if (p < end) {
memcpy(e, p, end - p);
e += end - p;
}
} else {
end = haystack_dup + length;
for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
memcpy(e, haystack + (p - haystack_dup), r - p);
e += r - p;
memcpy(e, str, str_len);
e += str_len;
if (replace_count) {
(*replace_count)++;
}
}
if (p < end) {
memcpy(e, haystack + (p - haystack_dup), end - p);
e += end - p;
}
}
if (haystack_dup) {
efree(haystack_dup);
}
if (needle_dup) {
efree(needle_dup);
}
*e = '\0';
*_new_length = e - s;
new_str = erealloc(new_str, *_new_length + 1);
return new_str;
}
} else if (needle_len > length) {
nothing_todo:
*_new_length = length;
new_str = estrndup(haystack, length);
return new_str;
} else {
if (case_sensitivity && memcmp(haystack, needle, length)) {
goto nothing_todo;
} else if (!case_sensitivity) {
char *l_haystack, *l_needle;
l_haystack = estrndup(haystack, length);
l_needle = estrndup(needle, length);
php_strtolower(l_haystack, length);
php_strtolower(l_needle, length);
if (memcmp(l_haystack, l_needle, length)) {
efree(l_haystack);
efree(l_needle);
goto nothing_todo;
}
efree(l_haystack);
efree(l_needle);
}
*_new_length = str_len;
new_str = estrndup(str, str_len);
if (replace_count) {
(*replace_count)++;
}
return new_str;
}
}
/* }}} */
/* {{{ php_str_to_str
*/
PHPAPI char *php_str_to_str(char *haystack, int length,
char *needle, int needle_len, char *str, int str_len, int *_new_length)
{
return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, _new_length, 1, NULL);
}
/* }}} */
/* {{{ php_str_replace_in_subject
*/
static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int *replace_count)
{
zval **search_entry,
**replace_entry = NULL,
temp_result;
char *replace_value = NULL;
int replace_len = 0;
/* Make sure we're dealing with strings. */
convert_to_string_ex(subject);
Z_TYPE_P(result) = IS_STRING;
if (Z_STRLEN_PP(subject) == 0) {
ZVAL_STRINGL(result, "", 0, 1);
return;
}
/* If search is an array */
if (Z_TYPE_P(search) == IS_ARRAY) {
/* Duplicate subject string for repeated replacement */
MAKE_COPY_ZVAL(subject, result);
zend_hash_internal_pointer_reset(Z_ARRVAL_P(search));
if (Z_TYPE_P(replace) == IS_ARRAY) {
zend_hash_internal_pointer_reset(Z_ARRVAL_P(replace));
} else {
/* Set replacement value to the passed one */
replace_value = Z_STRVAL_P(replace);
replace_len = Z_STRLEN_P(replace);
}
/* For each entry in the search array, get the entry */
while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) {
/* Make sure we're dealing with strings. */
SEPARATE_ZVAL(search_entry);
convert_to_string(*search_entry);
if (Z_STRLEN_PP(search_entry) == 0) {
zend_hash_move_forward(Z_ARRVAL_P(search));
if (Z_TYPE_P(replace) == IS_ARRAY) {
zend_hash_move_forward(Z_ARRVAL_P(replace));
}
continue;
}
/* If replace is an array. */
if (Z_TYPE_P(replace) == IS_ARRAY) {
/* Get current entry */
if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) {
/* Make sure we're dealing with strings. */
convert_to_string_ex(replace_entry);
/* Set replacement value to the one we got from array */
replace_value = Z_STRVAL_PP(replace_entry);
replace_len = Z_STRLEN_PP(replace_entry);
zend_hash_move_forward(Z_ARRVAL_P(replace));
} else {
/* We've run out of replacement strings, so use an empty one. */
replace_value = "";
replace_len = 0;
}
}
if (Z_STRLEN_PP(search_entry) == 1) {
php_char_to_str_ex(Z_STRVAL_P(result),
Z_STRLEN_P(result),
Z_STRVAL_PP(search_entry)[0],
replace_value,
replace_len,
&temp_result,
case_sensitivity,
replace_count);
} else if (Z_STRLEN_PP(search_entry) > 1) {
Z_STRVAL(temp_result) = php_str_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result),
Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry),
replace_value, replace_len, &Z_STRLEN(temp_result), case_sensitivity, replace_count);
}
str_efree(Z_STRVAL_P(result));
Z_STRVAL_P(result) = Z_STRVAL(temp_result);
Z_STRLEN_P(result) = Z_STRLEN(temp_result);
if (Z_STRLEN_P(result) == 0) {
return;
}
zend_hash_move_forward(Z_ARRVAL_P(search));
}
} else {
if (Z_STRLEN_P(search) == 1) {
php_char_to_str_ex(Z_STRVAL_PP(subject),
Z_STRLEN_PP(subject),
Z_STRVAL_P(search)[0],
Z_STRVAL_P(replace),
Z_STRLEN_P(replace),
result,
case_sensitivity,
replace_count);
} else if (Z_STRLEN_P(search) > 1) {
Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject),
Z_STRVAL_P(search), Z_STRLEN_P(search),
Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), case_sensitivity, replace_count);
} else {
MAKE_COPY_ZVAL(subject, result);
}
}
}
/* }}} */
/* {{{ php_str_replace_common
*/
static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
{
zval **subject, **search, **replace, **subject_entry, **zcount = NULL;
zval *result;
char *string_key;
uint string_key_len;
ulong num_key;
int count = 0;
int argc = ZEND_NUM_ARGS();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &search, &replace, &subject, &zcount) == FAILURE) {
return;
}
SEPARATE_ZVAL(search);
SEPARATE_ZVAL(replace);
SEPARATE_ZVAL(subject);
/* Make sure we're dealing with strings and do the replacement. */
if (Z_TYPE_PP(search) != IS_ARRAY) {
convert_to_string_ex(search);
convert_to_string_ex(replace);
} else if (Z_TYPE_PP(replace) != IS_ARRAY) {
convert_to_string_ex(replace);
}
/* if subject is an array */
if (Z_TYPE_PP(subject) == IS_ARRAY) {
array_init(return_value);
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject));
/* For each subject entry, convert it to string, then perform replacement
and add the result to the return_value array. */
while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) {
if (Z_TYPE_PP(subject_entry) != IS_ARRAY && Z_TYPE_PP(subject_entry) != IS_OBJECT) {
MAKE_STD_ZVAL(result);
SEPARATE_ZVAL(subject_entry);
php_str_replace_in_subject(*search, *replace, subject_entry, result, case_sensitivity, (argc > 3) ? &count : NULL);
} else {
ALLOC_ZVAL(result);
Z_ADDREF_P(*subject_entry);
COPY_PZVAL_TO_ZVAL(*result, *subject_entry);
}
/* Add to return array */
switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), &string_key,
&string_key_len, &num_key, 0, NULL)) {
case HASH_KEY_IS_STRING:
add_assoc_zval_ex(return_value, string_key, string_key_len, result);
break;
case HASH_KEY_IS_LONG:
add_index_zval(return_value, num_key, result);