1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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 281350 2009-05-28 21:57:24Z scottmac $ */
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 : {NULL, NULL, NULL}
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 0 : {
96 0 : Bucket *f = *((Bucket **) a);
97 0 : Bucket *s = *((Bucket **) b);
98 :
99 0 : if (((reg_cache *)f->pData)->lastuse <
100 : ((reg_cache *)s->pData)->lastuse) {
101 0 : return -1;
102 0 : } else if (((reg_cache *)f->pData)->lastuse ==
103 : ((reg_cache *)s->pData)->lastuse) {
104 0 : return 0;
105 : } else {
106 0 : return 1;
107 : }
108 : }
109 : /* }}} */
110 :
111 : /* {{{ static ereg_clean_cache */
112 : static int ereg_clean_cache(void *data, void *arg TSRMLS_DC)
113 0 : {
114 0 : int *num_clean = (int *)arg;
115 :
116 0 : if (*num_clean > 0) {
117 0 : (*num_clean)--;
118 0 : return ZEND_HASH_APPLY_REMOVE;
119 : } else {
120 0 : 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 670 : {
129 670 : int r = 0;
130 670 : int patlen = strlen(pattern);
131 670 : reg_cache *rc = NULL;
132 : TSRMLS_FETCH();
133 :
134 670 : if (zend_hash_num_elements(&EREG(ht_rc)) >= EREG_CACHE_SIZE) {
135 : /* easier than dealing with overflow as it happens */
136 0 : if (EREG(lru_counter) >= (1 << 31) || zend_hash_sort(&EREG(ht_rc), zend_qsort, ereg_lru_cmp, 0 TSRMLS_CC) == FAILURE) {
137 0 : zend_hash_clean(&EREG(ht_rc));
138 0 : EREG(lru_counter) = 0;
139 : } else {
140 0 : int num_clean = EREG_CACHE_SIZE / 4;
141 0 : zend_hash_apply_with_argument(&EREG(ht_rc), ereg_clean_cache, &num_clean TSRMLS_CC);
142 : }
143 : }
144 :
145 670 : 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 275 : if (rc->preg.re_magic != reg_magic) {
153 0 : zend_hash_clean(&EREG(ht_rc));
154 0 : EREG(lru_counter) = 0;
155 : } else {
156 275 : memcpy(preg, &rc->preg, sizeof(*preg));
157 275 : return r;
158 : }
159 : }
160 :
161 395 : r = regcomp(preg, pattern, cflags);
162 395 : if(!r) {
163 : reg_cache rcp;
164 :
165 253 : rcp.cflags = cflags;
166 253 : rcp.lastuse = ++(EREG(lru_counter));
167 253 : 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 253 : if (!reg_magic) reg_magic = preg->re_magic;
174 253 : 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 395 : return r;
193 : }
194 : /* }}} */
195 :
196 : static void _free_ereg_cache(reg_cache *rc)
197 253 : {
198 253 : regfree(&rc->preg);
199 253 : }
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 17633 : {
208 17633 : zend_hash_init(&ereg_globals->ht_rc, 0, NULL, (void (*)(void *)) _free_ereg_cache, 1);
209 17633 : ereg_globals->lru_counter = 0;
210 17633 : }
211 :
212 : static void php_ereg_destroy_globals(zend_ereg_globals *ereg_globals TSRMLS_DC)
213 17665 : {
214 17665 : zend_hash_destroy(&ereg_globals->ht_rc);
215 17665 : }
216 :
217 : PHP_MINIT_FUNCTION(ereg)
218 17633 : {
219 17633 : ZEND_INIT_MODULE_GLOBALS(ereg, php_ereg_init_globals, php_ereg_destroy_globals);
220 17633 : return SUCCESS;
221 : }
222 :
223 : PHP_MSHUTDOWN_FUNCTION(ereg)
224 17665 : {
225 : #ifndef ZTS
226 17665 : php_ereg_destroy_globals(&ereg_globals TSRMLS_CC);
227 : #endif
228 :
229 17665 : return SUCCESS;
230 : }
231 :
232 : PHP_MINFO_FUNCTION(ereg)
233 42 : {
234 42 : php_info_print_table_start();
235 : #if HSREGEX
236 42 : 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 42 : php_info_print_table_end();
241 42 : }
242 :
243 :
244 : /* {{{ php_ereg_eprint
245 : * php_ereg_eprint - convert error number to name
246 : */
247 142 : static void php_ereg_eprint(int err, regex_t *re) {
248 142 : 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 142 : buf_len = regerror(REG_ITOA | err, re, NULL, 0);
255 142 : if (buf_len) {
256 142 : buf = (char *)safe_emalloc(buf_len, sizeof(char), 0);
257 142 : if (!buf) return; /* fail silently */
258 : /* finally, get the error message */
259 142 : regerror(REG_ITOA | err, re, buf, buf_len);
260 : }
261 : #else
262 : buf_len = 0;
263 : #endif
264 142 : len = regerror(err, re, NULL, 0);
265 142 : if (len) {
266 : TSRMLS_FETCH();
267 :
268 142 : message = (char *)safe_emalloc((buf_len + len + 2), sizeof(char), 0);
269 142 : if (!message) {
270 0 : return; /* fail silently */
271 : }
272 142 : if (buf_len) {
273 142 : snprintf(message, buf_len, "%s: ", buf);
274 142 : buf_len += 1; /* so pointer math below works */
275 : }
276 : /* drop the message into place */
277 142 : regerror(err, re, message + buf_len, len);
278 :
279 142 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
280 : }
281 :
282 142 : STR_FREE(buf);
283 142 : STR_FREE(message);
284 : }
285 : /* }}} */
286 :
287 : /* {{{ php_ereg
288 : */
289 : static void php_ereg(INTERNAL_FUNCTION_PARAMETERS, int icase)
290 253 : {
291 : zval **regex, /* Regular expression */
292 253 : **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 253 : int copts = 0;
300 : off_t start, end;
301 253 : char *buf = NULL;
302 253 : char *string = NULL;
303 253 : int argc = ZEND_NUM_ARGS();
304 :
305 253 : if (zend_parse_parameters(argc TSRMLS_CC, "Zs|Z", ®ex, &findin, &findin_len, &array) == FAILURE) {
306 16 : return;
307 : }
308 :
309 237 : if (icase) {
310 117 : copts |= REG_ICASE;
311 : }
312 :
313 237 : if (argc == 2) {
314 57 : copts |= REG_NOSUB;
315 : }
316 :
317 : /* compile the regular expression from the supplied regex */
318 237 : if (Z_TYPE_PP(regex) == IS_STRING) {
319 191 : 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 46 : if (Z_TYPE_PP(regex) == IS_DOUBLE) {
323 10 : convert_to_long_ex(regex); /* get rid of decimal places */
324 : }
325 46 : convert_to_string_ex(regex);
326 : /* don't bother doing an extended regex with just a number */
327 46 : err = regcomp(&re, Z_STRVAL_PP(regex), copts);
328 : }
329 :
330 237 : if (err) {
331 46 : php_ereg_eprint(err, &re);
332 46 : RETURN_FALSE;
333 : }
334 :
335 : /* make a copy of the string we're looking in */
336 191 : string = estrndup(findin, findin_len);
337 :
338 : /* allocate storage for (sub-)expression-matches */
339 191 : subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
340 :
341 : /* actually execute the regular expression */
342 191 : err = regexec(&re, string, re.re_nsub+1, subs, 0);
343 191 : if (err && err != REG_NOMATCH) {
344 0 : php_ereg_eprint(err, &re);
345 : regfree(&re);
346 0 : efree(subs);
347 0 : RETURN_FALSE;
348 : }
349 191 : match_len = 1;
350 :
351 191 : if (array && err != REG_NOMATCH) {
352 99 : match_len = (int) (subs[0].rm_eo - subs[0].rm_so);
353 99 : string_len = findin_len + 1;
354 :
355 99 : buf = emalloc(string_len);
356 :
357 99 : zval_dtor(*array); /* start with clean array */
358 99 : array_init(*array);
359 :
360 4358 : for (i = 0; i <= re.re_nsub; i++) {
361 4259 : start = subs[i].rm_so;
362 4259 : end = subs[i].rm_eo;
363 8510 : if (start != -1 && end > 0 && start < string_len && end < string_len && start < end) {
364 4251 : add_index_stringl(*array, i, string+start, end-start, 1);
365 : } else {
366 8 : add_index_bool(*array, i, 0);
367 : }
368 : }
369 99 : efree(buf);
370 : }
371 :
372 191 : efree(subs);
373 191 : efree(string);
374 191 : if (err == REG_NOMATCH) {
375 63 : RETVAL_FALSE;
376 : } else {
377 128 : if (match_len == 0)
378 4 : match_len = 1;
379 128 : 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 128 : {
389 128 : php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
390 128 : }
391 : /* }}} */
392 :
393 : /* {{{ proto int eregi(string pattern, string string [, array registers])
394 : Case-insensitive regular expression match */
395 : PHP_FUNCTION(eregi)
396 125 : {
397 125 : php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
398 125 : }
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 222 : {
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 222 : int err, copts = 0;
415 :
416 222 : string_len = strlen(string);
417 :
418 222 : if (icase) {
419 103 : copts = REG_ICASE;
420 : }
421 222 : if (extended) {
422 222 : copts |= REG_EXTENDED;
423 : }
424 :
425 222 : err = regcomp(&re, pattern, copts);
426 222 : if (err) {
427 54 : php_ereg_eprint(err, &re);
428 54 : return ((char *) -1);
429 : }
430 :
431 :
432 : /* allocate storage for (sub-)expression-matches */
433 168 : 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 168 : buf_len = 2 * string_len + 1;
438 168 : buf = safe_emalloc(buf_len, sizeof(char), 0);
439 :
440 168 : err = pos = 0;
441 168 : buf[0] = '\0';
442 865 : while (!err) {
443 536 : err = regexec(&re, &string[pos], re.re_nsub+1, subs, (pos ? REG_NOTBOL : 0));
444 :
445 536 : if (err && err != REG_NOMATCH) {
446 0 : php_ereg_eprint(err, &re);
447 0 : efree(subs);
448 0 : efree(buf);
449 : regfree(&re);
450 0 : return ((char *) -1);
451 : }
452 :
453 536 : 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 375 : new_l = strlen(buf) + subs[0].rm_so; /* part before the match */
462 375 : walk = replace;
463 7533 : while (*walk) {
464 6793 : if ('\\' == *walk && isdigit((unsigned char)walk[1]) && ((unsigned char)walk[1]) - '0' <= (int)re.re_nsub) {
465 10 : if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1) {
466 10 : new_l += subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
467 : }
468 10 : walk += 2;
469 : } else {
470 6773 : new_l++;
471 6773 : walk++;
472 : }
473 : }
474 375 : if (new_l + 1 > buf_len) {
475 37 : buf_len = 1 + buf_len + 2 * new_l;
476 37 : nbuf = emalloc(buf_len);
477 37 : strcpy(nbuf, buf);
478 37 : efree(buf);
479 37 : buf = nbuf;
480 : }
481 375 : tmp = strlen(buf);
482 : /* copy the part of the string before the match */
483 375 : strncat(buf, &string[pos], subs[0].rm_so);
484 :
485 : /* copy replacement and backrefs */
486 375 : walkbuf = &buf[tmp + subs[0].rm_so];
487 375 : walk = replace;
488 7533 : while (*walk) {
489 6793 : if ('\\' == *walk && isdigit(walk[1]) && walk[1] - '0' <= (int)re.re_nsub) {
490 10 : if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1
491 : /* this next case shouldn't happen. it does. */
492 : && subs[walk[1] - '0'].rm_so <= subs[walk[1] - '0'].rm_eo) {
493 :
494 10 : tmp = subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
495 10 : memcpy (walkbuf, &string[pos + subs[walk[1] - '0'].rm_so], tmp);
496 10 : walkbuf += tmp;
497 : }
498 10 : walk += 2;
499 : } else {
500 6773 : *walkbuf++ = *walk++;
501 : }
502 : }
503 375 : *walkbuf = '\0';
504 :
505 : /* and get ready to keep looking for replacements */
506 375 : if (subs[0].rm_so == subs[0].rm_eo) {
507 144 : if (subs[0].rm_so + pos >= string_len) {
508 7 : break;
509 : }
510 137 : new_l = strlen (buf) + 1;
511 137 : if (new_l + 1 > buf_len) {
512 0 : buf_len = 1 + buf_len + 2 * new_l;
513 0 : nbuf = safe_emalloc(buf_len, sizeof(char), 0);
514 0 : strcpy(nbuf, buf);
515 0 : efree(buf);
516 0 : buf = nbuf;
517 : }
518 137 : pos += subs[0].rm_eo + 1;
519 137 : buf [new_l-1] = string [pos-1];
520 137 : buf [new_l] = '\0';
521 : } else {
522 231 : pos += subs[0].rm_eo;
523 : }
524 : } else { /* REG_NOMATCH */
525 161 : new_l = strlen(buf) + strlen(&string[pos]);
526 161 : if (new_l + 1 > buf_len) {
527 8 : buf_len = new_l + 1; /* now we know exactly how long it is */
528 8 : nbuf = safe_emalloc(buf_len, sizeof(char), 0);
529 8 : strcpy(nbuf, buf);
530 8 : efree(buf);
531 8 : buf = nbuf;
532 : }
533 : /* stick that last bit of string on our output */
534 161 : strlcat(buf, &string[pos], buf_len);
535 : }
536 : }
537 :
538 : /* don't want to leak memory .. */
539 168 : efree(subs);
540 : regfree(&re);
541 :
542 : /* whew. */
543 168 : return (buf);
544 : }
545 : /* }}} */
546 :
547 : /* {{{ php_do_ereg_replace
548 : */
549 : static void php_do_ereg_replace(INTERNAL_FUNCTION_PARAMETERS, int icase)
550 238 : {
551 : zval **arg_pattern,
552 : **arg_replace;
553 : char *pattern, *arg_string;
554 : char *string;
555 : char *replace;
556 : char *ret;
557 : int arg_string_len;
558 :
559 238 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZs", &arg_pattern, &arg_replace, &arg_string, &arg_string_len) == FAILURE) {
560 16 : return;
561 : }
562 :
563 222 : if (Z_TYPE_PP(arg_pattern) == IS_STRING) {
564 346 : if (Z_STRVAL_PP(arg_pattern) && Z_STRLEN_PP(arg_pattern)) {
565 170 : pattern = estrndup(Z_STRVAL_PP(arg_pattern), Z_STRLEN_PP(arg_pattern));
566 : } else {
567 6 : pattern = STR_EMPTY_ALLOC();
568 : }
569 : } else {
570 46 : convert_to_long_ex(arg_pattern);
571 46 : pattern = emalloc(2);
572 46 : pattern[0] = (char) Z_LVAL_PP(arg_pattern);
573 46 : pattern[1] = '\0';
574 : }
575 :
576 222 : if (Z_TYPE_PP(arg_replace) == IS_STRING) {
577 346 : if (Z_STRVAL_PP(arg_replace) && Z_STRLEN_PP(arg_replace)) {
578 170 : replace = estrndup(Z_STRVAL_PP(arg_replace), Z_STRLEN_PP(arg_replace));
579 : } else {
580 6 : replace = STR_EMPTY_ALLOC();
581 : }
582 : } else {
583 46 : convert_to_long_ex(arg_replace);
584 46 : replace = emalloc(2);
585 46 : replace[0] = (char) Z_LVAL_PP(arg_replace);
586 46 : replace[1] = '\0';
587 : }
588 :
589 428 : if (arg_string && arg_string_len) {
590 206 : string = estrndup(arg_string, arg_string_len);
591 : } else {
592 16 : string = STR_EMPTY_ALLOC();
593 : }
594 :
595 : /* do the actual work */
596 222 : ret = php_ereg_replace(pattern, replace, string, icase, 1);
597 222 : if (ret == (char *) -1) {
598 54 : RETVAL_FALSE;
599 : } else {
600 168 : RETVAL_STRING(ret, 1);
601 168 : STR_FREE(ret);
602 : }
603 :
604 222 : STR_FREE(string);
605 222 : STR_FREE(replace);
606 222 : STR_FREE(pattern);
607 : }
608 : /* }}} */
609 :
610 : /* {{{ proto string ereg_replace(string pattern, string replacement, string string)
611 : Replace regular expression */
612 : PHP_FUNCTION(ereg_replace)
613 127 : {
614 127 : php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
615 127 : }
616 : /* }}} */
617 :
618 : /* {{{ proto string eregi_replace(string pattern, string replacement, string string)
619 : Case insensitive replace regular expression */
620 : PHP_FUNCTION(eregi_replace)
621 111 : {
622 111 : php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
623 111 : }
624 : /* }}} */
625 :
626 : /* {{{ php_split
627 : */
628 : static void php_split(INTERNAL_FUNCTION_PARAMETERS, int icase)
629 263 : {
630 263 : long count = -1;
631 : regex_t re;
632 : regmatch_t subs[1];
633 : char *spliton, *str, *strp, *endp;
634 : int spliton_len, str_len;
635 263 : int err, size, copts = 0;
636 :
637 263 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &spliton, &spliton_len, &str, &str_len, &count) == FAILURE) {
638 52 : return;
639 : }
640 :
641 211 : if (icase) {
642 101 : copts = REG_ICASE;
643 : }
644 :
645 211 : strp = str;
646 211 : endp = strp + str_len;
647 :
648 211 : err = regcomp(&re, spliton, REG_EXTENDED | copts);
649 211 : if (err) {
650 42 : php_ereg_eprint(err, &re);
651 42 : RETURN_FALSE;
652 : }
653 :
654 169 : array_init(return_value);
655 :
656 : /* churn through str, generating array entries as we go */
657 529 : while ((count == -1 || count > 1) && !(err = regexec(&re, strp, 1, subs, 0))) {
658 301 : if (subs[0].rm_so == 0 && subs[0].rm_eo) {
659 : /* match is at start of string, return empty string */
660 102 : add_next_index_stringl(return_value, "", 0, 1);
661 : /* skip ahead the length of the regex match */
662 102 : strp += subs[0].rm_eo;
663 97 : } else if (subs[0].rm_so == 0 && subs[0].rm_eo == 0) {
664 : /* No more matches */
665 : regfree(&re);
666 :
667 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Regular Expression");
668 :
669 8 : zend_hash_destroy(Z_ARRVAL_P(return_value));
670 8 : efree(Z_ARRVAL_P(return_value));
671 8 : RETURN_FALSE;
672 : } else {
673 : /* On a real match */
674 :
675 : /* make a copy of the substring */
676 89 : size = subs[0].rm_so;
677 :
678 : /* add it to the array */
679 89 : add_next_index_stringl(return_value, strp, size, 1);
680 :
681 : /* point at our new starting point */
682 89 : strp = strp + subs[0].rm_eo;
683 : }
684 :
685 : /* if we're only looking for a certain number of points,
686 : stop looking once we hit it */
687 191 : if (count != -1) {
688 60 : count--;
689 : }
690 : }
691 :
692 : /* see if we encountered an error */
693 161 : if (err && err != REG_NOMATCH) {
694 0 : php_ereg_eprint(err, &re);
695 : regfree(&re);
696 0 : zend_hash_destroy(Z_ARRVAL_P(return_value));
697 0 : efree(Z_ARRVAL_P(return_value));
698 0 : RETURN_FALSE;
699 : }
700 :
701 : /* otherwise we just have one last element to add to the array */
702 161 : size = endp - strp;
703 :
704 161 : add_next_index_stringl(return_value, strp, size, 1);
705 :
706 : regfree(&re);
707 : }
708 : /* }}} */
709 :
710 : /* {{{ proto array split(string pattern, string string [, int limit])
711 : Split string into array by regular expression */
712 : PHP_FUNCTION(split)
713 136 : {
714 136 : php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
715 136 : }
716 : /* }}} */
717 :
718 : /* {{{ proto array spliti(string pattern, string string [, int limit])
719 : Split string into array by regular expression case-insensitive */
720 :
721 : PHP_FUNCTION(spliti)
722 127 : {
723 127 : php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
724 127 : }
725 :
726 : /* }}} */
727 :
728 : /* {{{ proto string sql_regcase(string string)
729 : Make regular expression for case insensitive match */
730 : PHPAPI PHP_FUNCTION(sql_regcase)
731 28 : {
732 : char *string, *tmp;
733 : int string_len;
734 : unsigned char c;
735 : register int i, j;
736 :
737 28 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &string_len) == FAILURE) {
738 8 : return;
739 : }
740 :
741 20 : tmp = safe_emalloc(string_len, 4, 1);
742 :
743 83 : for (i = j = 0; i < string_len; i++) {
744 63 : c = (unsigned char) string[i];
745 63 : if (isalpha(c)) {
746 10 : tmp[j++] = '[';
747 10 : tmp[j++] = toupper(c);
748 10 : tmp[j++] = tolower(c);
749 10 : tmp[j++] = ']';
750 : } else {
751 53 : tmp[j++] = c;
752 : }
753 : }
754 20 : tmp[j] = 0;
755 :
756 20 : RETVAL_STRINGL(tmp, j, 1);
757 20 : efree(tmp);
758 : }
759 : /* }}} */
760 :
761 : /*
762 : * Local variables:
763 : * tab-width: 4
764 : * c-basic-offset: 4
765 : * End:
766 : * vim600: noet sw=4 ts=4 fdm=marker
767 : * vim<600: noet sw=4 ts=4
768 : */
|