1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 6 |
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 281349 2009-05-28 21:56:35Z 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_EX(arginfo_eregi, 0, 0, 2)
37 : ZEND_ARG_INFO(0, pattern)
38 : ZEND_ARG_INFO(0, string)
39 : ZEND_ARG_INFO(1, registers) /* ARRAY_INFO(1, registers, 1) */
40 : ZEND_END_ARG_INFO()
41 :
42 : ZEND_BEGIN_ARG_INFO(arginfo_ereg_replace, 0)
43 : ZEND_ARG_INFO(0, pattern)
44 : ZEND_ARG_INFO(0, replacement)
45 : ZEND_ARG_INFO(0, string)
46 : ZEND_END_ARG_INFO()
47 :
48 : ZEND_BEGIN_ARG_INFO(arginfo_eregi_replace, 0)
49 : ZEND_ARG_INFO(0, pattern)
50 : ZEND_ARG_INFO(0, replacement)
51 : ZEND_ARG_INFO(0, string)
52 : ZEND_END_ARG_INFO()
53 :
54 : ZEND_BEGIN_ARG_INFO_EX(arginfo_split, 0, 0, 2)
55 : ZEND_ARG_INFO(0, pattern)
56 : ZEND_ARG_INFO(0, string)
57 : ZEND_ARG_INFO(0, limit)
58 : ZEND_END_ARG_INFO()
59 :
60 : ZEND_BEGIN_ARG_INFO_EX(arginfo_spliti, 0, 0, 2)
61 : ZEND_ARG_INFO(0, pattern)
62 : ZEND_ARG_INFO(0, string)
63 : ZEND_ARG_INFO(0, limit)
64 : ZEND_END_ARG_INFO()
65 :
66 : ZEND_BEGIN_ARG_INFO(arginfo_sql_regcase, 0)
67 : ZEND_ARG_INFO(0, string)
68 : ZEND_END_ARG_INFO()
69 : /* }}} */
70 :
71 : /* {{{ Function table */
72 : const zend_function_entry ereg_functions[] = {
73 : PHP_FE(ereg, arginfo_ereg)
74 : PHP_FE(ereg_replace, arginfo_ereg_replace)
75 : PHP_FE(eregi, arginfo_eregi)
76 : PHP_FE(eregi_replace, arginfo_eregi_replace)
77 : PHP_FE(split, arginfo_split)
78 : PHP_FE(spliti, arginfo_spliti)
79 : PHP_FE(sql_regcase, arginfo_sql_regcase)
80 : {NULL, NULL, NULL}
81 : };
82 : /* }}} */
83 :
84 : /* {{{ reg_cache */
85 : typedef struct {
86 : regex_t preg;
87 : int cflags;
88 : unsigned long lastuse;
89 : } reg_cache;
90 : static int reg_magic = 0;
91 : #define EREG_CACHE_SIZE 4096
92 : /* }}} */
93 :
94 : ZEND_DECLARE_MODULE_GLOBALS(ereg)
95 :
96 : /* {{{ Module entry */
97 : zend_module_entry ereg_module_entry = {
98 : STANDARD_MODULE_HEADER,
99 : "ereg",
100 : ereg_functions,
101 : PHP_MINIT(ereg),
102 : PHP_MSHUTDOWN(ereg),
103 : NULL,
104 : NULL,
105 : PHP_MINFO(ereg),
106 : NO_VERSION_YET,
107 : STANDARD_MODULE_PROPERTIES
108 : };
109 : /* }}} */
110 :
111 : /* {{{ ereg_lru_cmp */
112 : static int ereg_lru_cmp(const void *a, const void *b TSRMLS_DC)
113 0 : {
114 0 : Bucket *f = *((Bucket **) a);
115 0 : Bucket *s = *((Bucket **) b);
116 :
117 0 : if (((reg_cache *)f->pData)->lastuse <
118 : ((reg_cache *)s->pData)->lastuse) {
119 0 : return -1;
120 0 : } else if (((reg_cache *)f->pData)->lastuse ==
121 : ((reg_cache *)s->pData)->lastuse) {
122 0 : return 0;
123 : } else {
124 0 : return 1;
125 : }
126 : }
127 : /* }}} */
128 :
129 : /* {{{ static ereg_clean_cache */
130 : static int ereg_clean_cache(void *data, void *arg TSRMLS_DC)
131 0 : {
132 0 : int *num_clean = (int *)arg;
133 :
134 0 : if (*num_clean > 0) {
135 0 : (*num_clean)--;
136 0 : return ZEND_HASH_APPLY_REMOVE;
137 : } else {
138 0 : return ZEND_HASH_APPLY_STOP;
139 : }
140 : }
141 : /* }}} */
142 :
143 : /* {{{ _php_regcomp
144 : */
145 : static int _php_regcomp(regex_t *preg, const char *pattern, int cflags)
146 663 : {
147 663 : int r = 0;
148 663 : int patlen = strlen(pattern);
149 663 : reg_cache *rc = NULL;
150 : TSRMLS_FETCH();
151 :
152 663 : if (zend_hash_num_elements(&EREG(ht_rc)) >= EREG_CACHE_SIZE) {
153 : /* easier than dealing with overflow as it happens */
154 0 : if (EREG(lru_counter) >= (1 << 31) || zend_hash_sort(&EREG(ht_rc), zend_qsort, ereg_lru_cmp, 0 TSRMLS_CC) == FAILURE) {
155 0 : zend_hash_clean(&EREG(ht_rc));
156 0 : EREG(lru_counter) = 0;
157 : } else {
158 0 : int num_clean = EREG_CACHE_SIZE / 2;
159 0 : zend_hash_apply_with_argument(&EREG(ht_rc), ereg_clean_cache, &num_clean TSRMLS_CC);
160 : }
161 : }
162 :
163 663 : if(zend_hash_find(&EREG(ht_rc), (char *) pattern, patlen+1, (void **) &rc) == SUCCESS
164 : && rc->cflags == cflags) {
165 : #ifdef HAVE_REGEX_T_RE_MAGIC
166 : /*
167 : * We use a saved magic number to see whether cache is corrupted, and if it
168 : * is, we flush it and compile the pattern from scratch.
169 : */
170 292 : if (rc->preg.re_magic != reg_magic) {
171 0 : zend_hash_clean(&EREG(ht_rc));
172 0 : EREG(lru_counter) = 0;
173 : } else {
174 292 : memcpy(preg, &rc->preg, sizeof(*preg));
175 292 : return r;
176 : }
177 : }
178 :
179 371 : r = regcomp(preg, pattern, cflags);
180 371 : if(!r) {
181 : reg_cache rcp;
182 :
183 229 : rcp.cflags = cflags;
184 229 : rcp.lastuse = ++(EREG(lru_counter));
185 229 : memcpy(&rcp.preg, preg, sizeof(*preg));
186 : /*
187 : * Since we don't have access to the actual MAGIC1 definition in the private
188 : * header file, we save the magic value immediately after compilation. Hopefully,
189 : * it's good.
190 : */
191 229 : if (!reg_magic) reg_magic = preg->re_magic;
192 229 : zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
193 : (void *) &rcp, sizeof(rcp), NULL);
194 : }
195 : #else
196 : memcpy(preg, &rc->preg, sizeof(*preg));
197 : } else {
198 : r = regcomp(preg, pattern, cflags);
199 : if(!r) {
200 : reg_cache rcp;
201 :
202 : rcp.cflags = cflags;
203 : rcp.lastuse = ++(EREG(lru_counter));
204 : memcpy(&rcp.preg, preg, sizeof(*preg));
205 : zend_hash_update(&EREG(ht_rc), (char *) pattern, patlen+1,
206 : (void *) &rcp, sizeof(rcp), NULL);
207 : }
208 : }
209 : #endif
210 371 : return r;
211 : }
212 : /* }}} */
213 :
214 : static void _free_ereg_cache(reg_cache *rc)
215 229 : {
216 229 : regfree(&rc->preg);
217 229 : }
218 :
219 : #undef regfree
220 : #define regfree(a);
221 : #undef regcomp
222 : #define regcomp(a, b, c) _php_regcomp(a, b, c)
223 :
224 : static void php_ereg_init_globals(zend_ereg_globals *ereg_globals TSRMLS_DC)
225 17007 : {
226 17007 : zend_hash_init(&ereg_globals->ht_rc, 0, NULL, (void (*)(void *)) _free_ereg_cache, 1);
227 17007 : ereg_globals->lru_counter = 0;
228 17007 : }
229 :
230 : static void php_ereg_destroy_globals(zend_ereg_globals *ereg_globals TSRMLS_DC)
231 17039 : {
232 17039 : zend_hash_destroy(&ereg_globals->ht_rc);
233 17039 : }
234 :
235 : PHP_MINIT_FUNCTION(ereg)
236 17007 : {
237 17007 : ZEND_INIT_MODULE_GLOBALS(ereg, php_ereg_init_globals, php_ereg_destroy_globals);
238 17007 : return SUCCESS;
239 : }
240 :
241 : PHP_MSHUTDOWN_FUNCTION(ereg)
242 17039 : {
243 : #ifndef ZTS
244 17039 : php_ereg_destroy_globals(&ereg_globals TSRMLS_CC);
245 : #endif
246 :
247 17039 : return SUCCESS;
248 : }
249 :
250 : PHP_MINFO_FUNCTION(ereg)
251 43 : {
252 43 : php_info_print_table_start();
253 : #if HSREGEX
254 43 : php_info_print_table_row(2, "Regex Library", "Bundled library enabled");
255 : #else
256 : php_info_print_table_row(2, "Regex Library", "System library enabled");
257 : #endif
258 43 : php_info_print_table_end();
259 43 : }
260 :
261 :
262 : /* {{{ php_ereg_eprint
263 : * php_ereg_eprint - convert error number to name
264 : */
265 142 : static void php_ereg_eprint(int err, regex_t *re) {
266 142 : char *buf = NULL, *message = NULL;
267 : size_t len;
268 : size_t buf_len;
269 :
270 : #ifdef REG_ITOA
271 : /* get the length of the message */
272 142 : buf_len = regerror(REG_ITOA | err, re, NULL, 0);
273 142 : if (buf_len) {
274 142 : buf = (char *)safe_emalloc(buf_len, sizeof(char), 0);
275 142 : if (!buf) return; /* fail silently */
276 : /* finally, get the error message */
277 142 : regerror(REG_ITOA | err, re, buf, buf_len);
278 : }
279 : #else
280 : buf_len = 0;
281 : #endif
282 142 : len = regerror(err, re, NULL, 0);
283 142 : if (len) {
284 : TSRMLS_FETCH();
285 :
286 142 : message = (char *)safe_emalloc((buf_len + len + 2), sizeof(char), 0);
287 142 : if (!message) {
288 0 : return; /* fail silently */
289 : }
290 142 : if (buf_len) {
291 142 : snprintf(message, buf_len, "%s: ", buf);
292 142 : buf_len += 1; /* so pointer math below works */
293 : }
294 : /* drop the message into place */
295 142 : regerror(err, re, message + buf_len, len);
296 :
297 142 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", message);
298 : }
299 :
300 142 : STR_FREE(buf);
301 142 : STR_FREE(message);
302 : }
303 : /* }}} */
304 :
305 : /* {{{ php_ereg
306 : */
307 : static void php_ereg(INTERNAL_FUNCTION_PARAMETERS, int icase)
308 249 : {
309 : zval **regex, /* Regular expression */
310 : **findin, /* String to apply expression to */
311 249 : **array = NULL; /* Optional register array */
312 : regex_t re;
313 : regmatch_t *subs;
314 : int err, match_len, string_len;
315 : uint i;
316 249 : int copts = 0;
317 : off_t start, end;
318 249 : char *buf = NULL;
319 249 : char *string = NULL;
320 249 : int argc = ZEND_NUM_ARGS();
321 :
322 249 : if (argc < 2 || argc > 3 ||
323 : zend_get_parameters_ex(argc, ®ex, &findin, &array) == FAILURE) {
324 4 : WRONG_PARAM_COUNT;
325 : }
326 :
327 245 : if (icase)
328 123 : copts |= REG_ICASE;
329 :
330 245 : if (argc == 2)
331 54 : copts |= REG_NOSUB;
332 :
333 : /* compile the regular expression from the supplied regex */
334 245 : if (Z_TYPE_PP(regex) == IS_STRING) {
335 139 : err = regcomp(&re, Z_STRVAL_PP(regex), REG_EXTENDED | copts);
336 : } else {
337 : /* we convert numbers to integers and treat them as a string */
338 106 : if (Z_TYPE_PP(regex) == IS_DOUBLE)
339 10 : convert_to_long_ex(regex); /* get rid of decimal places */
340 106 : convert_to_string_ex(regex);
341 : /* don't bother doing an extended regex with just a number */
342 106 : err = regcomp(&re, Z_STRVAL_PP(regex), copts);
343 : }
344 :
345 245 : if (err) {
346 46 : php_ereg_eprint(err, &re);
347 46 : RETURN_FALSE;
348 : }
349 :
350 : /* make a copy of the string we're looking in */
351 199 : convert_to_string_ex(findin);
352 199 : string = estrndup(Z_STRVAL_PP(findin), Z_STRLEN_PP(findin));
353 :
354 : /* allocate storage for (sub-)expression-matches */
355 199 : subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
356 :
357 : /* actually execute the regular expression */
358 199 : err = regexec(&re, string, re.re_nsub+1, subs, 0);
359 199 : if (err && err != REG_NOMATCH) {
360 0 : php_ereg_eprint(err, &re);
361 : regfree(&re);
362 0 : efree(subs);
363 0 : RETURN_FALSE;
364 : }
365 199 : match_len = 1;
366 :
367 199 : if (array && err != REG_NOMATCH) {
368 98 : match_len = (int) (subs[0].rm_eo - subs[0].rm_so);
369 98 : string_len = Z_STRLEN_PP(findin) + 1;
370 :
371 98 : buf = emalloc(string_len);
372 :
373 98 : zval_dtor(*array); /* start with clean array */
374 98 : array_init(*array);
375 :
376 4354 : for (i = 0; i <= re.re_nsub; i++) {
377 4256 : start = subs[i].rm_so;
378 4256 : end = subs[i].rm_eo;
379 8504 : if (start != -1 && end > 0 && start < string_len && end < string_len && start < end) {
380 4248 : add_index_stringl(*array, i, string+start, end-start, 1);
381 : } else {
382 8 : add_index_bool(*array, i, 0);
383 : }
384 : }
385 98 : efree(buf);
386 : }
387 :
388 199 : efree(subs);
389 199 : efree(string);
390 199 : if (err == REG_NOMATCH) {
391 73 : RETVAL_FALSE;
392 : } else {
393 126 : if (match_len == 0)
394 4 : match_len = 1;
395 126 : RETVAL_LONG(match_len);
396 : }
397 : regfree(&re);
398 : }
399 : /* }}} */
400 :
401 : /* {{{ proto int ereg(string pattern, string string [, array registers])
402 : Regular expression match */
403 : PHP_FUNCTION(ereg)
404 124 : {
405 124 : php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
406 124 : }
407 : /* }}} */
408 :
409 : /* {{{ proto int eregi(string pattern, string string [, array registers])
410 : Case-insensitive regular expression match */
411 : PHP_FUNCTION(eregi)
412 125 : {
413 125 : php_ereg(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
414 125 : }
415 : /* }}} */
416 :
417 : /* {{{ php_ereg_replace
418 : * this is the meat and potatoes of regex replacement! */
419 : PHPAPI char *php_ereg_replace(const char *pattern, const char *replace, const char *string, int icase, int extended)
420 218 : {
421 : regex_t re;
422 : regmatch_t *subs;
423 :
424 : char *buf, /* buf is where we build the replaced string */
425 : *nbuf, /* nbuf is used when we grow the buffer */
426 : *walkbuf; /* used to walk buf when replacing backrefs */
427 : const char *walk; /* used to walk replacement string for backrefs */
428 : int buf_len;
429 : int pos, tmp, string_len, new_l;
430 218 : int err, copts = 0;
431 :
432 218 : string_len = strlen(string);
433 :
434 218 : if (icase) {
435 109 : copts = REG_ICASE;
436 : }
437 218 : if (extended) {
438 218 : copts |= REG_EXTENDED;
439 : }
440 :
441 218 : err = regcomp(&re, pattern, copts);
442 218 : if (err) {
443 54 : php_ereg_eprint(err, &re);
444 54 : return ((char *) -1);
445 : }
446 :
447 :
448 : /* allocate storage for (sub-)expression-matches */
449 164 : subs = (regmatch_t *)ecalloc(sizeof(regmatch_t),re.re_nsub+1);
450 :
451 : /* start with a buffer that is twice the size of the stringo
452 : we're doing replacements in */
453 164 : buf_len = 2 * string_len + 1;
454 164 : buf = safe_emalloc(buf_len, sizeof(char), 0);
455 :
456 164 : err = pos = 0;
457 164 : buf[0] = '\0';
458 839 : while (!err) {
459 515 : err = regexec(&re, &string[pos], re.re_nsub+1, subs, (pos ? REG_NOTBOL : 0));
460 :
461 515 : if (err && err != REG_NOMATCH) {
462 0 : php_ereg_eprint(err, &re);
463 0 : efree(subs);
464 0 : efree(buf);
465 : regfree(&re);
466 0 : return ((char *) -1);
467 : }
468 :
469 515 : if (!err) {
470 : /* backref replacement is done in two passes:
471 : 1) find out how long the string will be, and allocate buf
472 : 2) copy the part before match, replacement and backrefs to buf
473 :
474 : Jaakko Hyvätti <Jaakko.Hyvatti@iki.fi>
475 : */
476 :
477 355 : new_l = strlen(buf) + subs[0].rm_so; /* part before the match */
478 355 : walk = replace;
479 7435 : while (*walk) {
480 6728 : if ('\\' == *walk && isdigit((unsigned char)walk[1]) && ((unsigned char)walk[1]) - '0' <= (int)re.re_nsub) {
481 3 : if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1) {
482 3 : new_l += subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
483 : }
484 3 : walk += 2;
485 : } else {
486 6722 : new_l++;
487 6722 : walk++;
488 : }
489 : }
490 355 : if (new_l + 1 > buf_len) {
491 36 : buf_len = 1 + buf_len + 2 * new_l;
492 36 : nbuf = emalloc(buf_len);
493 36 : strcpy(nbuf, buf);
494 36 : efree(buf);
495 36 : buf = nbuf;
496 : }
497 355 : tmp = strlen(buf);
498 : /* copy the part of the string before the match */
499 355 : strncat(buf, &string[pos], subs[0].rm_so);
500 :
501 : /* copy replacement and backrefs */
502 355 : walkbuf = &buf[tmp + subs[0].rm_so];
503 355 : walk = replace;
504 7435 : while (*walk) {
505 6728 : if ('\\' == *walk && isdigit(walk[1]) && walk[1] - '0' <= (int)re.re_nsub) {
506 3 : if (subs[walk[1] - '0'].rm_so > -1 && subs[walk[1] - '0'].rm_eo > -1
507 : /* this next case shouldn't happen. it does. */
508 : && subs[walk[1] - '0'].rm_so <= subs[walk[1] - '0'].rm_eo) {
509 :
510 3 : tmp = subs[walk[1] - '0'].rm_eo - subs[walk[1] - '0'].rm_so;
511 3 : memcpy (walkbuf, &string[pos + subs[walk[1] - '0'].rm_so], tmp);
512 3 : walkbuf += tmp;
513 : }
514 3 : walk += 2;
515 : } else {
516 6722 : *walkbuf++ = *walk++;
517 : }
518 : }
519 355 : *walkbuf = '\0';
520 :
521 : /* and get ready to keep looking for replacements */
522 355 : if (subs[0].rm_so == subs[0].rm_eo) {
523 140 : if (subs[0].rm_so + pos >= string_len) {
524 4 : break;
525 : }
526 136 : new_l = strlen (buf) + 1;
527 136 : if (new_l + 1 > buf_len) {
528 0 : buf_len = 1 + buf_len + 2 * new_l;
529 0 : nbuf = safe_emalloc(buf_len, sizeof(char), 0);
530 0 : strcpy(nbuf, buf);
531 0 : efree(buf);
532 0 : buf = nbuf;
533 : }
534 136 : pos += subs[0].rm_eo + 1;
535 136 : buf [new_l-1] = string [pos-1];
536 136 : buf [new_l] = '\0';
537 : } else {
538 215 : pos += subs[0].rm_eo;
539 : }
540 : } else { /* REG_NOMATCH */
541 160 : new_l = strlen(buf) + strlen(&string[pos]);
542 160 : if (new_l + 1 > buf_len) {
543 8 : buf_len = new_l + 1; /* now we know exactly how long it is */
544 8 : nbuf = safe_emalloc(buf_len, sizeof(char), 0);
545 8 : strcpy(nbuf, buf);
546 8 : efree(buf);
547 8 : buf = nbuf;
548 : }
549 : /* stick that last bit of string on our output */
550 160 : strlcat(buf, &string[pos], buf_len);
551 : }
552 : }
553 :
554 : /* don't want to leak memory .. */
555 164 : efree(subs);
556 : regfree(&re);
557 :
558 : /* whew. */
559 164 : return (buf);
560 : }
561 : /* }}} */
562 :
563 : /* {{{ php_do_ereg_replace
564 : */
565 : static void php_do_ereg_replace(INTERNAL_FUNCTION_PARAMETERS, int icase)
566 222 : {
567 : zval **arg_pattern,
568 : **arg_replace,
569 : **arg_string;
570 : char *pattern;
571 : char *string;
572 : char *replace;
573 : char *ret;
574 :
575 222 : if (ZEND_NUM_ARGS() != 3 ||
576 : zend_get_parameters_ex(3, &arg_pattern, &arg_replace, &arg_string) == FAILURE) {
577 4 : WRONG_PARAM_COUNT;
578 : }
579 :
580 218 : if (Z_TYPE_PP(arg_pattern) == IS_STRING) {
581 334 : if (Z_STRVAL_PP(arg_pattern) && Z_STRLEN_PP(arg_pattern))
582 166 : pattern = estrndup(Z_STRVAL_PP(arg_pattern), Z_STRLEN_PP(arg_pattern));
583 : else
584 2 : pattern = STR_EMPTY_ALLOC();
585 : } else {
586 50 : convert_to_long_ex(arg_pattern);
587 50 : pattern = emalloc(2);
588 50 : pattern[0] = (char) Z_LVAL_PP(arg_pattern);
589 50 : pattern[1] = '\0';
590 : }
591 :
592 218 : if (Z_TYPE_PP(arg_replace) == IS_STRING) {
593 154 : if (Z_STRVAL_PP(arg_replace) && Z_STRLEN_PP(arg_replace))
594 77 : replace = estrndup(Z_STRVAL_PP(arg_replace), Z_STRLEN_PP(arg_replace));
595 : else
596 0 : replace = STR_EMPTY_ALLOC();
597 : } else {
598 141 : convert_to_long_ex(arg_replace);
599 141 : replace = emalloc(2);
600 141 : replace[0] = (char) Z_LVAL_PP(arg_replace);
601 141 : replace[1] = '\0';
602 : }
603 :
604 218 : convert_to_string_ex(arg_string);
605 420 : if (Z_STRVAL_PP(arg_string) && Z_STRLEN_PP(arg_string))
606 202 : string = estrndup(Z_STRVAL_PP(arg_string), Z_STRLEN_PP(arg_string));
607 : else
608 16 : string = STR_EMPTY_ALLOC();
609 :
610 : /* do the actual work */
611 218 : ret = php_ereg_replace(pattern, replace, string, icase, 1);
612 218 : if (ret == (char *) -1) {
613 54 : RETVAL_FALSE;
614 : } else {
615 164 : RETVAL_STRING(ret, 1);
616 164 : STR_FREE(ret);
617 : }
618 :
619 218 : STR_FREE(string);
620 218 : STR_FREE(replace);
621 218 : STR_FREE(pattern);
622 : }
623 : /* }}} */
624 :
625 : /* {{{ proto string ereg_replace(string pattern, string replacement, string string)
626 : Replace regular expression */
627 : PHP_FUNCTION(ereg_replace)
628 111 : {
629 111 : php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
630 111 : }
631 : /* }}} */
632 :
633 : /* {{{ proto string eregi_replace(string pattern, string replacement, string string)
634 : Case insensitive replace regular expression */
635 : PHP_FUNCTION(eregi_replace)
636 111 : {
637 111 : php_do_ereg_replace(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
638 111 : }
639 : /* }}} */
640 :
641 : /* {{{ php_split
642 : */
643 : static void php_split(INTERNAL_FUNCTION_PARAMETERS, int icase)
644 252 : {
645 252 : long count = -1;
646 : regex_t re;
647 : regmatch_t subs[1];
648 : char *spliton, *str, *strp, *endp;
649 : int spliton_len, str_len;
650 252 : int err, size, copts = 0;
651 :
652 252 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &spliton, &spliton_len, &str, &str_len, &count) == FAILURE) {
653 52 : return;
654 : }
655 :
656 200 : if (icase) {
657 101 : copts = REG_ICASE;
658 : }
659 :
660 200 : strp = str;
661 200 : endp = strp + str_len;
662 :
663 200 : err = regcomp(&re, spliton, REG_EXTENDED | copts);
664 200 : if (err) {
665 42 : php_ereg_eprint(err, &re);
666 42 : RETURN_FALSE;
667 : }
668 :
669 158 : array_init(return_value);
670 :
671 : /* churn through str, generating array entries as we go */
672 488 : while ((count == -1 || count > 1) && !(err = regexec(&re, strp, 1, subs, 0))) {
673 276 : if (subs[0].rm_so == 0 && subs[0].rm_eo) {
674 : /* match is at start of string, return empty string */
675 96 : add_next_index_stringl(return_value, "", 0, 1);
676 : /* skip ahead the length of the regex match */
677 96 : strp += subs[0].rm_eo;
678 84 : } else if (subs[0].rm_so == 0 && subs[0].rm_eo == 0) {
679 : /* No more matches */
680 : regfree(&re);
681 :
682 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Regular Expression");
683 :
684 8 : zend_hash_destroy(Z_ARRVAL_P(return_value));
685 8 : efree(Z_ARRVAL_P(return_value));
686 8 : RETURN_FALSE;
687 : } else {
688 : /* On a real match */
689 :
690 : /* make a copy of the substring */
691 76 : size = subs[0].rm_so;
692 :
693 : /* add it to the array */
694 76 : add_next_index_stringl(return_value, strp, size, 1);
695 :
696 : /* point at our new starting point */
697 76 : strp = strp + subs[0].rm_eo;
698 : }
699 :
700 : /* if we're only looking for a certain number of points,
701 : stop looking once we hit it */
702 172 : if (count != -1) {
703 48 : count--;
704 : }
705 : }
706 :
707 : /* see if we encountered an error */
708 150 : if (err && err != REG_NOMATCH) {
709 0 : php_ereg_eprint(err, &re);
710 : regfree(&re);
711 0 : zend_hash_destroy(Z_ARRVAL_P(return_value));
712 0 : efree(Z_ARRVAL_P(return_value));
713 0 : RETURN_FALSE;
714 : }
715 :
716 : /* otherwise we just have one last element to add to the array */
717 150 : size = endp - strp;
718 :
719 150 : add_next_index_stringl(return_value, strp, size, 1);
720 :
721 : regfree(&re);
722 : }
723 : /* }}} */
724 :
725 : /* {{{ proto array split(string pattern, string string [, int limit])
726 : Split string into array by regular expression */
727 : PHP_FUNCTION(split)
728 125 : {
729 125 : php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
730 125 : }
731 : /* }}} */
732 :
733 : /* {{{ proto array spliti(string pattern, string string [, int limit])
734 : Split string into array by regular expression case-insensitive */
735 :
736 : PHP_FUNCTION(spliti)
737 127 : {
738 127 : php_split(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
739 127 : }
740 :
741 : /* }}} */
742 :
743 : /* {{{ proto string sql_regcase(string string)
744 : Make regular expression for case insensitive match */
745 : PHPAPI PHP_FUNCTION(sql_regcase)
746 28 : {
747 : zval **string;
748 : char *tmp;
749 : unsigned char c;
750 : register int i, j;
751 :
752 28 : if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &string)==FAILURE) {
753 2 : WRONG_PARAM_COUNT;
754 : }
755 26 : convert_to_string_ex(string);
756 :
757 26 : tmp = safe_emalloc(Z_STRLEN_PP(string), 4, 1);
758 :
759 120 : for (i = j = 0; i < Z_STRLEN_PP(string); i++) {
760 94 : c = (unsigned char) Z_STRVAL_PP(string)[i];
761 94 : if(isalpha(c)) {
762 41 : tmp[j++] = '[';
763 41 : tmp[j++] = toupper(c);
764 41 : tmp[j++] = tolower(c);
765 41 : tmp[j++] = ']';
766 : } else {
767 53 : tmp[j++] = c;
768 : }
769 : }
770 26 : tmp[j] = 0;
771 :
772 26 : RETVAL_STRINGL(tmp, j, 1);
773 26 : efree(tmp);
774 : }
775 : /* }}} */
776 :
777 : /*
778 : * Local variables:
779 : * tab-width: 4
780 : * c-basic-offset: 4
781 : * End:
782 : * vim600: noet sw=4 ts=4 fdm=marker
783 : * vim<600: noet sw=4 ts=4
784 : */
|