Annotation of embedaddon/php/ext/ereg/ereg.c, revision 1.1.1.1

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:    |          Jim Winstead <jimw@php.net>                                 |
                     17:    |          Jaakko Hyvätti <jaakko@hyvatti.iki.fi>                      | 
                     18:    +----------------------------------------------------------------------+
                     19:  */
                     20: /* $Id: ereg.c 321634 2012-01-01 13:15:04Z felipe $ */
                     21: 
                     22: #include <stdio.h>
                     23: #include <ctype.h>
                     24: #include "php.h"
                     25: #include "ext/standard/php_string.h"
                     26: #include "php_ereg.h"
                     27: #include "ext/standard/info.h"
                     28: 
                     29: /* {{{ arginfo */
                     30: ZEND_BEGIN_ARG_INFO_EX(arginfo_ereg, 0, 0, 2)
                     31:        ZEND_ARG_INFO(0, pattern)
                     32:        ZEND_ARG_INFO(0, string) 
                     33:        ZEND_ARG_INFO(1, registers) /* ARRAY_INFO(1, registers, 1) */
                     34: ZEND_END_ARG_INFO()
                     35: 
                     36: ZEND_BEGIN_ARG_INFO(arginfo_ereg_replace, 0)
                     37:        ZEND_ARG_INFO(0, pattern)
                     38:        ZEND_ARG_INFO(0, replacement)
                     39:        ZEND_ARG_INFO(0, string)
                     40: ZEND_END_ARG_INFO()
                     41: 
                     42: ZEND_BEGIN_ARG_INFO_EX(arginfo_split, 0, 0, 2)
                     43:        ZEND_ARG_INFO(0, pattern)
                     44:        ZEND_ARG_INFO(0, string) 
                     45:        ZEND_ARG_INFO(0, limit)  
                     46: ZEND_END_ARG_INFO()
                     47: 
                     48: ZEND_BEGIN_ARG_INFO(arginfo_sql_regcase, 0)
                     49:        ZEND_ARG_INFO(0, string)
                     50: ZEND_END_ARG_INFO()
                     51: /* }}} */
                     52: 
                     53: /* {{{ Function table */
                     54: const zend_function_entry ereg_functions[] = {
                     55:        PHP_DEP_FE(ereg,                        arginfo_ereg)
                     56:        PHP_DEP_FE(ereg_replace,        arginfo_ereg_replace)
                     57:        PHP_DEP_FE(eregi,                       arginfo_ereg)
                     58:        PHP_DEP_FE(eregi_replace,       arginfo_ereg_replace)
                     59:        PHP_DEP_FE(split,                       arginfo_split)
                     60:        PHP_DEP_FE(spliti,                      arginfo_split)
                     61:        PHP_DEP_FE(sql_regcase,         arginfo_sql_regcase)
                     62:        PHP_FE_END
                     63: };
                     64: /* }}} */
                     65: 
                     66: /* {{{ reg_cache */
                     67: typedef struct {
                     68:        regex_t preg;
                     69:        int cflags;
                     70:        unsigned long lastuse;
                     71: } reg_cache;
                     72: static int reg_magic = 0;
                     73: #define EREG_CACHE_SIZE 4096
                     74: /* }}} */
                     75: 
                     76: ZEND_DECLARE_MODULE_GLOBALS(ereg)
                     77: 
                     78: /* {{{ Module entry */
                     79: zend_module_entry ereg_module_entry = {
                     80:        STANDARD_MODULE_HEADER,
                     81:        "ereg",
                     82:        ereg_functions,
                     83:        PHP_MINIT(ereg),
                     84:        PHP_MSHUTDOWN(ereg),
                     85:        NULL,
                     86:        NULL,
                     87:        PHP_MINFO(ereg),
                     88:        NO_VERSION_YET,
                     89:        STANDARD_MODULE_PROPERTIES
                     90: };
                     91: /* }}} */
                     92: 
                     93: /* {{{ ereg_lru_cmp */
                     94: static int ereg_lru_cmp(const void *a, const void *b TSRMLS_DC)
                     95: {
                     96:        Bucket *f = *((Bucket **) a);
                     97:        Bucket *s = *((Bucket **) b);
                     98: 
                     99:        if (((reg_cache *)f->pData)->lastuse <
                    100:                                ((reg_cache *)s->pData)->lastuse) {
                    101:                return -1;
                    102:        } else if (((reg_cache *)f->pData)->lastuse ==
                    103:                                ((reg_cache *)s->pData)->lastuse) {
                    104:                return 0;
                    105:        } else {
                    106:                return 1;
                    107:        }
                    108: }
                    109: /* }}} */
                    110: 
                    111: /* {{{ static ereg_clean_cache */
                    112: static int ereg_clean_cache(void *data, void *arg TSRMLS_DC)
                    113: {
                    114:        int *num_clean = (int *)arg;
                    115: 
                    116:        if (*num_clean > 0) {
                    117:                (*num_clean)--;
                    118:                return ZEND_HASH_APPLY_REMOVE;
                    119:        } else {
                    120:                return ZEND_HASH_APPLY_STOP;
                    121:        }
                    122: }
                    123: /* }}} */
                    124: 
                    125: /* {{{ _php_regcomp
                    126:  */
                    127: static int _php_regcomp(regex_t *preg, const char *pattern, int cflags)
                    128: {
                    129:        int r = 0;
                    130:        int patlen = strlen(pattern);
                    131:        reg_cache *rc = NULL;
                    132:        TSRMLS_FETCH();
                    133: 
                    134:        if (zend_hash_num_elements(&EREG(ht_rc)) >= EREG_CACHE_SIZE) {
                    135:                /* easier than dealing with overflow as it happens */
                    136:                if (EREG(lru_counter) >= (1 << 31) || zend_hash_sort(&EREG(ht_rc), zend_qsort, ereg_lru_cmp, 0 TSRMLS_CC) == FAILURE) {
                    137:                        zend_hash_clean(&EREG(ht_rc));
                    138:                        EREG(lru_counter) = 0;
                    139:                } else {
                    140:                        int num_clean = EREG_CACHE_SIZE / 4;
                    141:                        zend_hash_apply_with_argument(&EREG(ht_rc), ereg_clean_cache, &num_clean TSRMLS_CC);
                    142:                }
                    143:        }
                    144: 
                    145:        if(zend_hash_find(&EREG(ht_rc), (char *) pattern, patlen+1, (void **) &rc) == SUCCESS
                    146:           && rc->cflags == cflags) {
                    147: #ifdef HAVE_REGEX_T_RE_MAGIC
                    148:                /*
                    149:                 * We use a saved magic number to see whether cache is corrupted, and if it
                    150:                 * is, we flush it and compile the pattern from scratch.
                    151:                 */
                    152:                if (rc->preg.re_magic != reg_magic) {
                    153:                        zend_hash_clean(&EREG(ht_rc));
                    154:                        EREG(lru_counter) = 0;
                    155:                } else {
                    156:                        memcpy(preg, &rc->preg, sizeof(*preg));
                    157:                        return r;
                    158:                }
                    159:        }
                    160: 
                    161:        r = regcomp(preg, pattern, cflags);
                    162:        if(!r) {
                    163:                reg_cache rcp;
                    164: 
                    165:                rcp.cflags = cflags;
                    166:                rcp.lastuse = ++(EREG(lru_counter));
                    167:                memcpy(&rcp.preg, preg, sizeof(*preg));
                    168:                /*
                    169:                 * Since we don't have access to the actual MAGIC1 definition in the private
                    170:                 * header file, we save the magic value immediately after compilation. Hopefully,
                    171:                 * it's good.
                    172:                 */
                    173:                if (!reg_magic) reg_magic = preg->re_magic;
                    174:                zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
                    175:                                                 (void *) &rcp, sizeof(rcp), NULL);
                    176:        }
                    177: #else
                    178:                memcpy(preg, &rc->preg, sizeof(*preg));
                    179:        } else {
                    180:                r = regcomp(preg, pattern, cflags);
                    181:                if(!r) {
                    182:                        reg_cache rcp;
                    183: 
                    184:                        rcp.cflags = cflags;
                    185:                        rcp.lastuse = ++(EREG(lru_counter));
                    186:                        memcpy(&rcp.preg, preg, sizeof(*preg));
                    187:                        zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
                    188:                                                         (void *) &rcp, sizeof(rcp), NULL);
                    189:                }
                    190:        }
                    191: #endif
                    192:        return r;
                    193: }
                    194: /* }}} */
                    195: 
                    196: static void _free_ereg_cache(reg_cache *rc) 
                    197: {
                    198:        regfree(&rc->preg);
                    199: }
                    200: 
                    201: #undef regfree
                    202: #define regfree(a);
                    203: #undef regcomp
                    204: #define regcomp(a, b, c) _php_regcomp(a, b, c)
                    205:        
                    206: static void php_ereg_init_globals(zend_ereg_globals *ereg_globals TSRMLS_DC)
                    207: {
                    208:        zend_hash_init(&ereg_globals->ht_rc, 0, NULL, (void (*)(void *)) _free_ereg_cache, 1);
                    209:        ereg_globals->lru_counter = 0;
                    210: }
                    211: 
                    212: static void php_ereg_destroy_globals(zend_ereg_globals *ereg_globals TSRMLS_DC)
                    213: {
                    214:        zend_hash_destroy(&ereg_globals->ht_rc);
                    215: }
                    216: 
                    217: PHP_MINIT_FUNCTION(ereg)
                    218: {
                    219:        ZEND_INIT_MODULE_GLOBALS(ereg, php_ereg_init_globals, php_ereg_destroy_globals);
                    220:        return SUCCESS;
                    221: }
                    222: 
                    223: PHP_MSHUTDOWN_FUNCTION(ereg)
                    224: {
                    225: #ifndef ZTS
                    226:        php_ereg_destroy_globals(&ereg_globals TSRMLS_CC);
                    227: #endif
                    228: 
                    229:        return SUCCESS;
                    230: }
                    231: 
                    232: PHP_MINFO_FUNCTION(ereg)
                    233: {
                    234:        php_info_print_table_start();
                    235: #if HSREGEX
                    236:        php_info_print_table_row(2, "Regex Library", "Bundled library enabled");
                    237: #else
                    238:        php_info_print_table_row(2, "Regex Library", "System library enabled");
                    239: #endif
                    240:        php_info_print_table_end();
                    241: }
                    242: 
                    243: 
                    244: /* {{{ php_ereg_eprint
                    245:  * php_ereg_eprint - convert error number to name
                    246:  */
                    247: static void php_ereg_eprint(int err, regex_t *re) {
                    248:        char *buf = NULL, *message = NULL;
                    249:        size_t len;
                    250:        size_t buf_len;
                    251: 
                    252: #ifdef REG_ITOA
                    253:        /* get the length of the message */
                    254:        buf_len = regerror(REG_ITOA | err, re, NULL, 0);
                    255:        if (buf_len) {
                    256:                buf = (char *)safe_emalloc(buf_len, sizeof(char), 0);
                    257:                if (!buf) return; /* fail silently */
                    258:                /* finally, get the error message */
                    259:                regerror(REG_ITOA | err, re, buf, buf_len);
                    260:        }
                    261: #else
                    262:        buf_len = 0;
                    263: #endif
                    264:        len = regerror(err, re, NULL, 0);
                    265:        if (len) {
                    266:                TSRMLS_FETCH();
                    267: 
                    268:                message = (char *)safe_emalloc((buf_len + len + 2), sizeof(char), 0);
                    269:                if (!message) {
                    270:                        return; /* fail silently */
                    271:                }
                    272:                if (buf_len) {
                    273:                        snprintf(message, buf_len, "%s: ", buf);
                    274:                        buf_len += 1; /* so pointer math below works */
                    275:                }
                    276:                /* drop the message into place */
                    277:                regerror(err, re, message + buf_len, len);
                    278: 
                    279:                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
                    280:        }
                    281: 
                    282:        STR_FREE(buf);
                    283:        STR_FREE(message);
                    284: }
                    285: /* }}} */
                    286: 
                    287: /* {{{ php_ereg
                    288:  */
                    289: static void php_ereg(INTERNAL_FUNCTION_PARAMETERS, int icase)
                    290: {
                    291:        zval **regex,                   /* Regular expression */
                    292:                **array = NULL;         /* Optional register array */
                    293:        char *findin;           /* String to apply expression to */
                    294:        int findin_len;
                    295:        regex_t re;
                    296:        regmatch_t *subs;
                    297:        int err, match_len, string_len;
                    298:        uint i;
                    299:        int copts = 0;
                    300:        off_t start, end;
                    301:        char *buf = NULL;
                    302:        char *string = NULL;
                    303:        int   argc = ZEND_NUM_ARGS();
                    304: 
                    305:        if (zend_parse_parameters(argc TSRMLS_CC, "Zs|Z", &regex, &findin, &findin_len, &array) == FAILURE) {
                    306:                return;
                    307:        }
                    308: 
                    309:        if (icase) {
                    310:                copts |= REG_ICASE;
                    311:        }
                    312:        
                    313:        if (argc == 2) {
                    314:                copts |= REG_NOSUB;
                    315:        }
                    316: 
                    317:        /* compile the regular expression from the supplied regex */
                    318:        if (Z_TYPE_PP(regex) == IS_STRING) {
                    319:                err = regcomp(&re, Z_STRVAL_PP(regex), REG_EXTENDED | copts);
                    320:        } else {
                    321:                /* we convert numbers to integers and treat them as a string */
                    322:                if (Z_TYPE_PP(regex) == IS_DOUBLE) {
                    323:                        convert_to_long_ex(regex);      /* get rid of decimal places */
                    324:                }
                    325:                convert_to_string_ex(regex);
                    326:                /* don't bother doing an extended regex with just a number */
                    327:                err = regcomp(&re, Z_STRVAL_PP(regex), copts);
                    328:        }
                    329: 
                    330:        if (err) {
                    331:                php_ereg_eprint(err, &re);
                    332:                RETURN_FALSE;
                    333:        }
                    334: 
                    335:        /* make a copy of the string we're looking in */
                    336:        string = estrndup(findin, findin_len);
                    337: 
                    338:        /* allocate storage for (sub-)expression-matches */
                    339:        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
                    340:        
                    341:        /* actually execute the regular expression */
                    342:        err = regexec(&re, string, re.re_nsub+1, subs, 0);
                    343:        if (err && err != REG_NOMATCH) {
                    344:                php_ereg_eprint(err, &re);
                    345:                regfree(&re);
                    346:                efree(subs);
                    347:                RETURN_FALSE;
                    348:        }
                    349:        match_len = 1;
                    350: 
                    351:        if (array && err != REG_NOMATCH) {
                    352:                match_len = (int) (subs[0].rm_eo - subs[0].rm_so);
                    353:                string_len = findin_len + 1;
                    354: 
                    355:                buf = emalloc(string_len);
                    356: 
                    357:                zval_dtor(*array);      /* start with clean array */
                    358:                array_init(*array);
                    359: 
                    360:                for (i = 0; i <= re.re_nsub; i++) {
                    361:                        start = subs[i].rm_so;
                    362:                        end = subs[i].rm_eo;
                    363:                        if (start != -1 && end > 0 && start < string_len && end < string_len && start < end) {
                    364:                                add_index_stringl(*array, i, string+start, end-start, 1);
                    365:                        } else {
                    366:                                add_index_bool(*array, i, 0);
                    367:                        }
                    368:                }
                    369:                efree(buf);
                    370:        }
                    371: 
                    372:        efree(subs);
                    373:        efree(string);
                    374:        if (err == REG_NOMATCH) {
                    375:                RETVAL_FALSE;
                    376:        } else {
                    377:                if (match_len == 0)
                    378:                        match_len = 1;
                    379:                RETVAL_LONG(match_len);
                    380:        }
                    381:        regfree(&re);
                    382: }
                    383: /* }}} */
                    384: 
                    385: /* {{{ proto int ereg(string pattern, string string [, array registers])
                    386:    Regular expression match */
                    387: PHP_FUNCTION(ereg)
                    388: {
                    389:        php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
                    390: }
                    391: /* }}} */
                    392: 
                    393: /* {{{ proto int eregi(string pattern, string string [, array registers])
                    394:    Case-insensitive regular expression match */
                    395: PHP_FUNCTION(eregi)
                    396: {
                    397:        php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
                    398: }
                    399: /* }}} */
                    400: 
                    401: /* {{{ php_ereg_replace
                    402:  * this is the meat and potatoes of regex replacement! */
                    403: PHPAPI char *php_ereg_replace(const char *pattern, const char *replace, const char *string, int icase, int extended)
                    404: {
                    405:        regex_t re;
                    406:        regmatch_t *subs;
                    407: 
                    408:        char *buf,      /* buf is where we build the replaced string */
                    409:                 *nbuf, /* nbuf is used when we grow the buffer */
                    410:                 *walkbuf; /* used to walk buf when replacing backrefs */
                    411:        const char *walk; /* used to walk replacement string for backrefs */
                    412:        int buf_len;
                    413:        int pos, tmp, string_len, new_l;
                    414:        int err, copts = 0;
                    415: 
                    416:        string_len = strlen(string);
                    417: 
                    418:        if (icase) {
                    419:                copts = REG_ICASE;
                    420:        }
                    421:        if (extended) {
                    422:                copts |= REG_EXTENDED;
                    423:        }
                    424: 
                    425:        err = regcomp(&re, pattern, copts);
                    426:        if (err) {
                    427:                php_ereg_eprint(err, &re);
                    428:                return ((char *) -1);
                    429:        }
                    430: 
                    431: 
                    432:        /* allocate storage for (sub-)expression-matches */
                    433:        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
                    434: 
                    435:        /* start with a buffer that is twice the size of the stringo
                    436:           we're doing replacements in */
                    437:        buf_len = 2 * string_len + 1;
                    438:        buf = safe_emalloc(buf_len, sizeof(char), 0);
                    439: 
                    440:        err = pos = 0;
                    441:        buf[0] = '\0';
                    442:        while (!err) {
                    443:                err = regexec(&re, &string[pos], re.re_nsub+1, subs, (pos ? REG_NOTBOL : 0));
                    444: 
                    445:                if (err && err != REG_NOMATCH) {
                    446:                        php_ereg_eprint(err, &re);
                    447:                        efree(subs);
                    448:                        efree(buf);
                    449:                        regfree(&re);
                    450:                        return ((char *) -1);
                    451:                }
                    452: 
                    453:                if (!err) {
                    454:                        /* backref replacement is done in two passes:
                    455:                           1) find out how long the string will be, and allocate buf
                    456:                           2) copy the part before match, replacement and backrefs to buf
                    457: 
                    458:                           Jaakko Hyvätti <Jaakko.Hyvatti@iki.fi>
                    459:                           */
                    460: 
                    461:                        new_l = strlen(buf) + subs[0].rm_so; /* part before the match */
                    462:                        walk = replace;
                    463:                        while (*walk) {
                    464:                                if ('\\' == *walk && isdigit((unsigned char)walk[1]) && ((unsigned char)walk[1]) - '0' <= (int)re.re_nsub) {
                    465:                                        if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1) {
                    466:                                                new_l += subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
                    467:                                        }
                    468:                                        walk += 2;
                    469:                                } else {
                    470:                                        new_l++;
                    471:                                        walk++;
                    472:                                }
                    473:                        }
                    474:                        if (new_l + 1 > buf_len) {
                    475:                                buf_len = 1 + buf_len + 2 * new_l;
                    476:                                nbuf = emalloc(buf_len);
                    477:                                strncpy(nbuf, buf, buf_len-1);
                    478:                                nbuf[buf_len - 1] = '\0';
                    479:                                efree(buf);
                    480:                                buf = nbuf;
                    481:                        }
                    482:                        tmp = strlen(buf);
                    483:                        /* copy the part of the string before the match */
                    484:                        strncat(buf, &string[pos], subs[0].rm_so);
                    485: 
                    486:                        /* copy replacement and backrefs */
                    487:                        walkbuf = &buf[tmp + subs[0].rm_so];
                    488:                        walk = replace;
                    489:                        while (*walk) {
                    490:                                if ('\\' == *walk && isdigit((unsigned char)walk[1]) && ((unsigned char)walk[1]) - '0' <= (int)re.re_nsub) {
                    491:                                        if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1
                    492:                                                /* this next case shouldn't happen. it does. */
                    493:                                                && subs[walk[1] - '0'].rm_so <= subs[walk[1] - '0'].rm_eo) {
                    494:                                                
                    495:                                                tmp = subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
                    496:                                                memcpy (walkbuf, &string[pos + subs[walk[1] - '0'].rm_so], tmp);
                    497:                                                walkbuf += tmp;
                    498:                                        }
                    499:                                        walk += 2;
                    500:                                } else {
                    501:                                        *walkbuf++ = *walk++;
                    502:                                }
                    503:                        }
                    504:                        *walkbuf = '\0';
                    505: 
                    506:                        /* and get ready to keep looking for replacements */
                    507:                        if (subs[0].rm_so == subs[0].rm_eo) {
                    508:                                if (subs[0].rm_so + pos >= string_len) {
                    509:                                        break;
                    510:                                }
                    511:                                new_l = strlen (buf) + 1;
                    512:                                if (new_l + 1 > buf_len) {
                    513:                                        buf_len = 1 + buf_len + 2 * new_l;
                    514:                                        nbuf = safe_emalloc(buf_len, sizeof(char), 0);
                    515:                                        strncpy(nbuf, buf, buf_len-1);
                    516:                                        efree(buf);
                    517:                                        buf = nbuf;
                    518:                                }
                    519:                                pos += subs[0].rm_eo + 1;
                    520:                                buf [new_l-1] = string [pos-1];
                    521:                                buf [new_l] = '\0';
                    522:                        } else {
                    523:                                pos += subs[0].rm_eo;
                    524:                        }
                    525:                } else { /* REG_NOMATCH */
                    526:                        new_l = strlen(buf) + strlen(&string[pos]);
                    527:                        if (new_l + 1 > buf_len) {
                    528:                                buf_len = new_l + 1; /* now we know exactly how long it is */
                    529:                                nbuf = safe_emalloc(buf_len, sizeof(char), 0);
                    530:                                strncpy(nbuf, buf, buf_len-1);
                    531:                                efree(buf);
                    532:                                buf = nbuf;
                    533:                        }
                    534:                        /* stick that last bit of string on our output */
                    535:                        strlcat(buf, &string[pos], buf_len);
                    536:                }
                    537:        }
                    538: 
                    539:        /* don't want to leak memory .. */
                    540:        efree(subs);
                    541:        regfree(&re);
                    542: 
                    543:        /* whew. */
                    544:        return (buf);
                    545: }
                    546: /* }}} */
                    547: 
                    548: /* {{{ php_do_ereg_replace
                    549:  */
                    550: static void php_do_ereg_replace(INTERNAL_FUNCTION_PARAMETERS, int icase)
                    551: {
                    552:        zval **arg_pattern,
                    553:                **arg_replace;
                    554:        char *pattern, *arg_string;
                    555:        char *string;
                    556:        char *replace;
                    557:        char *ret;
                    558:        int arg_string_len;
                    559:        
                    560:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZs", &arg_pattern, &arg_replace, &arg_string, &arg_string_len) == FAILURE) {
                    561:                return;
                    562:        }
                    563: 
                    564:        if (Z_TYPE_PP(arg_pattern) == IS_STRING) {
                    565:                if (Z_STRVAL_PP(arg_pattern) && Z_STRLEN_PP(arg_pattern)) {
                    566:                        pattern = estrndup(Z_STRVAL_PP(arg_pattern), Z_STRLEN_PP(arg_pattern));
                    567:                } else {
                    568:                        pattern = STR_EMPTY_ALLOC();
                    569:                }
                    570:        } else {
                    571:                convert_to_long_ex(arg_pattern);
                    572:                pattern = emalloc(2);
                    573:                pattern[0] = (char) Z_LVAL_PP(arg_pattern);
                    574:                pattern[1] = '\0';
                    575:        }
                    576: 
                    577:        if (Z_TYPE_PP(arg_replace) == IS_STRING) {
                    578:                if (Z_STRVAL_PP(arg_replace) && Z_STRLEN_PP(arg_replace)) {
                    579:                        replace = estrndup(Z_STRVAL_PP(arg_replace), Z_STRLEN_PP(arg_replace));
                    580:                } else {
                    581:                        replace = STR_EMPTY_ALLOC();
                    582:                }
                    583:        } else {
                    584:                convert_to_long_ex(arg_replace);
                    585:                replace = emalloc(2);
                    586:                replace[0] = (char) Z_LVAL_PP(arg_replace);
                    587:                replace[1] = '\0';
                    588:        }
                    589: 
                    590:        if (arg_string && arg_string_len) {
                    591:                string = estrndup(arg_string, arg_string_len);
                    592:        } else {
                    593:                string = STR_EMPTY_ALLOC();
                    594:        }
                    595: 
                    596:        /* do the actual work */
                    597:        ret = php_ereg_replace(pattern, replace, string, icase, 1);
                    598:        if (ret == (char *) -1) {
                    599:                RETVAL_FALSE;
                    600:        } else {
                    601:                RETVAL_STRING(ret, 1);
                    602:                STR_FREE(ret);
                    603:        }
                    604: 
                    605:        STR_FREE(string);
                    606:        STR_FREE(replace);
                    607:        STR_FREE(pattern);
                    608: }
                    609: /* }}} */
                    610: 
                    611: /* {{{ proto string ereg_replace(string pattern, string replacement, string string)
                    612:    Replace regular expression */
                    613: PHP_FUNCTION(ereg_replace)
                    614: {
                    615:        php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
                    616: }
                    617: /* }}} */
                    618: 
                    619: /* {{{ proto string eregi_replace(string pattern, string replacement, string string)
                    620:    Case insensitive replace regular expression */
                    621: PHP_FUNCTION(eregi_replace)
                    622: {
                    623:        php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
                    624: }
                    625: /* }}} */
                    626: 
                    627: /* {{{ php_split
                    628:  */
                    629: static void php_split(INTERNAL_FUNCTION_PARAMETERS, int icase)
                    630: {
                    631:        long count = -1;
                    632:        regex_t re;
                    633:        regmatch_t subs[1];
                    634:        char *spliton, *str, *strp, *endp;
                    635:        int spliton_len, str_len;
                    636:        int err, size, copts = 0;
                    637: 
                    638:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &spliton, &spliton_len, &str, &str_len, &count) == FAILURE) {
                    639:                return;
                    640:        }
                    641: 
                    642:        if (icase) {
                    643:                copts = REG_ICASE;
                    644:        }
                    645: 
                    646:        strp = str;
                    647:        endp = strp + str_len;
                    648: 
                    649:        err = regcomp(&re, spliton, REG_EXTENDED | copts);
                    650:        if (err) {
                    651:                php_ereg_eprint(err, &re);
                    652:                RETURN_FALSE;
                    653:        }
                    654: 
                    655:        array_init(return_value);
                    656: 
                    657:        /* churn through str, generating array entries as we go */
                    658:        while ((count == -1 || count > 1) && !(err = regexec(&re, strp, 1, subs, 0))) {
                    659:                if (subs[0].rm_so == 0 && subs[0].rm_eo) {
                    660:                        /* match is at start of string, return empty string */
                    661:                        add_next_index_stringl(return_value, "", 0, 1);
                    662:                        /* skip ahead the length of the regex match */
                    663:                        strp += subs[0].rm_eo;
                    664:                } else if (subs[0].rm_so == 0 && subs[0].rm_eo == 0) {
                    665:                        /* No more matches */
                    666:                        regfree(&re);
                    667:                        
                    668:                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Regular Expression");
                    669:                        
                    670:                        zend_hash_destroy(Z_ARRVAL_P(return_value));
                    671:                        efree(Z_ARRVAL_P(return_value));
                    672:                        RETURN_FALSE;
                    673:                } else {
                    674:                        /* On a real match */
                    675: 
                    676:                        /* make a copy of the substring */
                    677:                        size = subs[0].rm_so;
                    678:                
                    679:                        /* add it to the array */
                    680:                        add_next_index_stringl(return_value, strp, size, 1);
                    681: 
                    682:                        /* point at our new starting point */
                    683:                        strp = strp + subs[0].rm_eo;
                    684:                }
                    685: 
                    686:                /* if we're only looking for a certain number of points,
                    687:                   stop looking once we hit it */
                    688:                if (count != -1) {
                    689:                        count--;
                    690:                }
                    691:        }
                    692: 
                    693:        /* see if we encountered an error */
                    694:        if (err && err != REG_NOMATCH) {
                    695:                php_ereg_eprint(err, &re);
                    696:                regfree(&re);
                    697:                zend_hash_destroy(Z_ARRVAL_P(return_value));
                    698:                efree(Z_ARRVAL_P(return_value));
                    699:                RETURN_FALSE;
                    700:        }
                    701: 
                    702:        /* otherwise we just have one last element to add to the array */
                    703:        size = endp - strp;
                    704:        
                    705:        add_next_index_stringl(return_value, strp, size, 1);
                    706: 
                    707:        regfree(&re);
                    708: }
                    709: /* }}} */
                    710: 
                    711: /* {{{ proto array split(string pattern, string string [, int limit])
                    712:    Split string into array by regular expression */
                    713: PHP_FUNCTION(split)
                    714: {
                    715:        php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
                    716: }
                    717: /* }}} */
                    718: 
                    719: /* {{{ proto array spliti(string pattern, string string [, int limit])
                    720:    Split string into array by regular expression case-insensitive */
                    721: 
                    722: PHP_FUNCTION(spliti)
                    723: {
                    724:        php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
                    725: }
                    726: 
                    727: /* }}} */
                    728: 
                    729: /* {{{ proto string sql_regcase(string string)
                    730:    Make regular expression for case insensitive match */
                    731: PHPAPI PHP_FUNCTION(sql_regcase)
                    732: {
                    733:        char *string, *tmp;
                    734:        int string_len;
                    735:        unsigned char c;
                    736:        register int i, j;
                    737: 
                    738:        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) {
                    739:                return;
                    740:        }
                    741:        
                    742:        tmp = safe_emalloc(string_len, 4, 1);
                    743:        
                    744:        for (i = j = 0; i < string_len; i++) {
                    745:                c = (unsigned char) string[i];
                    746:                if (isalpha(c)) {
                    747:                        tmp[j++] = '[';
                    748:                        tmp[j++] = toupper(c);
                    749:                        tmp[j++] = tolower(c);
                    750:                        tmp[j++] = ']';
                    751:                } else {
                    752:                        tmp[j++] = c;
                    753:                }
                    754:        }
                    755:        tmp[j] = 0;
                    756: 
                    757:        RETVAL_STRINGL(tmp, j, 1);
                    758:        efree(tmp);
                    759: }
                    760: /* }}} */
                    761: 
                    762: /*
                    763:  * Local variables:
                    764:  * tab-width: 4
                    765:  * c-basic-offset: 4
                    766:  * End:
                    767:  * vim600: noet sw=4 ts=4 fdm=marker
                    768:  * vim<600: noet sw=4 ts=4
                    769:  */

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