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