root/ext/ereg/ereg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. ereg_clean_cache
  3. _php_regcomp
  4. _free_ereg_cache
  5. PHP_GINIT_FUNCTION
  6. PHP_GSHUTDOWN_FUNCTION
  7. PHP_MINFO_FUNCTION
  8. php_ereg_eprint
  9. php_ereg
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. php_ereg_replace
  13. php_do_ereg_replace
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. php_split
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION

/*
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
   | Copyright (c) 1997-2013 The PHP Group                                |
   +----------------------------------------------------------------------+
   | This source file is subject to version 3.01 of the PHP license,      |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.php.net/license/3_01.txt                                  |
   | If you did not receive a copy of the PHP license and are unable to   |
   | obtain it through the world-wide-web, please send a note to          |
   | license@php.net so we can mail you a copy immediately.               |
   +----------------------------------------------------------------------+
   | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
   |          Jim Winstead <jimw@php.net>                                 |
   |          Jaakko Hyvätti <jaakko@hyvatti.iki.fi>                      | 
   +----------------------------------------------------------------------+
 */
/* $Id$ */

#include <stdio.h>
#include <ctype.h>
#include "php.h"
#include "ext/standard/php_string.h"
#include "php_ereg.h"
#include "ext/standard/info.h"

/* {{{ arginfo */
ZEND_BEGIN_ARG_INFO_EX(arginfo_ereg, 0, 0, 2)
        ZEND_ARG_INFO(0, pattern)
        ZEND_ARG_INFO(0, string) 
        ZEND_ARG_INFO(1, registers) /* ARRAY_INFO(1, registers, 1) */
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_ereg_replace, 0)
        ZEND_ARG_INFO(0, pattern)
        ZEND_ARG_INFO(0, replacement)
        ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO_EX(arginfo_split, 0, 0, 2)
        ZEND_ARG_INFO(0, pattern)
        ZEND_ARG_INFO(0, string) 
        ZEND_ARG_INFO(0, limit)  
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(arginfo_sql_regcase, 0)
        ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO()
/* }}} */

/* {{{ Function table */
const zend_function_entry ereg_functions[] = {
        PHP_DEP_FE(ereg,                        arginfo_ereg)
        PHP_DEP_FE(ereg_replace,        arginfo_ereg_replace)
        PHP_DEP_FE(eregi,                       arginfo_ereg)
        PHP_DEP_FE(eregi_replace,       arginfo_ereg_replace)
        PHP_DEP_FE(split,                       arginfo_split)
        PHP_DEP_FE(spliti,                      arginfo_split)
        PHP_DEP_FE(sql_regcase,         arginfo_sql_regcase)
        PHP_FE_END
};
/* }}} */

/* {{{ reg_cache */
typedef struct {
        regex_t preg;
        int cflags;
        unsigned long lastuse;
} reg_cache;
static int reg_magic = 0;
#define EREG_CACHE_SIZE 4096
/* }}} */

ZEND_DECLARE_MODULE_GLOBALS(ereg)
static PHP_GINIT_FUNCTION(ereg);
static PHP_GSHUTDOWN_FUNCTION(ereg);

