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

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

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