Annotation of embedaddon/php/ext/ereg/ereg.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:    |          Jim Winstead <jimw@php.net>                                 |
                     17:    |          Jaakko Hyvätti <jaakko@hyvatti.iki.fi>                      | 
                     18:    +----------------------------------------------------------------------+
                     19:  */
1.1.1.2 ! misho      20: /* $Id$ */
1.1       misho      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)
1.1.1.2 ! misho      77: static PHP_GINIT_FUNCTION(ereg);
        !            78: static PHP_GSHUTDOWN_FUNCTION(ereg);
1.1       misho      79: 
                     80: /* {{{ Module entry */
                     81: zend_module_entry ereg_module_entry = {
                     82:        STANDARD_MODULE_HEADER,
                     83:        "ereg",
                     84:        ereg_functions,
1.1.1.2 ! misho      85:        NULL,
        !            86:        NULL,
1.1       misho      87:        NULL,
                     88:        NULL,
                     89:        PHP_MINFO(ereg),
                     90:        NO_VERSION_YET,
1.1.1.2 ! misho      91:        PHP_MODULE_GLOBALS(ereg),
        !            92:        PHP_GINIT(ereg),
        !            93:        PHP_GSHUTDOWN(ereg),
        !            94:        NULL,
        !            95:        STANDARD_MODULE_PROPERTIES_EX
1.1       misho      96: };
                     97: /* }}} */
                     98: 
1.1.1.2 ! misho      99: /* {{{ COMPILE_DL_EREG */
        !           100: #ifdef COMPILE_DL_EREG
        !           101: ZEND_GET_MODULE(ereg)
        !           102: #endif
        !           103: /* }}} */
        !           104: 
1.1       misho     105: /* {{{ ereg_lru_cmp */
                    106: static int ereg_lru_cmp(const void *a, const void *b TSRMLS_DC)
                    107: {
                    108:        Bucket *f = *((Bucket **) a);
                    109:        Bucket *s = *((Bucket **) b);
                    110: 
                    111:        if (((reg_cache *)f->pData)->lastuse <
                    112:                                ((reg_cache *)s->pData)->lastuse) {
                    113:                return -1;
                    114:        } else if (((reg_cache *)f->pData)->lastuse ==
                    115:                                ((reg_cache *)s->pData)->lastuse) {
                    116:                return 0;
                    117:        } else {
                    118:                return 1;
                    119:        }
                    120: }
                    121: /* }}} */
                    122: 
                    123: /* {{{ static ereg_clean_cache */
                    124: static int ereg_clean_cache(void *data, void *arg TSRMLS_DC)
                    125: {
                    126:        int *num_clean = (int *)arg;
                    127: 
                    128:        if (*num_clean > 0) {
                    129:                (*num_clean)--;
                    130:                return ZEND_HASH_APPLY_REMOVE;
                    131:        } else {
                    132:                return ZEND_HASH_APPLY_STOP;
                    133:        }
                    134: }
                    135: /* }}} */
                    136: 
                    137: /* {{{ _php_regcomp
                    138:  */
1.1.1.2 ! misho     139: static int _php_regcomp(regex_t *preg, const char *pattern, int cflags TSRMLS_DC)
1.1       misho     140: {
                    141:        int r = 0;
                    142:        int patlen = strlen(pattern);
                    143:        reg_cache *rc = NULL;
                    144: 
                    145:        if (zend_hash_num_elements(&EREG(ht_rc)) >= EREG_CACHE_SIZE) {
                    146:                /* easier than dealing with overflow as it happens */
                    147:                if (EREG(lru_counter) >= (1 << 31) || zend_hash_sort(&EREG(ht_rc), zend_qsort, ereg_lru_cmp, 0 TSRMLS_CC) == FAILURE) {
                    148:                        zend_hash_clean(&EREG(ht_rc));
                    149:                        EREG(lru_counter) = 0;
                    150:                } else {
                    151:                        int num_clean = EREG_CACHE_SIZE / 4;
                    152:                        zend_hash_apply_with_argument(&EREG(ht_rc), ereg_clean_cache, &num_clean TSRMLS_CC);
                    153:                }
                    154:        }
                    155: 
                    156:        if(zend_hash_find(&EREG(ht_rc), (char *) pattern, patlen+1, (void **) &rc) == SUCCESS
                    157:           && rc->cflags == cflags) {
                    158: #ifdef HAVE_REGEX_T_RE_MAGIC
                    159:                /*
                    160:                 * We use a saved magic number to see whether cache is corrupted, and if it
                    161:                 * is, we flush it and compile the pattern from scratch.
                    162:                 */
                    163:                if (rc->preg.re_magic != reg_magic) {
                    164:                        zend_hash_clean(&EREG(ht_rc));
                    165:                        EREG(lru_counter) = 0;
                    166:                } else {
                    167:                        memcpy(preg, &rc->preg, sizeof(*preg));
                    168:                        return r;
                    169:                }
                    170:        }
                    171: 
                    172:        r = regcomp(preg, pattern, cflags);
                    173:        if(!r) {
                    174:                reg_cache rcp;
                    175: 
                    176:                rcp.cflags = cflags;
                    177:                rcp.lastuse = ++(EREG(lru_counter));
                    178:                memcpy(&rcp.preg, preg, sizeof(*preg));
                    179:                /*
                    180:                 * Since we don't have access to the actual MAGIC1 definition in the private
                    181:                 * header file, we save the magic value immediately after compilation. Hopefully,
                    182:                 * it's good.
                    183:                 */
                    184:                if (!reg_magic) reg_magic = preg->re_magic;
                    185:                zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
                    186:                                                 (void *) &rcp, sizeof(rcp), NULL);
                    187:        }
                    188: #else
                    189:                memcpy(preg, &rc->preg, sizeof(*preg));
                    190:        } else {
                    191:                r = regcomp(preg, pattern, cflags);
                    192:                if(!r) {
                    193:                        reg_cache rcp;
                    194: 
                    195:                        rcp.cflags = cflags;
                    196:                        rcp.lastuse = ++(EREG(lru_counter));
                    197:                        memcpy(&rcp.preg, preg, sizeof(*preg));
                    198:                        zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
                    199:                                                         (void *) &rcp, sizeof(rcp), NULL);
                    200:                }
                    201:        }
                    202: #endif
                    203:        return r;
                    204: }
                    205: /* }}} */
                    206: 
                    207: static void _free_ereg_cache(reg_cache *rc) 
                    208: {
                    209:        regfree(&rc->preg);
                    210: }
                    211: 
                    212: #undef regfree
                    213: #define regfree(a);
                    214: #undef regcomp
