/ext/standard/string.c
C | 6197 lines | 5022 code | 692 blank | 483 comment | 1234 complexity | 36aa99423264fce3e37fb1a5d0ece920 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Rasmus Lerdorf <rasmus@php.net> |
- | Stig Sæther Bakken <ssb@php.net> |
- | Zeev Suraski <zeev@php.net> |
- +----------------------------------------------------------------------+
- */
- #include <stdio.h>
- #include "php.h"
- #include "php_rand.h"
- #include "php_string.h"
- #include "php_variables.h"
- #include <locale.h>
- #ifdef HAVE_LANGINFO_H
- # include <langinfo.h>
- #endif
- #ifdef HAVE_LIBINTL
- # include <libintl.h> /* For LC_MESSAGES */
- #endif
- #include "scanf.h"
- #include "zend_API.h"
- #include "zend_execute.h"
- #include "php_globals.h"
- #include "basic_functions.h"
- #include "zend_smart_str.h"
- #include <Zend/zend_exceptions.h>
- #ifdef ZTS
- #include "TSRM.h"
- #endif
- /* For str_getcsv() support */
- #include "ext/standard/file.h"
- /* For php_next_utf8_char() */
- #include "ext/standard/html.h"
- #ifdef __SSE2__
- #include <emmintrin.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
- /* {{{ register_string_constants */
- void register_string_constants(INIT_FUNC_ARGS)
- {
- REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT);
- REGISTER_LONG_CONSTANT("PATHINFO_ALL", PHP_PATHINFO_ALL, CONST_CS | CONST_PERSISTENT);
- /* If last members of struct lconv equal CHAR_MAX, no grouping is done */
- REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
- 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
- }
- /* }}} */
- int php_tag_find(char *tag, size_t len, const char *set);
- /* this is read-only, so it's ok */
- ZEND_SET_ALIGNED(16, static const char hexconvtab[]) = "0123456789abcdef";
- /* localeconv mutex */
- #ifdef ZTS
- static MUTEX_T locale_mutex = NULL;
- #endif
- /* {{{ php_bin2hex */
- static zend_string *php_bin2hex(const unsigned char *old, const size_t oldlen)
- {
- zend_string *result;
- size_t i, j;
- result = zend_string_safe_alloc(oldlen, 2 * sizeof(char), 0, 0);
- for (i = j = 0; i < oldlen; i++) {
- ZSTR_VAL(result)[j++] = hexconvtab[old[i] >> 4];
- ZSTR_VAL(result)[j++] = hexconvtab[old[i] & 15];
- }
- ZSTR_VAL(result)[j] = '\0';
- return result;
- }
- /* }}} */
- /* {{{ php_hex2bin */
- static zend_string *php_hex2bin(const unsigned char *old, const size_t oldlen)
- {
- size_t target_length = oldlen >> 1;
- zend_string *str = zend_string_alloc(target_length, 0);
- unsigned char *ret = (unsigned char *)ZSTR_VAL(str);
- size_t i, j;
- for (i = j = 0; i < target_length; i++) {
- unsigned char c = old[j++];
- unsigned char l = c & ~0x20;
- int is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
- unsigned char d;
- /* basically (c >= '0' && c <= '9') || (l >= 'A' && l <= 'F') */
- if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
- d = (l - 0x10 - 0x27 * is_letter) << 4;
- } else {
- zend_string_efree(str);
- return NULL;
- }
- c = old[j++];
- l = c & ~0x20;
- is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
- if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
- d |= l - 0x10 - 0x27 * is_letter;
- } else {
- zend_string_efree(str);
- return NULL;
- }
- ret[i] = d;
- }
- ret[i] = '\0';
- return str;
- }
- /* }}} */
- /* {{{ localeconv_r
- * glibc's localeconv is not reentrant, so lets make it so ... sorta */
- PHPAPI struct lconv *localeconv_r(struct lconv *out)
- {
- #ifdef ZTS
- tsrm_mutex_lock( locale_mutex );
- #endif
- /* cur->locinfo is struct __crt_locale_info which implementation is
- hidden in vc14. TODO revisit this and check if a workaround available
- and needed. */
- #if defined(PHP_WIN32) && _MSC_VER < 1900 && defined(ZTS)
- {
- /* Even with the enabled per thread locale, localeconv
- won't check any locale change in the master thread. */
- _locale_t cur = _get_current_locale();
- *out = *cur->locinfo->lconv;
- _free_locale(cur);
- }
- #else
- /* localeconv doesn't return an error condition */
- *out = *localeconv();
- #endif
- #ifdef ZTS
- tsrm_mutex_unlock( locale_mutex );
- #endif
- return out;
- }
- /* }}} */
- #ifdef ZTS
- /* {{{ PHP_MINIT_FUNCTION */
- PHP_MINIT_FUNCTION(localeconv)
- {
- locale_mutex = tsrm_mutex_alloc();
- return SUCCESS;
- }
- /* }}} */
- /* {{{ PHP_MSHUTDOWN_FUNCTION */
- PHP_MSHUTDOWN_FUNCTION(localeconv)
- {
- tsrm_mutex_free( locale_mutex );
- locale_mutex = NULL;
- return SUCCESS;
- }
- /* }}} */
- #endif
- /* {{{ Converts the binary representation of data to hex */
- PHP_FUNCTION(bin2hex)
- {
- zend_string *result;
- zend_string *data;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(data)
- ZEND_PARSE_PARAMETERS_END();
- result = php_bin2hex((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data));
- RETURN_STR(result);
- }
- /* }}} */
- /* {{{ Converts the hex representation of data to binary */
- PHP_FUNCTION(hex2bin)
- {
- zend_string *result, *data;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(data)
- ZEND_PARSE_PARAMETERS_END();
- if (ZSTR_LEN(data) % 2 != 0) {
- php_error_docref(NULL, E_WARNING, "Hexadecimal input string must have an even length");
- RETURN_FALSE;
- }
- result = php_hex2bin((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data));
- if (!result) {
- php_error_docref(NULL, E_WARNING, "Input string must be hexadecimal string");
- RETURN_FALSE;
- }
- RETVAL_STR(result);
- }
- /* }}} */
- static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
- {
- zend_string *s11, *s22;
- zend_long start = 0, len = 0;
- bool len_is_null = 1;
- ZEND_PARSE_PARAMETERS_START(2, 4)
- Z_PARAM_STR(s11)
- Z_PARAM_STR(s22)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(start)
- Z_PARAM_LONG_OR_NULL(len, len_is_null)
- ZEND_PARSE_PARAMETERS_END();
- size_t remain_len = ZSTR_LEN(s11);
- if (start < 0) {
- start += remain_len;
- if (start < 0) {
- start = 0;
- }
- } else if ((size_t) start > remain_len) {
- start = remain_len;
- }
- remain_len -= start;
- if (!len_is_null) {
- if (len < 0) {
- len += remain_len;
- if (len < 0) {
- len = 0;
- }
- } else if ((size_t) len > remain_len) {
- len = remain_len;
- }
- } else {
- len = remain_len;
- }
- if (len == 0) {
- RETURN_LONG(0);
- }
- if (behavior == STR_STRSPN) {
- RETURN_LONG(php_strspn(ZSTR_VAL(s11) + start /*str1_start*/,
- ZSTR_VAL(s22) /*str2_start*/,
- ZSTR_VAL(s11) + start + len /*str1_end*/,
- ZSTR_VAL(s22) + ZSTR_LEN(s22) /*str2_end*/));
- } else {
- ZEND_ASSERT(behavior == STR_STRCSPN);
- RETURN_LONG(php_strcspn(ZSTR_VAL(s11) + start /*str1_start*/,
- ZSTR_VAL(s22) /*str2_start*/,
- ZSTR_VAL(s11) + start + len /*str1_end*/,
- ZSTR_VAL(s22) + ZSTR_LEN(s22) /*str2_end*/));
- }
- }
- /* }}} */
- /* {{{ Finds length of initial segment consisting entirely of characters found in mask. If start or/and length is provided works like strspn(substr($s,$start,$len),$good_chars) */
- PHP_FUNCTION(strspn)
- {
- php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN);
- }
- /* }}} */
- /* {{{ Finds length of initial segment consisting entirely of characters not found in mask. If start or/and length is provide works like strcspn(substr($s,$start,$len),$bad_chars) */
- PHP_FUNCTION(strcspn)
- {
- php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN);
- }
- /* }}} */
- /* {{{ PHP_MINIT_FUNCTION(nl_langinfo) */
- #if HAVE_NL_LANGINFO
- PHP_MINIT_FUNCTION(nl_langinfo)
- {
- #define REGISTER_NL_LANGINFO_CONSTANT(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS | CONST_PERSISTENT)
- #ifdef ABDAY_1
- REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
- REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
- REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
- REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
- REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
- REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
- REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
- #endif
- #ifdef DAY_1
- REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
- REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
- REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
- REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
- REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
- REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
- REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
- #endif
- #ifdef ABMON_1
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
- REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
- #endif
- #ifdef MON_1
- REGISTER_NL_LANGINFO_CONSTANT(MON_1);
- REGISTER_NL_LANGINFO_CONSTANT(MON_2);
- REGISTER_NL_LANGINFO_CONSTANT(MON_3);
- REGISTER_NL_LANGINFO_CONSTANT(MON_4);
- REGISTER_NL_LANGINFO_CONSTANT(MON_5);
- REGISTER_NL_LANGINFO_CONSTANT(MON_6);
- REGISTER_NL_LANGINFO_CONSTANT(MON_7);
- REGISTER_NL_LANGINFO_CONSTANT(MON_8);
- REGISTER_NL_LANGINFO_CONSTANT(MON_9);
- REGISTER_NL_LANGINFO_CONSTANT(MON_10);
- REGISTER_NL_LANGINFO_CONSTANT(MON_11);
- REGISTER_NL_LANGINFO_CONSTANT(MON_12);
- #endif
- #ifdef AM_STR
- REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
- #endif
- #ifdef PM_STR
- REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
- #endif
- #ifdef D_T_FMT
- REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
- #endif
- #ifdef D_FMT
- REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
- #endif
- #ifdef T_FMT
- REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
- #endif
- #ifdef T_FMT_AMPM
- REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
- #endif
- #ifdef ERA
- REGISTER_NL_LANGINFO_CONSTANT(ERA);
- #endif
- #ifdef ERA_YEAR
- REGISTER_NL_LANGINFO_CONSTANT(ERA_YEAR);
- #endif
- #ifdef ERA_D_T_FMT
- REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
- #endif
- #ifdef ERA_D_FMT
- REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
- #endif
- #ifdef ERA_T_FMT
- REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
- #endif
- #ifdef ALT_DIGITS
- REGISTER_NL_LANGINFO_CONSTANT(ALT_DIGITS);
- #endif
- #ifdef INT_CURR_SYMBOL
- REGISTER_NL_LANGINFO_CONSTANT(INT_CURR_SYMBOL);
- #endif
- #ifdef CURRENCY_SYMBOL
- REGISTER_NL_LANGINFO_CONSTANT(CURRENCY_SYMBOL);
- #endif
- #ifdef CRNCYSTR
- REGISTER_NL_LANGINFO_CONSTANT(CRNCYSTR);
- #endif
- #ifdef MON_DECIMAL_POINT
- REGISTER_NL_LANGINFO_CONSTANT(MON_DECIMAL_POINT);
- #endif
- #ifdef MON_THOUSANDS_SEP
- REGISTER_NL_LANGINFO_CONSTANT(MON_THOUSANDS_SEP);
- #endif
- #ifdef MON_GROUPING
- REGISTER_NL_LANGINFO_CONSTANT(MON_GROUPING);
- #endif
- #ifdef POSITIVE_SIGN
- REGISTER_NL_LANGINFO_CONSTANT(POSITIVE_SIGN);
- #endif
- #ifdef NEGATIVE_SIGN
- REGISTER_NL_LANGINFO_CONSTANT(NEGATIVE_SIGN);
- #endif
- #ifdef INT_FRAC_DIGITS
- REGISTER_NL_LANGINFO_CONSTANT(INT_FRAC_DIGITS);
- #endif
- #ifdef FRAC_DIGITS
- REGISTER_NL_LANGINFO_CONSTANT(FRAC_DIGITS);
- #endif
- #ifdef P_CS_PRECEDES
- REGISTER_NL_LANGINFO_CONSTANT(P_CS_PRECEDES);
- #endif
- #ifdef P_SEP_BY_SPACE
- REGISTER_NL_LANGINFO_CONSTANT(P_SEP_BY_SPACE);
- #endif
- #ifdef N_CS_PRECEDES
- REGISTER_NL_LANGINFO_CONSTANT(N_CS_PRECEDES);
- #endif
- #ifdef N_SEP_BY_SPACE
- REGISTER_NL_LANGINFO_CONSTANT(N_SEP_BY_SPACE);
- #endif
- #ifdef P_SIGN_POSN
- REGISTER_NL_LANGINFO_CONSTANT(P_SIGN_POSN);
- #endif
- #ifdef N_SIGN_POSN
- REGISTER_NL_LANGINFO_CONSTANT(N_SIGN_POSN);
- #endif
- #ifdef DECIMAL_POINT
- REGISTER_NL_LANGINFO_CONSTANT(DECIMAL_POINT);
- #endif
- #ifdef RADIXCHAR
- REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
- #endif
- #ifdef THOUSANDS_SEP
- REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
- #endif
- #ifdef THOUSEP
- REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
- #endif
- #ifdef GROUPING
- REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
- #endif
- #ifdef YESEXPR
- REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
- #endif
- #ifdef NOEXPR
- REGISTER_NL_LANGINFO_CONSTANT(NOEXPR);
- #endif
- #ifdef YESSTR
- REGISTER_NL_LANGINFO_CONSTANT(YESSTR);
- #endif
- #ifdef NOSTR
- REGISTER_NL_LANGINFO_CONSTANT(NOSTR);
- #endif
- #ifdef CODESET
- REGISTER_NL_LANGINFO_CONSTANT(CODESET);
- #endif
- #undef REGISTER_NL_LANGINFO_CONSTANT
- return SUCCESS;
- }
- /* }}} */
- /* {{{ Query language and locale information */
- PHP_FUNCTION(nl_langinfo)
- {
- zend_long item;
- char *value;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_LONG(item)
- ZEND_PARSE_PARAMETERS_END();
- 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, E_WARNING, "Item '" ZEND_LONG_FMT "' is not valid", item);
- RETURN_FALSE;
- }
- /* }}} */
- value = nl_langinfo(item);
- if (value == NULL) {
- RETURN_FALSE;
- } else {
- RETURN_STRING(value);
- }
- }
- #endif
- /* }}} */
- /* {{{ Compares two strings using the current locale */
- PHP_FUNCTION(strcoll)
- {
- zend_string *s1, *s2;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_STR(s1)
- Z_PARAM_STR(s2)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_LONG(strcoll((const char *) ZSTR_VAL(s1),
- (const char *) ZSTR_VAL(s2)));
- }
- /* }}} */
- /* {{{ php_charmask
- * Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
- * it needs to be incrementing.
- * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
- */
- static inline int php_charmask(const unsigned char *input, size_t len, char *mask)
- {
- const unsigned char *end;
- unsigned char c;
- int result = SUCCESS;
- memset(mask, 0, 256);
- for (end = input+len; input < end; input++) {
- c=*input;
- if ((input+3 < end) && input[1] == '.' && input[2] == '.'
- && input[3] >= c) {
- memset(mask+c, 1, input[3] - c + 1);
- input+=3;
- } else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
- /* Error, try to be as helpful as possible:
- (a range ending/starting with '.' won't be captured here) */
- if (end-len >= input) { /* there was no 'left' char */
- php_error_docref(NULL, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
- result = FAILURE;
- continue;
- }
- if (input+2 >= end) { /* there is no 'right' char */
- php_error_docref(NULL, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
- result = FAILURE;
- continue;
- }
- if (input[-1] > input[2]) { /* wrong order */
- php_error_docref(NULL, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
- result = FAILURE;
- continue;
- }
- /* FIXME: better error (a..b..c is the only left possibility?) */
- php_error_docref(NULL, E_WARNING, "Invalid '..'-range");
- result = FAILURE;
- continue;
- } else {
- mask[c]=1;
- }
- }
- return result;
- }
- /* }}} */
- /* {{{ php_trim_int()
- * mode 1 : trim left
- * mode 2 : trim right
- * mode 3 : trim left and right
- * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
- */
- static zend_always_inline zend_string *php_trim_int(zend_string *str, const char *what, size_t what_len, int mode)
- {
- const char *start = ZSTR_VAL(str);
- const char *end = start + ZSTR_LEN(str);
- char mask[256];
- if (what) {
- if (what_len == 1) {
- char p = *what;
- if (mode & 1) {
- while (start != end) {
- if (*start == p) {
- start++;
- } else {
- break;
- }
- }
- }
- if (mode & 2) {
- while (start != end) {
- if (*(end-1) == p) {
- end--;
- } else {
- break;
- }
- }
- }
- } else {
- php_charmask((const unsigned char *) what, what_len, mask);
- if (mode & 1) {
- while (start != end) {
- if (mask[(unsigned char)*start]) {
- start++;
- } else {
- break;
- }
- }
- }
- if (mode & 2) {
- while (start != end) {
- if (mask[(unsigned char)*(end-1)]) {
- end--;
- } else {
- break;
- }
- }
- }
- }
- } else {
- if (mode & 1) {
- while (start != end) {
- unsigned char c = (unsigned char)*start;
- if (c <= ' ' &&
- (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) {
- start++;
- } else {
- break;
- }
- }
- }
- if (mode & 2) {
- while (start != end) {
- unsigned char c = (unsigned char)*(end-1);
- if (c <= ' ' &&
- (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) {
- end--;
- } else {
- break;
- }
- }
- }
- }
- if (ZSTR_LEN(str) == end - start) {
- return zend_string_copy(str);
- } else if (end - start == 0) {
- return ZSTR_EMPTY_ALLOC();
- } else {
- return zend_string_init(start, end - start, 0);
- }
- }
- /* }}} */
- /* {{{ php_trim_int()
- * mode 1 : trim left
- * mode 2 : trim right
- * mode 3 : trim left and right
- * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
- */
- PHPAPI zend_string *php_trim(zend_string *str, const char *what, size_t what_len, int mode)
- {
- return php_trim_int(str, what, what_len, mode);
- }
- /* }}} */
- /* {{{ php_do_trim
- * Base for trim(), rtrim() and ltrim() functions.
- */
- static zend_always_inline void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
- {
- zend_string *str;
- zend_string *what = NULL;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STR(str)
- Z_PARAM_OPTIONAL
- Z_PARAM_STR(what)
- ZEND_PARSE_PARAMETERS_END();
- ZVAL_STR(return_value, php_trim_int(str, (what ? ZSTR_VAL(what) : NULL), (what ? ZSTR_LEN(what) : 0), mode));
- }
- /* }}} */
- /* {{{ Strips whitespace from the beginning and end of a string */
- PHP_FUNCTION(trim)
- {
- php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
- }
- /* }}} */
- /* {{{ Removes trailing whitespace */
- PHP_FUNCTION(rtrim)
- {
- php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
- }
- /* }}} */
- /* {{{ Strips whitespace from the beginning of a string */
- PHP_FUNCTION(ltrim)
- {
- php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
- }
- /* }}} */
- /* {{{ Wraps buffer to selected number of characters using string break char */
- PHP_FUNCTION(wordwrap)
- {
- zend_string *text;
- char *breakchar = "\n";
- size_t newtextlen, chk, breakchar_len = 1;
- size_t alloced;
- zend_long current = 0, laststart = 0, lastspace = 0;
- zend_long linelength = 75;
- bool docut = 0;
- zend_string *newtext;
- ZEND_PARSE_PARAMETERS_START(1, 4)
- Z_PARAM_STR(text)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(linelength)
- Z_PARAM_STRING(breakchar, breakchar_len)
- Z_PARAM_BOOL(docut)
- ZEND_PARSE_PARAMETERS_END();
- if (ZSTR_LEN(text) == 0) {
- RETURN_EMPTY_STRING();
- }
- if (breakchar_len == 0) {
- zend_argument_value_error(3, "cannot be empty");
- RETURN_THROWS();
- }
- if (linelength == 0 && docut) {
- zend_argument_value_error(4, "cannot be true when argument #2 ($width) is 0");
- RETURN_THROWS();
- }
- /* Special case for a single-character break as it needs no
- additional storage space */
- if (breakchar_len == 1 && !docut) {
- newtext = zend_string_init(ZSTR_VAL(text), ZSTR_LEN(text), 0);
- laststart = lastspace = 0;
- for (current = 0; current < (zend_long)ZSTR_LEN(text); current++) {
- if (ZSTR_VAL(text)[current] == breakchar[0]) {
- laststart = lastspace = current + 1;
- } else if (ZSTR_VAL(text)[current] == ' ') {
- if (current - laststart >= linelength) {
- ZSTR_VAL(newtext)[current] = breakchar[0];
- laststart = current + 1;
- }
- lastspace = current;
- } else if (current - laststart >= linelength && laststart != lastspace) {
- ZSTR_VAL(newtext)[lastspace] = breakchar[0];
- laststart = lastspace + 1;
- }
- }
- RETURN_NEW_STR(newtext);
- } else {
- /* Multiple character line break or forced cut */
- if (linelength > 0) {
- chk = (size_t)(ZSTR_LEN(text)/linelength + 1);
- newtext = zend_string_safe_alloc(chk, breakchar_len, ZSTR_LEN(text), 0);
- alloced = ZSTR_LEN(text) + chk * breakchar_len + 1;
- } else {
- chk = ZSTR_LEN(text);
- alloced = ZSTR_LEN(text) * (breakchar_len + 1) + 1;
- newtext = zend_string_safe_alloc(ZSTR_LEN(text), breakchar_len + 1, 0, 0);
- }
- /* now keep track of the actual new text length */
- newtextlen = 0;
- laststart = lastspace = 0;
- for (current = 0; current < (zend_long)ZSTR_LEN(text); current++) {
- if (chk == 0) {
- alloced += (size_t) (((ZSTR_LEN(text) - current + 1)/linelength + 1) * breakchar_len) + 1;
- newtext = zend_string_extend(newtext, alloced, 0);
- chk = (size_t) ((ZSTR_LEN(text) - current)/linelength) + 1;
- }
- /* when we hit an existing break, copy to new buffer, and
- * fix up laststart and lastspace */
- if (ZSTR_VAL(text)[current] == breakchar[0]
- && current + breakchar_len < ZSTR_LEN(text)
- && !strncmp(ZSTR_VAL(text) + current, breakchar, breakchar_len)) {
- memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart + breakchar_len);
- newtextlen += current - laststart + breakchar_len;
- current += breakchar_len - 1;
- laststart = lastspace = current + 1;
- chk--;
- }
- /* if it is a space, check if it is at the line boundary,
- * copy and insert a break, or just keep track of it */
- else if (ZSTR_VAL(text)[current] == ' ') {
- if (current - laststart >= linelength) {
- memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
- newtextlen += current - laststart;
- memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
- newtextlen += breakchar_len;
- laststart = current + 1;
- chk--;
- }
- lastspace = current;
- }
- /* if we are cutting, and we've accumulated enough
- * characters, and we haven't see a space for this line,
- * copy and insert a break. */
- else if (current - laststart >= linelength
- && docut && laststart >= lastspace) {
- memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
- newtextlen += current - laststart;
- memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
- newtextlen += breakchar_len;
- laststart = lastspace = current;
- chk--;
- }
- /* if the current word puts us over the linelength, copy
- * back up until the last space, insert a break, and move
- * up the laststart */
- else if (current - laststart >= linelength
- && laststart < lastspace) {
- memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, lastspace - laststart);
- newtextlen += lastspace - laststart;
- memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
- newtextlen += breakchar_len;
- laststart = lastspace = lastspace + 1;
- chk--;
- }
- }
- /* copy over any stragglers */
- if (laststart != current) {
- memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
- newtextlen += current - laststart;
- }
- ZSTR_VAL(newtext)[newtextlen] = '\0';
- /* free unused memory */
- newtext = zend_string_truncate(newtext, newtextlen, 0);
- RETURN_NEW_STR(newtext);
- }
- }
- /* }}} */
- /* {{{ php_explode */
- PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
- {
- const char *p1 = ZSTR_VAL(str);
- const char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
- const char *p2 = php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
- zval tmp;
- if (p2 == NULL) {
- ZVAL_STR_COPY(&tmp, str);
- zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
- } else {
- zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
- ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
- do {
- ZEND_HASH_FILL_GROW();
- ZEND_HASH_FILL_SET_STR(zend_string_init_fast(p1, p2 - p1));
- ZEND_HASH_FILL_NEXT();
- p1 = p2 + ZSTR_LEN(delim);
- p2 = php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
- } while (p2 != NULL && --limit > 1);
- if (p1 <= endp) {
- ZEND_HASH_FILL_GROW();
- ZEND_HASH_FILL_SET_STR(zend_string_init_fast(p1, endp - p1));
- ZEND_HASH_FILL_NEXT();
- }
- } ZEND_HASH_FILL_END();
- }
- }
- /* }}} */
- /* {{{ php_explode_negative_limit */
- PHPAPI void php_explode_negative_limit(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
- {
- #define EXPLODE_ALLOC_STEP 64
- const char *p1 = ZSTR_VAL(str);
- const char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
- const char *p2 = php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
- zval tmp;
- if (p2 == NULL) {
- /*
- do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0
- by doing nothing we return empty array
- */
- } else {
- size_t allocated = EXPLODE_ALLOC_STEP, found = 0;
- zend_long i, to_return;
- const char **positions = emalloc(allocated * sizeof(char *));
- positions[found++] = p1;
- do {
- if (found >= allocated) {
- allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */
- positions = erealloc(ZEND_VOIDP(positions), allocated*sizeof(char *));
- }
- positions[found++] = p1 = p2 + ZSTR_LEN(delim);
- p2 = php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
- } while (p2 != NULL);
- to_return = limit + found;
- /* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
- for (i = 0; i < to_return; i++) { /* this checks also for to_return > 0 */
- ZVAL_STRINGL(&tmp, positions[i], (positions[i+1] - ZSTR_LEN(delim)) - positions[i]);
- zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
- }
- efree((void *)positions);
- }
- #undef EXPLODE_ALLOC_STEP
- }
- /* }}} */
- /* {{{ Splits a string on string separator and return array of components. If limit is positive only limit number of components is returned. If limit is negative all components except the last abs(limit) are returned. */
- PHP_FUNCTION(explode)
- {
- zend_string *str, *delim;
- zend_long limit = ZEND_LONG_MAX; /* No limit */
- zval tmp;
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_STR(delim)
- Z_PARAM_STR(str)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(limit)
- ZEND_PARSE_PARAMETERS_END();
- if (ZSTR_LEN(delim) == 0) {
- zend_argument_value_error(1, "cannot be empty");
- RETURN_THROWS();
- }
- array_init(return_value);
- if (ZSTR_LEN(str) == 0) {
- if (limit >= 0) {
- ZVAL_EMPTY_STRING(&tmp);
- zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
- }
- return;
- }
- if (limit > 1) {
- php_explode(delim, str, return_value, limit);
- } else if (limit < 0) {
- php_explode_negative_limit(delim, str, return_value, limit);
- } else {
- ZVAL_STR_COPY(&tmp, str);
- zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
- }
- }
- /* }}} */
- /* {{{ An alias for implode */
- /* }}} */
- /* {{{ php_implode */
- PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return_value)
- {
- zval *tmp;
- int numelems;
- zend_string *str;
- char *cptr;
- size_t len = 0;
- struct {
- zend_string *str;
- zend_long lval;
- } *strings, *ptr;
- ALLOCA_FLAG(use_heap)
- numelems = zend_hash_num_elements(pieces);
- if (numelems == 0) {
- RETURN_EMPTY_STRING();
- } else if (numelems == 1) {
- /* loop to search the first not undefined element... */
- ZEND_HASH_FOREACH_VAL(pieces, tmp) {
- RETURN_STR(zval_get_string(tmp));
- } ZEND_HASH_FOREACH_END();
- }
- ptr = strings = do_alloca((sizeof(*strings)) * numelems, use_heap);
- ZEND_HASH_FOREACH_VAL(pieces, tmp) {
- if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) {
- ptr->str = Z_STR_P(tmp);
- len += ZSTR_LEN(ptr->str);
- ptr->lval = 0;
- ptr++;
- } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) {
- zend_long val = Z_LVAL_P(tmp);
- ptr->str = NULL;
- ptr->lval = val;
- ptr++;
- if (val <= 0) {
- len++;
- }
- while (val) {
- val /= 10;
- len++;
- }
- } else {
- ptr->str = zval_get_string_func(tmp);
- len += ZSTR_LEN(ptr->str);
- ptr->lval = 1;
- ptr++;
- }
- } ZEND_HASH_FOREACH_END();
- /* numelems cannot be 0, we checked above */
- str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(glue), len, 0);
- cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
- *cptr = 0;
- while (1) {
- ptr--;
- if (EXPECTED(ptr->str)) {
- cptr -= ZSTR_LEN(ptr->str);
- memcpy(cptr, ZSTR_VAL(ptr->str), ZSTR_LEN(ptr->str));
- if (ptr->lval) {
- zend_string_release_ex(ptr->str, 0);
- }
- } else {
- char *oldPtr = cptr;
- char oldVal = *cptr;
- cptr = zend_print_long_to_buf(cptr, ptr->lval);
- *oldPtr = oldVal;
- }
- if (ptr == strings) {
- break;
- }
- cptr -= ZSTR_LEN(glue);
- memcpy(cptr, ZSTR_VAL(glue), ZSTR_LEN(glue));
- }
- free_alloca(strings, use_heap);
- RETURN_NEW_STR(str);
- }
- /* }}} */
- /* {{{ Joins array elements placing glue string between items and return one string */
- PHP_FUNCTION(implode)
- {
- zend_string *arg1_str = NULL;
- HashTable *arg1_array = NULL;
- zend_array *pieces = NULL;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_ARRAY_HT_OR_STR(arg1_array, arg1_str)
- Z_PARAM_OPTIONAL
- Z_PARAM_ARRAY_HT_OR_NULL(pieces)
- ZEND_PARSE_PARAMETERS_END();
- if (pieces == NULL) {
- if (arg1_array == NULL) {
- zend_type_error("%s(): Argument #1 ($pieces) must be of type array, string given", get_active_function_name());
- RETURN_THROWS();
- }
- arg1_str = ZSTR_EMPTY_ALLOC();
- pieces = arg1_array;
- } else {
- if (arg1_str == NULL) {
- zend_argument_type_error(1, "must be of type string, array given");
- RETURN_THROWS();
- }
- }
- php_implode(arg1_str, pieces, return_value);
- }
- /* }}} */
- #define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
- /* {{{ Tokenize a string */
- PHP_FUNCTION(strtok)
- {
- zend_string *str, *tok = NULL;
- char *token;
- char *token_end;
- char *p;
- char *pe;
- size_t skipped = 0;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STR(str)
- Z_PARAM_OPTIONAL
- Z_PARAM_STR_OR_NULL(tok)
- ZEND_PARSE_PARAMETERS_END();
- if (!tok) {
- tok = str;
- } else {
- if (BG(strtok_string)) {
- zend_string_release(BG(strtok_string));
- }
- BG(strtok_string) = zend_string_copy(str);
- BG(strtok_last) = ZSTR_VAL(str);
- BG(strtok_len) = ZSTR_LEN(str);
- }
- if (!BG(strtok_string)) {
- /* String to tokenize not set. */
- // TODO: Should this warn?
- RETURN_FALSE;
- }
- p = BG(strtok_last); /* Where we start to search */
- pe = ZSTR_VAL(BG(strtok_string)) + BG(strtok_len);
- if (p >= pe) {
- /* Reached the end of the string. */
- RETURN_FALSE;
- }
- token = ZSTR_VAL(tok);
- token_end = token + ZSTR_LEN(tok);
- while (token < token_end) {
- STRTOK_TABLE(token++) = 1;
- }
- /* Skip leading delimiters */
- while (STRTOK_TABLE(p)) {
- if (++p >= pe) {
- /* no other chars left */
- goto return_false;
- }
- skipped++;
- }
- /* We know at this place that *p is no delimiter, so skip it */
- while (++p < pe) {
- if (STRTOK_TABLE(p)) {
- goto return_token;
- }
- }
- if (p - BG(strtok_last)) {
- return_token:
- RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped);
- BG(strtok_last) = p + 1;
- } else {
- return_false:
- RETVAL_FALSE;
- zend_string_release(BG(strtok_string));
- BG(strtok_string) = NULL;
- }
- /* Restore table -- usually faster then memset'ing the table on every invocation */
- token = ZSTR_VAL(tok);
- while (token < token_end) {
- STRTOK_TABLE(token++) = 0;
- }
- }
- /* }}} */
- /* {{{ php_strtoupper */
- PHPAPI char *php_strtoupper(char *s, size_t len)
- {
- unsigned char *c;
- const unsigned char *e;
- c = (unsigned char *)s;
- e = (unsigned char *)c+len;
- while (c < e) {
- *c = toupper(*c);
- c++;
- }
- return s;
- }
- /* }}} */
- /* {{{ php_string_toupper */
- PHPAPI zend_string *php_string_toupper(zend_string *s)
- {
- unsigned char *c;
- const unsigned char *e;
- if (EXPECTED(!BG(ctype_string))) {
- return zend_string_toupper(s);
- }
- c = (unsigned char *)ZSTR_VAL(s);
- e = c + ZSTR_LEN(s);
- while (c < e) {
- if (islower(*c)) {
- unsigned char *r;
- zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
- if (c != (unsigned char*)ZSTR_VAL(s)) {
- memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
- }
- r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
- while (c < e) {
- *r = toupper(*c);
- r++;
- c++;
- }
- *r = '\0';
- return res;
- }
- c++;
- }
- return zend_string_copy(s);
- }
- /* }}} */
- /* {{{ Makes a string uppercase */
- PHP_FUNCTION(strtoupper)
- {
- zend_string *arg;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(arg)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_STR(php_string_toupper(arg));
- }
- /* }}} */
- /* {{{ php_strtolower */
- PHPAPI char *php_strtolower(char *s, size_t len)
- {
- unsigned char *c;
- const unsigned char *e;
- c = (unsigned char *)s;
- e = c+len;
- while (c < e) {
- *c = tolower(*c);
- c++;
- }
- return s;
- }
- /* }}} */
- /* {{{ php_string_tolower */
- PHPAPI zend_string *php_string_tolower(zend_string *s)
- {
- if (EXPECTED(!BG(ctype_string))) {
- return zend_string_tolower(s);
- }
- unsigned char *c = (unsigned char *)ZSTR_VAL(s);
- const unsigned char *e = c + ZSTR_LEN(s);
- while (c < e) {
- if (isupper(*c)) {
- unsigned char *r;
- zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
- if (c != (unsigned char*)ZSTR_VAL(s)) {
- memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
- }
- r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
- while (c < e) {
- *r = tolower(*c);
- r++;
- c++;
- }
- *r = '\0';
- return res;
- }
- c++;
- }
- return zend_string_copy(s);
- }
- /* }}} */
- /* {{{ Makes a string lowercase */
- PHP_FUNCTION(strtolower)
- {
- zend_string *str;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(str)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_STR(php_string_tolower(str));
- }
- /* }}} */
- #if defined(PHP_WIN32)
- static bool _is_basename_start(const char *start, const char *pos)
- {
- if (pos - start >= 1
- && *(pos-1) != '/'
- && *(pos-1) != '\\') {
- if (pos - start == 1) {
- return 1;
- } else if (*(pos-2) == '/' || *(pos-2) == '\\') {
- return 1;
- } else if (*(pos-2) == ':'
- && _is_basename_start(start, pos - 2)) {
- return 1;
- }
- }
- return 0;
- }
- #endif
- /* {{{ php_basename */
- PHPAPI zend_string *php_basename(const char *s, size_t len, const char *suffix, size_t suffix_len)
- {
- const char *basename_start;
- const char *basename_end;
- if (CG(ascii_compatible_locale)) {
- basename_end = s + len - 1;
- /* Strip trailing slashes */
- while (basename_end >= s
- #if defined(PHP_WIN32)
- && (*basename_end == '/'
- || *basename_end == '\\'
- || (*basename_end == ':'
- && _is_basename_start(s, basename_end)))) {
- #else
- && *basename_end == '/') {
- #endif
- basename_end--;
- }
- if (basename_end < s) {
- return ZSTR_EMPTY_ALLOC();
- }
- /* Extract filename */
- basename_start = basename_end;
- basename_end++;
- while (basename_start > s
- #if defined(PHP_WIN32)
- && *(basename_start-1) != '/'
- && *(basename_start-1) != '\\') {
- if (*(basename_start-1) == ':' &&
- _is_basename_start(s, basename_start - 1)) {
- break;
- }
- #else
- && *(basename_start-1) != '/') {
- #endif
- basename_start--;
- }
- } else {
- /* State 0 is directly after a directory separator (or at the start of the string).
- * State 1 is everything else. */
- int state = 0;
- basename_start = s;
- basename_end = s;
- while (len > 0) {
- int inc_len = (*s == '\0' ? 1 : php_mblen(s, len));
- switch (inc_len) {
- case 0:
- goto quit_loop;
- case 1:
- #if defined(PHP_WIN32)
- if (*s == '/' || *s == '\\') {
- #else
- if (*s == '/') {
- #endif
- if (state == 1) {
- state = 0;
- basename_end = s;
- }
- #if defined(PHP_WIN32)
- /* Catch relative paths in c:file.txt style. They're not to confuse
- with the NTFS streams. This part ensures also, that no drive
- letter traversing happens. */
- } else if ((*s == ':' && (s - basename_start == 1))) {
- if (state == 0) {
- basename_start = s;
- state = 1;
- } else {
- basename_end = s;
- state = 0;
- }
- #endif
- } else {
- if (state == 0) {
- basename_start = s;
- state = 1;
- }
- }
- break;
- default:
- if (inc_len < 0) {
- /* If character is invalid, treat it like other non-significant characters. */
- inc_len = 1;
- php_mb_reset();
- }
- if (state == 0) {
- basename_start = s;
- state = 1;
- }
- break;
- }
- s += inc_len;
- len -= inc_len;
- }
- quit_loop:
- if (state == 1) {
- basename_end = s;
- }
- }
- if (suffix != NULL && suffix_len < (size_t)(basename_end - basename_start) &&
- memcmp(basename_end - suffix_len, suffix, suffix_len) == 0) {
- basename_end -= suffix_len;
- }
- return zend_string_init(basename_start, basename_end - basename_start, 0);
- }
- /* }}} */
- /* {{{ Returns the filename component of the path */
- PHP_FUNCTION(basename)
- {
- char *string, *suffix = NULL;
- size_t string_len, suffix_len = 0;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STRING(string, string_len)
- Z_PARAM_OPTIONAL
- Z_PARAM_STRING(suffix, suffix_len)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_STR(php_basename(string, string_len, suffix, suffix_len));
- }
- /* }}} */
- /* {{{ php_dirname
- Returns directory name component of path */
- PHPAPI size_t php_dirname(char *path, size_t len)
- {
- return zend_dirname(path, len);
- }
- /* }}} */
- /* {{{ Returns the directory name component of the path */
- PHP_FUNCTION(dirname)
- {
- char *str;
- size_t str_len;
- zend_string *ret;
- zend_long levels = 1;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STRING(str, str_len)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(levels)
- ZEND_PARSE_PARAMETERS_END();
- ret = zend_string_init(str, str_len, 0);
- if (levels == 1) {
- /* Default case */
- #ifdef PHP_WIN32
- ZSTR_LEN(ret) = php_win32_ioutil_dirname(ZSTR_VAL(ret), str_len);
- #else
- ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len);
- #endif
- } else if (levels < 1) {
- zend_argument_value_error(2, "must be greater than or equal to 1");
- zend_string_efree(ret);
- RETURN_THROWS();
- } else {
- /* Some levels up */
- do {
- #ifdef PHP_WIN32
- ZSTR_LEN(ret) = php_win32_ioutil_dirname(ZSTR_VAL(ret), str_len = ZSTR_LEN(ret));
- #else
- ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len = ZSTR_LEN(ret));
- #endif
- } while (ZSTR_LEN(ret) < str_len && --levels);
- }
- RETURN_NEW_STR(ret);
- }
- /* }}} */
- /* {{{ Returns information about a certain string */
- PHP_FUNCTION(pathinfo)
- {
- zval tmp;
- char *path, *dirname;
- size_t path_len;
- int have_basename;
- zend_long opt = PHP_PATHINFO_ALL;
- zend_string *ret = NULL;
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_STRING(path, path_len)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(opt)
- ZEND_PARSE_PARAMETERS_END();
- have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
- array_init(&tmp);
- if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
- dirname = estrndup(path, path_len);
- php_dirname(dirname, path_len);
- if (*dirname) {
- add_assoc_string(&tmp, "dirname", dirname);
- }
- efree(dirname);
- }
- if (have_basename) {
- ret = php_basename(path, path_len, NULL, 0);
- add_assoc_str(&tmp, "basename", zend_string_copy(ret));
- }
- if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
- const char *p;
- ptrdiff_t idx;
- if (!have_basename) {
- ret = php_basename(path, path_len, NULL, 0);
- }
- p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
- if (p) {
- idx = p - ZSTR_VAL(ret);
- add_assoc_stringl(&tmp, "extension", ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
- }
- }
- if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
- const char *p;
- ptrdiff_t idx;
- /* Have we already looked up the basename? */
- if (!have_basename && !ret) {
- ret = php_basename(path, path_len, NULL, 0);
- }
- p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
- idx = p ? (p - ZSTR_VAL(ret)) : (ptrdiff_t)ZSTR_LEN(ret);
- add_assoc_stringl(&tmp, "filename", ZSTR_VAL(ret), idx);
- }
- if (ret) {
- zend_string_release_ex(ret, 0);
- }
- if (opt == PHP_PATHINFO_ALL) {
- RETURN_COPY_VALUE(&tmp);
- } else {
- zval *element;
- if ((element = zend_hash_get_current_data(Z_ARRVAL(tmp))) != NULL) {
- RETVAL_COPY_DEREF(element);
- } else {
- RETVAL_EMPTY_STRING();
- }
- zval_ptr_dtor(&tmp);
- }
- }
- /* }}} */
- /* {{{ php_stristr
- case insensitive strstr */
- PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
- {
- php_strtolower(s, s_len);
- php_strtolower(t, t_len);
- return (char*)php_memnstr(s, t, t_len, s + s_len);
- }
- /* }}} */
- /* {{{ php_strspn */
- PHPAPI size_t php_strspn(const char *s1, const char *s2, const char *s1_end, const char *s2_end)
- {
- const char *p = s1, *spanp;
- char c = *p;
- cont:
- for (spanp = s2; p != s1_end && spanp != s2_end;) {
- if (*spanp++ == c) {
- c = *(++p);
- goto cont;
- }
- }
- return (p - s1);
- }
- /* }}} */
- /* {{{ php_strcspn */
- PHPAPI size_t php_strcspn(const char *s1, const char *s2, const char *s1_end, const char *s2_end)
- {
- const char *p, *spanp;
- char c = *s1;
- for (p = s1;;) {
- spanp = s2;
- do {
- if (*spanp == c || p == s1_end) {
- return p - s1;
- }
- } while (spanp++ < (s2_end - 1));
- c = *++p;
- }
- /* NOTREACHED */
- }
- /* }}} */
- /* {{{ Finds first occurrence of a string within another, case insensitive */
- PHP_FUNCTION(stristr)
- {
- zend_string *haystack, *needle;
- const char *found = NULL;
- size_t found_offset;
- char *haystack_dup;
- char *orig_needle;
- bool part = 0;
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- Z_PARAM_OPTIONAL
- Z_PARAM_BOOL(part)
- ZEND_PARSE_PARAMETERS_END();
- haystack_dup = estrndup(ZSTR_VAL(haystack), ZSTR_LEN(haystack));
- orig_needle = estrndup(ZSTR_VAL(needle), ZSTR_LEN(needle));
- found = php_stristr(haystack_dup, orig_needle, ZSTR_LEN(haystack), ZSTR_LEN(needle));
- efree(orig_needle);
- if (found) {
- found_offset = found - haystack_dup;
- if (part) {
- RETVAL_STRINGL(ZSTR_VAL(haystack), found_offset);
- } else {
- RETVAL_STRINGL(ZSTR_VAL(haystack) + found_offset, ZSTR_LEN(haystack) - found_offset);
- }
- } else {
- RETVAL_FALSE;
- }
- efree(haystack_dup);
- }
- /* }}} */
- /* {{{ Finds first occurrence of a string within another */
- PHP_FUNCTION(strstr)
- {
- zend_string *haystack, *needle;
- const char *found = NULL;
- zend_long found_offset;
- bool part = 0;
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- Z_PARAM_OPTIONAL
- Z_PARAM_BOOL(part)
- ZEND_PARSE_PARAMETERS_END();
- found = php_memnstr(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle), ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
- if (found) {
- found_offset = found - ZSTR_VAL(haystack);
- if (part) {
- RETURN_STRINGL(ZSTR_VAL(haystack), found_offset);
- } else {
- RETURN_STRINGL(found, ZSTR_LEN(haystack) - found_offset);
- }
- }
- RETURN_FALSE;
- }
- /* }}} */
- /* {{{ Checks if a string contains another */
- PHP_FUNCTION(str_contains)
- {
- zend_string *haystack, *needle;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- ZEND_PARSE_PARAMETERS_END();
- RETURN_BOOL(php_memnstr(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle), ZSTR_VAL(haystack) + ZSTR_LEN(haystack)));
- }
- /* }}} */
- /* {{{ Checks if haystack starts with needle */
- PHP_FUNCTION(str_starts_with)
- {
- zend_string *haystack, *needle;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- ZEND_PARSE_PARAMETERS_END();
- if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
- RETURN_FALSE;
- }
- RETURN_BOOL(memcmp(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
- }
- /* }}} */
- /* {{{ Checks if haystack ends with needle */
- PHP_FUNCTION(str_ends_with)
- {
- zend_string *haystack, *needle;
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- ZEND_PARSE_PARAMETERS_END();
- if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
- RETURN_FALSE;
- }
- RETURN_BOOL(memcmp(
- ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - ZSTR_LEN(needle),
- ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
- }
- /* }}} */
- /* {{{ An alias for strstr */
- /* }}} */
- /* {{{ Finds position of first occurrence of a string within another */
- PHP_FUNCTION(strpos)
- {
- zend_string *haystack, *needle;
- const char *found = NULL;
- zend_long offset = 0;
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(offset)
- ZEND_PARSE_PARAMETERS_END();
- if (offset < 0) {
- offset += (zend_long)ZSTR_LEN(haystack);
- }
- if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
- zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
- RETURN_THROWS();
- }
- found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
- ZSTR_VAL(needle), ZSTR_LEN(needle),
- ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
- if (found) {
- RETURN_LONG(found - ZSTR_VAL(haystack));
- } else {
- RETURN_FALSE;
- }
- }
- /* }}} */
- /* {{{ Finds position of first occurrence of a string within another, case insensitive */
- PHP_FUNCTION(stripos)
- {
- const char *found = NULL;
- zend_string *haystack, *needle;
- zend_long offset = 0;
- zend_string *needle_dup = NULL, *haystack_dup;
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(offset)
- ZEND_PARSE_PARAMETERS_END();
- if (offset < 0) {
- offset += (zend_long)ZSTR_LEN(haystack);
- }
- if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
- zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
- RETURN_THROWS();
- }
- if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
- RETURN_FALSE;
- }
- haystack_dup = php_string_tolower(haystack);
- needle_dup = php_string_tolower(needle);
- found = (char*)php_memnstr(ZSTR_VAL(haystack_dup) + offset,
- ZSTR_VAL(needle_dup), ZSTR_LEN(needle_dup), ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack));
- if (found) {
- RETVAL_LONG(found - ZSTR_VAL(haystack_dup));
- } else {
- RETVAL_FALSE;
- }
- zend_string_release_ex(haystack_dup, 0);
- zend_string_release_ex(needle_dup, 0);
- }
- /* }}} */
- /* {{{ Finds position of last occurrence of a string within another string */
- PHP_FUNCTION(strrpos)
- {
- zend_string *needle;
- zend_string *haystack;
- zend_long offset = 0;
- const char *p, *e, *found;
- ZEND_PARSE_PARAMETERS_START(2, 3)
- Z_PARAM_STR(haystack)
- Z_PARAM_STR(needle)
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG(offset)
- ZEND_PARSE_PARAMETERS_END();
- if (offset >= 0) {
- if ((size_t)offset > ZSTR_LEN(haystack)) {
- zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
- RETURN_THROWS();
- }
- p = ZSTR_VAL(haystack) + (size_t)offset;
- e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
- } else {
- if (offset < -ZEND_LONG_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) {
- zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
- RETURN_THROWS();
- }
- p = ZSTR_VAL(haystack);
- if ((size_t)-offset < ZSTR_LEN(needle)) {
- e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
- } else {
- e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack) + offset + ZSTR_LEN(needle);
- }
- }
- if ((found = zend_memnrstr(p, ZSTR_VAL(needle), ZSTR_LEN(needle), e))) {
- RETURN_LONG(found - ZSTR_VAL(haystack));…
Large files files are truncated, but you can click here to view the full file