Annotation of embedaddon/php/ext/ereg/ereg.c, revision 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>