/* {{{ Module entry */
zend_module_entry ereg_module_entry = {
        STANDARD_MODULE_HEADER,
        "ereg",
        ereg_functions,
        NULL,
        NULL,
        NULL,
        NULL,
        PHP_MINFO(ereg),
        NO_VERSION_YET,
        PHP_MODULE_GLOBALS(ereg),
        PHP_GINIT(ereg),
        PHP_GSHUTDOWN(ereg),
        NULL,
        STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */

/* {{{ COMPILE_DL_EREG */
#ifdef COMPILE_DL_EREG
ZEND_GET_MODULE(ereg)
#endif
/* }}} */

/* {{{ ereg_lru_cmp */
static int ereg_lru_cmp(const void *a, const void *b TSRMLS_DC)
{
        Bucket *f = *((Bucket **) a);
        Bucket *s = *((Bucket **) b);

        if (((reg_cache *)f->pData)->lastuse <
                                ((reg_cache *)s->pData)->lastuse) {
                return -1;
        } else if (((reg_cache *)f->pData)->lastuse ==
                                ((reg_cache *)s->pData)->lastuse) {
                return 0;
        } else {
                return 1;
        }
}
/* }}} */

/* {{{ static ereg_clean_cache */
static int ereg_clean_cache(void *data, void *arg TSRMLS_DC)
{
        int *num_clean = (int *)arg;

        if (*num_clean > 0) {
                (*num_clean)--;
                return ZEND_HASH_APPLY_REMOVE;
        } else {
                return ZEND_HASH_APPLY_STOP;
        }
}
/* }}} */

/* {{{ _php_regcomp
 */
static int _php_regcomp(regex_t *preg, const char *pattern, int cflags TSRMLS_DC)
{
        int r = 0;
        int patlen = strlen(pattern);
        reg_cache *rc = NULL;

        if (zend_hash_num_elements(&EREG(ht_rc)) >= EREG_CACHE_SIZE) {
                /* easier than dealing with overflow as it happens */
                if (EREG(lru_counter) >= (1 << 31) || zend_hash_sort(&EREG(ht_rc), zend_qsort, ereg_lru_cmp, 0 TSRMLS_CC) == FAILURE) {
                        zend_hash_clean(&EREG(ht_rc));
                        EREG(lru_counter) = 0;
                } else {
                        int num_clean = EREG_CACHE_SIZE / 4;
                        zend_hash_apply_with_argument(&EREG(ht_rc), ereg_clean_cache, &num_clean TSRMLS_CC);
                }
        }

        if(zend_hash_find(&EREG(ht_rc), (char *) pattern, patlen+1, (void **) &rc) == SUCCESS
           && rc->cflags == cflags) {
#ifdef HAVE_REGEX_T_RE_MAGIC
                /*
                 * We use a saved magic number to see whether cache is corrupted, and if it
                 * is, we flush it and compile the pattern from scratch.
                 */
                if (rc->preg.re_magic != reg_magic) {
                        zend_hash_clean(&EREG(ht_rc));
                        EREG(lru_counter) = 0;
                } else {
                        memcpy(preg, &rc->preg, sizeof(*preg));
                        return r;
                }
        }

        r = regcomp(preg, pattern, cflags);
        if(!r) {
                reg_cache rcp;

                rcp.cflags = cflags;
                rcp.lastuse = ++(EREG(lru_counter));
                memcpy(&rcp.preg, preg, sizeof(*preg));
                /*
                 * Since we don't have access to the actual MAGIC1 definition in the private
                 * header file, we save the magic value immediately after compilation. Hopefully,
                 * it's good.
                 */
                if (!reg_magic) reg_magic = preg->re_magic;
                zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
                                                 (void *) &rcp, sizeof(rcp), NULL);
        }
#else
                memcpy(preg, &rc->preg, sizeof(*preg));
        } else {
                r = regcomp(preg, pattern, cflags);
                if(!r) {
                        reg_cache rcp;

                        rcp.cflags = cflags;
                        rcp.lastuse = ++(EREG(lru_counter));
                        memcpy(&rcp.preg, preg, sizeof(*preg));
                        zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
                                                         (void *) &rcp, sizeof(rcp), NULL);
                }
        }
#endif
        return r;
}
/* }}} */

static void _free_ereg_cache(reg_cache *rc) 
{
        regfree(&rc->preg);
}

#undef regfree
#define regfree(a);
#undef regcomp
#define regcomp(a, b, c) _php_regcomp(a, b, c TSRMLS_CC)

/* {{{ PHP_GINIT_FUNCTION
 */
static PHP_GINIT_FUNCTION(ereg)
{
        zend_hash_init(&ereg_globals->ht_rc, 0, NULL, (void (*)(void *)) _free_ereg_cache, 1);
        ereg_globals->lru_counter = 0;
}
/* }}} */

/* {{{ PHP_GSHUTDOWN_FUNCTION
 */
static PHP_GSHUTDOWN_FUNCTION(ereg)
{
        zend_hash_destroy(&ereg_globals->ht_rc);
}
/* }}} */

