Annotation of embedaddon/php/ext/standard/string.c, revision 1.1.1.3

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>