1.1.1.2 ! misho     215: #define regcomp(a, b, c) _php_regcomp(a, b, c TSRMLS_CC)
        !           216: 
        !           217: /* {{{ PHP_GINIT_FUNCTION
        !           218:  */
        !           219: static PHP_GINIT_FUNCTION(ereg)
1.1       misho     220: {
                    221:        zend_hash_init(&ereg_globals->ht_rc, 0, NULL, (void (*)(void *)) _free_ereg_cache, 1);
                    222:        ereg_globals->lru_counter = 0;
                    223: }
1.1.1.2 ! misho     224: /* }}} */
1.1       misho     225: 
1.1.1.2 ! misho     226: /* {{{ PHP_GSHUTDOWN_FUNCTION
        !           227:  */
        !           228: static PHP_GSHUTDOWN_FUNCTION(ereg)
1.1       misho     229: {
                    230:        zend_hash_destroy(&ereg_globals->ht_rc);
                    231: }
1.1.1.2 ! misho     232: /* }}} */
1.1       misho     233: 
                    234: PHP_MINFO_FUNCTION(ereg)
                    235: {
                    236:        php_info_print_table_start();
                    237: #if HSREGEX
                    238:        php_info_print_table_row(2, "Regex Library", "Bundled library enabled");
                    239: #else
                    240:        php_info_print_table_row(2, "Regex Library", "System library enabled");
                    241: #endif
                    242:        php_info_print_table_end();
                    243: }
                    244: 
                    245: 
                    246: /* {{{ php_ereg_eprint
                    247:  * php_ereg_eprint - convert error number to name
                    248:  */
1.1.1.2 ! misho     249: static void php_ereg_eprint(int err, regex_t *re TSRMLS_DC) {
1.1       misho     250:        char *buf = NULL, *message = NULL;
                    251:        size_t len;
                    252:        size_t buf_len;
                    253: 
                    254: #ifdef REG_ITOA
                    255:        /* get the length of the message */
                    256:        buf_len = regerror(REG_ITOA | err, re, NULL, 0);
                    257:        if (buf_len) {
                    258:                buf = (char *)safe_emalloc(buf_len, sizeof(char), 0);
                    259:                if (!buf) return; /* fail silently */
                    260:                /* finally, get the error message */
                    261:                regerror(REG_ITOA | err, re, buf, buf_len);
                    262:        }
                    263: #else
                    264:        buf_len = 0;
                    265: #endif
                    266:        len = regerror(err, re, NULL, 0);
                    267:        if (len) {
                    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) {
1.1.1.2 ! misho     331:                php_ereg_eprint(err, &re TSRMLS_CC);
1.1       misho     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) {
1.1.1.2 ! misho     344:                php_ereg_eprint(err, &re TSRMLS_CC);
1.1       misho     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! */
1.1.1.2 ! misho     403: PHP_EREG_API char *php_ereg_replace(const char *pattern, const char *replace, const char *string, int icase, int extended TSRMLS_DC)
1.1       misho     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) {
1.1.1.2 ! misho     427:                php_ereg_eprint(err, &re TSRMLS_CC);
1.1       misho     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) {
1.1.1.2 ! misho     446:                        php_ereg_eprint(err, &re TSRMLS_CC);
1.1       misho     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);
1.1.1.2 ! misho     477:                                strncpy(nbuf, buf, buf_len - 1);
1.1       misho     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) {
1.1.1.2 ! misho     490:                                if ('\\' == *walk && isdigit((unsigned char)walk[1]) && (unsigned char)walk[1] - '0' <= (int)re.re_nsub) {
1.1       misho     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 */
1.1.1.2 ! misho     597:        ret = php_ereg_replace(pattern, replace, string, icase, 1 TSRMLS_CC);
1.1       misho     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) {
1.1.1.2 ! misho     651:                php_ereg_eprint(err, &re TSRMLS_CC);
1.1       misho     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) {
1.1.1.2 ! misho     695:                php_ereg_eprint(err, &re TSRMLS_CC);
1.1       misho     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 */
1.1.1.2 ! misho     731: PHP_EREG_API PHP_FUNCTION(sql_regcase)
1.1       misho     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>