Back to index

php5  5.3.10
ereg.c
Go to the documentation of this file.
00001 /*
00002    +----------------------------------------------------------------------+
00003    | PHP Version 5                                                        |
00004    +----------------------------------------------------------------------+
00005    | Copyright (c) 1997-2012 The PHP Group                                |
00006    +----------------------------------------------------------------------+
00007    | This source file is subject to version 3.01 of the PHP license,      |
00008    | that is bundled with this package in the file LICENSE, and is        |
00009    | available through the world-wide-web at the following url:           |
00010    | http://www.php.net/license/3_01.txt                                  |
00011    | If you did not receive a copy of the PHP license and are unable to   |
00012    | obtain it through the world-wide-web, please send a note to          |
00013    | license@php.net so we can mail you a copy immediately.               |
00014    +----------------------------------------------------------------------+
00015    | Authors: Rasmus Lerdorf <rasmus@php.net>                             |
00016    |          Jim Winstead <jimw@php.net>                                 |
00017    |          Jaakko Hyvätti <jaakko@hyvatti.iki.fi>                      | 
00018    +----------------------------------------------------------------------+
00019  */
00020 /* $Id: ereg.c 321634 2012-01-01 13:15:04Z felipe $ */
00021 
00022 #include <stdio.h>
00023 #include <ctype.h>
00024 #include "php.h"
00025 #include "ext/standard/php_string.h"
00026 #include "php_ereg.h"
00027 #include "ext/standard/info.h"
00028 
00029 /* {{{ arginfo */
00030 ZEND_BEGIN_ARG_INFO_EX(arginfo_ereg, 0, 0, 2)
00031        ZEND_ARG_INFO(0, pattern)
00032        ZEND_ARG_INFO(0, string) 
00033        ZEND_ARG_INFO(1, registers) /* ARRAY_INFO(1, registers, 1) */
00034 ZEND_END_ARG_INFO()
00035 
00036 ZEND_BEGIN_ARG_INFO(arginfo_ereg_replace, 0)
00037        ZEND_ARG_INFO(0, pattern)
00038        ZEND_ARG_INFO(0, replacement)
00039        ZEND_ARG_INFO(0, string)
00040 ZEND_END_ARG_INFO()
00041 
00042 ZEND_BEGIN_ARG_INFO_EX(arginfo_split, 0, 0, 2)
00043        ZEND_ARG_INFO(0, pattern)
00044        ZEND_ARG_INFO(0, string) 
00045        ZEND_ARG_INFO(0, limit)  
00046 ZEND_END_ARG_INFO()
00047 
00048 ZEND_BEGIN_ARG_INFO(arginfo_sql_regcase, 0)
00049        ZEND_ARG_INFO(0, string)
00050 ZEND_END_ARG_INFO()
00051 /* }}} */
00052 
00053 /* {{{ Function table */
00054 const zend_function_entry ereg_functions[] = {
00055        PHP_DEP_FE(ereg,                   arginfo_ereg)
00056        PHP_DEP_FE(ereg_replace,    arginfo_ereg_replace)
00057        PHP_DEP_FE(eregi,                  arginfo_ereg)
00058        PHP_DEP_FE(eregi_replace,   arginfo_ereg_replace)
00059        PHP_DEP_FE(split,                  arginfo_split)
00060        PHP_DEP_FE(spliti,                 arginfo_split)
00061        PHP_DEP_FE(sql_regcase,            arginfo_sql_regcase)
00062        PHP_FE_END
00063 };
00064 /* }}} */
00065 
00066 /* {{{ reg_cache */
00067 typedef struct {
00068        regex_t preg;
00069        int cflags;
00070        unsigned long lastuse;
00071 } reg_cache;
00072 static int reg_magic = 0;
00073 #define EREG_CACHE_SIZE 4096
00074 /* }}} */
00075 
00076 ZEND_DECLARE_MODULE_GLOBALS(ereg)
00077 
00078 /* {{{ Module entry */
00079 zend_module_entry ereg_module_entry = {
00080        STANDARD_MODULE_HEADER,
00081        "ereg",
00082        ereg_functions,
00083        PHP_MINIT(ereg),
00084        PHP_MSHUTDOWN(ereg),
00085        NULL,
00086        NULL,
00087        PHP_MINFO(ereg),
00088        NO_VERSION_YET,
00089        STANDARD_MODULE_PROPERTIES
00090 };
00091 /* }}} */
00092 
00093 /* {{{ ereg_lru_cmp */
00094 static int ereg_lru_cmp(const void *a, const void *b TSRMLS_DC)
00095 {
00096        Bucket *f = *((Bucket **) a);
00097        Bucket *s = *((Bucket **) b);
00098 
00099        if (((reg_cache *)f->pData)->lastuse <
00100                             ((reg_cache *)s->pData)->lastuse) {
00101               return -1;
00102        } else if (((reg_cache *)f->pData)->lastuse ==
00103                             ((reg_cache *)s->pData)->lastuse) {
00104               return 0;
00105        } else {
00106               return 1;
00107        }
00108 }
00109 /* }}} */
00110 
00111 /* {{{ static ereg_clean_cache */
00112 static int ereg_clean_cache(void *data, void *arg TSRMLS_DC)
00113 {
00114        int *num_clean = (int *)arg;
00115 
00116        if (*num_clean > 0) {
00117               (*num_clean)--;
00118               return ZEND_HASH_APPLY_REMOVE;
00119        } else {
00120               return ZEND_HASH_APPLY_STOP;
00121        }
00122 }
00123 /* }}} */
00124 
00125 /* {{{ _php_regcomp
00126  */
00127 static int _php_regcomp(regex_t *preg, const char *pattern, int cflags)
00128 {
00129        int r = 0;
00130        int patlen = strlen(pattern);
00131        reg_cache *rc = NULL;
00132        TSRMLS_FETCH();
00133 
00134        if (zend_hash_num_elements(&EREG(ht_rc)) >= EREG_CACHE_SIZE) {
00135               /* easier than dealing with overflow as it happens */
00136               if (EREG(lru_counter) >= (1 << 31) || zend_hash_sort(&EREG(ht_rc), zend_qsort, ereg_lru_cmp, 0 TSRMLS_CC) == FAILURE) {
00137                      zend_hash_clean(&EREG(ht_rc));
00138                      EREG(lru_counter) = 0;
00139               } else {
00140                      int num_clean = EREG_CACHE_SIZE / 4;
00141                      zend_hash_apply_with_argument(&EREG(ht_rc), ereg_clean_cache, &num_clean TSRMLS_CC);
00142               }
00143        }
00144 
00145        if(zend_hash_find(&EREG(ht_rc), (char *) pattern, patlen+1, (void **) &rc) == SUCCESS
00146           && rc->cflags == cflags) {
00147 #ifdef HAVE_REGEX_T_RE_MAGIC
00148               /*
00149                * We use a saved magic number to see whether cache is corrupted, and if it
00150                * is, we flush it and compile the pattern from scratch.
00151                */
00152               if (rc->preg.re_magic != reg_magic) {
00153                      zend_hash_clean(&EREG(ht_rc));
00154                      EREG(lru_counter) = 0;
00155               } else {
00156                      memcpy(preg, &rc->preg, sizeof(*preg));
00157                      return r;
00158               }
00159        }
00160 
00161        r = regcomp(preg, pattern, cflags);
00162        if(!r) {
00163               reg_cache rcp;
00164 
00165               rcp.cflags = cflags;
00166               rcp.lastuse = ++(EREG(lru_counter));
00167               memcpy(&rcp.preg, preg, sizeof(*preg));
00168               /*
00169                * Since we don't have access to the actual MAGIC1 definition in the private
00170                * header file, we save the magic value immediately after compilation. Hopefully,
00171                * it's good.
00172                */
00173               if (!reg_magic) reg_magic = preg->re_magic;
00174               zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
00175                                            (void *) &rcp, sizeof(rcp), NULL);
00176        }
00177 #else
00178               memcpy(preg, &rc->preg, sizeof(*preg));
00179        } else {
00180               r = regcomp(preg, pattern, cflags);
00181               if(!r) {
00182                      reg_cache rcp;
00183 
00184                      rcp.cflags = cflags;
00185                      rcp.lastuse = ++(EREG(lru_counter));
00186                      memcpy(&rcp.preg, preg, sizeof(*preg));
00187                      zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
00188                                                   (void *) &rcp, sizeof(rcp), NULL);
00189               }
00190        }
00191 #endif
00192        return r;
00193 }
00194 /* }}} */
00195 
00196 static void _free_ereg_cache(reg_cache *rc) 
00197 {
00198        regfree(&rc->preg);
00199 }
00200 
00201 #undef regfree
00202 #define regfree(a);
00203 #undef regcomp
00204 #define regcomp(a, b, c) _php_regcomp(a, b, c)
00205        
00206 static void php_ereg_init_globals(zend_ereg_globals *ereg_globals TSRMLS_DC)
00207 {
00208        zend_hash_init(&ereg_globals->ht_rc, 0, NULL, (void (*)(void *)) _free_ereg_cache, 1);
00209        ereg_globals->lru_counter = 0;
00210 }
00211 
00212 static void php_ereg_destroy_globals(zend_ereg_globals *ereg_globals TSRMLS_DC)
00213 {
00214        zend_hash_destroy(&ereg_globals->ht_rc);
00215 }
00216 
00217 PHP_MINIT_FUNCTION(ereg)
00218 {
00219        ZEND_INIT_MODULE_GLOBALS(ereg, php_ereg_init_globals, php_ereg_destroy_globals);
00220        return SUCCESS;
00221 }
00222 
00223 PHP_MSHUTDOWN_FUNCTION(ereg)
00224 {
00225 #ifndef ZTS
00226        php_ereg_destroy_globals(&ereg_globals TSRMLS_CC);
00227 #endif
00228 
00229        return SUCCESS;
00230 }
00231 
00232 PHP_MINFO_FUNCTION(ereg)
00233 {
00234        php_info_print_table_start();
00235 #if HSREGEX
00236        php_info_print_table_row(2, "Regex Library", "Bundled library enabled");
00237 #else
00238        php_info_print_table_row(2, "Regex Library", "System library enabled");
00239 #endif
00240        php_info_print_table_end();
00241 }
00242 
00243 
00244 /* {{{ php_ereg_eprint
00245  * php_ereg_eprint - convert error number to name
00246  */
00247 static void php_ereg_eprint(int err, regex_t *re) {
00248        char *buf = NULL, *message = NULL;
00249        size_t len;
00250        size_t buf_len;
00251 
00252 #ifdef REG_ITOA
00253        /* get the length of the message */
00254        buf_len = regerror(REG_ITOA | err, re, NULL, 0);
00255        if (buf_len) {
00256               buf = (char *)safe_emalloc(buf_len, sizeof(char), 0);
00257               if (!buf) return; /* fail silently */
00258               /* finally, get the error message */
00259               regerror(REG_ITOA | err, re, buf, buf_len);
00260        }
00261 #else
00262        buf_len = 0;
00263 #endif
00264        len = regerror(err, re, NULL, 0);
00265        if (len) {
00266               TSRMLS_FETCH();
00267 
00268               message = (char *)safe_emalloc((buf_len + len + 2), sizeof(char), 0);
00269               if (!message) {
00270                      return; /* fail silently */
00271               }
00272               if (buf_len) {
00273                      snprintf(message, buf_len, "%s: ", buf);
00274                      buf_len += 1; /* so pointer math below works */
00275               }
00276               /* drop the message into place */
00277               regerror(err, re, message + buf_len, len);
00278 
00279               php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
00280        }
00281 
00282        STR_FREE(buf);
00283        STR_FREE(message);
00284 }
00285 /* }}} */
00286 
00287 /* {{{ php_ereg
00288  */
00289 static void php_ereg(INTERNAL_FUNCTION_PARAMETERS, int icase)
00290 {
00291        zval **regex,               /* Regular expression */
00292               **array = NULL;             /* Optional register array */
00293        char *findin;        /* String to apply expression to */
00294        int findin_len;
00295        regex_t re;
00296        regmatch_t *subs;
00297        int err, match_len, string_len;
00298        uint i;
00299        int copts = 0;
00300        off_t start, end;
00301        char *buf = NULL;
00302        char *string = NULL;
00303        int   argc = ZEND_NUM_ARGS();
00304 
00305        if (zend_parse_parameters(argc TSRMLS_CC, "Zs|Z", &regex, &findin, &findin_len, &array) == FAILURE) {
00306               return;
00307        }
00308 
00309        if (icase) {
00310               copts |= REG_ICASE;
00311        }
00312        
00313        if (argc == 2) {
00314               copts |= REG_NOSUB;
00315        }
00316 
00317        /* compile the regular expression from the supplied regex */
00318        if (Z_TYPE_PP(regex) == IS_STRING) {
00319               err = regcomp(&re, Z_STRVAL_PP(regex), REG_EXTENDED | copts);
00320        } else {
00321               /* we convert numbers to integers and treat them as a string */
00322               if (Z_TYPE_PP(regex) == IS_DOUBLE) {
00323                      convert_to_long_ex(regex);  /* get rid of decimal places */
00324               }
00325               convert_to_string_ex(regex);
00326               /* don't bother doing an extended regex with just a number */
00327               err = regcomp(&re, Z_STRVAL_PP(regex), copts);
00328        }
00329 
00330        if (err) {
00331               php_ereg_eprint(err, &re);
00332               RETURN_FALSE;
00333        }
00334 
00335        /* make a copy of the string we're looking in */
00336        string = estrndup(findin, findin_len);
00337 
00338        /* allocate storage for (sub-)expression-matches */
00339        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
00340        
00341        /* actually execute the regular expression */
00342        err = regexec(&re, string, re.re_nsub+1, subs, 0);
00343        if (err && err != REG_NOMATCH) {
00344               php_ereg_eprint(err, &re);
00345               regfree(&re);
00346               efree(subs);
00347               RETURN_FALSE;
00348        }
00349        match_len = 1;
00350 
00351        if (array && err != REG_NOMATCH) {
00352               match_len = (int) (subs[0].rm_eo - subs[0].rm_so);
00353               string_len = findin_len + 1;
00354 
00355               buf = emalloc(string_len);
00356 
00357               zval_dtor(*array);   /* start with clean array */
00358               array_init(*array);
00359 
00360               for (i = 0; i <= re.re_nsub; i++) {
00361                      start = subs[i].rm_so;
00362                      end = subs[i].rm_eo;
00363                      if (start != -1 && end > 0 && start < string_len && end < string_len && start < end) {
00364                             add_index_stringl(*array, i, string+start, end-start, 1);
00365                      } else {
00366                             add_index_bool(*array, i, 0);
00367                      }
00368               }
00369               efree(buf);
00370        }
00371 
00372        efree(subs);
00373        efree(string);
00374        if (err == REG_NOMATCH) {
00375               RETVAL_FALSE;
00376        } else {
00377               if (match_len == 0)
00378                      match_len = 1;
00379               RETVAL_LONG(match_len);
00380        }
00381        regfree(&re);
00382 }
00383 /* }}} */
00384 
00385 /* {{{ proto int ereg(string pattern, string string [, array registers])
00386    Regular expression match */
00387 PHP_FUNCTION(ereg)
00388 {
00389        php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
00390 }
00391 /* }}} */
00392 
00393 /* {{{ proto int eregi(string pattern, string string [, array registers])
00394    Case-insensitive regular expression match */
00395 PHP_FUNCTION(eregi)
00396 {
00397        php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
00398 }
00399 /* }}} */
00400 
00401 /* {{{ php_ereg_replace
00402  * this is the meat and potatoes of regex replacement! */
00403 PHPAPI char *php_ereg_replace(const char *pattern, const char *replace, const char *string, int icase, int extended)
00404 {
00405        regex_t re;
00406        regmatch_t *subs;
00407 
00408        char *buf,    /* buf is where we build the replaced string */
00409                *nbuf,       /* nbuf is used when we grow the buffer */
00410                *walkbuf; /* used to walk buf when replacing backrefs */
00411        const char *walk; /* used to walk replacement string for backrefs */
00412        int buf_len;
00413        int pos, tmp, string_len, new_l;
00414        int err, copts = 0;
00415 
00416        string_len = strlen(string);
00417 
00418        if (icase) {
00419               copts = REG_ICASE;
00420        }
00421        if (extended) {
00422               copts |= REG_EXTENDED;
00423        }
00424 
00425        err = regcomp(&re, pattern, copts);
00426        if (err) {
00427               php_ereg_eprint(err, &re);
00428               return ((char *) -1);
00429        }
00430 
00431 
00432        /* allocate storage for (sub-)expression-matches */
00433        subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
00434 
00435        /* start with a buffer that is twice the size of the stringo
00436           we're doing replacements in */
00437        buf_len = 2 * string_len + 1;
00438        buf = safe_emalloc(buf_len, sizeof(char), 0);
00439 
00440        err = pos = 0;
00441        buf[0] = '\0';
00442        while (!err) {
00443               err = regexec(&re, &string[pos], re.re_nsub+1, subs, (pos ? REG_NOTBOL : 0));
00444 
00445               if (err && err != REG_NOMATCH) {
00446                      php_ereg_eprint(err, &re);
00447                      efree(subs);
00448                      efree(buf);
00449                      regfree(&re);
00450                      return ((char *) -1);
00451               }
00452 
00453               if (!err) {
00454                      /* backref replacement is done in two passes:
00455                         1) find out how long the string will be, and allocate buf
00456                         2) copy the part before match, replacement and backrefs to buf
00457 
00458                         Jaakko Hyvätti <Jaakko.Hyvatti@iki.fi>
00459                         */
00460 
00461                      new_l = strlen(buf) + subs[0].rm_so; /* part before the match */
00462                      walk = replace;
00463                      while (*walk) {
00464                             if ('\\' == *walk && isdigit((unsigned char)walk[1]) && ((unsigned char)walk[1]) - '0' <= (int)re.re_nsub) {
00465                                    if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1) {
00466                                           new_l += subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
00467                                    }
00468                                    walk += 2;
00469                             } else {
00470                                    new_l++;
00471                                    walk++;
00472                             }
00473                      }
00474                      if (new_l + 1 > buf_len) {
00475                             buf_len = 1 + buf_len + 2 * new_l;
00476                             nbuf = emalloc(buf_len);
00477                             strncpy(nbuf, buf, buf_len-1);
00478                             nbuf[buf_len - 1] = '\0';
00479                             efree(buf);
00480                             buf = nbuf;
00481                      }
00482                      tmp = strlen(buf);
00483                      /* copy the part of the string before the match */
00484                      strncat(buf, &string[pos], subs[0].rm_so);
00485 
00486                      /* copy replacement and backrefs */
00487                      walkbuf = &buf[tmp + subs[0].rm_so];
00488                      walk = replace;
00489                      while (*walk) {
00490                             if ('\\' == *walk && isdigit((unsigned char)walk[1]) && ((unsigned char)walk[1]) - '0' <= (int)re.re_nsub) {
00491                                    if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1
00492                                           /* this next case shouldn't happen. it does. */
00493                                           && subs[walk[1] - '0'].rm_so <= subs[walk[1] - '0'].rm_eo) {
00494                                           
00495                                           tmp = subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
00496                                           memcpy (walkbuf, &string[pos + subs[walk[1] - '0'].rm_so], tmp);
00497                                           walkbuf += tmp;
00498                                    }
00499                                    walk += 2;
00500                             } else {
00501                                    *walkbuf++ = *walk++;
00502                             }
00503                      }
00504                      *walkbuf = '\0';
00505 
00506                      /* and get ready to keep looking for replacements */
00507                      if (subs[0].rm_so == subs[0].rm_eo) {
00508                             if (subs[0].rm_so + pos >= string_len) {
00509                                    break;
00510                             }
00511                             new_l = strlen (buf) + 1;
00512                             if (new_l + 1 > buf_len) {
00513                                    buf_len = 1 + buf_len + 2 * new_l;
00514                                    nbuf = safe_emalloc(buf_len, sizeof(char), 0);
00515                                    strncpy(nbuf, buf, buf_len-1);
00516                                    efree(buf);
00517                                    buf = nbuf;
00518                             }
00519                             pos += subs[0].rm_eo + 1;
00520                             buf [new_l-1] = string [pos-1];
00521                             buf [new_l] = '\0';
00522                      } else {
00523                             pos += subs[0].rm_eo;
00524                      }
00525               } else { /* REG_NOMATCH */
00526                      new_l = strlen(buf) + strlen(&string[pos]);
00527                      if (new_l + 1 > buf_len) {
00528                             buf_len = new_l + 1; /* now we know exactly how long it is */
00529                             nbuf = safe_emalloc(buf_len, sizeof(char), 0);
00530                             strncpy(nbuf, buf, buf_len-1);
00531                             efree(buf);
00532                             buf = nbuf;
00533                      }
00534                      /* stick that last bit of string on our output */
00535                      strlcat(buf, &string[pos], buf_len);
00536               }
00537        }
00538 
00539        /* don't want to leak memory .. */
00540        efree(subs);
00541        regfree(&re);
00542 
00543        /* whew. */
00544        return (buf);
00545 }
00546 /* }}} */
00547 
00548 /* {{{ php_do_ereg_replace
00549  */
00550 static void php_do_ereg_replace(INTERNAL_FUNCTION_PARAMETERS, int icase)
00551 {
00552        zval **arg_pattern,
00553               **arg_replace;
00554        char *pattern, *arg_string;
00555        char *string;
00556        char *replace;
00557        char *ret;
00558        int arg_string_len;
00559        
00560        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZs", &arg_pattern, &arg_replace, &arg_string, &arg_string_len) == FAILURE) {
00561               return;
00562        }
00563 
00564        if (Z_TYPE_PP(arg_pattern) == IS_STRING) {
00565               if (Z_STRVAL_PP(arg_pattern) && Z_STRLEN_PP(arg_pattern)) {
00566                      pattern = estrndup(Z_STRVAL_PP(arg_pattern), Z_STRLEN_PP(arg_pattern));
00567               } else {
00568                      pattern = STR_EMPTY_ALLOC();
00569               }
00570        } else {
00571               convert_to_long_ex(arg_pattern);
00572               pattern = emalloc(2);
00573               pattern[0] = (char) Z_LVAL_PP(arg_pattern);
00574               pattern[1] = '\0';
00575        }
00576 
00577        if (Z_TYPE_PP(arg_replace) == IS_STRING) {
00578               if (Z_STRVAL_PP(arg_replace) && Z_STRLEN_PP(arg_replace)) {
00579                      replace = estrndup(Z_STRVAL_PP(arg_replace), Z_STRLEN_PP(arg_replace));
00580               } else {
00581                      replace = STR_EMPTY_ALLOC();
00582               }
00583        } else {
00584               convert_to_long_ex(arg_replace);
00585               replace = emalloc(2);
00586               replace[0] = (char) Z_LVAL_PP(arg_replace);
00587               replace[1] = '\0';
00588        }
00589 
00590        if (arg_string && arg_string_len) {
00591               string = estrndup(arg_string, arg_string_len);
00592        } else {
00593               string = STR_EMPTY_ALLOC();
00594        }
00595 
00596        /* do the actual work */
00597        ret = php_ereg_replace(pattern, replace, string, icase, 1);
00598        if (ret == (char *) -1) {
00599               RETVAL_FALSE;
00600        } else {
00601               RETVAL_STRING(ret, 1);
00602               STR_FREE(ret);
00603        }
00604 
00605        STR_FREE(string);
00606        STR_FREE(replace);
00607        STR_FREE(pattern);
00608 }
00609 /* }}} */
00610 
00611 /* {{{ proto string ereg_replace(string pattern, string replacement, string string)
00612    Replace regular expression */
00613 PHP_FUNCTION(ereg_replace)
00614 {
00615        php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
00616 }
00617 /* }}} */
00618 
00619 /* {{{ proto string eregi_replace(string pattern, string replacement, string string)
00620    Case insensitive replace regular expression */
00621 PHP_FUNCTION(eregi_replace)
00622 {
00623        php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
00624 }
00625 /* }}} */
00626 
00627 /* {{{ php_split
00628  */
00629 static void php_split(INTERNAL_FUNCTION_PARAMETERS, int icase)
00630 {
00631        long count = -1;
00632        regex_t re;
00633        regmatch_t subs[1];
00634        char *spliton, *str, *strp, *endp;
00635        int spliton_len, str_len;
00636        int err, size, copts = 0;
00637 
00638        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &spliton, &spliton_len, &str, &str_len, &count) == FAILURE) {
00639               return;
00640        }
00641 
00642        if (icase) {
00643               copts = REG_ICASE;
00644        }
00645 
00646        strp = str;
00647        endp = strp + str_len;
00648 
00649        err = regcomp(&re, spliton, REG_EXTENDED | copts);
00650        if (err) {
00651               php_ereg_eprint(err, &re);
00652               RETURN_FALSE;
00653        }
00654 
00655        array_init(return_value);
00656 
00657        /* churn through str, generating array entries as we go */
00658        while ((count == -1 || count > 1) && !(err = regexec(&re, strp, 1, subs, 0))) {
00659               if (subs[0].rm_so == 0 && subs[0].rm_eo) {
00660                      /* match is at start of string, return empty string */
00661                      add_next_index_stringl(return_value, "", 0, 1);
00662                      /* skip ahead the length of the regex match */
00663                      strp += subs[0].rm_eo;
00664               } else if (subs[0].rm_so == 0 && subs[0].rm_eo == 0) {
00665                      /* No more matches */
00666                      regfree(&re);
00667                      
00668                      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Regular Expression");
00669                      
00670                      zend_hash_destroy(Z_ARRVAL_P(return_value));
00671                      efree(Z_ARRVAL_P(return_value));
00672                      RETURN_FALSE;
00673               } else {
00674                      /* On a real match */
00675 
00676                      /* make a copy of the substring */
00677                      size = subs[0].rm_so;
00678               
00679                      /* add it to the array */
00680                      add_next_index_stringl(return_value, strp, size, 1);
00681 
00682                      /* point at our new starting point */
00683                      strp = strp + subs[0].rm_eo;
00684               }
00685 
00686               /* if we're only looking for a certain number of points,
00687                  stop looking once we hit it */
00688               if (count != -1) {
00689                      count--;
00690               }
00691        }
00692 
00693        /* see if we encountered an error */
00694        if (err && err != REG_NOMATCH) {
00695               php_ereg_eprint(err, &re);
00696               regfree(&re);
00697               zend_hash_destroy(Z_ARRVAL_P(return_value));
00698               efree(Z_ARRVAL_P(return_value));
00699               RETURN_FALSE;
00700        }
00701 
00702        /* otherwise we just have one last element to add to the array */
00703        size = endp - strp;
00704        
00705        add_next_index_stringl(return_value, strp, size, 1);
00706 
00707        regfree(&re);
00708 }
00709 /* }}} */
00710 
00711 /* {{{ proto array split(string pattern, string string [, int limit])
00712    Split string into array by regular expression */
00713 PHP_FUNCTION(split)
00714 {
00715        php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
00716 }
00717 /* }}} */
00718 
00719 /* {{{ proto array spliti(string pattern, string string [, int limit])
00720    Split string into array by regular expression case-insensitive */
00721 
00722 PHP_FUNCTION(spliti)
00723 {
00724        php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
00725 }
00726 
00727 /* }}} */
00728 
00729 /* {{{ proto string sql_regcase(string string)
00730    Make regular expression for case insensitive match */
00731 PHPAPI PHP_FUNCTION(sql_regcase)
00732 {
00733        char *string, *tmp;
00734        int string_len;
00735        unsigned char c;
00736        register int i, j;
00737 
00738        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) {
00739               return;
00740        }
00741        
00742        tmp = safe_emalloc(string_len, 4, 1);
00743        
00744        for (i = j = 0; i < string_len; i++) {
00745               c = (unsigned char) string[i];
00746               if (isalpha(c)) {
00747                      tmp[j++] = '[';
00748                      tmp[j++] = toupper(c);
00749                      tmp[j++] = tolower(c);
00750                      tmp[j++] = ']';
00751               } else {
00752                      tmp[j++] = c;
00753               }
00754        }
00755        tmp[j] = 0;
00756 
00757        RETVAL_STRINGL(tmp, j, 1);
00758        efree(tmp);
00759 }
00760 /* }}} */
00761 
00762 /*
00763  * Local variables:
00764  * tab-width: 4
00765  * c-basic-offset: 4
00766  * End:
00767  * vim600: noet sw=4 ts=4 fdm=marker
00768  * vim<600: noet sw=4 ts=4
00769  */