PHP_MINFO_FUNCTION(ereg)
{
        php_info_print_table_start();
#if HSREGEX
        php_info_print_table_row(2, "Regex Library", "Bundled library enabled");
#else
        php_info_print_table_row(2, "Regex Library", "System library enabled");
#endif
        php_info_print_table_end();
}


/* {{{ php_ereg_eprint
 * php_ereg_eprint - convert error number to name
 */
static void php_ereg_eprint(int err, regex_t *re TSRMLS_DC) {
        char *buf = NULL, *message = NULL;
        size_t len;
        size_t buf_len;

#ifdef REG_ITOA
        /* get the length of the message */
        buf_len = regerror(REG_ITOA | err, re, NULL, 0);
        if (buf_len) {
                buf = (char *)safe_emalloc(buf_len, sizeof(char), 0);
                if (!buf) return; /* fail silently */
                /* finally, get the error message */
                regerror(REG_ITOA | err, re, buf, buf_len);
        }
#else
        buf_len = 0;
#endif
        len = regerror(err, re, NULL, 0);
        if (len) {
                message = (char *)safe_emalloc((buf_len + len + 2), sizeof(char), 0);
                if (!message) {
                        return; /* fail silently */
                }
                if (buf_len) {
                        snprintf(message, buf_len, "%s: ", buf);
                        buf_len += 1; /* so pointer math below works */
                }
                /* drop the message into place */
                regerror(err, re, message + buf_len, len);

                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
        }

        STR_FREE(buf);
        STR_FREE(message);
}
/* }}} */

/* {{{ php_ereg
 */
static void php_ereg(INTERNAL_FUNCTION_PARAMETERS, int icase)
{
        zval **regex,                   /* Regular expression */
                **array = NULL;         /* Optional register array */
        char *findin;           /* String to apply expression to */
        int findin_len;
        regex_t re;
        regmatch_t *subs;
        int err, match_len, string_len;
        uint i;
        int copts = 0;
        off_t start, end;
        char *buf = NULL;
        char *string = NULL;
        int   argc = ZEND_NUM_ARGS();

        if (zend_parse_parameters(argc TSRMLS_CC, "Zs|Z", &regex, &findin, &findin_len, &array) == FAILURE) {
                return;
        }

        if (icase) {
                copts |= REG_ICASE;
        }
        
        if (argc == 2) {
                copts |= REG_NOSUB;
        }

        /* compile the regular expression from the supplied regex */
        if (Z_TYPE_PP(regex) == IS_STRING) {
                err = regcomp(&re, Z_STRVAL_PP(regex), REG_EXTENDED | copts);
        } else {
                /* we convert numbers to integers and treat them as a string */
                if (Z_TYPE_PP(regex) == IS_DOUBLE) {
                        convert_to_long_ex(regex);      /* get rid of decimal places */
                }
                convert_to_string_ex(regex);
                /* don't bother doing an extended regex with just a number */
                err = regcomp(&re, Z_STRVAL_PP(regex), copts);
        }

        if (err) {
                php_ereg_eprint(err, &re TSRMLS_CC);
                RETURN_FALSE;
        }

        /* make a copy of the string we're looking in */
        string = estrndup(findin, findin_len);

        /* allocate storage for (sub-)expression-matches */
        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
        
        /* actually execute the regular expression */
        err = regexec(&re, string, re.re_nsub+1, subs, 0);
        if (err && err != REG_NOMATCH) {
                php_ereg_eprint(err, &re TSRMLS_CC);
                regfree(&re);
                efree(subs);
                RETURN_FALSE;
        }
        match_len = 1;

        if (array && err != REG_NOMATCH) {
                match_len = (int) (subs[0].rm_eo - subs[0].rm_so);
                string_len = findin_len + 1;

                buf = emalloc(string_len);

                zval_dtor(*array);      /* start with clean array */
                array_init(*array);

                for (i = 0; i <= re.re_nsub; i++) {
                        start = subs[i].rm_so;
                        end = subs[i].rm_eo;
                        if (start != -1 && end > 0 && start < string_len && end < string_len && start < end) {
                                add_index_stringl(*array, i, string+start, end-start, 1);
                        } else {
                                add_index_bool(*array, i, 0);
                        }
                }
                efree(buf);
        }

        efree(subs);
        efree(string);
        if (err == REG_NOMATCH) {
                RETVAL_FALSE;
        } else {
                if (match_len == 0)
                        match_len = 1;
                RETVAL_LONG(match_len);
        }
        regfree(&re);
}
/* }}} */

