#include <stdio.h>
#include "php.h"
#include "reg.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
#ifdef HAVE_LIBINTL
# include <libintl.h>
#endif
#include <math.h>
#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
#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
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
# 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);
static char hexconvtab[] = "0123456789abcdef";
#ifdef ZTS
static MUTEX_T locale_mutex = NULL;
#endif
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 = (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 result;
}
#ifdef HAVE_LOCALECONV
PHPAPI struct lconv *localeconv_r(struct lconv *out)
{
struct lconv *res;
# ifdef ZTS
tsrm_mutex_lock( locale_mutex );
# endif
res = localeconv();
*out = *res;
# ifdef ZTS
tsrm_mutex_unlock( locale_mutex );
# endif
return out;
}
# ifdef ZTS
PHP_MINIT_FUNCTION(localeconv)
{
locale_mutex = tsrm_mutex_alloc();
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(localeconv)
{
tsrm_mutex_free( locale_mutex );
locale_mutex = NULL;
return SUCCESS;
}
# endif
#endif
PHP_FUNCTION(bin2hex)
{
zval **data;
char *result;
size_t newlen;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &data) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(data);
result = php_bin2hex(Z_STRVAL_PP(data), Z_STRLEN_PP(data), &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, len;
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;
}
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 ,
s22 ,
s11 + start + len ,
s22 + len2 ));
} else if (behavior == STR_STRCSPN) {
RETURN_LONG(php_strcspn(s11 + start ,
s22 ,
s11 + start + len ,
s22 + len2 ));
}
}
PHP_FUNCTION(strspn)
{
php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN);
}
PHP_FUNCTION(strcspn)
{
php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN);
}
#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;
}
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
PHP_FUNCTION(strcoll)
{
zval **s1, **s2;
if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(s1);
convert_to_string_ex(s2);
RETURN_LONG(strcoll((const char *) Z_STRVAL_PP(s1),
(const char *) Z_STRVAL_PP(s2)));
}
#endif
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] == '.') {
if (end-len >= input) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
result = FAILURE;
continue;
}
if (input+2 >= end) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
result = FAILURE;
continue;
}
if (input[-1] > input[2]) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
result = FAILURE;
continue;
}
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range");
result = FAILURE;
continue;
} else {
mask[c]=1;
}
}
return result;
}
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(what, what_len, mask TSRMLS_CC);
} else {
php_charmask(" \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 "";
}
static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
zval **str;
zval **what = NULL;
int argc = ZEND_NUM_ARGS();
if (argc < 1 || argc > 2 || zend_get_parameters_ex(argc, &str, &what) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
if (argc > 1) {
convert_to_string_ex(what);
php_trim(Z_STRVAL_PP(str), Z_STRLEN_PP(str), Z_STRVAL_PP(what), Z_STRLEN_PP(what), return_value, mode TSRMLS_CC);
} else {
php_trim(Z_STRVAL_PP(str), Z_STRLEN_PP(str), NULL, 0, return_value, mode TSRMLS_CC);
}
}
PHP_FUNCTION(trim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
}
PHP_FUNCTION(rtrim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
}
PHP_FUNCTION(ltrim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
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;
}
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;
} 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 {
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);
}
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;
}
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--;
}
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;
}
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--;
}
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--;
}
}
if (laststart != current) {
memcpy(newtext+newtextlen, text+laststart, current-laststart);
newtextlen += current - laststart;
}
newtext[newtextlen] = '\0';
newtext = erealloc(newtext, newtextlen+1);
RETURN_STRINGL(newtext, newtextlen, 0);
}
}
PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, int 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 || --limit > 1));
if (p1 <= endp)
add_next_index_stringl(return_value, p1, endp-p1, 1);
}
}
PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, int limit)
{
#define EXPLODE_ALLOC_STEP 50
char *p1, *p2, *endp;
int allocated = EXPLODE_ALLOC_STEP, found = 0, i = 0, to_return = 0;
char **positions = safe_emalloc(allocated, sizeof(char *), 0);
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) {
} else {
positions[found++] = p1;
do {
if (found >= allocated) {
allocated = found + EXPLODE_ALLOC_STEP;
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;
for (i = 0;i < to_return;i++) {
add_next_index_stringl(return_value, positions[i],
(positions[i+1] - Z_STRLEN_P(delim)) - positions[i],
1
);
}
}
efree(positions);
#undef EXPLODE_ALLOC_STEP
}
PHP_FUNCTION(explode)
{
zval **str, **delim, **zlimit = NULL;
int limit = -1;
int argc = ZEND_NUM_ARGS();
if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &delim, &str, &zlimit) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
convert_to_string_ex(delim);
if (argc > 2) {
convert_to_long_ex(zlimit);
limit = Z_LVAL_PP(zlimit);
}
if (! Z_STRLEN_PP(delim)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
array_init(return_value);
if (! Z_STRLEN_PP(str)) {
add_next_index_stringl(return_value, "", sizeof("") - 1, 1);
return;
}
if (limit == 0 || limit == 1) {
add_index_stringl(return_value, 0, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
} else if (limit < 0 && argc == 3) {
php_explode_negative_limit(*delim, *str, return_value, limit);
} else {
php_explode(*delim, *str, return_value, limit);
}
}
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, ©);
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();
}
}
PHP_FUNCTION(implode)
{
zval **arg1 = NULL, **arg2 = NULL, *delim, *arr;
int argc = ZEND_NUM_ARGS();
HashPosition pos;
if (argc < 1 || argc > 2 ||
zend_get_parameters_ex(argc, &arg1, &arg2) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (argc == 1) {
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;
}
}
pos = Z_ARRVAL_P(arr)->pInternalPointer;
php_implode(delim, arr, return_value TSRMLS_CC);
Z_ARRVAL_P(arr)->pInternalPointer = pos;
if (argc == 1) {
FREE_ZVAL(delim);
}
}
#define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
PHP_FUNCTION(strtok)
{
zval **args[2];
zval **tok, **str;
char *token;
char *token_end;
char *p;
char *pe;
int skipped = 0;
if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 2 || zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args) == FAILURE) {
WRONG_PARAM_COUNT;
}
switch (ZEND_NUM_ARGS()) {
case 1:
tok = args[0];
break;
default:
case 2:
str = args[0];
tok = args[1];
convert_to_string_ex(str);
zval_add_ref(str);
if (BG(strtok_zval)) {
zval_ptr_dtor(&BG(strtok_zval));
}
BG(strtok_zval) = *str;
BG(strtok_last) = BG(strtok_string) = Z_STRVAL_PP(str);
BG(strtok_len) = Z_STRLEN_PP(str);
break;
}
p = BG(strtok_last);
pe = BG(strtok_string) + BG(strtok_len);
if (!p || p >= pe) {
RETURN_FALSE;
}
convert_to_string_ex(tok);
token = Z_STRVAL_PP(tok);
token_end = token + Z_STRLEN_PP(tok);
while (token < token_end) {
STRTOK_TABLE(token++) = 1;
}
while (STRTOK_TABLE(p)) {
if (++p >= pe) {
BG(strtok_last) = NULL;
RETVAL_FALSE;
goto restore;
}
skipped++;
}
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:
token = Z_STRVAL_PP(tok);
while (token < token_end) {
STRTOK_TABLE(token++) = 0;
}
}
PHPAPI char *php_strtoupper(char *s, size_t len)
{
unsigned char *c, *e;
c = s;
e = c+len;
while (c < e) {
*c = toupper(*c);
c++;
}
return s;
}
PHP_FUNCTION(strtoupper)
{
zval **arg;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(arg);
RETVAL_ZVAL(*arg, 1, 0);
php_strtoupper(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
}
PHPAPI char *php_strtolower(char *s, size_t len)
{
unsigned char *c, *e;
c = s;
e = c+len;
while (c < e) {
*c = tolower(*c);
c++;
}
return s;
}
PHP_FUNCTION(strtolower)
{
zval **str;
char *ret;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str)) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
RETVAL_ZVAL(*str, 1, 0);
ret = php_strtolower(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value));
}
PHPAPI void php_basename(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 = 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_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;
}
}
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);
}
PHPAPI size_t php_dirname(char *path, size_t len)
{
register char *end = path + len - 1;
unsigned int len_adjust = 0;
#ifdef PHP_WIN32
if ((2 <= len) && isalpha((int)((unsigned char *)path)[0]) && (':' == path[1])) {
path += 2;
len_adjust += 2;
if (2 == len) {
return len;
}
}
#elif defined(NETWARE)
char *colonpos = NULL;
colonpos = strchr(path, ':');
if(colonpos != NULL) {
len_adjust = ((colonpos - path) + 1);
path += len_adjust;
if(len_adjust == len) {
return len;
}
}
#endif
if (len == 0) {
return 0;
}
while (end >= path && IS_SLASH_P(end)) {
end--;
}
if (end < path) {
path[0] = DEFAULT_SLASH;
path[1] = '\0';
return 1 + len_adjust;
}
while (end >= path && !IS_SLASH_P(end)) {
end--;
}
if (end < path) {
#ifdef NETWARE
if(len_adjust == 0) {
path[0] = '.';
path[1] = '\0';
return 1; }
else {
path[0] = '\0';
return len_adjust;
}
#else
path[0] = '.';
path[1] = '\0';
return 1 + len_adjust;
#endif
}
while (end >= path && IS_SLASH_P(end)) {
end--;
}
if (end < path) {
path[0] = DEFAULT_SLASH;
path[1] = '\0';
return 1 + len_adjust;
}
*(end+1) = '\0';
return (size_t)(end + 1 - path) + len_adjust;
}
PHP_FUNCTION(dirname)
{
zval **str;
char *ret;
size_t ret_len;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
ret = estrndup(Z_STRVAL_PP(str), Z_STRLEN_PP(str));
ret_len = php_dirname(ret, Z_STRLEN_PP(str));
RETURN_STRINGL(ret, ret_len, 0);
}
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) {
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) {
char *p;
int idx;
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);
}
PHPAPI char *php_stristr(unsigned char *s, unsigned 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);
}
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);
}
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;
}
}
PHP_FUNCTION(stristr)
{
zval **haystack, **needle;
char *found = NULL;
int found_offset;
char *haystack_orig;
char needle_char[2];
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) == FAILURE) {
WRONG_PARAM_COUNT;
}
SEPARATE_ZVAL(haystack);
SEPARATE_ZVAL(needle);
convert_to_string_ex(haystack);
haystack_orig = estrndup(Z_STRVAL_PP(haystack), Z_STRLEN_PP(haystack));
if (Z_TYPE_PP(needle) == IS_STRING) {
if (!Z_STRLEN_PP(needle)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
efree(haystack_orig);
RETURN_FALSE;
}
found = php_stristr(Z_STRVAL_PP(haystack),
Z_STRVAL_PP(needle),
Z_STRLEN_PP(haystack),
Z_STRLEN_PP(needle));
} else {
convert_to_long_ex(needle);
needle_char[0] = (char) Z_LVAL_PP(needle);
needle_char[1] = 0;
found = php_stristr(Z_STRVAL_PP(haystack),
needle_char,
Z_STRLEN_PP(haystack),
1);
}
if (found) {
found_offset = found - Z_STRVAL_PP(haystack);
RETVAL_STRINGL(haystack_orig + found_offset, Z_STRLEN_PP(haystack) - found_offset, 1);
} else {
RETVAL_FALSE;
}
efree(haystack_orig);
}
PHP_FUNCTION(strstr)
{
zval **haystack, **needle;
char *found = NULL;
char needle_char[2];
long found_offset;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(haystack);
if (Z_TYPE_PP(needle) == IS_STRING) {
if (!Z_STRLEN_PP(needle)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
found = php_memnstr(Z_STRVAL_PP(haystack),
Z_STRVAL_PP(needle),
Z_STRLEN_PP(needle),
Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
} else {
convert_to_long_ex(needle);
needle_char[0] = (char) Z_LVAL_PP(needle);
needle_char[1] = 0;
found = php_memnstr(Z_STRVAL_PP(haystack),
needle_char,
1,
Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
}
if (found) {
found_offset = found - Z_STRVAL_PP(haystack);
RETURN_STRINGL(found, Z_STRLEN_PP(haystack) - found_offset, 1);
} else {
RETURN_FALSE;
}
}
PHP_FUNCTION(strpos)
{
zval **haystack, **needle, **z_offset;
char *found = NULL;
char needle_char[2];
int offset = 0;
int argc = ZEND_NUM_ARGS();
if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &haystack, &needle, &z_offset) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(haystack);
if (argc > 2) {
convert_to_long_ex(z_offset);
offset = Z_LVAL_PP(z_offset);
}
if (offset < 0 || offset > Z_STRLEN_PP(haystack)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
RETURN_FALSE;
}
if (Z_TYPE_PP(needle) == IS_STRING) {
if (!Z_STRLEN_PP(needle)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
RETURN_FALSE;
}
found = php_memnstr(Z_STRVAL_PP(haystack) + offset,
Z_STRVAL_PP(needle),
Z_STRLEN_PP(needle),
Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
} else {
convert_to_long_ex(needle);
needle_char[0] = (char) Z_LVAL_PP(needle);
needle_char[1] = 0;
found = php_memnstr(Z_STRVAL_PP(haystack) + offset,
needle_char,
1,
Z_STRVAL_PP(haystack) + Z_STRLEN_PP(haystack));
}
if (found) {
RETURN_LONG(found - Z_STRVAL_PP(haystack));
} else {
RETURN_FALSE;
}
}
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 {
switch (Z_TYPE_P(needle)) {
case IS_LONG:
case IS_BOOL:
needle_char[0] = tolower((char) Z_LVAL_P(needle));
break;
case IS_DOUBLE:
needle_char[0] = tolower((char) Z_DVAL_P(needle));
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "needle is not a string or an integer");
efree(haystack_dup);
RETURN_FALSE;
break;
}
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;
}
}
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_PP(zneedle) == IS_STRING) {
needle = Z_STRVAL_PP(zneedle);
needle_len = Z_STRLEN_PP(zneedle);
} else {
convert_to_long_ex(zneedle);
ord_needle[0] = (char)(Z_LVAL_PP(zneedle) & 0xFF);
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_NOTICE, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack + offset;
e = haystack + haystack_len - needle_len;
} else {
if (-offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "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) {
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;
}
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_PP(zneedle) == IS_STRING) {
needle = Z_STRVAL_PP(zneedle);
needle_len = Z_STRLEN_PP(zneedle);
} else {
convert_to_long_ex(zneedle);
ord_needle[0] = (char)(Z_LVAL_PP(zneedle) & 0xFF);
ord_needle[1] = '\0';
needle = ord_needle;
needle_len = 1;
}
if ((haystack_len == 0) || (needle_len == 0)) {
RETURN_FALSE;
}
if (needle_len == 1) {
if (offset >= 0) {
if (offset > haystack_len) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
p = haystack + offset;
e = haystack + haystack_len - 1;
} else {
p = haystack;
if (-offset > haystack_len || offset < -INT_MAX) {
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Offset is greater than the length of haystack string");
RETURN_FALSE;
}
e = haystack + haystack_len + offset;
}
*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_NOTICE, "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 > haystack_len || offset < -INT_MAX) {
efree(needle_dup);
efree(haystack_dup);
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "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;
}
PHP_FUNCTION(strrchr)
{
zval **haystack, **needle;
char *found = NULL;
long found_offset;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) ==
FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(haystack);
if (Z_TYPE_PP(needle) == IS_STRING) {
found = zend_memrchr(Z_STRVAL_PP(haystack), *Z_STRVAL_PP(needle), Z_STRLEN_PP(haystack));
} else {
convert_to_long_ex(needle);
found = zend_memrchr(Z_STRVAL_PP(haystack), (char) Z_LVAL_PP(needle), Z_STRLEN_PP(haystack));
}
if (found) {
found_offset = found - Z_STRVAL_PP(haystack);
RETURN_STRINGL(found, Z_STRLEN_PP(haystack) - found_offset, 1);
} else {
RETURN_FALSE;
}
}
static char *php_chunk_split(char *src, int srclen, char *end, int endlen, int chunklen, int *destlen)
{
char *dest;
char *p, *q;
int chunks;
int restlen;
int out_len;
chunks = srclen / chunklen;
restlen = srclen - chunks * 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);
}
PHP_FUNCTION(chunk_split)
{
zval **p_str, **p_chunklen, **p_ending;
char *result;
char *end = "\r\n";
int endlen = 2;
int chunklen = 76;
int result_len;
int argc = ZEND_NUM_ARGS();
if (argc < 1 || argc > 3 || zend_get_parameters_ex(argc, &p_str, &p_chunklen, &p_ending) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(p_str);
if (argc > 1) {
convert_to_long_ex(p_chunklen);
chunklen = Z_LVAL_PP(p_chunklen);
}
if (argc > 2) {
convert_to_string_ex(p_ending);
end = Z_STRVAL_PP(p_ending);
endlen = Z_STRLEN_PP(p_ending);
}
if (chunklen <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Chunk length should be greater than zero");
RETURN_FALSE;
}
if (chunklen > Z_STRLEN_PP(p_str)) {
result_len = endlen + Z_STRLEN_PP(p_str);
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_PP(p_str), Z_STRLEN_PP(p_str));
memcpy(result + Z_STRLEN_PP(p_str), end, endlen);
result[result_len] = '\0';
RETURN_STRINGL(result, result_len, 0);
}
if (!Z_STRLEN_PP(p_str)) {
RETURN_EMPTY_STRING();
}
result = php_chunk_split(Z_STRVAL_PP(p_str), Z_STRLEN_PP(p_str), end, endlen, chunklen, &result_len);
if (result) {
RETURN_STRINGL(result, result_len, 0);
} else {
RETURN_FALSE;
}
}
PHP_FUNCTION(substr)
{
zval **str, **from, **len;
int l;
int f;
int argc = ZEND_NUM_ARGS();
if (argc < 2 || argc > 3 || zend_get_parameters_ex(argc, &str, &from, &len) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
convert_to_long_ex(from);
if (argc > 2) {
convert_to_long_ex(len);
l = Z_LVAL_PP(len);
if ((l < 0 && -l > Z_STRLEN_PP(str))) {
RETURN_FALSE;
} else if (l > Z_STRLEN_PP(str)) {
l = Z_STRLEN_PP(str);
}
} else {
l = Z_STRLEN_PP(str);
}
f = Z_LVAL_PP(from);
if (f > Z_STRLEN_PP(str)) {
RETURN_FALSE;
} else if (f < 0 && -f > Z_STRLEN_PP(str)) {
f = 0;
}
if (l < 0 && (l + Z_STRLEN_PP(str) - f) < 0) {
RETURN_FALSE;
}
if (f < 0) {
f = Z_STRLEN_PP(str) + f;
if (f < 0) {
f = 0;
}
}
if (l < 0) {
l = (Z_STRLEN_PP(str) - f) + l;
if (l < 0) {
l = 0;
}
}
if (f >= Z_STRLEN_PP(str)) {
RETURN_FALSE;
}
if ((f + l) > Z_STRLEN_PP(str)) {
l = Z_STRLEN_PP(str) - f;
}
RETURN_STRINGL(Z_STRVAL_PP(str) + f, l, 1);
}
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 (argc < 3 || argc > 4 || zend_get_parameters_ex(argc, &str, &repl, &from, &len) == FAILURE) {
WRONG_PARAM_COUNT;
}
if (Z_TYPE_PP(str) != IS_ARRAY) {
convert_to_string_ex(str);
}
if (Z_TYPE_PP(repl) != IS_ARRAY) {
convert_to_string_ex(repl);
}
if (Z_TYPE_PP(from) != IS_ARRAY) {
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 (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 (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 {
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) {
convert_to_string_ex(tmp_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)) {
convert_to_long_ex(tmp_from);
f = Z_LVAL_PP(tmp_from);
if (f < 0) {
f = Z_STRLEN_PP(tmp_str) + f;
if (f < 0) {
f = 0;
}
} else if (f > Z_STRLEN_PP(tmp_str)) {
f = Z_STRLEN_PP(tmp_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_PP(tmp_str) + f;
if (f < 0) {
f = 0;
}
} else if (f > Z_STRLEN_PP(tmp_str)) {
f = Z_STRLEN_PP(tmp_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)) {
convert_to_long_ex(tmp_len);
l = Z_LVAL_PP(tmp_len);
zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len);
} else {
l = Z_STRLEN_PP(tmp_str);
}
} else if (argc > 3) {
l = Z_LVAL_PP(len);
} else {
l = Z_STRLEN_PP(tmp_str);
}
if (l < 0) {
l = (Z_STRLEN_PP(tmp_str) - f) + l;
if (l < 0) {
l = 0;
}
}
if ((f + l) > Z_STRLEN_PP(tmp_str)) {
l = Z_STRLEN_PP(tmp_str) - f;
}
result_len = Z_STRLEN_PP(tmp_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)) {
convert_to_string_ex(tmp_repl);
result_len += Z_STRLEN_PP(tmp_repl);
zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_PP(tmp_str), f);
memcpy((result + f), Z_STRVAL_PP(tmp_repl), Z_STRLEN_PP(tmp_repl));
memcpy((result + f + Z_STRLEN_PP(tmp_repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
} else {
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_PP(tmp_str), f);
memcpy((result + f), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
}
} else {
result_len += Z_STRLEN_PP(repl);
result = emalloc(result_len + 1);
memcpy(result, Z_STRVAL_PP(tmp_str), f);
memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl));
memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
}
result[result_len] = '\0';
add_next_index_stringl(return_value, result, result_len, 0);
zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str);
}
}
}
PHP_FUNCTION(quotemeta)
{
zval **arg;
char *str, *old;
char *old_end;
char *p, *q;
char c;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(arg);
old = Z_STRVAL_PP(arg);
old_end = Z_STRVAL_PP(arg) + Z_STRLEN_PP(arg);
if (old == old_end) {
RETURN_FALSE;
}
str = safe_emalloc(2, Z_STRLEN_PP(arg), 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++ = '\\';
default:
*q++ = c;
}
}
*q = 0;
RETURN_STRINGL(erealloc(str, q - str + 1), q - str, 0);
}
PHP_FUNCTION(ord)
{
zval **str;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
RETURN_LONG((unsigned char) Z_STRVAL_PP(str)[0]);
}
PHP_FUNCTION(chr)
{
zval **num;
char temp[2];
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_long_ex(num);
temp[0] = (char) Z_LVAL_PP(num);
temp[1] = 0;
RETVAL_STRINGL(temp, 1, 1);
}
PHP_FUNCTION(ucfirst)
{
zval **str;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
if (!Z_STRLEN_PP(str)) {
RETURN_EMPTY_STRING();
}
ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
*Z_STRVAL_P(return_value) = toupper((unsigned char) *Z_STRVAL_P(return_value));
}
PHP_FUNCTION(ucwords)
{
zval **str;
register char *r, *r_end;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
if (!Z_STRLEN_PP(str)) {
RETURN_EMPTY_STRING();
}
ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 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);
}
}
}
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;
}
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);
}
PHP_FUNCTION(strtr)
{
zval **str, **from, **to;
int ac = ZEND_NUM_ARGS();
if (ac < 2 || ac > 3 || zend_get_parameters_ex(ac, &str, &from, &to) == FAILURE) {
WRONG_PARAM_COUNT;
}
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;
}
convert_to_string_ex(str);
if (Z_STRLEN_PP(str) == 0) {
RETURN_EMPTY_STRING();
}
if (ac == 2) {
php_strtr_array(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), HASH_OF(*from));
} else {
convert_to_string_ex(from);
convert_to_string_ex(to);
ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
php_strtr(Z_STRVAL_P(return_value),
Z_STRLEN_P(return_value),
Z_STRVAL_PP(from),
Z_STRVAL_PP(to),
MIN(Z_STRLEN_PP(from),
Z_STRLEN_PP(to)));
}
}
PHP_FUNCTION(strrev)
{
zval **str;
char *s, *e, *n, *p;
if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
n = emalloc(Z_STRLEN_PP(str)+1);
p = n;
s = Z_STRVAL_PP(str);
e = s + Z_STRLEN_PP(str);
while (--e>=s) {
*p++ = *e;
}
*p = '\0';
RETVAL_STRINGL(n, Z_STRLEN_PP(str), 0);
}
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;
}
}
}
}
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;
}
PHP_FUNCTION(similar_text)
{
zval **t1, **t2, **percent;
int ac = ZEND_NUM_ARGS();
int sim;
if (ac < 2 || ac > 3 || zend_get_parameters_ex(ac, &t1, &t2, &percent) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(t1);
convert_to_string_ex(t2);
if (ac > 2) {
convert_to_double_ex(percent);
}
if (Z_STRLEN_PP(t1) + Z_STRLEN_PP(t2) == 0) {
if (ac > 2) {
Z_DVAL_PP(percent) = 0;
}
RETURN_LONG(0);
}
sim = php_similar_char(Z_STRVAL_PP(t1), Z_STRLEN_PP(t1), Z_STRVAL_PP(t2), Z_STRLEN_PP(t2));
if (ac > 2) {
Z_DVAL_PP(percent) = sim * 200.0 / (Z_STRLEN_PP(t1) + Z_STRLEN_PP(t2));
}
RETURN_LONG(sim);
}
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;
if (PG(magic_quotes_sybase)) {
while (l > 0) {
if (*t == '\'') {
if ((l > 0) && (t[1] == '\'')) {
t++;
if (len != NULL) {
(*len)--;
}
l--;
}
*s++ = *t++;
} else if (*t == '\\' && t[1] == '0' && l > 0) {
*s++='\0';
t+=2;
if (len != NULL) {
(*len)--;
}
l--;
} else {
*s++ = *t++;
}
l--;
}
*s = '\0';
return;
}
while (l > 0) {
if (*t == '\\') {
t++;
if (len != NULL) {
(*len)--;
}
l--;
if (l > 0) {
if (*t == '0') {
*s++='\0';
t++;
} else {
*s++ = *t++;
}
l--;
}
} else {
*s++ = *t++;
l--;
}
}
if (s != t) {
*s = '\0';
}
}
PHP_FUNCTION(addcslashes)
{
zval **str, **what;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &str, &what) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
convert_to_string_ex(what);
if (Z_STRLEN_PP(str) == 0) {
RETURN_EMPTY_STRING();
}
if (Z_STRLEN_PP(what) == 0) {
RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
}
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);
RETURN_STRINGL(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), 0);
}
PHP_FUNCTION(addslashes)
{
zval **str;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
if (Z_STRLEN_PP(str) == 0) {
RETURN_EMPTY_STRING();
}
RETURN_STRING(php_addslashes(Z_STRVAL_PP(str),
Z_STRLEN_PP(str),
&Z_STRLEN_P(return_value), 0
TSRMLS_CC), 0);
}
PHP_FUNCTION(stripcslashes)
{
zval **str;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
php_stripcslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value));
}
PHP_FUNCTION(stripslashes)
{
zval **str;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(str);
ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
php_stripslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC);
}
#ifndef HAVE_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
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;
}
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;
}
PHPAPI char *php_addcslashes(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(what, wlength, flags TSRMLS_CC);
for (source = 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(str);
}
return new_str;
}
PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC)
{
return php_addslashes_ex(str, length, new_length, should_free, 0 TSRMLS_CC);
}
PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int should_free, int ignore_sybase TSRMLS_DC)
{
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;
if (!ignore_sybase && PG(magic_quotes_sybase)) {
while (source < end) {
switch (*source) {
case '\0':
*target++ = '\\';
*target++ = '0';
break;
case '\'':
*target++ = '\'';
*target++ = '\'';
break;
default:
*target++ = *source;
break;
}
source++;
}
} else {
while (source < end) {
switch (*source) {
case '\0':
*target++ = '\\';
*target++ = '0';
break;
case '\'':
case '\"':
case '\\':
*target++ = '\\';
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)
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;
}
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);
}
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) {
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;
}
}
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);
}
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;
convert_to_string_ex(subject);
Z_TYPE_P(result) = IS_STRING;
if (Z_STRLEN_PP(subject) == 0) {
ZVAL_STRINGL(result, "", 0, 1);
return;
}
if (Z_TYPE_P(search) == IS_ARRAY) {
*result = **subject;
zval_copy_ctor(result);
INIT_PZVAL(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 {
replace_value = Z_STRVAL_P(replace);
replace_len = Z_STRLEN_P(replace);
}
while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) {
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 (Z_TYPE_P(replace) == IS_ARRAY) {
if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) {
convert_to_string_ex(replace_entry);
replace_value = Z_STRVAL_PP(replace_entry);
replace_len = Z_STRLEN_PP(replace_entry);
zend_hash_move_forward(Z_ARRVAL_P(replace));
} else {
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);
}
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 {
*result = **subject;
zval_copy_ctor(result);
INIT_PZVAL(result);
}
}
}
static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
{
zval **subject, **search, **replace, **subject_entry, **zcount;
zval *result;
char *string_key;
uint string_key_len;
ulong num_key;
int count = 0;
int argc = ZEND_NUM_ARGS();
if (argc < 3 || argc > 4 ||
zend_get_parameters_ex(argc, &search, &replace, &subject, &zcount) == FAILURE) {
WRONG_PARAM_COUNT;
}
SEPARATE_ZVAL(search);
SEPARATE_ZVAL(replace);
SEPARATE_ZVAL(subject);
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 (Z_TYPE_PP(subject) == IS_ARRAY) {
array_init(return_value);
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject));
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);
ZVAL_ADDREF(*subject_entry);
COPY_PZVAL_TO_ZVAL(*result, *subject_entry);
}
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);
break;
}
zend_hash_move_forward(Z_ARRVAL_PP(subject));
}
} else {
php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? &count : NULL);
}
if (argc > 3) {
zval_dtor(*zcount);
ZVAL_LONG(*zcount, count);
}
}
PHP_FUNCTION(str_replace)
{
php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
PHP_FUNCTION(str_ireplace)
{
php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
{
zval **str, **max_chars_per_line;
char *heb_str, *tmp, *target, *broken_str;
int block_start, block_end, block_type, block_length, i;
long max_chars=0;
int begin, end, char_count, orig_begin;
switch (ZEND_NUM_ARGS()) {
case 1:
if (zend_get_parameters_ex(1, &str) == FAILURE) {
RETURN_FALSE;
}
break;
case 2:
if (zend_get_parameters_ex(2, &str, &max_chars_per_line) == FAILURE) {
RETURN_FALSE;
}
convert_to_long_ex(max_chars_per_line);
max_chars = Z_LVAL_PP(max_chars_per_line);
break;
default:
WRONG_PARAM_COUNT;
break;
}
convert_to_string_ex(str);
if (Z_STRLEN_PP(str) == 0) {
RETURN_FALSE;
}
tmp = Z_STRVAL_PP(str);
block_start=block_end=0;
heb_str = (char *) emalloc(Z_STRLEN_PP(str)+1);
target = heb_str+Z_STRLEN_PP(str);
*target = 0;
target--;
block_length=0;
if (isheb(*tmp)) {
block_type = _HEB_BLOCK_TYPE_HEB;
} else {
block_type = _HEB_BLOCK_TYPE_ENG;
}
do {
if (block_type == _HEB_BLOCK_TYPE_HEB) {
while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<Z_STRLEN_PP(str)-1) {
tmp++;
block_end++;
block_length++;
}
for (i = block_start; i<= block_end; i++) {
*target = Z_STRVAL_PP(str)[i];
switch (*target) {
case '(':
*target = ')';
break;
case ')':
*target = '(';
break;
case '[':
*target = ']';
break;
case ']':
*target = '[';
break;
case '{':
*target = '}';
break;
case '}':
*target = '{';
break;
case '<':
*target = '>';
break;
case '>':
*target = '<';
break;
case '\\':
*target = '/';
break;
case '/':
*target = '\\';
break;
default:
break;
}
target--;
}
block_type = _HEB_BLOCK_TYPE_ENG;
} else {
while (!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end < Z_STRLEN_PP(str)-1) {
tmp++;
block_end++;
block_length++;
}
while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
tmp--;
block_end--;
}
for (i = block_end; i >= block_start; i--) {
*target = Z_STRVAL_PP(str)[i];
target--;
}
block_type = _HEB_BLOCK_TYPE_HEB;
}
block_start=block_end+1;
} while (block_end < Z_STRLEN_PP(str)-1);
broken_str = (char *) emalloc(Z_STRLEN_PP(str)+1);
begin=end=Z_STRLEN_PP(str)-1;
target = broken_str;
while (1) {
char_count=0;
while ((!max_chars || char_count < max_chars) && begin > 0) {
char_count++;
begin--;
if (begin <= 0 || _isnewline(heb_str[begin])) {
while (begin > 0 && _isnewline(heb_str[begin-1])) {
begin--;
char_count++;
}
break;
}
}
if (char_count == max_chars) {
int new_char_count=char_count, new_begin=begin;
while (new_char_count > 0) {
if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
break;
}
new_begin++;
new_char_count--;
}
if (new_char_count > 0) {
char_count=new_char_count;
begin=new_begin;
}
}
orig_begin=begin;
if (_isblank(heb_str[begin])) {
heb_str[begin]='\n';
}
while (begin <= end && _isnewline(heb_str[begin])) {
begin++;
}
for (i = begin; i <= end; i++) {
*target = heb_str[i];
target++;
}
for (i = orig_begin; i <= end && _isnewline(heb_str[i]); i++) {
*target = heb_str[i];
target++;
}
begin=orig_begin;
if (begin <= 0) {
*target = 0;
break;
}
begin--;
end=begin;
}
efree(heb_str);
if (convert_newlines) {
php_char_to_str(broken_str, Z_STRLEN_PP(str),'\n', "<br />\n", 7, return_value);
efree(broken_str);
} else {
Z_STRVAL_P(return_value) = broken_str;
Z_STRLEN_P(return_value) = Z_STRLEN_PP(str);
Z_TYPE_P(return_value) = IS_STRING;
}
}
PHP_FUNCTION(hebrev)
{
php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
PHP_FUNCTION(hebrevc)
{
php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
PHP_FUNCTION(nl2br)
{
zval **zstr;
char *tmp, *str;
int new_length;
char *end, *target;
int repl_cnt = 0;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &zstr) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(zstr);
str = Z_STRVAL_PP(zstr);
end = str + Z_STRLEN_PP(zstr);
while (str < end) {
if (*str == '\r') {
if (*(str+1) == '\n') {
str++;
}
repl_cnt++;
} else if (*str == '\n') {
if (*(str+1) == '\r') {
str++;
}
repl_cnt++;
}
str++;
}
if (repl_cnt == 0) {
RETURN_STRINGL(Z_STRVAL_PP(zstr), Z_STRLEN_PP(zstr), 1);
}
new_length = Z_STRLEN_PP(zstr) + repl_cnt * (sizeof("<br />") - 1);
tmp = target = emalloc(new_length + 1);
str = Z_STRVAL_PP(zstr);
while (str < end) {
switch (*str) {
case '\r':
case '\n':
*target++ = '<';
*target++ = 'b';
*target++ = 'r';
*target++ = ' ';
*target++ = '/';
*target++ = '>';
if ((*str == '\r' && *(str+1) == '\n') || (*str == '\n' && *(str+1) == '\r')) {
*target++ = *str++;
}
default:
*target++ = *str;
}
str++;
}
*target = '\0';
RETURN_STRINGL(tmp, new_length, 0);
}
PHP_FUNCTION(strip_tags)
{
char *buf;
zval **str, **allow=NULL;
char *allowed_tags=NULL;
int allowed_tags_len=0;
size_t retval_len;
switch (ZEND_NUM_ARGS()) {
case 1:
if (zend_get_parameters_ex(1, &str) == FAILURE) {
RETURN_FALSE;
}
break;
case 2:
if (zend_get_parameters_ex(2, &str, &allow) == FAILURE) {
RETURN_FALSE;
}
convert_to_string_ex(allow);
allowed_tags = Z_STRVAL_PP(allow);
allowed_tags_len = Z_STRLEN_PP(allow);
break;
default:
WRONG_PARAM_COUNT;
break;
}
convert_to_string_ex(str);
buf = estrndup(Z_STRVAL_PP(str), Z_STRLEN_PP(str));
retval_len = php_strip_tags_ex(buf, Z_STRLEN_PP(str), NULL, allowed_tags, allowed_tags_len, 0);
RETURN_STRINGL(buf, retval_len, 0);
}
PHP_FUNCTION(setlocale)
{
zval ***args = (zval ***) safe_emalloc(sizeof(zval **), ZEND_NUM_ARGS(), 0);
zval **pcategory, **plocale;
int i, cat, n_args=ZEND_NUM_ARGS();
char *loc, *retval;
if (zend_get_parameters_array_ex(n_args, args) == FAILURE || n_args < 2) {
efree(args);
WRONG_PARAM_COUNT;
}
#ifdef HAVE_SETLOCALE
pcategory = args[0];
if (Z_TYPE_PP(pcategory) == IS_LONG) {
convert_to_long_ex(pcategory);
cat = Z_LVAL_PP(pcategory);
} else {
char *category;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Passing locale category name as string is deprecated. Use the LC_* -constants instead");
convert_to_string_ex(pcategory);
category = Z_STRVAL_P(*pcategory);
if (!strcasecmp ("LC_ALL", category))
cat = LC_ALL;
else if (!strcasecmp ("LC_COLLATE", category))
cat = LC_COLLATE;
else if (!strcasecmp ("LC_CTYPE", category))
cat = LC_CTYPE;
#ifdef LC_MESSAGES
else if (!strcasecmp ("LC_MESSAGES", category))
cat = LC_MESSAGES;
#endif
else if (!strcasecmp ("LC_MONETARY", category))
cat = LC_MONETARY;
else if (!strcasecmp ("LC_NUMERIC", category))
cat = LC_NUMERIC;
else if (!strcasecmp ("LC_TIME", category))
cat = LC_TIME;
else {
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);
efree(args);
RETURN_FALSE;
}
}
if (Z_TYPE_PP(args[1]) == IS_ARRAY) {
zend_hash_internal_pointer_reset(Z_ARRVAL_PP(args[1]));
i=0;
} else {
i=1;
}
while (1) {
if (Z_TYPE_PP(args[1]) == IS_ARRAY) {
if (!zend_hash_num_elements(Z_ARRVAL_PP(args[1]))) {
break;
}
zend_hash_get_current_data(Z_ARRVAL_PP(args[1]),(void **)&plocale);
} else {
plocale = args[i];
}
convert_to_string_ex(plocale);
if (!strcmp ("0", Z_STRVAL_PP(plocale))) {
loc = NULL;
} else {
loc = Z_STRVAL_PP(plocale);
if (Z_STRLEN_PP(plocale) >= 255) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Specified locale name is too long");
break;
}
}
retval = setlocale (cat, loc);
zend_update_current_locale();
if (retval) {
if (loc) {
STR_FREE(BG(locale_string));
BG(locale_string) = estrdup(retval);
}
efree(args);
RETVAL_STRING(retval, 1);
return;
}
if (Z_TYPE_PP(args[1]) == IS_ARRAY) {
if (zend_hash_move_forward(Z_ARRVAL_PP(args[1])) == FAILURE) break;
} else {
if (++i >= n_args) break;
}
}
#endif
efree(args);
RETURN_FALSE;
}
PHP_FUNCTION(parse_str)
{
zval **arg;
zval **arrayArg;
zval *sarg;
char *res = NULL;
int argCount;
argCount = ZEND_NUM_ARGS();
if (argCount < 1 || argCount > 2 || zend_get_parameters_ex(argCount, &arg, &arrayArg) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(arg);
sarg = *arg;
if (Z_STRVAL_P(sarg) && *Z_STRVAL_P(sarg)) {
res = estrndup(Z_STRVAL_P(sarg), Z_STRLEN_P(sarg));
}
if (argCount == 1) {
zval tmp;
Z_ARRVAL(tmp) = EG(active_symbol_table);
sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
} else {
zval_dtor(*arrayArg);
array_init(*arrayArg);
sapi_module.treat_data(PARSE_STRING, res, *arrayArg TSRMLS_CC);
}
}
#define PHP_TAG_BUF_SIZE 1023
int php_tag_find(char *tag, int len, char *set) {
char c, *n, *t;
int state=0, done=0;
char *norm;
if (len <= 0) {
return 0;
}
norm = emalloc(len+1);
n = norm;
t = tag;
c = tolower(*t);
while (!done) {
switch (c) {
case '<':
*(n++) = c;
break;
case '>':
done =1;
break;
default:
if (!isspace((int)c)) {
if (state == 0) {
state=1;
if (c != '/')
*(n++) = c;
} else {
*(n++) = c;
}
} else {
if (state == 1)
done=1;
}
break;
}
c = tolower(*(++t));
}
*(n++) = '>';
*n = '\0';
if (strstr(set, norm)) {
done=1;
} else {
done=0;
}
efree(norm);
return done;
}
PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, int allow_len)
{
return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0);
}
PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow, int allow_len, zend_bool allow_tag_spaces)
{
char *tbuf, *buf, *p, *tp, *rp, c, lc;
int br, i=0, depth=0, in_q = 0;
int state = 0;
if (stateptr)
state = *stateptr;
buf = estrndup(rbuf, len);
c = *buf;
lc = '\0';
p = buf;
rp = rbuf;
br = 0;
if (allow) {
php_strtolower(allow, allow_len);
tbuf = emalloc(PHP_TAG_BUF_SIZE+1);
tp = tbuf;
} else {
tbuf = tp = NULL;
}
while (i < len) {
switch (c) {
case '\0':
break;
case '<':
if (in_q) {
break;
}
if (isspace(*(p + 1)) && !allow_tag_spaces) {
goto reg_char;
}
if (state == 0) {
lc = '<';
state = 1;
if (allow) {
tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
*(tp++) = '<';
}
} else if (state == 1) {
depth++;
}
break;
case '(':
if (state == 2) {
if (lc != '"' && lc != '\'') {
lc = '(';
br++;
}
} else if (allow && state == 1) {
tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
*(tp++) = c;
} else if (state == 0) {
*(rp++) = c;
}
break;
case ')':
if (state == 2) {
if (lc != '"' && lc != '\'') {
lc = ')';
br--;
}
} else if (allow && state == 1) {
tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
*(tp++) = c;
} else if (state == 0) {
*(rp++) = c;
}
break;
case '>':
if (depth) {
depth--;
break;
}
if (in_q) {
break;
}
switch (state) {
case 1:
lc = '>';
in_q = state = 0;
if (allow) {
tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
*(tp++) = '>';
*tp='\0';
if (php_tag_find(tbuf, tp-tbuf, allow)) {
memcpy(rp, tbuf, tp-tbuf);
rp += tp-tbuf;
}
tp = tbuf;
}
break;
case 2:
if (!br && lc != '\"' && *(p-1) == '?') {
in_q = state = 0;
tp = tbuf;
}
break;
case 3:
in_q = state = 0;
tp = tbuf;
break;
case 4:
if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') {
in_q = state = 0;
tp = tbuf;
}
break;
default:
*(rp++) = c;
break;
}
break;
case '"':
case '\'':
if (state == 2 && *(p-1) != '\\') {
if (lc == c) {
lc = '\0';
} else if (lc != '\\') {
lc = c;
}
} else if (state == 0) {
*(rp++) = c;
} else if (allow && state == 1) {
tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
*(tp++) = c;
}
if (state && p != buf && *(p-1) != '\\' && (!in_q || *p == in_q)) {
if (in_q) {
in_q = 0;
} else {
in_q = *p;
}
}
break;
case '!':
if (state == 1 && *(p-1) == '<') {
state = 3;
lc = c;
} else {
if (state == 0) {
*(rp++) = c;
} else if (allow && state == 1) {
tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
*(tp++) = c;
}
}
break;
case '-':
if (state == 3 && p >= buf + 2 && *(p-1) == '-' && *(p-2) == '!') {
state = 4;
} else {
goto reg_char;
}
break;
case '?':
if (state == 1 && *(p-1) == '<') {
br=0;
state=2;
break;
}
case 'E':
case 'e':
if (state==3 && p > buf+6
&& tolower(*(p-1)) == 'p'
&& tolower(*(p-2)) == 'y'
&& tolower(*(p-3)) == 't'
&& tolower(*(p-4)) == 'c'
&& tolower(*(p-5)) == 'o'
&& tolower(*(p-6)) == 'd') {
state = 1;
break;
}
case 'l':
case 'L':
if (state == 2 && p > buf+2 && strncasecmp(p-2, "xm", 2) == 0) {
state = 1;
break;
}
default:
reg_char:
if (state == 0) {
*(rp++) = c;
} else if (allow && state == 1) {
tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
*(tp++) = c;
}
break;
}
c = *(++p);
i++;
}
if (rp < rbuf + len) {
*rp = '\0';
}
efree(buf);
if (allow)
efree(tbuf);
if (stateptr)
*stateptr = state;
return (size_t)(rp - rbuf);
}
PHP_FUNCTION(str_repeat)
{
zval **input_str;
zval **mult;
char *result;
size_t result_len;
if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &input_str, &mult) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(input_str);
convert_to_long_ex(mult);
if (Z_LVAL_PP(mult) < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be greater than or equal to 0");
return;
}
if (Z_STRLEN_PP(input_str) == 0)
RETURN_STRINGL("", 0, 1);
if (Z_LVAL_PP(mult) == 0)
RETURN_STRINGL("", 0, 1);
result_len = Z_STRLEN_PP(input_str) * Z_LVAL_PP(mult);
result = (char *)safe_emalloc(Z_STRLEN_PP(input_str), Z_LVAL_PP(mult), 1);
if (Z_STRLEN_PP(input_str) == 1) {
memset(result, *(Z_STRVAL_PP(input_str)), Z_LVAL_PP(mult));
} else {
char *s, *e, *ee;
int l=0;
memcpy(result, Z_STRVAL_PP(input_str), Z_STRLEN_PP(input_str));
s = result;
e = result + Z_STRLEN_PP(input_str);
ee = result + result_len;
while (e<ee) {
l = (e-s) < (ee-e) ? (e-s) : (ee-e);
memmove(e, s, l);
e += l;
}
}
result[result_len] = '\0';
RETURN_STRINGL(result, result_len, 0);
}
PHP_FUNCTION(count_chars)
{
zval **input, **mode;
int chars[256];
int ac=ZEND_NUM_ARGS();
int mymode=0;
unsigned char *buf;
int len, inx;
char retstr[256];
int retlen=0;
if (ac < 1 || ac > 2 || zend_get_parameters_ex(ac, &input, &mode) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(input);
if (ac == 2) {
convert_to_long_ex(mode);
mymode = Z_LVAL_PP(mode);
if (mymode < 0 || mymode > 4) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown mode");
RETURN_FALSE;
}
}
len = Z_STRLEN_PP(input);
buf = (unsigned char *) Z_STRVAL_PP(input);
memset((void*) chars, 0, sizeof(chars));
while (len > 0) {
chars[*buf]++;
buf++;
len--;
}
if (mymode < 3) {
array_init(return_value);
}
for (inx = 0; inx < 256; inx++) {
switch (mymode) {
case 0:
add_index_long(return_value, inx, chars[inx]);
break;
case 1:
if (chars[inx] != 0) {
add_index_long(return_value, inx, chars[inx]);
}
break;
case 2:
if (chars[inx] == 0) {
add_index_long(return_value, inx, chars[inx]);
}
break;
case 3:
if (chars[inx] != 0) {
retstr[retlen++] = inx;
}
break;
case 4:
if (chars[inx] == 0) {
retstr[retlen++] = inx;
}
break;
}
}
if (mymode >= 3 && mymode <= 4) {
RETURN_STRINGL(retstr, retlen, 1);
}
}
static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
{
zval **s1, **s2;
if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(s1);
convert_to_string_ex(s2);
RETURN_LONG(strnatcmp_ex(Z_STRVAL_PP(s1), Z_STRLEN_PP(s1),
Z_STRVAL_PP(s2), Z_STRLEN_PP(s2),
fold_case));
}
PHP_FUNCTION(strnatcmp)
{
php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
PHP_FUNCTION(localeconv)
{
zval *grouping, *mon_grouping;
int len, i;
if (ZEND_NUM_ARGS() > 0) {
WRONG_PARAM_COUNT;
}
MAKE_STD_ZVAL(grouping);
MAKE_STD_ZVAL(mon_grouping);
array_init(return_value);
array_init(grouping);
array_init(mon_grouping);
#ifdef HAVE_LOCALECONV
{
struct lconv currlocdata;
localeconv_r( &currlocdata );
len = strlen(currlocdata.grouping);
for (i = 0; i < len; i++) {
add_index_long(grouping, i, currlocdata.grouping[i]);
}
len = strlen(currlocdata.mon_grouping);
for (i = 0; i < len; i++) {
add_index_long(mon_grouping, i, currlocdata.mon_grouping[i]);
}
add_assoc_string(return_value, "decimal_point", currlocdata.decimal_point, 1);
add_assoc_string(return_value, "thousands_sep", currlocdata.thousands_sep, 1);
add_assoc_string(return_value, "int_curr_symbol", currlocdata.int_curr_symbol, 1);
add_assoc_string(return_value, "currency_symbol", currlocdata.currency_symbol, 1);
add_assoc_string(return_value, "mon_decimal_point", currlocdata.mon_decimal_point, 1);
add_assoc_string(return_value, "mon_thousands_sep", currlocdata.mon_thousands_sep, 1);
add_assoc_string(return_value, "positive_sign", currlocdata.positive_sign, 1);
add_assoc_string(return_value, "negative_sign", currlocdata.negative_sign, 1);
add_assoc_long( return_value, "int_frac_digits", currlocdata.int_frac_digits );
add_assoc_long( return_value, "frac_digits", currlocdata.frac_digits );
add_assoc_long( return_value, "p_cs_precedes", currlocdata.p_cs_precedes );
add_assoc_long( return_value, "p_sep_by_space", currlocdata.p_sep_by_space );
add_assoc_long( return_value, "n_cs_precedes", currlocdata.n_cs_precedes );
add_assoc_long( return_value, "n_sep_by_space", currlocdata.n_sep_by_space );
add_assoc_long( return_value, "p_sign_posn", currlocdata.p_sign_posn );
add_assoc_long( return_value, "n_sign_posn", currlocdata.n_sign_posn );
}
#else
add_index_long(grouping, 0, -1);
add_index_long(mon_grouping, 0, -1);
add_assoc_string(return_value, "decimal_point", "\x2E", 1);
add_assoc_string(return_value, "thousands_sep", "", 1);
add_assoc_string(return_value, "int_curr_symbol", "", 1);
add_assoc_string(return_value, "currency_symbol", "", 1);
add_assoc_string(return_value, "mon_decimal_point", "\x2E", 1);
add_assoc_string(return_value, "mon_thousands_sep", "", 1);
add_assoc_string(return_value, "positive_sign", "", 1);
add_assoc_string(return_value, "negative_sign", "", 1);
add_assoc_long( return_value, "int_frac_digits", CHAR_MAX );
add_assoc_long( return_value, "frac_digits", CHAR_MAX );
add_assoc_long( return_value, "p_cs_precedes", CHAR_MAX );
add_assoc_long( return_value, "p_sep_by_space", CHAR_MAX );
add_assoc_long( return_value, "n_cs_precedes", CHAR_MAX );
add_assoc_long( return_value, "n_sep_by_space", CHAR_MAX );
add_assoc_long( return_value, "p_sign_posn", CHAR_MAX );
add_assoc_long( return_value, "n_sign_posn", CHAR_MAX );
#endif
zend_hash_update(Z_ARRVAL_P(return_value), "grouping", 9, &grouping, sizeof(zval *), NULL);
zend_hash_update(Z_ARRVAL_P(return_value), "mon_grouping", 13, &mon_grouping, sizeof(zval *), NULL);
}
PHP_FUNCTION(strnatcasecmp)
{
php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
PHP_FUNCTION(substr_count)
{
zval **haystack, **needle, **offset, **length;
int ac = ZEND_NUM_ARGS();
int count = 0;
char *p, *endp, cmp;
if (ac < 2 || ac > 4 || zend_get_parameters_ex(ac, &haystack, &needle, &offset, &length) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(haystack);
convert_to_string_ex(needle);
if (Z_STRLEN_PP(needle) == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring");
RETURN_FALSE;
}
p = Z_STRVAL_PP(haystack);
endp = p + Z_STRLEN_PP(haystack);
if (ac > 2) {
convert_to_long_ex(offset);
if (Z_LVAL_PP(offset) < 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset should be greater than or equal to 0");
RETURN_FALSE;
}
if (Z_LVAL_PP(offset) > Z_STRLEN_PP(haystack)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length", Z_LVAL_PP(offset));
RETURN_FALSE;
}
p += Z_LVAL_PP(offset);
if (ac == 4) {
convert_to_long_ex(length);
if (Z_LVAL_PP(length) <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length should be greater than 0");
RETURN_FALSE;
}
if (Z_LVAL_PP(length) > (Z_STRLEN_PP(haystack) - Z_LVAL_PP(offset))) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length value %ld exceeds string length", Z_LVAL_PP(length));
RETURN_FALSE;
}
endp = p + Z_LVAL_PP(length);
}
}
if (Z_STRLEN_PP(needle) == 1) {
cmp = Z_STRVAL_PP(needle)[0];
while ((p = memchr(p, cmp, endp - p))) {
count++;
p++;
}
} else {
while ((p = php_memnstr(p, Z_STRVAL_PP(needle), Z_STRLEN_PP(needle), endp))) {
p += Z_STRLEN_PP(needle);
count++;
}
}
RETURN_LONG(count);
}
PHP_FUNCTION(str_pad)
{
zval **input,
**pad_length,
**pad_string,
**pad_type;
int num_pad_chars;
char *result = NULL;
int result_len = 0;
char *pad_str_val = " ";
int pad_str_len = 1;
int pad_type_val = STR_PAD_RIGHT;
int i, left_pad=0, right_pad=0;
if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 4 ||
zend_get_parameters_ex(ZEND_NUM_ARGS(), &input, &pad_length, &pad_string, &pad_type) == FAILURE) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(input);
convert_to_long_ex(pad_length);
num_pad_chars = Z_LVAL_PP(pad_length) - Z_STRLEN_PP(input);
if (Z_LVAL_PP(pad_length) < 0 || num_pad_chars < 0) {
RETURN_ZVAL(*input, 1, 0);
}
if (ZEND_NUM_ARGS() > 2) {
convert_to_string_ex(pad_string);
if (Z_STRLEN_PP(pad_string) == 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding string cannot be empty");
return;
}
pad_str_val = Z_STRVAL_PP(pad_string);
pad_str_len = Z_STRLEN_PP(pad_string);
if (ZEND_NUM_ARGS() > 3) {
convert_to_long_ex(pad_type);
pad_type_val = Z_LVAL_PP(pad_type);
if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH");
return;
}
}
}
result = (char *)emalloc(Z_STRLEN_PP(input) + num_pad_chars + 1);
switch (pad_type_val) {
case STR_PAD_RIGHT:
left_pad = 0;
right_pad = num_pad_chars;
break;
case STR_PAD_LEFT:
left_pad = num_pad_chars;
right_pad = 0;
break;
case STR_PAD_BOTH:
left_pad = num_pad_chars / 2;
right_pad = num_pad_chars - left_pad;
break;
}
for (i = 0; i < left_pad; i++)
result[result_len++] = pad_str_val[i % pad_str_len];
memcpy(result + result_len, Z_STRVAL_PP(input), Z_STRLEN_PP(input));
result_len += Z_STRLEN_PP(input);
for (i = 0; i < right_pad; i++)
result[result_len++] = pad_str_val[i % pad_str_len];
result[result_len] = '\0';
RETURN_STRINGL(result, result_len, 0);
}
PHP_FUNCTION(sscanf)
{
zval ***args;
int result;
int argc = ZEND_NUM_ARGS();
if (argc < 2) {
WRONG_PARAM_COUNT;
}
args = (zval ***) safe_emalloc(argc, sizeof(zval **), 0);
if (zend_get_parameters_array_ex(argc, args) == FAILURE) {
efree(args);
WRONG_PARAM_COUNT;
}
convert_to_string_ex(args[0]);
convert_to_string_ex(args[1]);
result = php_sscanf_internal(Z_STRVAL_PP(args[0]),
Z_STRVAL_PP(args[1]),
argc, args,
2, &return_value TSRMLS_CC);
efree(args);
if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
WRONG_PARAM_COUNT;
}
}
static char rot13_from[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
static char rot13_to[] = "nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM";
PHP_FUNCTION(str_rot13)
{
zval **arg;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(arg);
RETVAL_ZVAL(*arg, 1, 0);
php_strtr(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), rot13_from, rot13_to, 52);
}
static void php_string_shuffle(char *str, long len TSRMLS_DC)
{
long n_elems, rnd_idx, n_left;
char temp;
n_elems = len;
if (n_elems <= 1) {
return;
}
n_left = n_elems;
while (--n_left) {
rnd_idx = php_rand(TSRMLS_C);
RAND_RANGE(rnd_idx, 0, n_left, PHP_RAND_MAX);
if (rnd_idx != n_left) {
temp = str[n_left];
str[n_left] = str[rnd_idx];
str[rnd_idx] = temp;
}
}
}
PHP_FUNCTION(str_shuffle)
{
zval **arg;
if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
WRONG_PARAM_COUNT;
}
convert_to_string_ex(arg);
RETVAL_ZVAL(*arg, 1, 0);
if (Z_STRLEN_P(return_value) > 1) {
php_string_shuffle(Z_STRVAL_P(return_value), (long) Z_STRLEN_P(return_value) TSRMLS_CC);
}
}
PHP_FUNCTION(str_word_count)
{
char *buf, *str, *char_list = NULL, *p, *e, *s, ch[256];
int str_len, char_list_len, word_count = 0;
long type = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, &type, &char_list, &char_list_len) == FAILURE) {
return;
}
switch(type) {
case 1:
case 2:
array_init(return_value);
if (!str_len) {
return;
}
break;
case 0:
if (!str_len) {
RETURN_LONG(0);
}
break;
default:
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid format value %ld", type);
RETURN_FALSE;
}
if (char_list) {
php_charmask(char_list, char_list_len, ch TSRMLS_CC);
}
p = str;
e = str + str_len;
if ((*p == '\'' && (!char_list || !ch['\''])) || (*p == '-' && (!char_list || !ch['-']))) {
p++;
}
if (*(e - 1) == '-' && (!char_list || !ch['-'])) {
e--;
}
while (p < e) {
s = p;
while (p < e && (isalpha((unsigned char)*p) || (char_list && ch[(unsigned char)*p]) || *p == '\'' || *p == '-')) {
p++;
}
if (p > s) {
switch (type)
{
case 1:
buf = estrndup(s, (p-s));
add_next_index_stringl(return_value, buf, (p-s), 0);
break;
case 2:
buf = estrndup(s, (p-s));
add_index_stringl(return_value, (s - str), buf, p-s, 0);
break;
default:
word_count++;
break;
}
}
p++;
}
if (!type) {
RETURN_LONG(word_count);
}
}
#if HAVE_STRFMON
PHP_FUNCTION(money_format)
{
int format_len = 0, str_len;
char *format, *str, *p, *e;
double value;
zend_bool check = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sd", &format, &format_len, &value) == FAILURE) {
return;
}
p = format;
e = p + format_len;
while ((p = memchr(p, '%', (e - p)))) {
if (*(p + 1) == '%') {
p += 2;
} else if (!check) {
check = 1;
p++;
} else {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Only a single %%i or %%n token can be used");
RETURN_FALSE;
}
}
str_len = format_len + 1024;
str = emalloc(str_len);
if ((str_len = strfmon(str, str_len, format, value)) < 0) {
efree(str);
RETURN_FALSE;
}
str[str_len] = 0;
RETURN_STRINGL(erealloc(str, str_len + 1), str_len, 0);
}
#endif
PHP_FUNCTION(str_split)
{
char *str;
int str_len;
long split_length = 1;
char *p;
int n_reg_segments;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &split_length) == FAILURE) {
return;
}
if (split_length <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The length of each segment must be greater than zero");
RETURN_FALSE;
}
array_init(return_value);
if (split_length >= str_len) {
add_next_index_stringl(return_value, str, str_len, 1);
return;
}
n_reg_segments = floor(str_len / split_length);
p = str;
while (n_reg_segments-- > 0) {
add_next_index_stringl(return_value, p, split_length, 1);
p += split_length;
}
if (p != (str + str_len)) {
add_next_index_stringl(return_value, p, (str + str_len - p), 1);
}
}
PHP_FUNCTION(strpbrk)
{
char *haystack, *char_list;
int haystack_len, char_list_len;
char *p;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &haystack, &haystack_len, &char_list, &char_list_len) == FAILURE) {
RETURN_FALSE;
}
if (!char_list_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The character list cannot be empty");
RETURN_FALSE;
}
if ((p = strpbrk(haystack, char_list))) {
RETURN_STRINGL(p, (haystack + haystack_len - p), 1);
} else {
RETURN_FALSE;
}
}
PHP_FUNCTION(substr_compare)
{
char *s1, *s2;
int s1_len, s2_len;
long offset, len=0;
zend_bool cs=0;
uint cmp_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssl|lb", &s1, &s1_len, &s2, &s2_len, &offset, &len, &cs) == FAILURE) {
RETURN_FALSE;
}
if (ZEND_NUM_ARGS() >= 4 && len <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The length must be greater than zero");
RETURN_FALSE;
}
if (offset < 0) {
offset = s1_len + offset;
offset = (offset < 0) ? 0 : offset;
}
if (offset > s1_len) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The start position cannot exceed initial string length");
RETURN_FALSE;
}
if (len > s1_len - offset) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The length cannot exceed initial string length");
RETURN_FALSE;
}
cmp_len = (uint) (len ? len : MAX(s2_len, (s1_len - offset)));
if (!cs) {
RETURN_LONG(zend_binary_strncmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len));
} else {
RETURN_LONG(zend_binary_strncasecmp(s1 + offset, (s1_len - offset), s2, s2_len, cmp_len));
}
}