/* {{{ proto int ereg(string pattern, string string [, array registers])
   Regular expression match */
PHP_FUNCTION(ereg)
{
        php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */

/* {{{ proto int eregi(string pattern, string string [, array registers])
   Case-insensitive regular expression match */
PHP_FUNCTION(eregi)
{
        php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */

/* {{{ php_ereg_replace
 * this is the meat and potatoes of regex replacement! */
PHP_EREG_API char *php_ereg_replace(const char *pattern, const char *replace, const char *string, int icase, int extended TSRMLS_DC)
{
        regex_t re;
        regmatch_t *subs;

        char *buf,      /* buf is where we build the replaced string */
                 *nbuf, /* nbuf is used when we grow the buffer */
                 *walkbuf; /* used to walk buf when replacing backrefs */
        const char *walk; /* used to walk replacement string for backrefs */
        int buf_len;
        int pos, tmp, string_len, new_l;
        int err, copts = 0;

        string_len = strlen(string);

        if (icase) {
                copts = REG_ICASE;
        }
        if (extended) {
                copts |= REG_EXTENDED;
        }

        err = regcomp(&re, pattern, copts);
        if (err) {
                php_ereg_eprint(err, &re TSRMLS_CC);
                return ((char *) -1);
        }


        /* allocate storage for (sub-)expression-matches */
        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);

        /* start with a buffer that is twice the size of the stringo
           we're doing replacements in */
        buf_len = 2 * string_len + 1;
        buf = safe_emalloc(buf_len, sizeof(char), 0);

        err = pos = 0;
        buf[0] = '\0';
        while (!err) {
                err = regexec(&re, &string[pos], re.re_nsub+1, subs, (pos ? REG_NOTBOL : 0));

                if (err && err != REG_NOMATCH) {
                        php_ereg_eprint(err, &re TSRMLS_CC);
                        efree(subs);
                        efree(buf);
                        regfree(&re);
                        return ((char *) -1);
                }

                if (!err) {
                        /* backref replacement is done in two passes:
                           1) find out how long the string will be, and allocate buf
                           2) copy the part before match, replacement and backrefs to buf

                           Jaakko Hyvätti <Jaakko.Hyvatti@iki.fi>
                           */

                        new_l = strlen(buf) + subs[0].rm_so; /* part before the match */
                        walk = replace;
                        while (*walk) {
                                if ('\\' == *walk && isdigit((unsigned char)walk[1]) && ((unsigned char)walk[1]) - '0' <= (int)re.re_nsub) {
                                        if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1) {
                                                new_l += subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
                                        }
                                        walk += 2;
                                } else {
                                        new_l++;
                                        walk++;
                                }
                        }
                        if (new_l + 1 > buf_len) {
                                buf_len = 1 + buf_len + 2 * new_l;
                                nbuf = emalloc(buf_len);
                                strncpy(nbuf, buf, buf_len - 1);
                                nbuf[buf_len - 1] = '\0';
                                efree(buf);
                                buf = nbuf;
                        }
                        tmp = strlen(buf);
                        /* copy the part of the string before the match */
                        strncat(buf, &string[pos], subs[0].rm_so);

                        /* copy replacement and backrefs */
                        walkbuf = &buf[tmp + subs[0].rm_so];
                        walk = replace;
                        while (*walk) {
                                if ('\\' == *walk && isdigit((unsigned char)walk[1]) && (unsigned char)walk[1] - '0' <= (int)re.re_nsub) {
                                        if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1
                                                /* this next case shouldn't happen. it does. */
                                                && subs[walk[1] - '0'].rm_so <= subs[walk[1] - '0'].rm_eo) {
                                                
                                                tmp = subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
                                                memcpy (walkbuf, &string[pos + subs[walk[1] - '0'].rm_so], tmp);
                                                walkbuf += tmp;
                                        }
                                        walk += 2;
                                } else {
                                        *walkbuf++ = *walk++;
                                }
                        }
                        *walkbuf = '\0';

                        /* and get ready to keep looking for replacements */
                        if (subs[0].rm_so == subs[0].rm_eo) {
                                if (subs[0].rm_so + pos >= string_len) {
                                        break;
                                }
                                new_l = strlen (buf) + 1;
                                if (new_l + 1 > buf_len) {
                                        buf_len = 1 + buf_len + 2 * new_l;
                                        nbuf = safe_emalloc(buf_len, sizeof(char), 0);
                                        strncpy(nbuf, buf, buf_len-1);
                                        efree(buf);
                                        buf = nbuf;
                                }
                                pos += subs[0].rm_eo + 1;
                                buf [new_l-1] = string [pos-1];
                                buf [new_l] = '\0';
                        } else {
                                pos += subs[0].rm_eo;
                        }
                } else { /* REG_NOMATCH */
                        new_l = strlen(buf) + strlen(&string[pos]);
                        if (new_l + 1 > buf_len) {
                                buf_len = new_l + 1; /* now we know exactly how long it is */
                                nbuf = safe_emalloc(buf_len, sizeof(char), 0);
                                strncpy(nbuf, buf, buf_len-1);
                                efree(buf);
                                buf = nbuf;
                        }
                        /* stick that last bit of string on our output */
                        strlcat(buf, &string[pos], buf_len);
                }
        }

        /* don't want to leak memory .. */
        efree(subs);
        regfree(&re);

        /* whew. */
        return (buf);
}
/* }}} */

/* {{{ php_do_ereg_replace
 */
static void php_do_ereg_replace(INTERNAL_FUNCTION_PARAMETERS, int icase)
{
        zval **arg_pattern,
                **arg_replace;
        char *pattern, *arg_string;
        char *string;
        char *replace;
        char *ret;
        int arg_string_len;
        
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZs", &arg_pattern, &arg_replace, &arg_string, &arg_string_len) == FAILURE) {
                return;
        }

        if (Z_TYPE_PP(arg_pattern) == IS_STRING) {
                if (Z_STRVAL_PP(arg_pattern) && Z_STRLEN_PP(arg_pattern)) {
                        pattern = estrndup(Z_STRVAL_PP(arg_pattern), Z_STRLEN_PP(arg_pattern));
                } else {
                        pattern = STR_EMPTY_ALLOC();
                }
        } else {
                convert_to_long_ex(arg_pattern);
                pattern = emalloc(2);
                pattern[0] = (char) Z_LVAL_PP(arg_pattern);
                pattern[1] = '\0';
        }

        if (Z_TYPE_PP(arg_replace) == IS_STRING) {
                if (Z_STRVAL_PP(arg_replace) && Z_STRLEN_PP(arg_replace)) {
                        replace = estrndup(Z_STRVAL_PP(arg_replace), Z_STRLEN_PP(arg_replace));
                } else {
                        replace = STR_EMPTY_ALLOC();
                }
        } else {
                convert_to_long_ex(arg_replace);
                replace = emalloc(2);
                replace[0] = (char) Z_LVAL_PP(arg_replace);
                replace[1] = '\0';
        }

        if (arg_string && arg_string_len) {
                string = estrndup(arg_string, arg_string_len);
        } else {
                string = STR_EMPTY_ALLOC();
        }

        /* do the actual work */
        ret = php_ereg_replace(pattern, replace, string, icase, 1 TSRMLS_CC);
        if (ret == (char *) -1) {
                RETVAL_FALSE;
        } else {
                RETVAL_STRING(ret, 1);
                STR_FREE(ret);
        }

        STR_FREE(string);
        STR_FREE(replace);
        STR_FREE(pattern);
}
/* }}} */

/* {{{ proto string ereg_replace(string pattern, string replacement, string string)
   Replace regular expression */
PHP_FUNCTION(ereg_replace)
{
        php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */

/* {{{ proto string eregi_replace(string pattern, string replacement, string string)
   Case insensitive replace regular expression */
PHP_FUNCTION(eregi_replace)
{
        php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}
/* }}} */

/* {{{ php_split
 */
static void php_split(INTERNAL_FUNCTION_PARAMETERS, int icase)
{
        long count = -1;
        regex_t re;
        regmatch_t subs[1];
        char *spliton, *str, *strp, *endp;
        int spliton_len, str_len;
        int err, size, copts = 0;

        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &spliton, &spliton_len, &str, &str_len, &count) == FAILURE) {
                return;
        }

        if (icase) {
                copts = REG_ICASE;
        }

        strp = str;
        endp = strp + str_len;

        err = regcomp(&re, spliton, REG_EXTENDED | copts);
        if (err) {
                php_ereg_eprint(err, &re TSRMLS_CC);
                RETURN_FALSE;
        }

        array_init(return_value);

        /* churn through str, generating array entries as we go */
        while ((count == -1 || count > 1) && !(err = regexec(&re, strp, 1, subs, 0))) {
                if (subs[0].rm_so == 0 && subs[0].rm_eo) {
                        /* match is at start of string, return empty string */
                        add_next_index_stringl(return_value, "", 0, 1);
                        /* skip ahead the length of the regex match */
                        strp += subs[0].rm_eo;
                } else if (subs[0].rm_so == 0 && subs[0].rm_eo == 0) {
                        /* No more matches */
                        regfree(&re);
                        
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Regular Expression");
                        
                        zend_hash_destroy(Z_ARRVAL_P(return_value));
                        efree(Z_ARRVAL_P(return_value));
                        RETURN_FALSE;
                } else {
                        /* On a real match */

                        /* make a copy of the substring */
                        size = subs[0].rm_so;
                
                        /* add it to the array */
                        add_next_index_stringl(return_value, strp, size, 1);

                        /* point at our new starting point */
                        strp = strp + subs[0].rm_eo;
                }

                /* if we're only looking for a certain number of points,
                   stop looking once we hit it */
                if (count != -1) {
                        count--;
                }
        }

        /* see if we encountered an error */
        if (err && err != REG_NOMATCH) {
                php_ereg_eprint(err, &re TSRMLS_CC);
                regfree(&re);
                zend_hash_destroy(Z_ARRVAL_P(return_value));
                efree(Z_ARRVAL_P(return_value));
                RETURN_FALSE;
        }

        /* otherwise we just have one last element to add to the array */
        size = endp - strp;
        
        add_next_index_stringl(return_value, strp, size, 1);

        regfree(&re);
}
/* }}} */

/* {{{ proto array split(string pattern, string string [, int limit])
   Split string into array by regular expression */
PHP_FUNCTION(split)
{
        php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
}
/* }}} */

/* {{{ proto array spliti(string pattern, string string [, int limit])
   Split string into array by regular expression case-insensitive */

PHP_FUNCTION(spliti)
{
        php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
}

/* }}} */

/* {{{ proto string sql_regcase(string string)
   Make regular expression for case insensitive match */
PHP_EREG_API PHP_FUNCTION(sql_regcase)
{
        char *string, *tmp;
        int string_len;
        unsigned char c;
        register int i, j;

        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) {
                return;
        }
        
        tmp = safe_emalloc(string_len, 4, 1);
        
        for (i = j = 0; i < string_len; i++) {
                c = (unsigned char) string[i];
                if (isalpha(c)) {
                        tmp[j++] = '[';
                        tmp[j++] = toupper(c);
                        tmp[j++] = tolower(c);
                        tmp[j++] = ']';
                } else {
                        tmp[j++] = c;
                }
        }
        tmp[j] = 0;

        RETVAL_STRINGL(tmp, j, 1);
        efree(tmp);
}
/* }}} */

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */

/* [<][>][^][v][top][bottom][index][help] */