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 : | Stig Sæther Bakken <ssb@php.net> |
17 : | Zeev Suraski <zeev@zend.com> |
18 : +----------------------------------------------------------------------+
19 : */
20 :
21 : /* $Id: string.c 290368 2009-11-06 09:02:52Z scottmac $ */
22 :
23 : /* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */
24 :
25 : #include <stdio.h>
26 : #include "php.h"
27 : #include "php_rand.h"
28 : #include "php_string.h"
29 : #include "php_variables.h"
30 : #ifdef HAVE_LOCALE_H
31 : # include <locale.h>
32 : #endif
33 : #ifdef HAVE_LANGINFO_H
34 : # include <langinfo.h>
35 : #endif
36 : #ifdef HAVE_MONETARY_H
37 : # include <monetary.h>
38 : #endif
39 : #ifdef HAVE_LIBINTL
40 : # include <libintl.h> /* For LC_MESSAGES */
41 : #endif
42 :
43 : #include "scanf.h"
44 : #include "zend_API.h"
45 : #include "zend_execute.h"
46 : #include "php_globals.h"
47 : #include "basic_functions.h"
48 : #include "php_smart_str.h"
49 : #ifdef ZTS
50 : #include "TSRM.h"
51 : #endif
52 :
53 : /* For str_getcsv() support */
54 : #include "ext/standard/file.h"
55 :
56 : #define STR_PAD_LEFT 0
57 : #define STR_PAD_RIGHT 1
58 : #define STR_PAD_BOTH 2
59 : #define PHP_PATHINFO_DIRNAME 1
60 : #define PHP_PATHINFO_BASENAME 2
61 : #define PHP_PATHINFO_EXTENSION 4
62 : #define PHP_PATHINFO_FILENAME 8
63 : #define PHP_PATHINFO_ALL (PHP_PATHINFO_DIRNAME | PHP_PATHINFO_BASENAME | PHP_PATHINFO_EXTENSION | PHP_PATHINFO_FILENAME)
64 :
65 : #define STR_STRSPN 0
66 : #define STR_STRCSPN 1
67 :
68 : /* {{{ register_string_constants
69 : */
70 : void register_string_constants(INIT_FUNC_ARGS)
71 17633 : {
72 17633 : REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
73 17633 : REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
74 17633 : REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
75 17633 : REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
76 17633 : REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
77 17633 : REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
78 17633 : REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT);
79 :
80 : #ifdef HAVE_LOCALECONV
81 : /* If last members of struct lconv equal CHAR_MAX, no grouping is done */
82 :
83 : /* This is bad, but since we are going to be hardcoding in the POSIX stuff anyway... */
84 : # ifndef HAVE_LIMITS_H
85 : # define CHAR_MAX 127
86 : # endif
87 :
88 17633 : REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
89 : #endif
90 :
91 : #ifdef HAVE_LOCALE_H
92 17633 : REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT);
93 17633 : REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT);
94 17633 : REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT);
95 17633 : REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT);
96 17633 : REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT);
97 17633 : REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT);
98 : # ifdef LC_MESSAGES
99 17633 : REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
100 : # endif
101 : #endif
102 :
103 17633 : }
104 : /* }}} */
105 :
106 : int php_tag_find(char *tag, int len, char *set);
107 :
108 : /* this is read-only, so it's ok */
109 : static char hexconvtab[] = "0123456789abcdef";
110 :
111 : /* localeconv mutex */
112 : #ifdef ZTS
113 : static MUTEX_T locale_mutex = NULL;
114 : #endif
115 :
116 : /* {{{ php_bin2hex
117 : */
118 : static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *newlen)
119 8546 : {
120 8546 : register unsigned char *result = NULL;
121 : size_t i, j;
122 :
123 8546 : result = (unsigned char *) safe_emalloc(oldlen * 2, sizeof(char), 1);
124 :
125 45217 : for (i = j = 0; i < oldlen; i++) {
126 36671 : result[j++] = hexconvtab[old[i] >> 4];
127 36671 : result[j++] = hexconvtab[old[i] & 15];
128 : }
129 8546 : result[j] = '\0';
130 :
131 8546 : if (newlen)
132 8546 : *newlen = oldlen * 2 * sizeof(char);
133 :
134 8546 : return (char *)result;
135 : }
136 : /* }}} */
137 :
138 : #ifdef HAVE_LOCALECONV
139 : /* {{{ localeconv_r
140 : * glibc's localeconv is not reentrant, so lets make it so ... sorta */
141 : PHPAPI struct lconv *localeconv_r(struct lconv *out)
142 11 : {
143 : struct lconv *res;
144 :
145 : # ifdef ZTS
146 : tsrm_mutex_lock( locale_mutex );
147 : # endif
148 :
149 : /* localeconv doesn't return an error condition */
150 11 : res = localeconv();
151 :
152 11 : *out = *res;
153 :
154 : # ifdef ZTS
155 : tsrm_mutex_unlock( locale_mutex );
156 : # endif
157 :
158 11 : return out;
159 : }
160 : /* }}} */
161 :
162 : # ifdef ZTS
163 : /* {{{ PHP_MINIT_FUNCTION
164 : */
165 : PHP_MINIT_FUNCTION(localeconv)
166 : {
167 : locale_mutex = tsrm_mutex_alloc();
168 : return SUCCESS;
169 : }
170 : /* }}} */
171 :
172 : /* {{{ PHP_MSHUTDOWN_FUNCTION
173 : */
174 : PHP_MSHUTDOWN_FUNCTION(localeconv)
175 : {
176 : tsrm_mutex_free( locale_mutex );
177 : locale_mutex = NULL;
178 : return SUCCESS;
179 : }
180 : /* }}} */
181 : # endif
182 : #endif
183 :
184 : /* {{{ proto string bin2hex(string data)
185 : Converts the binary representation of data to hex */
186 : PHP_FUNCTION(bin2hex)
187 8552 : {
188 : char *result, *data;
189 : size_t newlen;
190 : int datalen;
191 :
192 8552 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &data, &datalen) == FAILURE) {
193 6 : return;
194 : }
195 :
196 8546 : result = php_bin2hex((unsigned char *)data, datalen, &newlen);
197 :
198 8546 : if (!result) {
199 0 : RETURN_FALSE;
200 : }
201 :
202 8546 : RETURN_STRINGL(result, newlen, 0);
203 : }
204 : /* }}} */
205 :
206 : static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
207 13045 : {
208 : char *s11, *s22;
209 : int len1, len2;
210 13045 : long start = 0, len = 0;
211 :
212 13045 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &s11, &len1,
213 : &s22, &len2, &start, &len) == FAILURE) {
214 144 : return;
215 : }
216 :
217 12901 : if (ZEND_NUM_ARGS() < 4) {
218 4086 : len = len1;
219 : }
220 :
221 : /* look at substr() function for more information */
222 :
223 12901 : if (start < 0) {
224 4336 : start += len1;
225 4336 : if (start < 0) {
226 2306 : start = 0;
227 : }
228 8565 : } else if (start > len1) {
229 2662 : RETURN_FALSE;
230 : }
231 :
232 10239 : if (len < 0) {
233 2227 : len += (len1 - start);
234 2227 : if (len < 0) {
235 1286 : len = 0;
236 : }
237 : }
238 :
239 10239 : if (len > len1 - start) {
240 3429 : len = len1 - start;
241 : }
242 :
243 10239 : if(len == 0) {
244 3625 : RETURN_LONG(0);
245 : }
246 :
247 6614 : if (behavior == STR_STRSPN) {
248 3381 : RETURN_LONG(php_strspn(s11 + start /*str1_start*/,
249 : s22 /*str2_start*/,
250 : s11 + start + len /*str1_end*/,
251 : s22 + len2 /*str2_end*/));
252 3233 : } else if (behavior == STR_STRCSPN) {
253 3233 : RETURN_LONG(php_strcspn(s11 + start /*str1_start*/,
254 : s22 /*str2_start*/,
255 : s11 + start + len /*str1_end*/,
256 : s22 + len2 /*str2_end*/));
257 : }
258 :
259 : }
260 : /* }}} */
261 :
262 : /* {{{ proto int strspn(string str, string mask [, start [, len]])
263 : Finds length of initial segment consisting entirely of characters found in mask. If start or/and length is provided works like strspn(substr($s,$start,$len),$good_chars) */
264 : PHP_FUNCTION(strspn)
265 6718 : {
266 6718 : php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN);
267 6718 : }
268 : /* }}} */
269 :
270 : /* {{{ proto int strcspn(string str, string mask [, start [, len]])
271 : Finds length of initial segment consisting entirely of characters not found in mask. If start or/and length is provide works like strcspn(substr($s,$start,$len),$bad_chars) */
272 : PHP_FUNCTION(strcspn)
273 6327 : {
274 6327 : php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN);
275 6327 : }
276 : /* }}} */
277 :
278 : /* {{{ PHP_MINIT_FUNCTION(nl_langinfo) */
279 : #if HAVE_NL_LANGINFO
280 : PHP_MINIT_FUNCTION(nl_langinfo)
281 17633 : {
282 : #define REGISTER_NL_LANGINFO_CONSTANT(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS | CONST_PERSISTENT)
283 : #ifdef ABDAY_1
284 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
285 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
286 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
287 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
288 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
289 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
290 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
291 : #endif
292 : #ifdef DAY_1
293 17633 : REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
294 17633 : REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
295 17633 : REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
296 17633 : REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
297 17633 : REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
298 17633 : REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
299 17633 : REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
300 : #endif
301 : #ifdef ABMON_1
302 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
303 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
304 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
305 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
306 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
307 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
308 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
309 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
310 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
311 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
312 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
313 17633 : REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
314 : #endif
315 : #ifdef MON_1
316 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_1);
317 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_2);
318 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_3);
319 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_4);
320 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_5);
321 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_6);
322 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_7);
323 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_8);
324 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_9);
325 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_10);
326 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_11);
327 17633 : REGISTER_NL_LANGINFO_CONSTANT(MON_12);
328 : #endif
329 : #ifdef AM_STR
330 17633 : REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
331 : #endif
332 : #ifdef PM_STR
333 17633 : REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
334 : #endif
335 : #ifdef D_T_FMT
336 17633 : REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
337 : #endif
338 : #ifdef D_FMT
339 17633 : REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
340 : #endif
341 : #ifdef T_FMT
342 17633 : REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
343 : #endif
344 : #ifdef T_FMT_AMPM
345 17633 : REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
346 : #endif
347 : #ifdef ERA
348 17633 : REGISTER_NL_LANGINFO_CONSTANT(ERA);
349 : #endif
350 : #ifdef ERA_YEAR
351 : REGISTER_NL_LANGINFO_CONSTANT(ERA_YEAR);
352 : #endif
353 : #ifdef ERA_D_T_FMT
354 17633 : REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
355 : #endif
356 : #ifdef ERA_D_FMT
357 17633 : REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
358 : #endif
359 : #ifdef ERA_T_FMT
360 17633 : REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
361 : #endif
362 : #ifdef ALT_DIGITS
363 17633 : REGISTER_NL_LANGINFO_CONSTANT(ALT_DIGITS);
364 : #endif
365 : #ifdef INT_CURR_SYMBOL
366 : REGISTER_NL_LANGINFO_CONSTANT(INT_CURR_SYMBOL);
367 : #endif
368 : #ifdef CURRENCY_SYMBOL
369 : REGISTER_NL_LANGINFO_CONSTANT(CURRENCY_SYMBOL);
370 : #endif
371 : #ifdef CRNCYSTR
372 17633 : REGISTER_NL_LANGINFO_CONSTANT(CRNCYSTR);
373 : #endif
374 : #ifdef MON_DECIMAL_POINT
375 : REGISTER_NL_LANGINFO_CONSTANT(MON_DECIMAL_POINT);
376 : #endif
377 : #ifdef MON_THOUSANDS_SEP
378 : REGISTER_NL_LANGINFO_CONSTANT(MON_THOUSANDS_SEP);
379 : #endif
380 : #ifdef MON_GROUPING
381 : REGISTER_NL_LANGINFO_CONSTANT(MON_GROUPING);
382 : #endif
383 : #ifdef POSITIVE_SIGN
384 : REGISTER_NL_LANGINFO_CONSTANT(POSITIVE_SIGN);
385 : #endif
386 : #ifdef NEGATIVE_SIGN
387 : REGISTER_NL_LANGINFO_CONSTANT(NEGATIVE_SIGN);
388 : #endif
389 : #ifdef INT_FRAC_DIGITS
390 : REGISTER_NL_LANGINFO_CONSTANT(INT_FRAC_DIGITS);
391 : #endif
392 : #ifdef FRAC_DIGITS
393 : REGISTER_NL_LANGINFO_CONSTANT(FRAC_DIGITS);
394 : #endif
395 : #ifdef P_CS_PRECEDES
396 : REGISTER_NL_LANGINFO_CONSTANT(P_CS_PRECEDES);
397 : #endif
398 : #ifdef P_SEP_BY_SPACE
399 : REGISTER_NL_LANGINFO_CONSTANT(P_SEP_BY_SPACE);
400 : #endif
401 : #ifdef N_CS_PRECEDES
402 : REGISTER_NL_LANGINFO_CONSTANT(N_CS_PRECEDES);
403 : #endif
404 : #ifdef N_SEP_BY_SPACE
405 : REGISTER_NL_LANGINFO_CONSTANT(N_SEP_BY_SPACE);
406 : #endif
407 : #ifdef P_SIGN_POSN
408 : REGISTER_NL_LANGINFO_CONSTANT(P_SIGN_POSN);
409 : #endif
410 : #ifdef N_SIGN_POSN
411 : REGISTER_NL_LANGINFO_CONSTANT(N_SIGN_POSN);
412 : #endif
413 : #ifdef DECIMAL_POINT
414 : REGISTER_NL_LANGINFO_CONSTANT(DECIMAL_POINT);
415 : #endif
416 : #ifdef RADIXCHAR
417 17633 : REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
418 : #endif
419 : #ifdef THOUSANDS_SEP
420 : REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
421 : #endif
422 : #ifdef THOUSEP
423 17633 : REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
424 : #endif
425 : #ifdef GROUPING
426 : REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
427 : #endif
428 : #ifdef YESEXPR
429 17633 : REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
430 : #endif
431 : #ifdef NOEXPR
432 17633 : REGISTER_NL_LANGINFO_CONSTANT(NOEXPR);
433 : #endif
434 : #ifdef YESSTR
435 : REGISTER_NL_LANGINFO_CONSTANT(YESSTR);
436 : #endif
437 : #ifdef NOSTR
438 : REGISTER_NL_LANGINFO_CONSTANT(NOSTR);
439 : #endif
440 : #ifdef CODESET
441 17633 : REGISTER_NL_LANGINFO_CONSTANT(CODESET);
442 : #endif
443 : #undef REGISTER_NL_LANGINFO_CONSTANT
444 17633 : return SUCCESS;
445 : }
446 : /* }}} */
447 :
448 : /* {{{ proto string nl_langinfo(int item)
449 : Query language and locale information */
450 : PHP_FUNCTION(nl_langinfo)
451 28 : {
452 : long item;
453 : char *value;
454 :
455 28 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &item) == FAILURE) {
456 7 : return;
457 : }
458 :
459 21 : switch(item) { /* {{{ */
460 : #ifdef ABDAY_1
461 : case ABDAY_1:
462 : case ABDAY_2:
463 : case ABDAY_3:
464 : case ABDAY_4:
465 : case ABDAY_5:
466 : case ABDAY_6:
467 : case ABDAY_7:
468 : #endif
469 : #ifdef DAY_1
470 : case DAY_1:
471 : case DAY_2:
472 : case DAY_3:
473 : case DAY_4:
474 : case DAY_5:
475 : case DAY_6:
476 : case DAY_7:
477 : #endif
478 : #ifdef ABMON_1
479 : case ABMON_1:
480 : case ABMON_2:
481 : case ABMON_3:
482 : case ABMON_4:
483 : case ABMON_5:
484 : case ABMON_6:
485 : case ABMON_7:
486 : case ABMON_8:
487 : case ABMON_9:
488 : case ABMON_10:
489 : case ABMON_11:
490 : case ABMON_12:
491 : #endif
492 : #ifdef MON_1
493 : case MON_1:
494 : case MON_2:
495 : case MON_3:
496 : case MON_4:
497 : case MON_5:
498 : case MON_6:
499 : case MON_7:
500 : case MON_8:
501 : case MON_9:
502 : case MON_10:
503 : case MON_11:
504 : case MON_12:
505 : #endif
506 : #ifdef AM_STR
507 : case AM_STR:
508 : #endif
509 : #ifdef PM_STR
510 : case PM_STR:
511 : #endif
512 : #ifdef D_T_FMT
513 : case D_T_FMT:
514 : #endif
515 : #ifdef D_FMT
516 : case D_FMT:
517 : #endif
518 : #ifdef T_FMT
519 : case T_FMT:
520 : #endif
521 : #ifdef T_FMT_AMPM
522 : case T_FMT_AMPM:
523 : #endif
524 : #ifdef ERA
525 : case ERA:
526 : #endif
527 : #ifdef ERA_YEAR
528 : case ERA_YEAR:
529 : #endif
530 : #ifdef ERA_D_T_FMT
531 : case ERA_D_T_FMT:
532 : #endif
533 : #ifdef ERA_D_FMT
534 : case ERA_D_FMT:
535 : #endif
536 : #ifdef ERA_T_FMT
537 : case ERA_T_FMT:
538 : #endif
539 : #ifdef ALT_DIGITS
540 : case ALT_DIGITS:
541 : #endif
542 : #ifdef INT_CURR_SYMBOL
543 : case INT_CURR_SYMBOL:
544 : #endif
545 : #ifdef CURRENCY_SYMBOL
546 : case CURRENCY_SYMBOL:
547 : #endif
548 : #ifdef CRNCYSTR
549 : case CRNCYSTR:
550 : #endif
551 : #ifdef MON_DECIMAL_POINT
552 : case MON_DECIMAL_POINT:
553 : #endif
554 : #ifdef MON_THOUSANDS_SEP
555 : case MON_THOUSANDS_SEP:
556 : #endif
557 : #ifdef MON_GROUPING
558 : case MON_GROUPING:
559 : #endif
560 : #ifdef POSITIVE_SIGN
561 : case POSITIVE_SIGN:
562 : #endif
563 : #ifdef NEGATIVE_SIGN
564 : case NEGATIVE_SIGN:
565 : #endif
566 : #ifdef INT_FRAC_DIGITS
567 : case INT_FRAC_DIGITS:
568 : #endif
569 : #ifdef FRAC_DIGITS
570 : case FRAC_DIGITS:
571 : #endif
572 : #ifdef P_CS_PRECEDES
573 : case P_CS_PRECEDES:
574 : #endif
575 : #ifdef P_SEP_BY_SPACE
576 : case P_SEP_BY_SPACE:
577 : #endif
578 : #ifdef N_CS_PRECEDES
579 : case N_CS_PRECEDES:
580 : #endif
581 : #ifdef N_SEP_BY_SPACE
582 : case N_SEP_BY_SPACE:
583 : #endif
584 : #ifdef P_SIGN_POSN
585 : case P_SIGN_POSN:
586 : #endif
587 : #ifdef N_SIGN_POSN
588 : case N_SIGN_POSN:
589 : #endif
590 : #ifdef DECIMAL_POINT
591 : case DECIMAL_POINT:
592 : #elif defined(RADIXCHAR)
593 : case RADIXCHAR:
594 : #endif
595 : #ifdef THOUSANDS_SEP
596 : case THOUSANDS_SEP:
597 : #elif defined(THOUSEP)
598 : case THOUSEP:
599 : #endif
600 : #ifdef GROUPING
601 : case GROUPING:
602 : #endif
603 : #ifdef YESEXPR
604 : case YESEXPR:
605 : #endif
606 : #ifdef NOEXPR
607 : case NOEXPR:
608 : #endif
609 : #ifdef YESSTR
610 : case YESSTR:
611 : #endif
612 : #ifdef NOSTR
613 : case NOSTR:
614 : #endif
615 : #ifdef CODESET
616 : case CODESET:
617 : #endif
618 : break;
619 : default:
620 16 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Item '%ld' is not valid", item);
621 16 : RETURN_FALSE;
622 : }
623 : /* }}} */
624 :
625 5 : value = nl_langinfo(item);
626 5 : if (value == NULL) {
627 0 : RETURN_FALSE;
628 : } else {
629 5 : RETURN_STRING(value, 1);
630 : }
631 : }
632 : #endif
633 : /* }}} */
634 :
635 : #ifdef HAVE_STRCOLL
636 : /* {{{ proto int strcoll(string str1, string str2)
637 : Compares two strings using the current locale */
638 : PHP_FUNCTION(strcoll)
639 5 : {
640 : char *s1, *s2;
641 : int s1len, s2len;
642 :
643 5 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &s1, &s1len, &s2, &s2len) == FAILURE) {
644 4 : return;
645 : }
646 :
647 1 : RETURN_LONG(strcoll((const char *) s1,
648 : (const char *) s2));
649 : }
650 : /* }}} */
651 : #endif
652 :
653 : /* {{{ php_charmask
654 : * Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
655 : * it needs to be incrementing.
656 : * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
657 : */
658 : static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC)
659 843013 : {
660 : unsigned char *end;
661 : unsigned char c;
662 843013 : int result = SUCCESS;
663 :
664 843013 : memset(mask, 0, 256);
665 5894912 : for (end = input+len; input < end; input++) {
666 5051899 : c=*input;
667 5051924 : if ((input+3 < end) && input[1] == '.' && input[2] == '.'
668 : && input[3] >= c) {
669 25 : memset(mask+c, 1, input[3] - c + 1);
670 25 : input+=3;
671 5051874 : } else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
672 : /* Error, try to be as helpful as possible:
673 : (a range ending/starting with '.' won't be captured here) */
674 14 : if (end-len >= input) { /* there was no 'left' char */
675 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
676 3 : result = FAILURE;
677 3 : continue;
678 : }
679 11 : if (input+2 >= end) { /* there is no 'right' char */
680 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
681 3 : result = FAILURE;
682 3 : continue;
683 : }
684 8 : if (input[-1] > input[2]) { /* wrong order */
685 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
686 5 : result = FAILURE;
687 5 : continue;
688 : }
689 : /* FIXME: better error (a..b..c is the only left possibility?) */
690 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range");
691 3 : result = FAILURE;
692 3 : continue;
693 : } else {
694 5051860 : mask[c]=1;
695 : }
696 : }
697 843013 : return result;
698 : }
699 : /* }}} */
700 :
701 : /* {{{ php_trim()
702 : * mode 1 : trim left
703 : * mode 2 : trim right
704 : * mode 3 : trim left and right
705 : * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
706 : */
707 : PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC)
708 841597 : {
709 : register int i;
710 841597 : int trimmed = 0;
711 : char mask[256];
712 :
713 841597 : if (what) {
714 242 : php_charmask((unsigned char*)what, what_len, mask TSRMLS_CC);
715 : } else {
716 841355 : php_charmask((unsigned char*)" \n\r\t\v\0", 6, mask TSRMLS_CC);
717 : }
718 :
719 841597 : if (mode & 1) {
720 845343 : for (i = 0; i < len; i++) {
721 731527 : if (mask[(unsigned char)c[i]]) {
722 3937 : trimmed++;
723 : } else {
724 727590 : break;
725 : }
726 : }
727 841406 : len -= trimmed;
728 841406 : c += trimmed;
729 : }
730 841597 : if (mode & 2) {
731 866595 : for (i = len - 1; i >= 0; i--) {
732 768485 : if (mask[(unsigned char)c[i]]) {
733 41538 : len--;
734 : } else {
735 726947 : break;
736 : }
737 : }
738 : }
739 :
740 841597 : if (return_value) {
741 841592 : RETVAL_STRINGL(c, len, 1);
742 : } else {
743 5 : return estrndup(c, len);
744 : }
745 841592 : return "";
746 : }
747 : /* }}} */
748 :
749 : /* {{{ php_do_trim
750 : * Base for trim(), rtrim() and ltrim() functions.
751 : */
752 : static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
753 824011 : {
754 : char *str;
755 824011 : char *what = NULL;
756 824011 : int str_len, what_len = 0;
757 :
758 824011 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &what, &what_len) == FAILURE) {
759 57 : return;
760 : }
761 :
762 823954 : php_trim(str, str_len, what, what_len, return_value, mode TSRMLS_CC);
763 : }
764 : /* }}} */
765 :
766 : /* {{{ proto string trim(string str [, string character_mask])
767 : Strips whitespace from the beginning and end of a string */
768 : PHP_FUNCTION(trim)
769 807236 : {
770 807236 : php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
771 807236 : }
772 : /* }}} */
773 :
774 : /* {{{ proto string rtrim(string str [, string character_mask])
775 : Removes trailing whitespace */
776 : PHP_FUNCTION(rtrim)
777 223 : {
778 223 : php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
779 223 : }
780 : /* }}} */
781 :
782 : /* {{{ proto string ltrim(string str [, string character_mask])
783 : Strips whitespace from the beginning of a string */
784 : PHP_FUNCTION(ltrim)
785 16552 : {
786 16552 : php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
787 16552 : }
788 : /* }}} */
789 :
790 : /* {{{ proto string wordwrap(string str [, int width [, string break [, boolean cut]]])
791 : Wraps buffer to selected number of characters using string break char */
792 : PHP_FUNCTION(wordwrap)
793 357 : {
794 357 : const char *text, *breakchar = "\n";
795 : char *newtext;
796 357 : int textlen, breakcharlen = 1, newtextlen, chk;
797 : size_t alloced;
798 357 : long current = 0, laststart = 0, lastspace = 0;
799 357 : long linelength = 75;
800 357 : zend_bool docut = 0;
801 :
802 357 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lsb", &text, &textlen, &linelength, &breakchar, &breakcharlen, &docut) == FAILURE) {
803 108 : return;
804 : }
805 :
806 249 : if (textlen == 0) {
807 40 : RETURN_EMPTY_STRING();
808 : }
809 :
810 209 : if (breakcharlen == 0) {
811 25 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Break string cannot be empty");
812 25 : RETURN_FALSE;
813 : }
814 :
815 184 : if (linelength == 0 && docut) {
816 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't force cut when width is zero");
817 8 : RETURN_FALSE;
818 : }
819 :
820 : /* Special case for a single-character break as it needs no
821 : additional storage space */
822 176 : if (breakcharlen == 1 && !docut) {
823 50 : newtext = estrndup(text, textlen);
824 :
825 50 : laststart = lastspace = 0;
826 1009 : for (current = 0; current < textlen; current++) {
827 959 : if (text[current] == breakchar[0]) {
828 4 : laststart = lastspace = current + 1;
829 955 : } else if (text[current] == ' ') {
830 72 : if (current - laststart >= linelength) {
831 30 : newtext[current] = breakchar[0];
832 30 : laststart = current + 1;
833 : }
834 72 : lastspace = current;
835 883 : } else if (current - laststart >= linelength && laststart != lastspace) {
836 220 : newtext[lastspace] = breakchar[0];
837 220 : laststart = lastspace + 1;
838 : }
839 : }
840 :
841 50 : RETURN_STRINGL(newtext, textlen, 0);
842 : } else {
843 : /* Multiple character line break or forced cut */
844 126 : if (linelength > 0) {
845 102 : chk = (int)(textlen/linelength + 1);
846 102 : newtext = safe_emalloc(chk, breakcharlen, textlen + 1);
847 102 : alloced = textlen + chk * breakcharlen + 1;
848 : } else {
849 24 : chk = textlen;
850 24 : alloced = textlen * (breakcharlen + 1) + 1;
851 24 : newtext = safe_emalloc(textlen, (breakcharlen + 1), 1);
852 : }
853 :
854 : /* now keep track of the actual new text length */
855 126 : newtextlen = 0;
856 :
857 126 : laststart = lastspace = 0;
858 2742 : for (current = 0; current < textlen; current++) {
859 2616 : if (chk <= 0) {
860 6 : alloced += (int) (((textlen - current + 1)/linelength + 1) * breakcharlen) + 1;
861 6 : newtext = erealloc(newtext, alloced);
862 6 : chk = (int) ((textlen - current)/linelength) + 1;
863 : }
864 : /* when we hit an existing break, copy to new buffer, and
865 : * fix up laststart and lastspace */
866 2630 : if (text[current] == breakchar[0]
867 : && current + breakcharlen < textlen
868 : && !strncmp(text+current, breakchar, breakcharlen)) {
869 14 : memcpy(newtext+newtextlen, text+laststart, current-laststart+breakcharlen);
870 14 : newtextlen += current-laststart+breakcharlen;
871 14 : current += breakcharlen - 1;
872 14 : laststart = lastspace = current + 1;
873 14 : chk--;
874 : }
875 : /* if it is a space, check if it is at the line boundary,
876 : * copy and insert a break, or just keep track of it */
877 2602 : else if (text[current] == ' ') {
878 214 : if (current - laststart >= linelength) {
879 85 : memcpy(newtext+newtextlen, text+laststart, current-laststart);
880 85 : newtextlen += current - laststart;
881 85 : memcpy(newtext+newtextlen, breakchar, breakcharlen);
882 85 : newtextlen += breakcharlen;
883 85 : laststart = current + 1;
884 85 : chk--;
885 : }
886 214 : lastspace = current;
887 : }
888 : /* if we are cutting, and we've accumulated enough
889 : * characters, and we haven't see a space for this line,
890 : * copy and insert a break. */
891 2556 : else if (current - laststart >= linelength
892 : && docut && laststart >= lastspace) {
893 168 : memcpy(newtext+newtextlen, text+laststart, current-laststart);
894 168 : newtextlen += current - laststart;
895 168 : memcpy(newtext+newtextlen, breakchar, breakcharlen);
896 168 : newtextlen += breakcharlen;
897 168 : laststart = lastspace = current;
898 168 : chk--;
899 : }
900 : /* if the current word puts us over the linelength, copy
901 : * back up until the last space, insert a break, and move
902 : * up the laststart */
903 2220 : else if (current - laststart >= linelength
904 : && laststart < lastspace) {
905 107 : memcpy(newtext+newtextlen, text+laststart, lastspace-laststart);
906 107 : newtextlen += lastspace - laststart;
907 107 : memcpy(newtext+newtextlen, breakchar, breakcharlen);
908 107 : newtextlen += breakcharlen;
909 107 : laststart = lastspace = lastspace + 1;
910 107 : chk--;
911 : }
912 : }
913 :
914 : /* copy over any stragglers */
915 126 : if (laststart != current) {
916 126 : memcpy(newtext+newtextlen, text+laststart, current-laststart);
917 126 : newtextlen += current - laststart;
918 : }
919 :
920 126 : newtext[newtextlen] = '\0';
921 : /* free unused memory */
922 126 : newtext = erealloc(newtext, newtextlen+1);
923 :
924 126 : RETURN_STRINGL(newtext, newtextlen, 0);
925 : }
926 : }
927 : /* }}} */
928 :
929 : /* {{{ php_explode
930 : */
931 : PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, long limit)
932 483305 : {
933 : char *p1, *p2, *endp;
934 :
935 483305 : endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
936 :
937 483305 : p1 = Z_STRVAL_P(str);
938 483305 : p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
939 :
940 483305 : if (p2 == NULL) {
941 68 : add_next_index_stringl(return_value, p1, Z_STRLEN_P(str), 1);
942 : } else {
943 : do {
944 494115 : add_next_index_stringl(return_value, p1, p2 - p1, 1);
945 494115 : p1 = p2 + Z_STRLEN_P(delim);
946 : } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL &&
947 494115 : --limit > 1);
948 :
949 483237 : if (p1 <= endp)
950 483237 : add_next_index_stringl(return_value, p1, endp-p1, 1);
951 : }
952 483305 : }
953 : /* }}} */
954 :
955 : /* {{{ php_explode_negative_limit
956 : */
957 : PHPAPI void php_explode_negative_limit(zval *delim, zval *str, zval *return_value, long limit)
958 22 : {
959 : #define EXPLODE_ALLOC_STEP 64
960 : char *p1, *p2, *endp;
961 :
962 22 : endp = Z_STRVAL_P(str) + Z_STRLEN_P(str);
963 :
964 22 : p1 = Z_STRVAL_P(str);
965 22 : p2 = php_memnstr(Z_STRVAL_P(str), Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp);
966 :
967 22 : if (p2 == NULL) {
968 : /*
969 : do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0
970 : by doing nothing we return empty array
971 : */
972 : } else {
973 21 : int allocated = EXPLODE_ALLOC_STEP, found = 0;
974 : long i, to_return;
975 21 : char **positions = emalloc(allocated * sizeof(char *));
976 :
977 21 : positions[found++] = p1;
978 : do {
979 114 : if (found >= allocated) {
980 0 : allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */
981 0 : positions = erealloc(positions, allocated*sizeof(char *));
982 : }
983 114 : positions[found++] = p1 = p2 + Z_STRLEN_P(delim);
984 114 : } while ((p2 = php_memnstr(p1, Z_STRVAL_P(delim), Z_STRLEN_P(delim), endp)) != NULL);
985 :
986 21 : to_return = limit + found;
987 : /* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
988 116 : for (i = 0;i < to_return;i++) { /* this checks also for to_return > 0 */
989 95 : add_next_index_stringl(return_value, positions[i],
990 : (positions[i+1] - Z_STRLEN_P(delim)) - positions[i],
991 : 1
992 : );
993 : }
994 21 : efree(positions);
995 : }
996 : #undef EXPLODE_ALLOC_STEP
997 22 : }
998 : /* }}} */
999 :
1000 : /* {{{ proto array explode(string separator, string str [, int limit])
1001 : Splits a string on string separator and return array of components. If limit is positive only limit number of components is returned. If limit is negative all components except the last abs(limit) are returned. */
1002 : PHP_FUNCTION(explode)
1003 483419 : {
1004 : char *str, *delim;
1005 483419 : int str_len = 0, delim_len = 0;
1006 483419 : long limit = LONG_MAX; /* No limit */
1007 : zval zdelim, zstr;
1008 :
1009 483419 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|l", &delim, &delim_len, &str, &str_len, &limit) == FAILURE) {
1010 22 : return;
1011 : }
1012 :
1013 483397 : if (delim_len == 0) {
1014 28 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
1015 28 : RETURN_FALSE;
1016 : }
1017 :
1018 483369 : array_init(return_value);
1019 :
1020 483369 : if (str_len == 0) {
1021 12 : if (limit >= 0) {
1022 11 : add_next_index_stringl(return_value, "", sizeof("") - 1, 1);
1023 : }
1024 12 : return;
1025 : }
1026 :
1027 483357 : ZVAL_STRINGL(&zstr, str, str_len, 0);
1028 483357 : ZVAL_STRINGL(&zdelim, delim, delim_len, 0);
1029 483357 : if (limit > 1) {
1030 483305 : php_explode(&zdelim, &zstr, return_value, limit);
1031 52 : } else if (limit < 0) {
1032 22 : php_explode_negative_limit(&zdelim, &zstr, return_value, limit);
1033 : } else {
1034 30 : add_index_stringl(return_value, 0, str, str_len, 1);
1035 : }
1036 : }
1037 : /* }}} */
1038 :
1039 : /* {{{ proto string join(array src, string glue)
1040 : An alias for implode */
1041 : /* }}} */
1042 :
1043 : /* {{{ php_implode
1044 : */
1045 : PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value TSRMLS_DC)
1046 90795 : {
1047 : zval **tmp;
1048 : HashPosition pos;
1049 90795 : smart_str implstr = {0};
1050 90795 : int numelems, i = 0;
1051 : zval tmp_val;
1052 : int str_len;
1053 :
1054 90795 : numelems = zend_hash_num_elements(Z_ARRVAL_P(arr));
1055 :
1056 90795 : if (numelems == 0) {
1057 48 : RETURN_EMPTY_STRING();
1058 : }
1059 :
1060 90747 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(arr), &pos);
1061 :
1062 546289 : while (zend_hash_get_current_data_ex(Z_ARRVAL_P(arr), (void **) &tmp, &pos) == SUCCESS) {
1063 364795 : switch ((*tmp)->type) {
1064 : case IS_STRING:
1065 3989 : smart_str_appendl(&implstr, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp));
1066 3989 : break;
1067 :
1068 : case IS_LONG: {
1069 : char stmp[MAX_LENGTH_OF_LONG + 1];
1070 360647 : str_len = slprintf(stmp, sizeof(stmp), "%ld", Z_LVAL_PP(tmp));
1071 360647 : smart_str_appendl(&implstr, stmp, str_len);
1072 : }
1073 360647 : break;
1074 :
1075 : case IS_BOOL:
1076 47 : if (Z_LVAL_PP(tmp) == 1) {
1077 23 : smart_str_appendl(&implstr, "1", sizeof("1")-1);
1078 : }
1079 47 : break;
1080 :
1081 : case IS_NULL:
1082 66 : break;
1083 :
1084 : case IS_DOUBLE: {
1085 : char *stmp;
1086 24 : str_len = spprintf(&stmp, 0, "%.*G", (int) EG(precision), Z_DVAL_PP(tmp));
1087 24 : smart_str_appendl(&implstr, stmp, str_len);
1088 24 : efree(stmp);
1089 : }
1090 24 : break;
1091 :
1092 : case IS_OBJECT: {
1093 : int copy;
1094 : zval expr;
1095 6 : zend_make_printable_zval(*tmp, &expr, ©);
1096 6 : smart_str_appendl(&implstr, Z_STRVAL(expr), Z_STRLEN(expr));
1097 6 : if (copy) {
1098 6 : zval_dtor(&expr);
1099 : }
1100 : }
1101 6 : break;
1102 :
1103 : default:
1104 16 : tmp_val = **tmp;
1105 16 : zval_copy_ctor(&tmp_val);
1106 16 : convert_to_string(&tmp_val);
1107 16 : smart_str_appendl(&implstr, Z_STRVAL(tmp_val), Z_STRLEN(tmp_val));
1108 16 : zval_dtor(&tmp_val);
1109 : break;
1110 :
1111 : }
1112 :
1113 364795 : if (++i != numelems) {
1114 274048 : smart_str_appendl(&implstr, Z_STRVAL_P(delim), Z_STRLEN_P(delim));
1115 : }
1116 364795 : zend_hash_move_forward_ex(Z_ARRVAL_P(arr), &pos);
1117 : }
1118 90747 : smart_str_0(&implstr);
1119 :
1120 90747 : if (implstr.len) {
1121 90742 : RETURN_STRINGL(implstr.c, implstr.len, 0);
1122 : } else {
1123 5 : smart_str_free(&implstr);
1124 5 : RETURN_EMPTY_STRING();
1125 : }
1126 : }
1127 : /* }}} */
1128 :
1129 : /* {{{ proto string implode([string glue,] array pieces)
1130 : Joins array elements placing glue string between items and return one string */
1131 : PHP_FUNCTION(implode)
1132 90829 : {
1133 90829 : zval **arg1 = NULL, **arg2 = NULL, *delim, *arr;
1134 :
1135 90829 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|Z", &arg1, &arg2) == FAILURE) {
1136 4 : return;
1137 : }
1138 :
1139 90825 : if (arg2 == NULL) {
1140 8 : if (Z_TYPE_PP(arg1) != IS_ARRAY) {
1141 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument must be an array");
1142 3 : return;
1143 : }
1144 :
1145 5 : MAKE_STD_ZVAL(delim);
1146 : #define _IMPL_EMPTY ""
1147 5 : ZVAL_STRINGL(delim, _IMPL_EMPTY, sizeof(_IMPL_EMPTY) - 1, 0);
1148 :
1149 5 : SEPARATE_ZVAL(arg1);
1150 5 : arr = *arg1;
1151 : } else {
1152 90817 : if (Z_TYPE_PP(arg1) == IS_ARRAY) {
1153 36 : arr = *arg1;
1154 36 : convert_to_string_ex(arg2);
1155 36 : delim = *arg2;
1156 90781 : } else if (Z_TYPE_PP(arg2) == IS_ARRAY) {
1157 90754 : arr = *arg2;
1158 90754 : convert_to_string_ex(arg1);
1159 90754 : delim = *arg1;
1160 : } else {
1161 27 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid arguments passed");
1162 27 : return;
1163 : }
1164 : }
1165 :
1166 90795 : php_implode(delim, arr, return_value TSRMLS_CC);
1167 :
1168 90795 : if (arg2 == NULL) {
1169 5 : FREE_ZVAL(delim);
1170 : }
1171 : }
1172 : /* }}} */
1173 :
1174 : #define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
1175 :
1176 : /* {{{ proto string strtok([string str,] string token)
1177 : Tokenize a string */
1178 : PHP_FUNCTION(strtok)
1179 344 : {
1180 344 : char *str, *tok = NULL;
1181 344 : int str_len, tok_len = 0;
1182 : zval *zv;
1183 :
1184 : char *token;
1185 : char *token_end;
1186 : char *p;
1187 : char *pe;
1188 344 : int skipped = 0;
1189 :
1190 344 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &tok, &tok_len) == FAILURE) {
1191 14 : return;
1192 : }
1193 :
1194 330 : if (ZEND_NUM_ARGS() == 1) {
1195 241 : tok = str;
1196 241 : tok_len = str_len;
1197 : } else {
1198 89 : if (BG(strtok_zval)) {
1199 80 : zval_ptr_dtor(&BG(strtok_zval));
1200 : }
1201 89 : MAKE_STD_ZVAL(zv);
1202 89 : ZVAL_STRINGL(zv, str, str_len, 1);
1203 :
1204 89 : BG(strtok_zval) = zv;
1205 89 : BG(strtok_last) = BG(strtok_string) = Z_STRVAL_P(zv);
1206 89 : BG(strtok_len) = str_len;
1207 : }
1208 :
1209 330 : p = BG(strtok_last); /* Where we start to search */
1210 330 : pe = BG(strtok_string) + BG(strtok_len);
1211 :
1212 330 : if (!p || p >= pe) {
1213 160 : RETURN_FALSE;
1214 : }
1215 :
1216 170 : token = tok;
1217 170 : token_end = token + tok_len;
1218 :
1219 987 : while (token < token_end) {
1220 647 : STRTOK_TABLE(token++) = 1;
1221 : }
1222 :
1223 : /* Skip leading delimiters */
1224 427 : while (STRTOK_TABLE(p)) {
1225 99 : if (++p >= pe) {
1226 : /* no other chars left */
1227 12 : BG(strtok_last) = NULL;
1228 12 : RETVAL_FALSE;
1229 12 : goto restore;
1230 : }
1231 87 : skipped++;
1232 : }
1233 :
1234 : /* We know at this place that *p is no delimiter, so skip it */
1235 1487 : while (++p < pe) {
1236 1278 : if (STRTOK_TABLE(p)) {
1237 107 : goto return_token;
1238 : }
1239 : }
1240 :
1241 51 : if (p - BG(strtok_last)) {
1242 158 : return_token:
1243 158 : RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped, 1);
1244 158 : BG(strtok_last) = p + 1;
1245 : } else {
1246 0 : RETVAL_FALSE;
1247 0 : BG(strtok_last) = NULL;
1248 : }
1249 :
1250 : /* Restore table -- usually faster then memset'ing the table on every invocation */
1251 170 : restore:
1252 170 : token = tok;
1253 :
1254 987 : while (token < token_end) {
1255 647 : STRTOK_TABLE(token++) = 0;
1256 : }
1257 : }
1258 : /* }}} */
1259 :
1260 : /* {{{ php_strtoupper
1261 : */
1262 : PHPAPI char *php_strtoupper(char *s, size_t len)
1263 956 : {
1264 : unsigned char *c, *e;
1265 :
1266 956 : c = (unsigned char *)s;
1267 956 : e = (unsigned char *)c+len;
1268 :
1269 8519 : while (c < e) {
1270 6607 : *c = toupper(*c);
1271 6607 : c++;
1272 : }
1273 956 : return s;
1274 : }
1275 : /* }}} */
1276 :
1277 : /* {{{ proto string strtoupper(string str)
1278 : Makes a string uppercase */
1279 : PHP_FUNCTION(strtoupper)
1280 752 : {
1281 : char *arg;
1282 : int arglen;
1283 :
1284 752 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arglen) == FAILURE) {
1285 3 : return;
1286 : }
1287 :
1288 749 : arg = estrndup(arg, arglen);
1289 749 : php_strtoupper(arg, arglen);
1290 749 : RETURN_STRINGL(arg, arglen, 0);
1291 : }
1292 : /* }}} */
1293 :
1294 : /* {{{ php_strtolower
1295 : */
1296 : PHPAPI char *php_strtolower(char *s, size_t len)
1297 587162 : {
1298 : unsigned char *c, *e;
1299 :
1300 587162 : c = (unsigned char *)s;
1301 587162 : e = c+len;
1302 :
1303 14610721 : while (c < e) {
1304 13436397 : *c = tolower(*c);
1305 13436397 : c++;
1306 : }
1307 587162 : return s;
1308 : }
1309 : /* }}} */
1310 :
1311 : /* {{{ proto string strtolower(string str)
1312 : Makes a string lowercase */
1313 : PHP_FUNCTION(strtolower)
1314 382241 : {
1315 : char *str;
1316 : int arglen;
1317 :
1318 382241 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &arglen) == FAILURE) {
1319 3 : return;
1320 : }
1321 :
1322 382238 : str = estrndup(str, arglen);
1323 382238 : php_strtolower(str, arglen);
1324 382238 : RETURN_STRINGL(str, arglen, 0);
1325 : }
1326 : /* }}} */
1327 :
1328 : /* {{{ php_basename
1329 : */
1330 : PHPAPI void php_basename(char *s, size_t len, char *suffix, size_t sufflen, char **p_ret, size_t *p_len TSRMLS_DC)
1331 13527 : {
1332 13527 : char *ret = NULL, *c, *comp, *cend;
1333 : size_t inc_len, cnt;
1334 : int state;
1335 :
1336 13527 : c = comp = cend = s;
1337 13527 : cnt = len;
1338 13527 : state = 0;
1339 790544 : while (cnt > 0) {
1340 763490 : inc_len = (*c == '\0' ? 1: php_mblen(c, cnt));
1341 :
1342 763490 : switch (inc_len) {
1343 : case -2:
1344 : case -1:
1345 0 : inc_len = 1;
1346 0 : php_mblen(NULL, 0);
1347 0 : break;
1348 : case 0:
1349 0 : goto quit_loop;
1350 : case 1:
1351 : #if defined(PHP_WIN32) || defined(NETWARE)
1352 : if (*c == '/' || *c == '\\') {
1353 : #else
1354 763490 : if (*c == '/') {
1355 : #endif
1356 88429 : if (state == 1) {
1357 76142 : state = 0;
1358 76142 : cend = c;
1359 : }
1360 : } else {
1361 675061 : if (state == 0) {
1362 89433 : comp = c;
1363 89433 : state = 1;
1364 : }
1365 : }
1366 763490 : break;
1367 : default:
1368 0 : if (state == 0) {
1369 0 : comp = c;
1370 0 : state = 1;
1371 : }
1372 : break;
1373 : }
1374 763490 : c += inc_len;
1375 763490 : cnt -= inc_len;
1376 : }
1377 :
1378 13527 : quit_loop:
1379 13527 : if (state == 1) {
1380 13291 : cend = c;
1381 : }
1382 13527 : if (suffix != NULL && sufflen < (uint)(cend - comp) &&
1383 : memcmp(cend - sufflen, suffix, sufflen) == 0) {
1384 11958 : cend -= sufflen;
1385 : }
1386 :
1387 13527 : len = cend - comp;
1388 :
1389 13527 : if (p_ret) {
1390 13527 : ret = emalloc(len + 1);
1391 13527 : memcpy(ret, comp, len);
1392 13527 : ret[len] = '\0';
1393 13527 : *p_ret = ret;
1394 : }
1395 13527 : if (p_len) {
1396 13497 : *p_len = len;
1397 : }
1398 13527 : }
1399 : /* }}} */
1400 :
1401 : /* {{{ proto string basename(string path [, string suffix])
1402 : Returns the filename component of the path */
1403 : PHP_FUNCTION(basename)
1404 12385 : {
1405 12385 : char *string, *suffix = NULL, *ret;
1406 12385 : int string_len, suffix_len = 0;
1407 : size_t ret_len;
1408 :
1409 12385 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &string, &string_len, &suffix, &suffix_len) == FAILURE) {
1410 30 : return;
1411 : }
1412 :
1413 12355 : php_basename(string, string_len, suffix, suffix_len, &ret, &ret_len TSRMLS_CC);
1414 12355 : RETURN_STRINGL(ret, (int)ret_len, 0);
1415 : }
1416 : /* }}} */
1417 :
1418 : /* {{{ php_dirname
1419 : Returns directory name component of path */
1420 : PHPAPI size_t php_dirname(char *path, size_t len)
1421 22062 : {
1422 22062 : return zend_dirname(path, len);
1423 : }
1424 : /* }}} */
1425 :
1426 : /* {{{ proto string dirname(string path)
1427 : Returns the directory name component of the path */
1428 : PHP_FUNCTION(dirname)
1429 21633 : {
1430 : char *str;
1431 : char *ret;
1432 : int str_len;
1433 : size_t ret_len;
1434 :
1435 21633 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
1436 9 : return;
1437 : }
1438 :
1439 21624 : ret = estrndup(str, str_len);
1440 21624 : ret_len = php_dirname(ret, str_len);
1441 :
1442 21624 : RETURN_STRINGL(ret, ret_len, 0);
1443 : }
1444 : /* }}} */
1445 :
1446 : /* {{{ proto array pathinfo(string path[, int options])
1447 : Returns information about a certain string */
1448 : PHP_FUNCTION(pathinfo)
1449 605 : {
1450 : zval *tmp;
1451 605 : char *path, *ret = NULL;
1452 : int path_len, have_basename;
1453 : size_t ret_len;
1454 605 : long opt = PHP_PATHINFO_ALL;
1455 :
1456 605 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &path, &path_len, &opt) == FAILURE) {
1457 25 : return;
1458 : }
1459 :
1460 580 : have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
1461 :
1462 580 : MAKE_STD_ZVAL(tmp);
1463 580 : array_init(tmp);
1464 :
1465 580 : if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
1466 247 : ret = estrndup(path, path_len);
1467 247 : php_dirname(ret, path_len);
1468 247 : if (*ret) {
1469 224 : add_assoc_string(tmp, "dirname", ret, 1);
1470 : }
1471 247 : efree(ret);
1472 247 : ret = NULL;
1473 : }
1474 :
1475 580 : if (have_basename) {
1476 227 : php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
1477 227 : add_assoc_stringl(tmp, "basename", ret, ret_len, 0);
1478 : }
1479 :
1480 580 : if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
1481 : char *p;
1482 : int idx;
1483 :
1484 228 : if (!have_basename) {
1485 110 : php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
1486 : }
1487 :
1488 228 : p = zend_memrchr(ret, '.', ret_len);
1489 :
1490 228 : if (p) {
1491 122 : idx = p - ret;
1492 122 : add_assoc_stringl(tmp, "extension", ret + idx + 1, ret_len - idx - 1, 1);
1493 : }
1494 : }
1495 :
1496 580 : if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
1497 : char *p;
1498 : int idx;
1499 :
1500 : /* Have we alrady looked up the basename? */
1501 232 : if (!have_basename && !ret) {
1502 110 : php_basename(path, path_len, NULL, 0, &ret, &ret_len TSRMLS_CC);
1503 : }
1504 :
1505 232 : p = zend_memrchr(ret, '.', ret_len);
1506 :
1507 232 : idx = p ? (p - ret) : ret_len;
1508 232 : add_assoc_stringl(tmp, "filename", ret, idx, 1);
1509 : }
1510 :
1511 580 : if (!have_basename && ret) {
1512 220 : efree(ret);
1513 : }
1514 :
1515 580 : if (opt == PHP_PATHINFO_ALL) {
1516 113 : RETURN_ZVAL(tmp, 0, 1);
1517 : } else {
1518 : zval **element;
1519 467 : if (zend_hash_get_current_data(Z_ARRVAL_P(tmp), (void **) &element) == SUCCESS) {
1520 393 : RETVAL_ZVAL(*element, 1, 0);
1521 : } else {
1522 74 : ZVAL_EMPTY_STRING(return_value);
1523 : }
1524 : }
1525 :
1526 467 : zval_ptr_dtor(&tmp);
1527 : }
1528 : /* }}} */
1529 :
1530 : /* {{{ php_stristr
1531 : case insensitve strstr */
1532 : PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
1533 7676 : {
1534 7676 : php_strtolower(s, s_len);
1535 7676 : php_strtolower(t, t_len);
1536 7676 : return php_memnstr(s, t, t_len, s + s_len);
1537 : }
1538 : /* }}} */
1539 :
1540 : /* {{{ php_strspn
1541 : */
1542 : PHPAPI size_t php_strspn(char *s1, char *s2, char *s1_end, char *s2_end)
1543 3381 : {
1544 3381 : register const char *p = s1, *spanp;
1545 3381 : register char c = *p;
1546 :
1547 6573 : cont:
1548 44080 : for (spanp = s2; p != s1_end && spanp != s2_end;) {
1549 34126 : if (*spanp++ == c) {
1550 3192 : c = *(++p);
1551 3192 : goto cont;
1552 : }
1553 : }
1554 3381 : return (p - s1);
1555 : }
1556 : /* }}} */
1557 :
1558 : /* {{{ php_strcspn
1559 : */
1560 : PHPAPI size_t php_strcspn(char *s1, char *s2, char *s1_end, char *s2_end)
1561 3233 : {
1562 : register const char *p, *spanp;
1563 3233 : register char c = *s1;
1564 :
1565 3233 : for (p = s1;;) {
1566 24665 : spanp = s2;
1567 : do {
1568 55603 : if (*spanp == c || p == s1_end) {
1569 3233 : return p - s1;
1570 : }
1571 52370 : } while (spanp++ < (s2_end - 1));
1572 21432 : c = *++p;
1573 21432 : }
1574 : /* NOTREACHED */
1575 : }
1576 : /* }}} */
1577 :
1578 : /* {{{ php_needle_char
1579 : */
1580 : static int php_needle_char(zval *needle, char *target TSRMLS_DC)
1581 329 : {
1582 329 : switch (Z_TYPE_P(needle)) {
1583 : case IS_LONG:
1584 : case IS_BOOL:
1585 158 : *target = (char)Z_LVAL_P(needle);
1586 158 : return SUCCESS;
1587 : case IS_NULL:
1588 87 : *target = '\0';
1589 87 : return SUCCESS;
1590 : case IS_DOUBLE:
1591 52 : *target = (char)(int)Z_DVAL_P(needle);
1592 52 : return SUCCESS;
1593 : case IS_OBJECT:
1594 : {
1595 9 : zval holder = *needle;
1596 9 : zval_copy_ctor(&(holder));
1597 9 : convert_to_long(&(holder));
1598 9 : if(Z_TYPE(holder) != IS_LONG) {
1599 0 : return FAILURE;
1600 : }
1601 9 : *target = (char)Z_LVAL(holder);
1602 9 : return SUCCESS;
1603 : }
1604 : default: {
1605 23 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "needle is not a string or an integer");
1606 23 : return FAILURE;
1607 : }
1608 : }
1609 : }
1610 : /* }}} */
1611 :
1612 : /* {{{ proto string stristr(string haystack, string needle[, bool part])
1613 : Finds first occurrence of a string within another, case insensitive */
1614 : PHP_FUNCTION(stristr)
1615 7696 : {
1616 : zval *needle;
1617 : char *haystack;
1618 : int haystack_len;
1619 7696 : char *found = NULL;
1620 : int found_offset;
1621 : char *haystack_dup;
1622 : char needle_char[2];
1623 7696 : zend_bool part = 0;
1624 :
1625 7696 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) {
1626 11 : return;
1627 : }
1628 :
1629 7685 : haystack_dup = estrndup(haystack, haystack_len);
1630 :
1631 7685 : if (Z_TYPE_P(needle) == IS_STRING) {
1632 : char *orig_needle;
1633 7662 : if (!Z_STRLEN_P(needle)) {
1634 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
1635 4 : efree(haystack_dup);
1636 4 : RETURN_FALSE;
1637 : }
1638 7658 : orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
1639 7658 : found = php_stristr(haystack_dup, orig_needle, haystack_len, Z_STRLEN_P(needle));
1640 7658 : efree(orig_needle);
1641 : } else {
1642 23 : if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
1643 5 : efree(haystack_dup);
1644 5 : RETURN_FALSE;
1645 : }
1646 18 : needle_char[1] = 0;
1647 :
1648 18 : found = php_stristr(haystack_dup, needle_char, haystack_len, 1);
1649 : }
1650 :
1651 7676 : if (found) {
1652 1604 : found_offset = found - haystack_dup;
1653 1604 : if (part) {
1654 4 : RETVAL_STRINGL(haystack, found_offset, 1);
1655 : } else {
1656 1600 : RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1);
1657 : }
1658 : } else {
1659 6072 : RETVAL_FALSE;
1660 : }
1661 :
1662 7676 : efree(haystack_dup);
1663 : }
1664 : /* }}} */
1665 :
1666 : /* {{{ proto string strstr(string haystack, string needle[, bool part])
1667 : Finds first occurrence of a string within another */
1668 : PHP_FUNCTION(strstr)
1669 7744 : {
1670 : zval *needle;
1671 : char *haystack;
1672 : int haystack_len;
1673 7744 : char *found = NULL;
1674 : char needle_char[2];
1675 : long found_offset;
1676 7744 : zend_bool part = 0;
1677 :
1678 7744 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &haystack, &haystack_len, &needle, &part) == FAILURE) {
1679 6 : return;
1680 : }
1681 :
1682 7738 : if (Z_TYPE_P(needle) == IS_STRING) {
1683 7726 : if (!Z_STRLEN_P(needle)) {
1684 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
1685 5 : RETURN_FALSE;
1686 : }
1687 :
1688 7721 : found = php_memnstr(haystack, Z_STRVAL_P(needle), Z_STRLEN_P(needle), haystack + haystack_len);
1689 : } else {
1690 12 : if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
1691 0 : RETURN_FALSE;
1692 : }
1693 12 : needle_char[1] = 0;
1694 :
1695 12 : found = php_memnstr(haystack, needle_char, 1, haystack + haystack_len);
1696 : }
1697 :
1698 7733 : if (found) {
1699 2865 : found_offset = found - haystack;
1700 2865 : if (part) {
1701 5 : RETURN_STRINGL(haystack, found_offset, 1);
1702 : } else {
1703 2860 : RETURN_STRINGL(found, haystack_len - found_offset, 1);
1704 : }
1705 : }
1706 4868 : RETURN_FALSE;
1707 : }
1708 : /* }}} */
1709 :
1710 : /* {{{ proto string strchr(string haystack, string needle)
1711 : An alias for strstr */
1712 : /* }}} */
1713 :
1714 : /* {{{ proto int strpos(string haystack, string needle [, int offset])
1715 : Finds position of first occurrence of a string within another */
1716 : PHP_FUNCTION(strpos)
1717 796603 : {
1718 : zval *needle;
1719 : char *haystack;
1720 796603 : char *found = NULL;
1721 : char needle_char[2];
1722 796603 : long offset = 0;
1723 : int haystack_len;
1724 :
1725 796603 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
1726 11 : return;
1727 : }
1728 :
1729 796592 : if (offset < 0 || offset > haystack_len) {
1730 9 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
1731 9 : RETURN_FALSE;
1732 : }
1733 :
1734 796583 : if (Z_TYPE_P(needle) == IS_STRING) {
1735 796570 : if (!Z_STRLEN_P(needle)) {
1736 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty delimiter");
1737 5 : RETURN_FALSE;
1738 : }
1739 :
1740 796565 : found = php_memnstr(haystack + offset,
1741 : Z_STRVAL_P(needle),
1742 : Z_STRLEN_P(needle),
1743 : haystack + haystack_len);
1744 : } else {
1745 13 : if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
1746 0 : RETURN_FALSE;
1747 : }
1748 13 : needle_char[1] = 0;
1749 :
1750 13 : found = php_memnstr(haystack + offset,
1751 : needle_char,
1752 : 1,
1753 : haystack + haystack_len);
1754 : }
1755 :
1756 796578 : if (found) {
1757 402212 : RETURN_LONG(found - haystack);
1758 : } else {
1759 394366 : RETURN_FALSE;
1760 : }
1761 : }
1762 : /* }}} */
1763 :
1764 : /* {{{ proto int stripos(string haystack, string needle [, int offset])
1765 : Finds position of first occurrence of a string within another, case insensitive */
1766 : PHP_FUNCTION(stripos)
1767 605 : {
1768 605 : char *found = NULL;
1769 : char *haystack;
1770 : int haystack_len;
1771 605 : long offset = 0;
1772 605 : char *needle_dup = NULL, *haystack_dup;
1773 : char needle_char[2];
1774 : zval *needle;
1775 :
1776 605 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
1777 39 : return;
1778 : }
1779 :
1780 566 : if (offset < 0 || offset > haystack_len) {
1781 22 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
1782 22 : RETURN_FALSE;
1783 : }
1784 :
1785 544 : if (haystack_len == 0) {
1786 30 : RETURN_FALSE;
1787 : }
1788 :
1789 514 : haystack_dup = estrndup(haystack, haystack_len);
1790 514 : php_strtolower(haystack_dup, haystack_len);
1791 :
1792 514 : if (Z_TYPE_P(needle) == IS_STRING) {
1793 436 : if (Z_STRLEN_P(needle) == 0 || Z_STRLEN_P(needle) > haystack_len) {
1794 20 : efree(haystack_dup);
1795 20 : RETURN_FALSE;
1796 : }
1797 :
1798 416 : needle_dup = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
1799 416 : php_strtolower(needle_dup, Z_STRLEN_P(needle));
1800 416 : found = php_memnstr(haystack_dup + offset, needle_dup, Z_STRLEN_P(needle), haystack_dup + haystack_len);
1801 : } else {
1802 78 : if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
1803 6 : efree(haystack_dup);
1804 6 : RETURN_FALSE;
1805 : }
1806 72 : needle_char[0] = tolower(needle_char[0]);
1807 72 : needle_char[1] = '\0';
1808 72 : found = php_memnstr(haystack_dup + offset,
1809 : needle_char,
1810 : sizeof(needle_char) - 1,
1811 : haystack_dup + haystack_len);
1812 : }
1813 :
1814 488 : efree(haystack_dup);
1815 488 : if (needle_dup) {
1816 416 : efree(needle_dup);
1817 : }
1818 :
1819 488 : if (found) {
1820 319 : RETURN_LONG(found - haystack_dup);
1821 : } else {
1822 169 : RETURN_FALSE;
1823 : }
1824 : }
1825 : /* }}} */
1826 :
1827 : /* {{{ proto int strrpos(string haystack, string needle [, int offset])
1828 : Finds position of last occurrence of a string within another string */
1829 : PHP_FUNCTION(strrpos)
1830 464 : {
1831 : zval *zneedle;
1832 : char *needle, *haystack;
1833 : int needle_len, haystack_len;
1834 464 : long offset = 0;
1835 : char *p, *e, ord_needle[2];
1836 :
1837 464 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
1838 39 : RETURN_FALSE;
1839 : }
1840 :
1841 425 : if (Z_TYPE_P(zneedle) == IS_STRING) {
1842 324 : needle = Z_STRVAL_P(zneedle);
1843 324 : needle_len = Z_STRLEN_P(zneedle);
1844 : } else {
1845 101 : if (php_needle_char(zneedle, ord_needle TSRMLS_CC) != SUCCESS) {
1846 6 : RETURN_FALSE;
1847 : }
1848 95 : ord_needle[1] = '\0';
1849 95 : needle = ord_needle;
1850 95 : needle_len = 1;
1851 : }
1852 :
1853 419 : if ((haystack_len == 0) || (needle_len == 0)) {
1854 44 : RETURN_FALSE;
1855 : }
1856 :
1857 375 : if (offset >= 0) {
1858 355 : if (offset > haystack_len) {
1859 6 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
1860 6 : RETURN_FALSE;
1861 : }
1862 349 : p = haystack + offset;
1863 349 : e = haystack + haystack_len - needle_len;
1864 : } else {
1865 20 : if (-offset > haystack_len || offset < -INT_MAX) {
1866 12 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
1867 12 : RETURN_FALSE;
1868 : }
1869 :
1870 8 : p = haystack;
1871 8 : if (needle_len > -offset) {
1872 3 : e = haystack + haystack_len - needle_len;
1873 : } else {
1874 5 : e = haystack + haystack_len + offset;
1875 : }
1876 : }
1877 :
1878 357 : if (needle_len == 1) {
1879 : /* Single character search can shortcut memcmps */
1880 4367 : while (e >= p) {
1881 4086 : if (*e == *needle) {
1882 111 : RETURN_LONG(e - p + (offset > 0 ? offset : 0));
1883 : }
1884 3975 : e--;
1885 : }
1886 85 : RETURN_FALSE;
1887 : }
1888 :
1889 2864 : while (e >= p) {
1890 2628 : if (memcmp(e, needle, needle_len) == 0) {
1891 86 : RETURN_LONG(e - p + (offset > 0 ? offset : 0));
1892 : }
1893 2542 : e--;
1894 : }
1895 :
1896 75 : RETURN_FALSE;
1897 : }
1898 : /* }}} */
1899 :
1900 : /* {{{ proto int strripos(string haystack, string needle [, int offset])
1901 : Finds position of last occurrence of a string within another string */
1902 : PHP_FUNCTION(strripos)
1903 365 : {
1904 : zval *zneedle;
1905 : char *needle, *haystack;
1906 : int needle_len, haystack_len;
1907 365 : long offset = 0;
1908 : char *p, *e, ord_needle[2];
1909 : char *needle_dup, *haystack_dup;
1910 :
1911 365 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &zneedle, &offset) == FAILURE) {
1912 4 : RETURN_FALSE;
1913 : }
1914 :
1915 361 : if (Z_TYPE_P(zneedle) == IS_STRING) {
1916 321 : needle = Z_STRVAL_P(zneedle);
1917 321 : needle_len = Z_STRLEN_P(zneedle);
1918 : } else {
1919 40 : if (php_needle_char(zneedle, ord_needle TSRMLS_CC) != SUCCESS) {
1920 0 : RETURN_FALSE;
1921 : }
1922 40 : ord_needle[1] = '\0';
1923 40 : needle = ord_needle;
1924 40 : needle_len = 1;
1925 : }
1926 :
1927 361 : if ((haystack_len == 0) || (needle_len == 0)) {
1928 12 : RETURN_FALSE;
1929 : }
1930 :
1931 349 : if (needle_len == 1) {
1932 : /* Single character search can shortcut memcmps
1933 : Can also avoid tolower emallocs */
1934 162 : if (offset >= 0) {
1935 119 : if (offset > haystack_len) {
1936 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
1937 0 : RETURN_FALSE;
1938 : }
1939 119 : p = haystack + offset;
1940 119 : e = haystack + haystack_len - 1;
1941 : } else {
1942 43 : p = haystack;
1943 43 : if (-offset > haystack_len || offset < -INT_MAX) {
1944 5 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
1945 5 : RETURN_FALSE;
1946 : }
1947 38 : e = haystack + haystack_len + offset;
1948 : }
1949 : /* Borrow that ord_needle buffer to avoid repeatedly tolower()ing needle */
1950 157 : *ord_needle = tolower(*needle);
1951 4076 : while (e >= p) {
1952 3883 : if (tolower(*e) == *ord_needle) {
1953 121 : RETURN_LONG(e - p + (offset > 0 ? offset : 0));
1954 : }
1955 3762 : e--;
1956 : }
1957 36 : RETURN_FALSE;
1958 : }
1959 :
1960 187 : needle_dup = estrndup(needle, needle_len);
1961 187 : php_strtolower(needle_dup, needle_len);
1962 187 : haystack_dup = estrndup(haystack, haystack_len);
1963 187 : php_strtolower(haystack_dup, haystack_len);
1964 :
1965 187 : if (offset >= 0) {
1966 143 : if (offset > haystack_len) {
1967 2 : efree(needle_dup);
1968 2 : efree(haystack_dup);
1969 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
1970 2 : RETURN_FALSE;
1971 : }
1972 141 : p = haystack_dup + offset;
1973 141 : e = haystack_dup + haystack_len - needle_len;
1974 : } else {
1975 44 : if (-offset > haystack_len || offset < -INT_MAX) {
1976 3 : efree(needle_dup);
1977 3 : efree(haystack_dup);
1978 3 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is greater than the length of haystack string");
1979 3 : RETURN_FALSE;
1980 : }
1981 41 : p = haystack_dup;
1982 41 : if (needle_len > -offset) {
1983 36 : e = haystack_dup + haystack_len - needle_len;
1984 : } else {
1985 5 : e = haystack_dup + haystack_len + offset;
1986 : }
1987 : }
1988 :
1989 4357 : while (e >= p) {
1990 4125 : if (memcmp(e, needle_dup, needle_len) == 0) {
1991 132 : efree(haystack_dup);
1992 132 : efree(needle_dup);
1993 132 : RETURN_LONG(e - p + (offset > 0 ? offset : 0));
1994 : }
1995 3993 : e--;
1996 : }
1997 :
1998 50 : efree(haystack_dup);
1999 50 : efree(needle_dup);
2000 50 : RETURN_FALSE;
2001 : }
2002 : /* }}} */
2003 :
2004 : /* {{{ proto string strrchr(string haystack, string needle)
2005 : Finds the last occurrence of a character in a string within another */
2006 : PHP_FUNCTION(strrchr)
2007 244 : {
2008 : zval *needle;
2009 : char *haystack;
2010 244 : char *found = NULL;
2011 : long found_offset;
2012 : int haystack_len;
2013 :
2014 244 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &haystack, &haystack_len, &needle) == FAILURE) {
2015 15 : return;
2016 : }
2017 :
2018 229 : if (Z_TYPE_P(needle) == IS_STRING) {
2019 167 : found = zend_memrchr(haystack, *Z_STRVAL_P(needle), haystack_len);
2020 : } else {
2021 : char needle_chr;
2022 62 : if (php_needle_char(needle, &needle_chr TSRMLS_CC) != SUCCESS) {
2023 6 : RETURN_FALSE;
2024 : }
2025 :
2026 56 : found = zend_memrchr(haystack, needle_chr, haystack_len);
2027 : }
2028 :
2029 223 : if (found) {
2030 143 : found_offset = found - haystack;
2031 143 : RETURN_STRINGL(found, haystack_len - found_offset, 1);
2032 : } else {
2033 80 : RETURN_FALSE;
2034 : }
2035 : }
2036 : /* }}} */
2037 :
2038 : /* {{{ php_chunk_split
2039 : */
2040 : static char *php_chunk_split(char *src, int srclen, char *end, int endlen, int chunklen, int *destlen)
2041 128 : {
2042 : char *dest;
2043 : char *p, *q;
2044 : int chunks; /* complete chunks! */
2045 : int restlen;
2046 : int out_len;
2047 :
2048 128 : chunks = srclen / chunklen;
2049 128 : restlen = srclen - chunks * chunklen; /* srclen % chunklen */
2050 :
2051 128 : if(chunks > INT_MAX - 1) {
2052 0 : return NULL;
2053 : }
2054 128 : out_len = chunks + 1;
2055 128 : if(endlen !=0 && out_len > INT_MAX/endlen) {
2056 2 : return NULL;
2057 : }
2058 126 : out_len *= endlen;
2059 126 : if(out_len > INT_MAX - srclen - 1) {
2060 0 : return NULL;
2061 : }
2062 126 : out_len += srclen + 1;
2063 :
2064 126 : dest = safe_emalloc((int)out_len, sizeof(char), 0);
2065 :
2066 1286 : for (p = src, q = dest; p < (src + srclen - chunklen + 1); ) {
2067 1034 : memcpy(q, p, chunklen);
2068 1034 : q += chunklen;
2069 1034 : memcpy(q, end, endlen);
2070 1034 : q += endlen;
2071 1034 : p += chunklen;
2072 : }
2073 :
2074 126 : if (restlen) {
2075 114 : memcpy(q, p, restlen);
2076 114 : q += restlen;
2077 114 : memcpy(q, end, endlen);
2078 114 : q += endlen;
2079 : }
2080 :
2081 126 : *q = '\0';
2082 126 : if (destlen) {
2083 126 : *destlen = q - dest;
2084 : }
2085 :
2086 126 : return(dest);
2087 : }
2088 : /* }}} */
2089 :
2090 : /* {{{ proto string chunk_split(string str [, int chunklen [, string ending]])
2091 : Returns split line */
2092 : PHP_FUNCTION(chunk_split)
2093 185 : {
2094 : char *str;
2095 : char *result;
2096 185 : char *end = "\r\n";
2097 185 : int endlen = 2;
2098 185 : long chunklen = 76;
2099 : int result_len;
2100 : int str_len;
2101 :
2102 185 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ls", &str, &str_len, &chunklen, &end, &endlen) == FAILURE) {
2103 25 : return;
2104 : }
2105 :
2106 160 : if (chunklen <= 0) {
2107 10 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Chunk length should be greater than zero");
2108 10 : RETURN_FALSE;
2109 : }
2110 :
2111 150 : if (chunklen > str_len) {
2112 : /* to maintain BC, we must return original string + ending */
2113 22 : result_len = endlen + str_len;
2114 22 : result = emalloc(result_len + 1);
2115 22 : memcpy(result, str, str_len);
2116 22 : memcpy(result + str_len, end, endlen);
2117 22 : result[result_len] = '\0';
2118 22 : RETURN_STRINGL(result, result_len, 0);
2119 : }
2120 :
2121 128 : if (!str_len) {
2122 0 : RETURN_EMPTY_STRING();
2123 : }
2124 :
2125 128 : result = php_chunk_split(str, str_len, end, endlen, chunklen, &result_len);
2126 :
2127 128 : if (result) {
2128 126 : RETURN_STRINGL(result, result_len, 0);
2129 : } else {
2130 2 : RETURN_FALSE;
2131 : }
2132 : }
2133 : /* }}} */
2134 :
2135 : /* {{{ proto string substr(string str, int start [, int length])
2136 : Returns part of a string */
2137 : PHP_FUNCTION(substr)
2138 139384 : {
2139 : char *str;
2140 139384 : long l = 0, f;
2141 : int str_len;
2142 139384 : int argc = ZEND_NUM_ARGS();
2143 :
2144 139384 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|l", &str, &str_len, &f, &l) == FAILURE) {
2145 6 : return;
2146 : }
2147 :
2148 139378 : if (argc > 2) {
2149 29542 : if ((l < 0 && -l > str_len)) {
2150 10 : RETURN_FALSE;
2151 29532 : } else if (l > str_len) {
2152 259 : l = str_len;
2153 : }
2154 : } else {
2155 109836 : l = str_len;
2156 : }
2157 :
2158 139368 : if (f > str_len) {
2159 6997 : RETURN_FALSE;
2160 132371 : } else if (f < 0 && -f > str_len) {
2161 12088 : f = 0;
2162 : }
2163 :
2164 132371 : if (l < 0 && (l + str_len - f) < 0) {
2165 1 : RETURN_FALSE;
2166 : }
2167 :
2168 : /* if "from" position is negative, count start position from the end
2169 : * of the string
2170 : */
2171 132370 : if (f < 0) {
2172 97876 : f = str_len + f;
2173 97876 : if (f < 0) {
2174 0 : f = 0;
2175 : }
2176 : }
2177 :
2178 : /* if "length" position is negative, set it to the length
2179 : * needed to stop that many chars from the end of the string
2180 : */
2181 132370 : if (l < 0) {
2182 56 : l = (str_len - f) + l;
2183 56 : if (l < 0) {
2184 5 : l = 0;
2185 : }
2186 : }
2187 :
2188 132370 : if (f >= str_len) {
2189 196 : RETURN_FALSE;
2190 : }
2191 :
2192 132174 : if ((f + l) > str_len) {
2193 97368 : l = str_len - f;
2194 : }
2195 :
2196 132174 : RETURN_STRINGL(str + f, l, 1);
2197 : }
2198 : /* }}} */
2199 :
2200 : /* {{{ proto mixed substr_replace(mixed str, mixed repl, mixed start [, mixed length])
2201 : Replaces part of a string with another string */
2202 : PHP_FUNCTION(substr_replace)
2203 54 : {
2204 : zval **str;
2205 : zval **from;
2206 54 : zval **len = NULL;
2207 : zval **repl;
2208 : char *result;
2209 : int result_len;
2210 54 : int l = 0;
2211 : int f;
2212 54 : int argc = ZEND_NUM_ARGS();
2213 :
2214 : HashPosition pos_str, pos_from, pos_repl, pos_len;
2215 54 : zval **tmp_str = NULL, **tmp_from = NULL, **tmp_repl = NULL, **tmp_len= NULL;
2216 :
2217 54 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &str, &repl, &from, &len) == FAILURE) {
2218 3 : return;
2219 : }
2220 :
2221 51 : if (Z_TYPE_PP(str) != IS_ARRAY) {
2222 11 : convert_to_string_ex(str);
2223 : }
2224 51 : if (Z_TYPE_PP(repl) != IS_ARRAY) {
2225 30 : convert_to_string_ex(repl);
2226 : }
2227 51 : if (Z_TYPE_PP(from) != IS_ARRAY) {
2228 16 : convert_to_long_ex(from);
2229 : }
2230 :
2231 51 : if (argc > 3) {
2232 42 : SEPARATE_ZVAL(len);
2233 42 : if (Z_TYPE_PP(len) != IS_ARRAY) {
2234 23 : convert_to_long_ex(len);
2235 23 : l = Z_LVAL_PP(len);
2236 : }
2237 : } else {
2238 9 : if (Z_TYPE_PP(str) != IS_ARRAY) {
2239 3 : l = Z_STRLEN_PP(str);
2240 : }
2241 : }
2242 :
2243 51 : if (Z_TYPE_PP(str) == IS_STRING) {
2244 11 : if (
2245 : (argc == 3 && Z_TYPE_PP(from) == IS_ARRAY) ||
2246 : (argc == 4 && Z_TYPE_PP(from) != Z_TYPE_PP(len))
2247 : ) {
2248 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should be of same type - numerical or array ");
2249 2 : RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
2250 : }
2251 9 : if (argc == 4 && Z_TYPE_PP(from) == IS_ARRAY) {
2252 2 : if (zend_hash_num_elements(Z_ARRVAL_PP(from)) != zend_hash_num_elements(Z_ARRVAL_PP(len))) {
2253 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "'from' and 'len' should have the same number of elements");
2254 1 : RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
2255 : }
2256 : }
2257 : }
2258 :
2259 48 : if (Z_TYPE_PP(str) != IS_ARRAY) {
2260 8 : if (Z_TYPE_PP(from) != IS_ARRAY) {
2261 7 : int repl_len = 0;
2262 :
2263 7 : f = Z_LVAL_PP(from);
2264 :
2265 : /* if "from" position is negative, count start position from the end
2266 : * of the string
2267 : */
2268 7 : if (f < 0) {
2269 0 : f = Z_STRLEN_PP(str) + f;
2270 0 : if (f < 0) {
2271 0 : f = 0;
2272 : }
2273 7 : } else if (f > Z_STRLEN_PP(str)) {
2274 1 : f = Z_STRLEN_PP(str);
2275 : }
2276 : /* if "length" position is negative, set it to the length
2277 : * needed to stop that many chars from the end of the string
2278 : */
2279 7 : if (l < 0) {
2280 1 : l = (Z_STRLEN_PP(str) - f) + l;
2281 1 : if (l < 0) {
2282 0 : l = 0;
2283 : }
2284 : }
2285 :
2286 7 : if (f > Z_STRLEN_PP(str) || (f < 0 && -f > Z_STRLEN_PP(str))) {
2287 0 : RETURN_FALSE;
2288 7 : } else if (l > Z_STRLEN_PP(str) || (l < 0 && -l > Z_STRLEN_PP(str))) {
2289 1 : l = Z_STRLEN_PP(str);
2290 : }
2291 :
2292 7 : if ((f + l) > Z_STRLEN_PP(str)) {
2293 3 : l = Z_STRLEN_PP(str) - f;
2294 : }
2295 7 : if (Z_TYPE_PP(repl) == IS_ARRAY) {
2296 2 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl);
2297 2 : if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
2298 2 : convert_to_string_ex(tmp_repl);
2299 2 : repl_len = Z_STRLEN_PP(tmp_repl);
2300 : }
2301 : } else {
2302 5 : repl_len = Z_STRLEN_PP(repl);
2303 : }
2304 7 : result_len = Z_STRLEN_PP(str) - l + repl_len;
2305 7 : result = emalloc(result_len + 1);
2306 :
2307 7 : memcpy(result, Z_STRVAL_PP(str), f);
2308 7 : if (repl_len) {
2309 7 : memcpy((result + f), (Z_TYPE_PP(repl) == IS_ARRAY ? Z_STRVAL_PP(tmp_repl) : Z_STRVAL_PP(repl)), repl_len);
2310 : }
2311 7 : memcpy((result + f + repl_len), Z_STRVAL_PP(str) + f + l, Z_STRLEN_PP(str) - f - l);
2312 7 : result[result_len] = '\0';
2313 7 : RETURN_STRINGL(result, result_len, 0);
2314 : } else {
2315 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Functionality of 'from' and 'len' as arrays is not implemented");
2316 1 : RETURN_STRINGL(Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
2317 : }
2318 : } else { /* str is array of strings */
2319 40 : array_init(return_value);
2320 :
2321 40 : if (Z_TYPE_PP(from) == IS_ARRAY) {
2322 32 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(from), &pos_from);
2323 : }
2324 :
2325 40 : if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
2326 16 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(len), &pos_len);
2327 : }
2328 :
2329 40 : if (Z_TYPE_PP(repl) == IS_ARRAY) {
2330 19 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(repl), &pos_repl);
2331 : }
2332 :
2333 40 : zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(str), &pos_str);
2334 151 : while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) {
2335 71 : convert_to_string_ex(tmp_str);
2336 :
2337 71 : if (Z_TYPE_PP(from) == IS_ARRAY) {
2338 56 : if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) {
2339 50 : convert_to_long_ex(tmp_from);
2340 :
2341 50 : f = Z_LVAL_PP(tmp_from);
2342 50 : if (f < 0) {
2343 0 : f = Z_STRLEN_PP(tmp_str) + f;
2344 0 : if (f < 0) {
2345 0 : f = 0;
2346 : }
2347 50 : } else if (f > Z_STRLEN_PP(tmp_str)) {
2348 0 : f = Z_STRLEN_PP(tmp_str);
2349 : }
2350 50 : zend_hash_move_forward_ex(Z_ARRVAL_PP(from), &pos_from);
2351 : } else {
2352 6 : f = 0;
2353 : }
2354 : } else {
2355 15 : f = Z_LVAL_PP(from);
2356 15 : if (f < 0) {
2357 0 : f = Z_STRLEN_PP(tmp_str) + f;
2358 0 : if (f < 0) {
2359 0 : f = 0;
2360 : }
2361 15 : } else if (f > Z_STRLEN_PP(tmp_str)) {
2362 0 : f = Z_STRLEN_PP(tmp_str);
2363 : }
2364 : }
2365 :
2366 100 : if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
2367 29 : if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(len), (void **) &tmp_len, &pos_len)) {
2368 23 : convert_to_long_ex(tmp_len);
2369 :
2370 23 : l = Z_LVAL_PP(tmp_len);
2371 23 : zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len);
2372 : } else {
2373 6 : l = Z_STRLEN_PP(tmp_str);
2374 : }
2375 42 : } else if (argc > 3) {
2376 36 : l = Z_LVAL_PP(len);
2377 : } else {
2378 6 : l = Z_STRLEN_PP(tmp_str);
2379 : }
2380 :
2381 71 : if (l < 0) {
2382 19 : l = (Z_STRLEN_PP(tmp_str) - f) + l;
2383 19 : if (l < 0) {
2384 0 : l = 0;
2385 : }
2386 : }
2387 :
2388 71 : if ((f + l) > Z_STRLEN_PP(tmp_str)) {
2389 14 : l = Z_STRLEN_PP(tmp_str) - f;
2390 : }
2391 :
2392 71 : result_len = Z_STRLEN_PP(tmp_str) - l;
2393 :
2394 71 : if (Z_TYPE_PP(repl) == IS_ARRAY) {
2395 34 : if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
2396 19 : convert_to_string_ex(tmp_repl);
2397 19 : result_len += Z_STRLEN_PP(tmp_repl);
2398 19 : zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);
2399 19 : result = emalloc(result_len + 1);
2400 :
2401 19 : memcpy(result, Z_STRVAL_PP(tmp_str), f);
2402 19 : memcpy((result + f), Z_STRVAL_PP(tmp_repl), Z_STRLEN_PP(tmp_repl));
2403 19 : memcpy((result + f + Z_STRLEN_PP(tmp_repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
2404 : } else {
2405 15 : result = emalloc(result_len + 1);
2406 :
2407 15 : memcpy(result, Z_STRVAL_PP(tmp_str), f);
2408 15 : memcpy((result + f), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
2409 : }
2410 : } else {
2411 37 : result_len += Z_STRLEN_PP(repl);
2412 :
2413 37 : result = emalloc(result_len + 1);
2414 :
2415 37 : memcpy(result, Z_STRVAL_PP(tmp_str), f);
2416 37 : memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl));
2417 37 : memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
2418 : }
2419 :
2420 71 : result[result_len] = '\0';
2421 71 : add_next_index_stringl(return_value, result, result_len, 0);
2422 :
2423 71 : zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str);
2424 : } /*while*/
2425 : } /* if */
2426 : }
2427 : /* }}} */
2428 :
2429 : /* {{{ proto string quotemeta(string str)
2430 : Quotes meta characters */
2431 : PHP_FUNCTION(quotemeta)
2432 6 : {
2433 : char *str, *old;
2434 : char *old_end;
2435 : char *p, *q;
2436 : char c;
2437 : int old_len;
2438 :
2439 6 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &old, &old_len) == FAILURE) {
2440 2 : return;
2441 : }
2442 :
2443 4 : old_end = old + old_len;
2444 :
2445 4 : if (old == old_end) {
2446 0 : RETURN_FALSE;
2447 : }
2448 :
2449 4 : str = safe_emalloc(2, old_len, 1);
2450 :
2451 60 : for (p = old, q = str; p != old_end; p++) {
2452 56 : c = *p;
2453 56 : switch (c) {
2454 : case '.':
2455 : case '\\':
2456 : case '+':
2457 : case '*':
2458 : case '?':
2459 : case '[':
2460 : case '^':
2461 : case ']':
2462 : case '$':
2463 : case '(':
2464 : case ')':
2465 24 : *q++ = '\\';
2466 : /* break is missing _intentionally_ */
2467 : default:
2468 56 : *q++ = c;
2469 : }
2470 : }
2471 4 : *q = 0;
2472 :
2473 4 : RETURN_STRINGL(erealloc(str, q - str + 1), q - str, 0);
2474 : }
2475 : /* }}} */
2476 :
2477 : /* {{{ proto int ord(string character)
2478 : Returns ASCII value of character */
2479 : PHP_FUNCTION(ord)
2480 24064 : {
2481 : char *str;
2482 : int str_len;
2483 :
2484 24064 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
2485 8 : return;
2486 : }
2487 :
2488 24056 : RETURN_LONG((unsigned char) str[0]);
2489 : }
2490 : /* }}} */
2491 :
2492 : /* {{{ proto string chr(int ascii)
2493 : Converts ASCII code to a character */
2494 : PHP_FUNCTION(chr)
2495 638086 : {
2496 : long c;
2497 : char temp[2];
2498 :
2499 638086 : if (ZEND_NUM_ARGS() != 1) {
2500 4 : WRONG_PARAM_COUNT;
2501 : }
2502 :
2503 638082 : if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "l", &c) == FAILURE) {
2504 15 : c = 0;
2505 : }
2506 :
2507 638082 : temp[0] = (char)c;
2508 638082 : temp[1] = '\0';
2509 :
2510 638082 : RETURN_STRINGL(temp, 1, 1);
2511 : }
2512 : /* }}} */
2513 :
2514 : /* {{{ php_ucfirst
2515 : Uppercase the first character of the word in a native string */
2516 : static void php_ucfirst(char *str)
2517 56 : {
2518 : register char *r;
2519 56 : r = str;
2520 56 : *r = toupper((unsigned char) *r);
2521 56 : }
2522 : /* }}} */
2523 :
2524 : /* {{{ proto string ucfirst(string str)
2525 : Makes a string's first character uppercase */
2526 : PHP_FUNCTION(ucfirst)
2527 64 : {
2528 : char *str;
2529 : int str_len;
2530 :
2531 64 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
2532 4 : return;
2533 : }
2534 :
2535 60 : if (!str_len) {
2536 4 : RETURN_EMPTY_STRING();
2537 : }
2538 :
2539 56 : ZVAL_STRINGL(return_value, str, str_len, 1);
2540 56 : php_ucfirst(Z_STRVAL_P(return_value));
2541 : }
2542 : /* }}} */
2543 :
2544 : /* {{{
2545 : Lowercase the first character of the word in a native string */
2546 : static void php_lcfirst(char *str)
2547 41 : {
2548 : register char *r;
2549 41 : r = str;
2550 41 : *r = tolower((unsigned char) *r);
2551 41 : }
2552 : /* }}} */
2553 :
2554 : /* {{{ proto string ucfirst(string str)
2555 : Make a string's first character lowercase */
2556 : PHP_FUNCTION(lcfirst)
2557 49 : {
2558 : char *str;
2559 : int str_len;
2560 :
2561 49 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
2562 4 : return;
2563 : }
2564 :
2565 45 : if (!str_len) {
2566 4 : RETURN_EMPTY_STRING();
2567 : }
2568 :
2569 41 : ZVAL_STRINGL(return_value, str, str_len, 1);
2570 41 : php_lcfirst(Z_STRVAL_P(return_value));
2571 : }
2572 : /* }}} */
2573 :
2574 : /* {{{ proto string ucwords(string str)
2575 : Uppercase the first character of every word in a string */
2576 : PHP_FUNCTION(ucwords)
2577 111 : {
2578 : char *str;
2579 : register char *r, *r_end;
2580 : int str_len;
2581 :
2582 111 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
2583 8 : return;
2584 : }
2585 :
2586 103 : if (!str_len) {
2587 10 : RETURN_EMPTY_STRING();
2588 : }
2589 :
2590 93 : ZVAL_STRINGL(return_value, str, str_len, 1);
2591 93 : r = Z_STRVAL_P(return_value);
2592 :
2593 93 : *r = toupper((unsigned char) *r);
2594 1942 : for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) {
2595 1756 : if (isspace((int) *(unsigned char *)r++)) {
2596 201 : *r = toupper((unsigned char) *r);
2597 : }
2598 : }
2599 : }
2600 : /* }}} */
2601 :
2602 : /* {{{ php_strtr
2603 : */
2604 : PHPAPI char *php_strtr(char *str, int len, char *str_from, char *str_to, int trlen)
2605 142 : {
2606 : int i;
2607 : unsigned char xlat[256];
2608 :
2609 142 : if ((trlen < 1) || (len < 1)) {
2610 12 : return str;
2611 : }
2612 :
2613 130 : for (i = 0; i < 256; xlat[i] = i, i++);
2614 :
2615 3125 : for (i = 0; i < trlen; i++) {
2616 2995 : xlat[(unsigned char) str_from[i]] = str_to[i];
2617 : }
2618 :
2619 83402 : for (i = 0; i < len; i++) {
2620 83272 : str[i] = xlat[(unsigned char) str[i]];
2621 : }
2622 :
2623 130 : return str;
2624 : }
2625 : /* }}} */
2626 :
2627 : /* {{{ php_strtr_array
2628 : */
2629 : static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *hash)
2630 40 : {
2631 : zval **entry;
2632 : char *string_key;
2633 : uint string_key_len;
2634 : zval **trans;
2635 : zval ctmp;
2636 : ulong num_key;
2637 40 : int minlen = 128*1024;
2638 40 : int maxlen = 0, pos, len, found;
2639 : char *key;
2640 : HashPosition hpos;
2641 40 : smart_str result = {0};
2642 : HashTable tmp_hash;
2643 :
2644 40 : zend_hash_init(&tmp_hash, zend_hash_num_elements(hash), NULL, NULL, 0);
2645 40 : zend_hash_internal_pointer_reset_ex(hash, &hpos);
2646 191 : while (zend_hash_get_current_data_ex(hash, (void **)&entry, &hpos) == SUCCESS) {
2647 111 : switch (zend_hash_get_current_key_ex(hash, &string_key, &string_key_len, &num_key, 0, &hpos)) {
2648 : case HASH_KEY_IS_STRING:
2649 100 : len = string_key_len-1;
2650 100 : if (len < 1) {
2651 0 : zend_hash_destroy(&tmp_hash);
2652 0 : RETURN_FALSE;
2653 : }
2654 100 : zend_hash_add(&tmp_hash, string_key, string_key_len, entry, sizeof(zval*), NULL);
2655 100 : if (len > maxlen) {
2656 68 : maxlen = len;
2657 : }
2658 100 : if (len < minlen) {
2659 32 : minlen = len;
2660 : }
2661 100 : break;
2662 :
2663 : case HASH_KEY_IS_LONG:
2664 11 : Z_TYPE(ctmp) = IS_LONG;
2665 11 : Z_LVAL(ctmp) = num_key;
2666 :
2667 11 : convert_to_string(&ctmp);
2668 11 : len = Z_STRLEN(ctmp);
2669 11 : zend_hash_add(&tmp_hash, Z_STRVAL(ctmp), len+1, entry, sizeof(zval*), NULL);
2670 11 : zval_dtor(&ctmp);
2671 :
2672 11 : if (len > maxlen) {
2673 10 : maxlen = len;
2674 : }
2675 11 : if (len < minlen) {
2676 10 : minlen = len;
2677 : }
2678 : break;
2679 : }
2680 111 : zend_hash_move_forward_ex(hash, &hpos);
2681 : }
2682 :
2683 40 : key = emalloc(maxlen+1);
2684 40 : pos = 0;
2685 :
2686 1039 : while (pos < slen) {
2687 959 : if ((pos + maxlen) > slen) {
2688 77 : maxlen = slen - pos;
2689 : }
2690 :
2691 959 : found = 0;
2692 959 : memcpy(key, str+pos, maxlen);
2693 :
2694 3033 : for (len = maxlen; len >= minlen; len--) {
2695 2166 : key[len] = 0;
2696 :
2697 2166 : if (zend_hash_find(&tmp_hash, key, len+1, (void**)&trans) == SUCCESS) {
2698 : char *tval;
2699 : int tlen;
2700 : zval tmp;
2701 :
2702 92 : if (Z_TYPE_PP(trans) != IS_STRING) {
2703 9 : tmp = **trans;
2704 9 : zval_copy_ctor(&tmp);
2705 9 : convert_to_string(&tmp);
2706 9 : tval = Z_STRVAL(tmp);
2707 9 : tlen = Z_STRLEN(tmp);
2708 : } else {
2709 83 : tval = Z_STRVAL_PP(trans);
2710 83 : tlen = Z_STRLEN_PP(trans);
2711 : }
2712 :
2713 92 : smart_str_appendl(&result, tval, tlen);
2714 92 : pos += len;
2715 92 : found = 1;
2716 :
2717 92 : if (Z_TYPE_PP(trans) != IS_STRING) {
2718 9 : zval_dtor(&tmp);
2719 : }
2720 92 : break;
2721 : }
2722 : }
2723 :
2724 959 : if (! found) {
2725 867 : smart_str_appendc(&result, str[pos++]);
2726 : }
2727 : }
2728 :
2729 40 : efree(key);
2730 40 : zend_hash_destroy(&tmp_hash);
2731 40 : smart_str_0(&result);
2732 40 : RETVAL_STRINGL(result.c, result.len, 0);
2733 : }
2734 : /* }}} */
2735 :
2736 : /* {{{ proto string strtr(string str, string from[, string to])
2737 : Translates characters in str using given translation tables */
2738 : PHP_FUNCTION(strtr)
2739 210 : {
2740 : zval **from;
2741 210 : char *str, *to = NULL;
2742 210 : int str_len, to_len = 0;
2743 210 : int ac = ZEND_NUM_ARGS();
2744 :
2745 210 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &str, &str_len, &from, &to, &to_len) == FAILURE) {
2746 23 : return;
2747 : }
2748 :
2749 187 : if (ac == 2 && Z_TYPE_PP(from) != IS_ARRAY) {
2750 31 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument is not an array");
2751 31 : RETURN_FALSE;
2752 : }
2753 :
2754 : /* shortcut for empty string */
2755 156 : if (str_len == 0) {
2756 27 : RETURN_EMPTY_STRING();
2757 : }
2758 :
2759 129 : if (ac == 2) {
2760 40 : php_strtr_array(return_value, str, str_len, HASH_OF(*from));
2761 : } else {
2762 89 : convert_to_string_ex(from);
2763 :
2764 89 : ZVAL_STRINGL(return_value, str, str_len, 1);
2765 :
2766 89 : php_strtr(Z_STRVAL_P(return_value),
2767 : Z_STRLEN_P(return_value),
2768 : Z_STRVAL_PP(from),
2769 : to,
2770 : MIN(Z_STRLEN_PP(from),
2771 : to_len));
2772 : }
2773 : }
2774 : /* }}} */
2775 :
2776 : /* {{{ proto string strrev(string str)
2777 : Reverse a string */
2778 : PHP_FUNCTION(strrev)
2779 101 : {
2780 : char *str;
2781 : char *e, *n, *p;
2782 : int str_len;
2783 :
2784 101 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
2785 8 : return;
2786 : }
2787 :
2788 93 : n = emalloc(str_len+1);
2789 93 : p = n;
2790 :
2791 93 : e = str + str_len;
2792 :
2793 4301 : while (--e>=str) {
2794 4115 : *p++ = *e;
2795 : }
2796 :
2797 93 : *p = '\0';
2798 :
2799 93 : RETVAL_STRINGL(n, str_len, 0);
2800 : }
2801 : /* }}} */
2802 :
2803 : /* {{{ php_similar_str
2804 : */
2805 : static void php_similar_str(const char *txt1, int len1, const char *txt2, int len2, int *pos1, int *pos2, int *max)
2806 10 : {
2807 : char *p, *q;
2808 10 : char *end1 = (char *) txt1 + len1;
2809 10 : char *end2 = (char *) txt2 + len2;
2810 : int l;
2811 :
2812 10 : *max = 0;
2813 104 : for (p = (char *) txt1; p < end1; p++) {
2814 602 : for (q = (char *) txt2; q < end2; q++) {
2815 508 : for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]); l++);
2816 508 : if (l > *max) {
2817 6 : *max = l;
2818 6 : *pos1 = p - txt1;
2819 6 : *pos2 = q - txt2;
2820 : }
2821 : }
2822 : }
2823 10 : }
2824 : /* }}} */
2825 :
2826 : /* {{{ php_similar_char
2827 : */
2828 : static int php_similar_char(const char *txt1, int len1, const char *txt2, int len2)
2829 10 : {
2830 : int sum;
2831 : int pos1, pos2, max;
2832 :
2833 10 : php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
2834 10 : if ((sum = max)) {
2835 6 : if (pos1 && pos2) {
2836 0 : sum += php_similar_char(txt1, pos1,
2837 : txt2, pos2);
2838 : }
2839 6 : if ((pos1 + max < len1) && (pos2 + max < len2)) {
2840 2 : sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
2841 : txt2 + pos2 + max, len2 - pos2 - max);
2842 : }
2843 : }
2844 :
2845 10 : return sum;
2846 : }
2847 : /* }}} */
2848 :
2849 : /* {{{ proto int similar_text(string str1, string str2 [, float percent])
2850 : Calculates the similarity between two strings */
2851 : PHP_FUNCTION(similar_text)
2852 10 : {
2853 : char *t1, *t2;
2854 10 : zval **percent = NULL;
2855 10 : int ac = ZEND_NUM_ARGS();
2856 : int sim;
2857 : int t1_len, t2_len;
2858 :
2859 10 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|Z", &t1, &t1_len, &t2, &t2_len, &percent) == FAILURE) {
2860 2 : return;
2861 : }
2862 :
2863 8 : if (ac > 2) {
2864 4 : convert_to_double_ex(percent);
2865 : }
2866 :
2867 8 : if (t1_len + t2_len == 0) {
2868 0 : if (ac > 2) {
2869 0 : Z_DVAL_PP(percent) = 0;
2870 : }
2871 :
2872 0 : RETURN_LONG(0);
2873 : }
2874 :
2875 8 : sim = php_similar_char(t1, t1_len, t2, t2_len);
2876 :
2877 8 : if (ac > 2) {
2878 4 : Z_DVAL_PP(percent) = sim * 200.0 / (t1_len + t2_len);
2879 : }
2880 :
2881 8 : RETURN_LONG(sim);
2882 : }
2883 : /* }}} */
2884 :
2885 : /* {{{ php_stripslashes
2886 : *
2887 : * be careful, this edits the string in-place */
2888 : PHPAPI void php_stripslashes(char *str, int *len TSRMLS_DC)
2889 145 : {
2890 : char *s, *t;
2891 : int l;
2892 :
2893 145 : if (len != NULL) {
2894 145 : l = *len;
2895 : } else {
2896 0 : l = strlen(str);
2897 : }
2898 145 : s = str;
2899 145 : t = str;
2900 :
2901 145 : if (PG(magic_quotes_sybase)) {
2902 1016 : while (l > 0) {
2903 950 : if (*t == '\'') {
2904 22 : if ((l > 0) && (t[1] == '\'')) {
2905 22 : t++;
2906 22 : if (len != NULL) {
2907 22 : (*len)--;
2908 : }
2909 22 : l--;
2910 : }
2911 22 : *s++ = *t++;
2912 941 : } else if (*t == '\\' && t[1] == '0' && l > 0) {
2913 13 : *s++='\0';
2914 13 : t+=2;
2915 13 : if (len != NULL) {
2916 13 : (*len)--;
2917 : }
2918 13 : l--;
2919 : } else {
2920 915 : *s++ = *t++;
2921 : }
2922 950 : l--;
2923 : }
2924 33 : *s = '\0';
2925 :
2926 33 : return;
2927 : }
2928 :
2929 1649 : while (l > 0) {
2930 1425 : if (*t == '\\') {
2931 117 : t++; /* skip the slash */
2932 117 : if (len != NULL) {
2933 117 : (*len)--;
2934 : }
2935 117 : l--;
2936 117 : if (l > 0) {
2937 117 : if (*t == '0') {
2938 15 : *s++='\0';
2939 15 : t++;
2940 : } else {
2941 102 : *s++ = *t++; /* preserve the next character */
2942 : }
2943 117 : l--;
2944 : }
2945 : } else {
2946 1308 : *s++ = *t++;
2947 1308 : l--;
2948 : }
2949 : }
2950 112 : if (s != t) {
2951 68 : *s = '\0';
2952 : }
2953 : }
2954 : /* }}} */
2955 :
2956 : /* {{{ proto string addcslashes(string str, string charlist)
2957 : Escapes all chars mentioned in charlist with backslash. It creates octal representations if asked to backslash characters with 8th bit set or with ASCII<32 (except '\n', '\r', '\t' etc...) */
2958 : PHP_FUNCTION(addcslashes)
2959 45 : {
2960 : char *str, *what;
2961 : int str_len, what_len;
2962 :
2963 45 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &str, &str_len, &what, &what_len) == FAILURE) {
2964 4 : return;
2965 : }
2966 :
2967 41 : if (str_len == 0) {
2968 6 : RETURN_EMPTY_STRING();
2969 : }
2970 :
2971 35 : if (what_len == 0) {
2972 5 : RETURN_STRINGL(str, str_len, 1);
2973 : }
2974 :
2975 30 : Z_STRVAL_P(return_value) = php_addcslashes(str, str_len, &Z_STRLEN_P(return_value), 0, what, what_len TSRMLS_CC);
2976 30 : RETURN_STRINGL(Z_STRVAL_P(return_value), Z_STRLEN_P(return_value), 0);
2977 : }
2978 : /* }}} */
2979 :
2980 : /* {{{ proto string addslashes(string str)
2981 : Escapes single quote, double quotes and backslash characters in a string with backslashes */
2982 : PHP_FUNCTION(addslashes)
2983 381255 : {
2984 : char *str;
2985 : int str_len;
2986 :
2987 381255 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
2988 8 : return;
2989 : }
2990 :
2991 381247 : if (str_len == 0) {
2992 97853 : RETURN_EMPTY_STRING();
2993 : }
2994 :
2995 283394 : RETURN_STRING(php_addslashes(str,
2996 : str_len,
2997 : &Z_STRLEN_P(return_value), 0
2998 : TSRMLS_CC), 0);
2999 : }
3000 : /* }}} */
3001 :
3002 : /* {{{ proto string stripcslashes(string str)
3003 : Strips backslashes from a string. Uses C-style conventions */
3004 : PHP_FUNCTION(stripcslashes)
3005 35 : {
3006 : char *str;
3007 : int str_len;
3008 :
3009 35 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
3010 8 : return;
3011 : }
3012 :
3013 27 : ZVAL_STRINGL(return_value, str, str_len, 1);
3014 27 : php_stripcslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value));
3015 : }
3016 : /* }}} */
3017 :
3018 : /* {{{ proto string stripslashes(string str)
3019 : Strips backslashes from a string */
3020 : PHP_FUNCTION(stripslashes)
3021 144 : {
3022 : char *str;
3023 : int str_len;
3024 :
3025 144 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) {
3026 8 : return;
3027 : }
3028 :
3029 136 : ZVAL_STRINGL(return_value, str, str_len, 1);
3030 136 : php_stripslashes(Z_STRVAL_P(return_value), &Z_STRLEN_P(return_value) TSRMLS_CC);
3031 : }
3032 : /* }}} */
3033 :
3034 : #ifndef HAVE_STRERROR
3035 : /* {{{ php_strerror
3036 : */
3037 : char *php_strerror(int errnum)
3038 : {
3039 : extern int sys_nerr;
3040 : extern char *sys_errlist[];
3041 : TSRMLS_FETCH();
3042 :
3043 : if ((unsigned int) errnum < sys_nerr) {
3044 : return(sys_errlist[errnum]);
3045 : }
3046 :
3047 : (void) snprintf(BG(str_ebuf), sizeof(php_basic_globals.str_ebuf), "Unknown error: %d", errnum);
3048 : return(BG(str_ebuf));
3049 : }
3050 : /* }}} */
3051 : #endif
3052 :
3053 : /* {{{ php_stripcslashes
3054 : */
3055 : PHPAPI void php_stripcslashes(char *str, int *len)
3056 27 : {
3057 : char *source, *target, *end;
3058 27 : int nlen = *len, i;
3059 : char numtmp[4];
3060 :
3061 134 : for (source=str, end=str+nlen, target=str; source < end; source++) {
3062 142 : if (*source == '\\' && source+1 < end) {
3063 35 : source++;
3064 35 : switch (*source) {
3065 2 : case 'n': *target++='\n'; nlen--; break;
3066 2 : case 'r': *target++='\r'; nlen--; break;
3067 0 : case 'a': *target++='\a'; nlen--; break;
3068 0 : case 't': *target++='\t'; nlen--; break;
3069 0 : case 'v': *target++='\v'; nlen--; break;
3070 0 : case 'b': *target++='\b'; nlen--; break;
3071 0 : case 'f': *target++='\f'; nlen--; break;
3072 0 : case '\\': *target++='\\'; nlen--; break;
3073 : case 'x':
3074 11 : if (source+1 < end && isxdigit((int)(*(source+1)))) {
3075 11 : numtmp[0] = *++source;
3076 22 : if (source+1 < end && isxdigit((int)(*(source+1)))) {
3077 11 : numtmp[1] = *++source;
3078 11 : numtmp[2] = '\0';
3079 11 : nlen-=3;
3080 : } else {
3081 0 : numtmp[1] = '\0';
3082 0 : nlen-=2;
3083 : }
3084 11 : *target++=(char)strtol(numtmp, NULL, 16);
3085 11 : break;
3086 : }
3087 : /* break is left intentionally */
3088 : default:
3089 20 : i=0;
3090 73 : while (source < end && *source >= '0' && *source <= '7' && i<3) {
3091 33 : numtmp[i++] = *source++;
3092 : }
3093 20 : if (i) {
3094 11 : numtmp[i]='\0';
3095 11 : *target++=(char)strtol(numtmp, NULL, 8);
3096 11 : nlen-=i;
3097 11 : source--;
3098 : } else {
3099 9 : *target++=*source;
3100 9 : nlen--;
3101 : }
3102 : }
3103 : } else {
3104 72 : *target++=*source;
3105 : }
3106 : }
3107 :
3108 27 : if (nlen != 0) {
3109 18 : *target='\0';
3110 : }
3111 :
3112 27 : *len = nlen;
3113 27 : }
3114 : /* }}} */
3115 :
3116 : /* {{{ php_addcslashes
3117 : */
3118 : PHPAPI char *php_addcslashes(char *str, int length, int *new_length, int should_free, char *what, int wlength TSRMLS_DC)
3119 1401 : {
3120 : char flags[256];
3121 1401 : char *new_str = safe_emalloc(4, (length?length:(length=strlen(str))), 1);
3122 : char *source, *target;
3123 : char *end;
3124 : char c;
3125 : int newlen;
3126 :
3127 1401 : if (!wlength) {
3128 0 : wlength = strlen(what);
3129 : }
3130 :
3131 1401 : php_charmask((unsigned char *)what, wlength, flags TSRMLS_CC);
3132 :
3133 15533 : for (source = str, end = source + length, target = new_str; source < end; source++) {
3134 14132 : c = *source;
3135 14132 : if (flags[(unsigned char)c]) {
3136 127 : if ((unsigned char) c < 32 || (unsigned char) c > 126) {
3137 16 : *target++ = '\\';
3138 16 : switch (c) {
3139 2 : case '\n': *target++ = 'n'; break;
3140 2 : case '\t': *target++ = 't'; break;
3141 2 : case '\r': *target++ = 'r'; break;
3142 0 : case '\a': *target++ = 'a'; break;
3143 2 : case '\v': *target++ = 'v'; break;
3144 0 : case '\b': *target++ = 'b'; break;
3145 2 : case '\f': *target++ = 'f'; break;
3146 6 : default: target += sprintf(target, "%03o", (unsigned char) c);
3147 : }
3148 16 : continue;
3149 : }
3150 111 : *target++ = '\\';
3151 : }
3152 14116 : *target++ = c;
3153 : }
3154 1401 : *target = 0;
3155 1401 : newlen = target - new_str;
3156 1401 : if (target - new_str < length * 4) {
3157 1352 : new_str = erealloc(new_str, newlen + 1);
3158 : }
3159 1401 : if (new_length) {
3160 1401 : *new_length = newlen;
3161 : }
3162 1401 : if (should_free) {
3163 0 : STR_FREE(str);
3164 : }
3165 1401 : return new_str;
3166 : }
3167 : /* }}} */
3168 :
3169 : /* {{{ php_addslashes
3170 : */
3171 : PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free TSRMLS_DC)
3172 284950 : {
3173 284950 : return php_addslashes_ex(str, length, new_length, should_free, 0 TSRMLS_CC);
3174 : }
3175 : /* }}} */
3176 :
3177 : /* {{{ php_addslashes_ex
3178 : */
3179 : PHPAPI char *php_addslashes_ex(char *str, int length, int *new_length, int should_free, int ignore_sybase TSRMLS_DC)
3180 284958 : {
3181 : /* maximum string length, worst case situation */
3182 : char *new_str;
3183 : char *source, *target;
3184 : char *end;
3185 : int local_new_length;
3186 :
3187 284958 : if (!new_length) {
3188 18 : new_length = &local_new_length;
3189 : }
3190 284958 : if (!str) {
3191 0 : *new_length = 0;
3192 0 : return str;
3193 : }
3194 284958 : new_str = (char *) safe_emalloc(2, (length ? length : (length = strlen(str))), 1);
3195 284958 : source = str;
3196 284958 : end = source + length;
3197 284958 : target = new_str;
3198 :
3199 285019 : if (!ignore_sybase && PG(magic_quotes_sybase)) {
3200 1524 : while (source < end) {
3201 1402 : switch (*source) {
3202 : case '\0':
3203 24 : *target++ = '\\';
3204 24 : *target++ = '0';
3205 24 : break;
3206 : case '\'':
3207 42 : *target++ = '\'';
3208 42 : *target++ = '\'';
3209 42 : break;
3210 : default:
3211 1336 : *target++ = *source;
3212 : break;
3213 : }
3214 1402 : source++;
3215 : }
3216 : } else {
3217 1572258 : while (source < end) {
3218 1002464 : switch (*source) {
3219 : case '\0':
3220 36 : *target++ = '\\';
3221 36 : *target++ = '0';
3222 36 : break;
3223 : case '\'':
3224 : case '\"':
3225 : case '\\':
3226 339 : *target++ = '\\';
3227 : /* break is missing *intentionally* */
3228 : default:
3229 1002428 : *target++ = *source;
3230 : break;
3231 : }
3232 :
3233 1002464 : source++;
3234 : }
3235 : }
3236 :
3237 284958 : *target = 0;
3238 284958 : *new_length = target - new_str;
3239 284958 : if (should_free) {
3240 6 : STR_FREE(str);
3241 : }
3242 284958 : new_str = (char *) erealloc(new_str, *new_length + 1);
3243 284958 : return new_str;
3244 : }
3245 : /* }}} */
3246 :
3247 : #define _HEB_BLOCK_TYPE_ENG 1
3248 : #define _HEB_BLOCK_TYPE_HEB 2
3249 : #define isheb(c) (((((unsigned char) c) >= 224) && (((unsigned char) c) <= 250)) ? 1 : 0)
3250 : #define _isblank(c) (((((unsigned char) c) == ' ' || ((unsigned char) c) == '\t')) ? 1 : 0)
3251 : #define _isnewline(c) (((((unsigned char) c) == '\n' || ((unsigned char) c) == '\r')) ? 1 : 0)
3252 :
3253 : /* {{{ php_char_to_str_ex
3254 : */
3255 : PHPAPI int php_char_to_str_ex(char *str, uint len, char from, char *to, int to_len, zval *result, int case_sensitivity, int *replace_count)
3256 5433 : {
3257 5433 : int char_count = 0;
3258 5433 : int replaced = 0;
3259 5433 : char *source, *target, *tmp, *source_end=str+len, *tmp_end = NULL;
3260 :
3261 5433 : if (case_sensitivity) {
3262 5423 : char *p = str, *e = p + len;
3263 18977 : while ((p = memchr(p, from, (e - p)))) {
3264 8131 : char_count++;
3265 8131 : p++;
3266 : }
3267 : } else {
3268 327 : for (source = str; source < source_end; source++) {
3269 317 : if (tolower(*source) == tolower(from)) {
3270 29 : char_count++;
3271 : }
3272 : }
3273 : }
3274 :
3275 5433 : if (char_count == 0 && case_sensitivity) {
3276 801 : ZVAL_STRINGL(result, str, len, 1);
3277 801 : return 0;
3278 : }
3279 :
3280 4632 : Z_STRLEN_P(result) = len + (char_count * (to_len - 1));
3281 4632 : Z_STRVAL_P(result) = target = safe_emalloc(char_count, to_len, len + 1);
3282 4632 : Z_TYPE_P(result) = IS_STRING;
3283 :
3284 4632 : if (case_sensitivity) {
3285 4622 : char *p = str, *e = p + len, *s = str;
3286 17375 : while ((p = memchr(p, from, (e - p)))) {
3287 8131 : memcpy(target, s, (p - s));
3288 8131 : target += p - s;
3289 8131 : memcpy(target, to, to_len);
3290 8131 : target += to_len;
3291 8131 : p++;
3292 8131 : s = p;
3293 8131 : if (replace_count) {
3294 266 : *replace_count += 1;
3295 : }
3296 : }
3297 4622 : if (s < e) {
3298 834 : memcpy(target, s, (e - s));
3299 834 : target += e - s;
3300 : }
3301 : } else {
3302 327 : for (source = str; source < source_end; source++) {
3303 317 : if (tolower(*source) == tolower(from)) {
3304 29 : replaced = 1;
3305 29 : if (replace_count) {
3306 0 : *replace_count += 1;
3307 : }
3308 117 : for (tmp = to, tmp_end = tmp+to_len; tmp < tmp_end; tmp++) {
3309 88 : *target = *tmp;
3310 88 : target++;
3311 : }
3312 : } else {
3313 288 : *target = *source;
3314 288 : target++;
3315 : }
3316 : }
3317 : }
3318 4632 : *target = 0;
3319 4632 : return replaced;
3320 : }
3321 : /* }}} */
3322 :
3323 : /* {{{ php_char_to_str
3324 : */
3325 : PHPAPI int php_char_to_str(char *str, uint len, char from, char *to, int to_len, zval *result)
3326 34 : {
3327 34 : return php_char_to_str_ex(str, len, from, to, to_len, result, 1, NULL);
3328 : }
3329 : /* }}} */
3330 :
3331 : /* {{{ php_str_to_str_ex
3332 : */
3333 : PHPAPI char *php_str_to_str_ex(char *haystack, int length,
3334 : char *needle, int needle_len, char *str, int str_len, int *_new_length, int case_sensitivity, int *replace_count)
3335 146133 : {
3336 : char *new_str;
3337 :
3338 146133 : if (needle_len < length) {
3339 144591 : char *end, *haystack_dup = NULL, *needle_dup = NULL;
3340 : char *e, *s, *p, *r;
3341 :
3342 144591 : if (needle_len == str_len) {
3343 20972 : new_str = estrndup(haystack, length);
3344 20972 : *_new_length = length;
3345 :
3346 20972 : if (case_sensitivity) {
3347 20970 : end = new_str + length;
3348 21186 : for (p = new_str; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
3349 216 : memcpy(r, str, str_len);
3350 216 : if (replace_count) {
3351 8 : (*replace_count)++;
3352 : }
3353 : }
3354 : } else {
3355 2 : haystack_dup = estrndup(haystack, length);
3356 2 : needle_dup = estrndup(needle, needle_len);
3357 2 : php_strtolower(haystack_dup, length);
3358 2 : php_strtolower(needle_dup, needle_len);
3359 2 : end = haystack_dup + length;
3360 16 : for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
3361 14 : memcpy(new_str + (r - haystack_dup), str, str_len);
3362 14 : if (replace_count) {
3363 7 : (*replace_count)++;
3364 : }
3365 : }
3366 2 : efree(haystack_dup);
3367 2 : efree(needle_dup);
3368 : }
3369 20972 : return new_str;
3370 : } else {
3371 123619 : if (!case_sensitivity) {
3372 1057 : haystack_dup = estrndup(haystack, length);
3373 1057 : needle_dup = estrndup(needle, needle_len);
3374 1057 : php_strtolower(haystack_dup, length);
3375 1057 : php_strtolower(needle_dup, needle_len);
3376 : }
3377 :
3378 123619 : if (str_len < needle_len) {
3379 73625 : new_str = emalloc(length + 1);
3380 : } else {
3381 49994 : int count = 0;
3382 : char *o, *n, *endp;
3383 :
3384 49994 : if (case_sensitivity) {
3385 48986 : o = haystack;
3386 48986 : n = needle;
3387 : } else {
3388 1008 : o = haystack_dup;
3389 1008 : n = needle_dup;
3390 : }
3391 49994 : endp = o + length;
3392 :
3393 155442 : while ((o = php_memnstr(o, n, needle_len, endp))) {
3394 55454 : o += needle_len;
3395 55454 : count++;
3396 : }
3397 49994 : if (count == 0) {
3398 : /* Needle doesn't occur, shortcircuit the actual replacement. */
3399 41470 : if (haystack_dup) {
3400 987 : efree(haystack_dup);
3401 : }
3402 41470 : if (needle_dup) {
3403 987 : efree(needle_dup);
3404 : }
3405 41470 : new_str = estrndup(haystack, length);
3406 41470 : if (_new_length) {
3407 41470 : *_new_length = length;
3408 : }
3409 41470 : return new_str;
3410 : } else {
3411 8524 : new_str = safe_emalloc(count, str_len - needle_len, length + 1);
3412 : }
3413 : }
3414 :
3415 82149 : e = s = new_str;
3416 :
3417 82149 : if (case_sensitivity) {
3418 82079 : end = haystack + length;
3419 171719 : for (p = haystack; (r = php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
3420 89640 : memcpy(e, p, r - p);
3421 89640 : e += r - p;
3422 89640 : memcpy(e, str, str_len);
3423 89640 : e += str_len;
3424 89640 : if (replace_count) {
3425 66 : (*replace_count)++;
3426 : }
3427 : }
3428 :
3429 82079 : if (p < end) {
3430 82078 : memcpy(e, p, end - p);
3431 82078 : e += end - p;
3432 : }
3433 : } else {
3434 70 : end = haystack_dup + length;
3435 :
3436 234 : for (p = haystack_dup; (r = php_memnstr(p, needle_dup, needle_len, end)); p = r + needle_len) {
3437 164 : memcpy(e, haystack + (p - haystack_dup), r - p);
3438 164 : e += r - p;
3439 164 : memcpy(e, str, str_len);
3440 164 : e += str_len;
3441 164 : if (replace_count) {
3442 21 : (*replace_count)++;
3443 : }
3444 : }
3445 :
3446 70 : if (p < end) {
3447 28 : memcpy(e, haystack + (p - haystack_dup), end - p);
3448 28 : e += end - p;
3449 : }
3450 : }
3451 :
3452 82149 : if (haystack_dup) {
3453 70 : efree(haystack_dup);
3454 : }
3455 82149 : if (needle_dup) {
3456 70 : efree(needle_dup);
3457 : }
3458 :
3459 82149 : *e = '\0';
3460 82149 : *_new_length = e - s;
3461 :
3462 82149 : new_str = erealloc(new_str, *_new_length + 1);
3463 82149 : return new_str;
3464 : }
3465 1542 : } else if (needle_len > length) {
3466 1463 : nothing_todo:
3467 1463 : *_new_length = length;
3468 1463 : new_str = estrndup(haystack, length);
3469 1463 : return new_str;
3470 : } else {
3471 488 : if (case_sensitivity && memcmp(haystack, needle, length)) {
3472 : goto nothing_todo;
3473 405 : } else if (!case_sensitivity) {
3474 : char *l_haystack, *l_needle;
3475 :
3476 368 : l_haystack = estrndup(haystack, length);
3477 368 : l_needle = estrndup(needle, length);
3478 :
3479 368 : php_strtolower(l_haystack, length);
3480 368 : php_strtolower(l_needle, length);
3481 :
3482 368 : if (memcmp(l_haystack, l_needle, length)) {
3483 326 : efree(l_haystack);
3484 326 : efree(l_needle);
3485 326 : goto nothing_todo;
3486 : }
3487 42 : efree(l_haystack);
3488 42 : efree(l_needle);
3489 : }
3490 :
3491 79 : *_new_length = str_len;
3492 79 : new_str = estrndup(str, str_len);
3493 :
3494 79 : if (replace_count) {
3495 16 : (*replace_count)++;
3496 : }
3497 79 : return new_str;
3498 : }
3499 :
3500 : }
3501 : /* }}} */
3502 :
3503 : /* {{{ php_str_to_str
3504 : */
3505 : PHPAPI char *php_str_to_str(char *haystack, int length,
3506 : char *needle, int needle_len, char *str, int str_len, int *_new_length)
3507 26 : {
3508 26 : return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, _new_length, 1, NULL);
3509 : }
3510 : /* }}} */
3511 :
3512 : /* {{{ php_str_replace_in_subject
3513 : */
3514 : static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int case_sensitivity, int *replace_count)
3515 135460 : {
3516 : zval **search_entry,
3517 135460 : **replace_entry = NULL,
3518 : temp_result;
3519 135460 : char *replace_value = NULL;
3520 135460 : int replace_len = 0;
3521 :
3522 : /* Make sure we're dealing with strings. */
3523 135460 : convert_to_string_ex(subject);
3524 135460 : Z_TYPE_P(result) = IS_STRING;
3525 135460 : if (Z_STRLEN_PP(subject) == 0) {
3526 87 : ZVAL_STRINGL(result, "", 0, 1);
3527 87 : return;
3528 : }
3529 :
3530 : /* If search is an array */
3531 135373 : if (Z_TYPE_P(search) == IS_ARRAY) {
3532 : /* Duplicate subject string for repeated replacement */
3533 28800 : *result = **subject;
3534 28800 : zval_copy_ctor(result);
3535 28800 : INIT_PZVAL(result);
3536 :
3537 28800 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(search));
3538 :
3539 28800 : if (Z_TYPE_P(replace) == IS_ARRAY) {
3540 36 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(replace));
3541 : } else {
3542 : /* Set replacement value to the passed one */
3543 28764 : replace_value = Z_STRVAL_P(replace);
3544 28764 : replace_len = Z_STRLEN_P(replace);
3545 : }
3546 :
3547 : /* For each entry in the search array, get the entry */
3548 101214 : while (zend_hash_get_current_data(Z_ARRVAL_P(search), (void **) &search_entry) == SUCCESS) {
3549 : /* Make sure we're dealing with strings. */
3550 43616 : SEPARATE_ZVAL(search_entry);
3551 43616 : convert_to_string(*search_entry);
3552 43616 : if (Z_STRLEN_PP(search_entry) == 0) {
3553 0 : zend_hash_move_forward(Z_ARRVAL_P(search));
3554 0 : if (Z_TYPE_P(replace) == IS_ARRAY) {
3555 0 : zend_hash_move_forward(Z_ARRVAL_P(replace));
3556 : }
3557 0 : continue;
3558 : }
3559 :
3560 : /* If replace is an array. */
3561 43616 : if (Z_TYPE_P(replace) == IS_ARRAY) {
3562 : /* Get current entry */
3563 88 : if (zend_hash_get_current_data(Z_ARRVAL_P(replace), (void **)&replace_entry) == SUCCESS) {
3564 : /* Make sure we're dealing with strings. */
3565 78 : convert_to_string_ex(replace_entry);
3566 :
3567 : /* Set replacement value to the one we got from array */
3568 78 : replace_value = Z_STRVAL_PP(replace_entry);
3569 78 : replace_len = Z_STRLEN_PP(replace_entry);
3570 :
3571 78 : zend_hash_move_forward(Z_ARRVAL_P(replace));
3572 : } else {
3573 : /* We've run out of replacement strings, so use an empty one. */
3574 10 : replace_value = "";
3575 10 : replace_len = 0;
3576 : }
3577 : }
3578 :
3579 43616 : if (Z_STRLEN_PP(search_entry) == 1) {
3580 1674 : php_char_to_str_ex(Z_STRVAL_P(result),
3581 : Z_STRLEN_P(result),
3582 : Z_STRVAL_PP(search_entry)[0],
3583 : replace_value,
3584 : replace_len,
3585 : &temp_result,
3586 : case_sensitivity,
3587 : replace_count);
3588 41942 : } else if (Z_STRLEN_PP(search_entry) > 1) {
3589 41942 : Z_STRVAL(temp_result) = php_str_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result),
3590 : Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry),
3591 : replace_value, replace_len, &Z_STRLEN(temp_result), case_sensitivity, replace_count);
3592 : }
3593 :
3594 43616 : efree(Z_STRVAL_P(result));
3595 43616 : Z_STRVAL_P(result) = Z_STRVAL(temp_result);
3596 43616 : Z_STRLEN_P(result) = Z_STRLEN(temp_result);
3597 :
3598 43616 : if (Z_STRLEN_P(result) == 0) {
3599 2 : return;
3600 : }
3601 :
3602 43614 : zend_hash_move_forward(Z_ARRVAL_P(search));
3603 : }
3604 : } else {
3605 106573 : if (Z_STRLEN_P(search) == 1) {
3606 3725 : php_char_to_str_ex(Z_STRVAL_PP(subject),
3607 : Z_STRLEN_PP(subject),
3608 : Z_STRVAL_P(search)[0],
3609 : Z_STRVAL_P(replace),
3610 : Z_STRLEN_P(replace),
3611 : result,
3612 : case_sensitivity,
3613 : replace_count);
3614 102848 : } else if (Z_STRLEN_P(search) > 1) {
3615 102794 : Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject),
3616 : Z_STRVAL_P(search), Z_STRLEN_P(search),
3617 : Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), case_sensitivity, replace_count);
3618 : } else {
3619 54 : *result = **subject;
3620 54 : zval_copy_ctor(result);
3621 54 : INIT_PZVAL(result);
3622 : }
3623 : }
3624 : }
3625 : /* }}} */
3626 :
3627 : /* {{{ php_str_replace_common
3628 : */
3629 : static void php_str_replace_common(INTERNAL_FUNCTION_PARAMETERS, int case_sensitivity)
3630 135206 : {
3631 135206 : zval **subject, **search, **replace, **subject_entry, **zcount = NULL;
3632 : zval *result;
3633 : char *string_key;
3634 : uint string_key_len;
3635 : ulong num_key;
3636 135206 : int count = 0;
3637 135206 : int argc = ZEND_NUM_ARGS();
3638 :
3639 135206 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|Z", &search, &replace, &subject, &zcount) == FAILURE) {
3640 15 : return;
3641 : }
3642 :
3643 135191 : SEPARATE_ZVAL(search);
3644 135191 : SEPARATE_ZVAL(replace);
3645 135191 : SEPARATE_ZVAL(subject);
3646 :
3647 : /* Make sure we're dealing with strings and do the replacement. */
3648 135191 : if (Z_TYPE_PP(search) != IS_ARRAY) {
3649 106414 : convert_to_string_ex(search);
3650 106414 : convert_to_string_ex(replace);
3651 28777 : } else if (Z_TYPE_PP(replace) != IS_ARRAY) {
3652 28750 : convert_to_string_ex(replace);
3653 : }
3654 :
3655 : /* if subject is an array */
3656 135191 : if (Z_TYPE_PP(subject) == IS_ARRAY) {
3657 45 : array_init(return_value);
3658 45 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject));
3659 :
3660 : /* For each subject entry, convert it to string, then perform replacement
3661 : and add the result to the return_value array. */
3662 432 : while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) {
3663 656 : if (Z_TYPE_PP(subject_entry) != IS_ARRAY && Z_TYPE_PP(subject_entry) != IS_OBJECT) {
3664 314 : MAKE_STD_ZVAL(result);
3665 314 : SEPARATE_ZVAL(subject_entry);
3666 314 : php_str_replace_in_subject(*search, *replace, subject_entry, result, case_sensitivity, (argc > 3) ? &count : NULL);
3667 : } else {
3668 28 : ALLOC_ZVAL(result);
3669 28 : Z_ADDREF_P(*subject_entry);
3670 28 : COPY_PZVAL_TO_ZVAL(*result, *subject_entry);
3671 : }
3672 : /* Add to return array */
3673 : switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), &string_key,
3674 342 : &string_key_len, &num_key, 0, NULL)) {
3675 : case HASH_KEY_IS_STRING:
3676 4 : add_assoc_zval_ex(return_value, string_key, string_key_len, result);
3677 4 : break;
3678 :
3679 : case HASH_KEY_IS_LONG:
3680 338 : add_index_zval(return_value, num_key, result);
3681 : break;
3682 : }
3683 :
3684 342 : zend_hash_move_forward(Z_ARRVAL_PP(subject));
3685 : }
3686 : } else { /* if subject is not an array */
3687 135146 : php_str_replace_in_subject(*search, *replace, subject, return_value, case_sensitivity, (argc > 3) ? &count : NULL);
3688 : }
3689 135191 : if (argc > 3) {
3690 134 : zval_dtor(*zcount);
3691 134 : ZVAL_LONG(*zcount, count);
3692 : }
3693 : }
3694 : /* }}} */
3695 :
3696 : /* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, int &replace_count])
3697 : Replaces all occurrences of search in haystack with replace */
3698 : PHP_FUNCTION(str_replace)
3699 135102 : {
3700 135102 : php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3701 135102 : }
3702 : /* }}} */
3703 :
3704 : /* {{{ proto mixed str_ireplace(mixed search, mixed replace, mixed subject [, int &replace_count])
3705 : Replaces all occurrences of search in haystack with replace / case-insensitive */
3706 : PHP_FUNCTION(str_ireplace)
3707 104 : {
3708 104 : php_str_replace_common(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3709 104 : }
3710 : /* }}} */
3711 :
3712 : /* {{{ php_hebrev
3713 : *
3714 : * Converts Logical Hebrew text (Hebrew Windows style) to Visual text
3715 : * Cheers/complaints/flames - Zeev Suraski <zeev@php.net>
3716 : */
3717 : static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS, int convert_newlines)
3718 106 : {
3719 : char *str;
3720 : char *heb_str, *tmp, *target, *broken_str;
3721 : int block_start, block_end, block_type, block_length, i;
3722 106 : long max_chars=0;
3723 : int begin, end, char_count, orig_begin;
3724 : int str_len;
3725 :
3726 106 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &str, &str_len, &max_chars) == FAILURE) {
3727 26 : return;
3728 : }
3729 :
3730 80 : if (str_len == 0) {
3731 12 : RETURN_FALSE;
3732 : }
3733 :
3734 68 : tmp = str;
3735 68 : block_start=block_end=0;
3736 :
3737 68 : heb_str = (char *) emalloc(str_len+1);
3738 68 : target = heb_str+str_len;
3739 68 : *target = 0;
3740 68 : target--;
3741 :
3742 68 : block_length=0;
3743 :
3744 68 : if (isheb(*tmp)) {
3745 0 : block_type = _HEB_BLOCK_TYPE_HEB;
3746 : } else {
3747 68 : block_type = _HEB_BLOCK_TYPE_ENG;
3748 : }
3749 :
3750 : do {
3751 288 : if (block_type == _HEB_BLOCK_TYPE_HEB) {
3752 660 : while ((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<str_len-1) {
3753 396 : tmp++;
3754 396 : block_end++;
3755 396 : block_length++;
3756 : }
3757 528 : for (i = block_start; i<= block_end; i++) {
3758 396 : *target = str[i];
3759 396 : switch (*target) {
3760 : case '(':
3761 22 : *target = ')';
3762 22 : break;
3763 : case ')':
3764 22 : *target = '(';
3765 22 : break;
3766 : case '[':
3767 0 : *target = ']';
3768 0 : break;
3769 : case ']':
3770 0 : *target = '[';
3771 0 : break;
3772 : case '{':
3773 0 : *target = '}';
3774 0 : break;
3775 : case '}':
3776 0 : *target = '{';
3777 0 : break;
3778 : case '<':
3779 0 : *target = '>';
3780 0 : break;
3781 : case '>':
3782 22 : *target = '<';
3783 22 : break;
3784 : case '\\':
3785 0 : *target = '/';
3786 0 : break;
3787 : case '/':
3788 0 : *target = '\\';
3789 : break;
3790 : default:
3791 : break;
3792 : }
3793 396 : target--;
3794 : }
3795 132 : block_type = _HEB_BLOCK_TYPE_ENG;
3796 : } else {
3797 7164 : while (!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end < str_len-1) {
3798 6852 : tmp++;
3799 6852 : block_end++;
3800 6852 : block_length++;
3801 : }
3802 466 : while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end > block_start) {
3803 154 : tmp--;
3804 154 : block_end--;
3805 : }
3806 6922 : for (i = block_end; i >= block_start; i--) {
3807 6766 : *target = str[i];
3808 6766 : target--;
3809 : }
3810 156 : block_type = _HEB_BLOCK_TYPE_HEB;
3811 : }
3812 288 : block_start=block_end+1;
3813 288 : } while (block_end < str_len-1);
3814 :
3815 :
3816 68 : broken_str = (char *) emalloc(str_len+1);
3817 68 : begin=end=str_len-1;
3818 68 : target = broken_str;
3819 :
3820 : while (1) {
3821 1483 : char_count=0;
3822 8747 : while ((!max_chars || char_count < max_chars) && begin > 0) {
3823 5915 : char_count++;
3824 5915 : begin--;
3825 5915 : if (begin <= 0 || _isnewline(heb_str[begin])) {
3826 268 : while (begin > 0 && _isnewline(heb_str[begin-1])) {
3827 0 : begin--;
3828 0 : char_count++;
3829 : }
3830 134 : break;
3831 : }
3832 : }
3833 1483 : if (char_count == max_chars) { /* try to avoid breaking words */
3834 712 : int new_char_count=char_count, new_begin=begin;
3835 :
3836 2398 : while (new_char_count > 0) {
3837 1160 : if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
3838 : break;
3839 : }
3840 974 : new_begin++;
3841 974 : new_char_count--;
3842 : }
3843 712 : if (new_char_count > 0) {
3844 186 : char_count=new_char_count;
3845 186 : begin=new_begin;
3846 : }
3847 : }
3848 1483 : orig_begin=begin;
3849 :
3850 1483 : if (_isblank(heb_str[begin])) {
3851 267 : heb_str[begin]='\n';
3852 : }
3853 3371 : while (begin <= end && _isnewline(heb_str[begin])) { /* skip leading newlines */
3854 405 : begin++;
3855 : }
3856 8240 : for (i = begin; i <= end; i++) { /* copy content */
3857 6757 : *target = heb_str[i];
3858 6757 : target++;
3859 : }
3860 1888 : for (i = orig_begin; i <= end && _isnewline(heb_str[i]); i++) {
3861 405 : *target = heb_str[i];
3862 405 : target++;
3863 : }
3864 1483 : begin=orig_begin;
3865 :
3866 1483 : if (begin <= 0) {
3867 68 : *target = 0;
3868 : break;
3869 : }
3870 1415 : begin--;
3871 1415 : end=begin;
3872 1415 : }
3873 68 : efree(heb_str);
3874 :
3875 68 : if (convert_newlines) {
3876 34 : php_char_to_str(broken_str, str_len,'\n', "<br />\n", 7, return_value);
3877 34 : efree(broken_str);
3878 : } else {
3879 34 : Z_STRVAL_P(return_value) = broken_str;
3880 34 : Z_STRLEN_P(return_value) = str_len;
3881 34 : Z_TYPE_P(return_value) = IS_STRING;
3882 : }
3883 : }
3884 : /* }}} */
3885 :
3886 : /* {{{ proto string hebrev(string str [, int max_chars_per_line])
3887 : Converts logical Hebrew text to visual text */
3888 : PHP_FUNCTION(hebrev)
3889 53 : {
3890 53 : php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3891 53 : }
3892 : /* }}} */
3893 :
3894 : /* {{{ proto string hebrevc(string str [, int max_chars_per_line])
3895 : Converts logical Hebrew text to visual text with newline conversion */
3896 : PHP_FUNCTION(hebrevc)
3897 53 : {
3898 53 : php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3899 53 : }
3900 : /* }}} */
3901 :
3902 : /* {{{ proto string nl2br(string str [, bool is_xhtml])
3903 : Converts newlines to HTML line breaks */
3904 : PHP_FUNCTION(nl2br)
3905 60 : {
3906 : /* in brief this inserts <br /> or <br> before matched regexp \n\r?|\r\n? */
3907 : char *tmp, *str;
3908 : int new_length;
3909 : char *end, *target;
3910 60 : int repl_cnt = 0;
3911 : int str_len;
3912 60 : zend_bool is_xhtml = 1;
3913 :
3914 60 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &str, &str_len, &is_xhtml) == FAILURE) {
3915 8 : return;
3916 : }
3917 :
3918 52 : tmp = str;
3919 52 : end = str + str_len;
3920 :
3921 : /* it is really faster to scan twice and allocate mem once instead of scanning once
3922 : and constantly reallocing */
3923 513 : while (tmp < end) {
3924 409 : if (*tmp == '\r') {
3925 33 : if (*(tmp+1) == '\n') {
3926 14 : tmp++;
3927 : }
3928 33 : repl_cnt++;
3929 376 : } else if (*tmp == '\n') {
3930 46 : if (*(tmp+1) == '\r') {
3931 13 : tmp++;
3932 : }
3933 46 : repl_cnt++;
3934 : }
3935 :
3936 409 : tmp++;
3937 : }
3938 :
3939 52 : if (repl_cnt == 0) {
3940 29 : RETURN_STRINGL(str, str_len, 1);
3941 : }
3942 :
3943 23 : if (is_xhtml) {
3944 23 : new_length = str_len + repl_cnt * (sizeof("<br />") - 1);
3945 : } else {
3946 0 : new_length = str_len + repl_cnt * (sizeof("<br>") - 1);
3947 : }
3948 :
3949 23 : tmp = target = emalloc(new_length + 1);
3950 :
3951 303 : while (str < end) {
3952 257 : switch (*str) {
3953 : case '\r':
3954 : case '\n':
3955 79 : *target++ = '<';
3956 79 : *target++ = 'b';
3957 79 : *target++ = 'r';
3958 :
3959 79 : if (is_xhtml) {
3960 79 : *target++ = ' ';
3961 79 : *target++ = '/';
3962 : }
3963 :
3964 79 : *target++ = '>';
3965 :
3966 79 : if ((*str == '\r' && *(str+1) == '\n') || (*str == '\n' && *(str+1) == '\r')) {
3967 27 : *target++ = *str++;
3968 : }
3969 : /* lack of a break; is intentional */
3970 : default:
3971 257 : *target++ = *str;
3972 : }
3973 :
3974 257 : str++;
3975 : }
3976 :
3977 23 : *target = '\0';
3978 :
3979 23 : RETURN_STRINGL(tmp, new_length, 0);
3980 : }
3981 : /* }}} */
3982 :
3983 : /* {{{ proto string strip_tags(string str [, string allowable_tags])
3984 : Strips HTML and PHP tags from a string */
3985 : PHP_FUNCTION(strip_tags)
3986 188 : {
3987 : char *buf;
3988 : char *str;
3989 188 : zval **allow=NULL;
3990 188 : char *allowed_tags=NULL;
3991 188 : int allowed_tags_len=0;
3992 : int str_len;
3993 : size_t retval_len;
3994 :
3995 188 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|Z", &str, &str_len, &allow) == FAILURE) {
3996 14 : return;
3997 : }
3998 :
3999 : /* To maintain a certain BC, we allow anything for the second parameter and return original string */
4000 174 : if (allow != NULL) {
4001 109 : convert_to_string_ex(allow);
4002 109 : allowed_tags = Z_STRVAL_PP(allow);
4003 109 : allowed_tags_len = Z_STRLEN_PP(allow);
4004 : }
4005 :
4006 174 : buf = estrndup(str, str_len);
4007 174 : retval_len = php_strip_tags_ex(buf, str_len, NULL, allowed_tags, allowed_tags_len, 0);
4008 174 : RETURN_STRINGL(buf, retval_len, 0);
4009 : }
4010 : /* }}} */
4011 :
4012 : /* {{{ proto string setlocale(mixed category, string locale [, string ...])
4013 : Set locale information */
4014 : PHP_FUNCTION(setlocale)
4015 913 : {
4016 913 : zval ***args = NULL;
4017 : zval **pcategory, **plocale;
4018 913 : int num_args, cat, i = 0;
4019 : char *loc, *retval;
4020 :
4021 913 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z+", &pcategory, &args, &num_args) == FAILURE) {
4022 2 : return;
4023 : }
4024 :
4025 : #ifdef HAVE_SETLOCALE
4026 911 : if (Z_TYPE_PP(pcategory) == IS_LONG) {
4027 910 : convert_to_long_ex(pcategory);
4028 910 : cat = Z_LVAL_PP(pcategory);
4029 : } else {
4030 : /* FIXME: The following behaviour should be removed. */
4031 : char *category;
4032 :
4033 1 : php_error_docref(NULL TSRMLS_CC, E_DEPRECATED, "Passing locale category name as string is deprecated. Use the LC_* -constants instead");
4034 :
4035 1 : convert_to_string_ex(pcategory);
4036 1 : category = Z_STRVAL_PP(pcategory);
4037 :
4038 1 : if (!strcasecmp("LC_ALL", category)) {
4039 0 : cat = LC_ALL;
4040 1 : } else if (!strcasecmp("LC_COLLATE", category)) {
4041 0 : cat = LC_COLLATE;
4042 1 : } else if (!strcasecmp("LC_CTYPE", category)) {
4043 0 : cat = LC_CTYPE;
4044 : #ifdef LC_MESSAGES
4045 1 : } else if (!strcasecmp("LC_MESSAGES", category)) {
4046 0 : cat = LC_MESSAGES;
4047 : #endif
4048 1 : } else if (!strcasecmp("LC_MONETARY", category)) {
4049 0 : cat = LC_MONETARY;
4050 1 : } else if (!strcasecmp("LC_NUMERIC", category)) {
4051 0 : cat = LC_NUMERIC;
4052 1 : } else if (!strcasecmp("LC_TIME", category)) {
4053 0 : cat = LC_TIME;
4054 : } else {
4055 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid locale category name %s, must be one of LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, or LC_TIME", category);
4056 :
4057 1 : if (args) {
4058 1 : efree(args);
4059 : }
4060 1 : RETURN_FALSE;
4061 : }
4062 : }
4063 :
4064 910 : if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
4065 2 : zend_hash_internal_pointer_reset(Z_ARRVAL_PP(args[0]));
4066 : }
4067 :
4068 : while (1) {
4069 927 : if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
4070 5 : if (!zend_hash_num_elements(Z_ARRVAL_PP(args[0]))) {
4071 0 : break;
4072 : }
4073 5 : zend_hash_get_current_data(Z_ARRVAL_PP(args[0]), (void **)&plocale);
4074 : } else {
4075 922 : plocale = args[i];
4076 : }
4077 :
4078 927 : convert_to_string_ex(plocale);
4079 :
4080 927 : if (!strcmp ("0", Z_STRVAL_PP(plocale))) {
4081 5 : loc = NULL;
4082 : } else {
4083 922 : loc = Z_STRVAL_PP(plocale);
4084 922 : if (Z_STRLEN_PP(plocale) >= 255) {
4085 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Specified locale name is too long");
4086 0 : break;
4087 : }
4088 : }
4089 :
4090 927 : retval = setlocale(cat, loc);
4091 : zend_update_current_locale();
4092 927 : if (retval) {
4093 : /* Remember if locale was changed */
4094 906 : if (loc) {
4095 901 : STR_FREE(BG(locale_string));
4096 901 : BG(locale_string) = estrdup(retval);
4097 : }
4098 :
4099 906 : if (args) {
4100 906 : efree(args);
4101 : }
4102 906 : RETURN_STRING(retval, 1);
4103 : }
4104 :
4105 21 : if (Z_TYPE_PP(args[0]) == IS_ARRAY) {
4106 4 : if (zend_hash_move_forward(Z_ARRVAL_PP(args[0])) == FAILURE) break;
4107 : } else {
4108 17 : if (++i >= num_args) break;
4109 : }
4110 17 : }
4111 :
4112 : #endif
4113 4 : if (args) {
4114 4 : efree(args);
4115 : }
4116 4 : RETURN_FALSE;
4117 : }
4118 : /* }}} */
4119 :
4120 : /* {{{ proto void parse_str(string encoded_string [, array result])
4121 : Parses GET/POST/COOKIE data and sets global variables */
4122 : PHP_FUNCTION(parse_str)
4123 32 : {
4124 : char *arg;
4125 32 : zval *arrayArg = NULL;
4126 32 : char *res = NULL;
4127 : int arglen;
4128 :
4129 32 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &arg, &arglen, &arrayArg) == FAILURE) {
4130 2 : return;
4131 : }
4132 :
4133 30 : res = estrndup(arg, arglen);
4134 :
4135 30 : if (arrayArg == NULL) {
4136 : zval tmp;
4137 :
4138 15 : if (!EG(active_symbol_table)) {
4139 0 : zend_rebuild_symbol_table(TSRMLS_C);
4140 : }
4141 15 : Z_ARRVAL(tmp) = EG(active_symbol_table);
4142 15 : sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
4143 : } else {
4144 : /* Clear out the array that was passed in. */
4145 15 : zval_dtor(arrayArg);
4146 15 : array_init(arrayArg);
4147 :
4148 15 : sapi_module.treat_data(PARSE_STRING, res, arrayArg TSRMLS_CC);
4149 : }
4150 : }
4151 : /* }}} */
4152 :
4153 : #define PHP_TAG_BUF_SIZE 1023
4154 :
4155 : /* {{{ php_tag_find
4156 : *
4157 : * Check if tag is in a set of tags
4158 : *
4159 : * states:
4160 : *
4161 : * 0 start tag
4162 : * 1 first non-whitespace char seen
4163 : */
4164 541 : int php_tag_find(char *tag, int len, char *set) {
4165 : char c, *n, *t;
4166 541 : int state=0, done=0;
4167 : char *norm;
4168 :
4169 541 : if (len <= 0) {
4170 0 : return 0;
4171 : }
4172 :
4173 541 : norm = emalloc(len+1);
4174 :
4175 541 : n = norm;
4176 541 : t = tag;
4177 541 : c = tolower(*t);
4178 : /*
4179 : normalize the tag removing leading and trailing whitespace
4180 : and turn any <a whatever...> into just <a> and any </tag>
4181 : into <tag>
4182 : */
4183 3754 : while (!done) {
4184 2672 : switch (c) {
4185 : case '<':
4186 540 : *(n++) = c;
4187 540 : break;
4188 : case '>':
4189 522 : done =1;
4190 522 : break;
4191 : default:
4192 1610 : if (!isspace((int)c)) {
4193 1589 : if (state == 0) {
4194 540 : state=1;
4195 540 : if (c != '/')
4196 282 : *(n++) = c;
4197 : } else {
4198 1049 : *(n++) = c;
4199 : }
4200 : } else {
4201 21 : if (state == 1)
4202 19 : done=1;
4203 : }
4204 : break;
4205 : }
4206 2672 : c = tolower(*(++t));
4207 : }
4208 541 : *(n++) = '>';
4209 541 : *n = '\0';
4210 541 : if (strstr(set, norm)) {
4211 141 : done=1;
4212 : } else {
4213 400 : done=0;
4214 : }
4215 541 : efree(norm);
4216 541 : return done;
4217 : }
4218 : /* }}} */
4219 :
4220 : PHPAPI size_t php_strip_tags(char *rbuf, int len, int *stateptr, char *allow, int allow_len) /* {{{ */
4221 232 : {
4222 232 : return php_strip_tags_ex(rbuf, len, stateptr, allow, allow_len, 0);
4223 : }
4224 : /* }}} */
4225 :
4226 : /* {{{ php_strip_tags
4227 :
4228 : A simple little state-machine to strip out html and php tags
4229 :
4230 : State 0 is the output state, State 1 means we are inside a
4231 : normal html tag and state 2 means we are inside a php tag.
4232 :
4233 : The state variable is passed in to allow a function like fgetss
4234 : to maintain state across calls to the function.
4235 :
4236 : lc holds the last significant character read and br is a bracket
4237 : counter.
4238 :
4239 : When an allow string is passed in we keep track of the string
4240 : in state 1 and when the tag is closed check it against the
4241 : allow string to see if we should allow it.
4242 :
4243 : swm: Added ability to strip <?xml tags without assuming it PHP
4244 : code.
4245 : */
4246 : PHPAPI size_t php_strip_tags_ex(char *rbuf, int len, int *stateptr, char *allow, int allow_len, zend_bool allow_tag_spaces)
4247 711 : {
4248 : char *tbuf, *buf, *p, *tp, *rp, c, lc;
4249 711 : int br, i=0, depth=0, in_q = 0;
4250 711 : int state = 0;
4251 :
4252 711 : if (stateptr)
4253 232 : state = *stateptr;
4254 :
4255 711 : buf = estrndup(rbuf, len);
4256 711 : c = *buf;
4257 711 : lc = '\0';
4258 711 : p = buf;
4259 711 : rp = rbuf;
4260 711 : br = 0;
4261 711 : if (allow) {
4262 277 : php_strtolower(allow, allow_len);
4263 277 : tbuf = emalloc(PHP_TAG_BUF_SIZE+1);
4264 277 : tp = tbuf;
4265 : } else {
4266 434 : tbuf = tp = NULL;
4267 : }
4268 :
4269 19853 : while (i < len) {
4270 18431 : switch (c) {
4271 : case '\0':
4272 2 : break;
4273 : case '<':
4274 928 : if (in_q) {
4275 3 : break;
4276 : }
4277 925 : if (isspace(*(p + 1)) && !allow_tag_spaces) {
4278 6 : goto reg_char;
4279 : }
4280 919 : if (state == 0) {
4281 894 : lc = '<';
4282 894 : state = 1;
4283 894 : if (allow) {
4284 649 : tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
4285 649 : *(tp++) = '<';
4286 : }
4287 25 : } else if (state == 1) {
4288 20 : depth++;
4289 : }
4290 919 : break;
4291 :
4292 : case '(':
4293 63 : if (state == 2) {
4294 0 : if (lc != '"' && lc != '\'') {
4295 0 : lc = '(';
4296 0 : br++;
4297 : }
4298 64 : } else if (allow && state == 1) {
4299 1 : tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
4300 1 : *(tp++) = c;
4301 62 : } else if (state == 0) {
4302 61 : *(rp++) = c;
4303 : }
4304 63 : break;
4305 :
4306 : case ')':
4307 63 : if (state == 2) {
4308 0 : if (lc != '"' && lc != '\'') {
4309 0 : lc = ')';
4310 0 : br--;
4311 : }
4312 64 : } else if (allow && state == 1) {
4313 1 : tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
4314 1 : *(tp++) = c;
4315 62 : } else if (state == 0) {
4316 61 : *(rp++) = c;
4317 : }
4318 63 : break;
4319 :
4320 : case '>':
4321 921 : if (depth) {
4322 20 : depth--;
4323 20 : break;
4324 : }
4325 :
4326 901 : if (in_q) {
4327 4 : break;
4328 : }
4329 :
4330 897 : switch (state) {
4331 : case 1: /* HTML/XML */
4332 755 : lc = '>';
4333 755 : in_q = state = 0;
4334 755 : if (allow) {
4335 541 : tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
4336 541 : *(tp++) = '>';
4337 541 : *tp='\0';
4338 541 : if (php_tag_find(tbuf, tp-tbuf, allow)) {
4339 141 : memcpy(rp, tbuf, tp-tbuf);
4340 141 : rp += tp-tbuf;
4341 : }
4342 541 : tp = tbuf;
4343 : }
4344 755 : break;
4345 :
4346 : case 2: /* PHP */
4347 97 : if (!br && lc != '\"' && *(p-1) == '?') {
4348 91 : in_q = state = 0;
4349 91 : tp = tbuf;
4350 : }
4351 97 : break;
4352 :
4353 : case 3:
4354 1 : in_q = state = 0;
4355 1 : tp = tbuf;
4356 1 : break;
4357 :
4358 : case 4: /* JavaScript/CSS/etc... */
4359 37 : if (p >= buf + 2 && *(p-1) == '-' && *(p-2) == '-') {
4360 36 : in_q = state = 0;
4361 36 : tp = tbuf;
4362 : }
4363 37 : break;
4364 :
4365 : default:
4366 7 : *(rp++) = c;
4367 : break;
4368 : }
4369 897 : break;
4370 :
4371 : case '"':
4372 : case '\'':
4373 178 : if (state == 4) {
4374 : /* Inside <!-- comment --> */
4375 1 : break;
4376 241 : } else if (state == 2 && *(p-1) != '\\') {
4377 64 : if (lc == c) {
4378 32 : lc = '\0';
4379 32 : } else if (lc != '\\') {
4380 32 : lc = c;
4381 : }
4382 113 : } else if (state == 0) {
4383 16 : *(rp++) = c;
4384 97 : } else if (allow && state == 1) {
4385 27 : tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
4386 27 : *(tp++) = c;
4387 : }
4388 177 : if (state && p != buf && *(p-1) != '\\' && (!in_q || *p == in_q)) {
4389 154 : if (in_q) {
4390 76 : in_q = 0;
4391 : } else {
4392 78 : in_q = *p;
4393 : }
4394 : }
4395 177 : break;
4396 :
4397 : case '!':
4398 : /* JavaScript & Other HTML scripting languages */
4399 109 : if (state == 1 && *(p-1) == '<') {
4400 40 : state = 3;
4401 40 : lc = c;
4402 : } else {
4403 29 : if (state == 0) {
4404 20 : *(rp++) = c;
4405 9 : } else if (allow && state == 1) {
4406 6 : tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
4407 6 : *(tp++) = c;
4408 : }
4409 : }
4410 69 : break;
4411 :
4412 : case '-':
4413 168 : if (state == 3 && p >= buf + 2 && *(p-1) == '-' && *(p-2) == '!') {
4414 36 : state = 4;
4415 : } else {
4416 : goto reg_char;
4417 : }
4418 36 : break;
4419 :
4420 : case '?':
4421 :
4422 204 : if (state == 1 && *(p-1) == '<') {
4423 94 : br=0;
4424 94 : state=2;
4425 94 : break;
4426 : }
4427 :
4428 : case 'E':
4429 : case 'e':
4430 : /* !DOCTYPE exception */
4431 1069 : if (state==3 && p > buf+6
4432 : && tolower(*(p-1)) == 'p'
4433 : && tolower(*(p-2)) == 'y'
4434 : && tolower(*(p-3)) == 't'
4435 : && tolower(*(p-4)) == 'c'
4436 : && tolower(*(p-5)) == 'o'
4437 : && tolower(*(p-6)) == 'd') {
4438 3 : state = 1;
4439 3 : break;
4440 : }
4441 : /* fall-through */
4442 :
4443 : case 'l':
4444 : case 'L':
4445 :
4446 : /* swm: If we encounter '<?xml' then we shouldn't be in
4447 : * state == 2 (PHP). Switch back to HTML.
4448 : */
4449 :
4450 1846 : if (state == 2 && p > buf+2 && strncasecmp(p-2, "xm", 2) == 0) {
4451 2 : state = 1;
4452 2 : break;
4453 : }
4454 :
4455 : /* fall-through */
4456 : default:
4457 16078 : reg_char:
4458 16078 : if (state == 0) {
4459 10210 : *(rp++) = c;
4460 5868 : } else if (allow && state == 1) {
4461 1914 : tp = ((tp-tbuf) >= PHP_TAG_BUF_SIZE ? tbuf: tp);
4462 1914 : *(tp++) = c;
4463 : }
4464 : break;
4465 : }
4466 18431 : c = *(++p);
4467 18431 : i++;
4468 : }
4469 711 : if (rp < rbuf + len) {
4470 258 : *rp = '\0';
4471 : }
4472 711 : efree(buf);
4473 711 : if (allow)
4474 277 : efree(tbuf);
4475 711 : if (stateptr)
4476 232 : *stateptr = state;
4477 :
4478 711 : return (size_t)(rp - rbuf);
4479 : }
4480 : /* }}} */
4481 :
4482 : /* {{{ proto array str_getcsv(string input[, string delimiter[, string enclosure[, string escape]]])
4483 : Parse a CSV string into an array */
4484 : PHP_FUNCTION(str_getcsv)
4485 12 : {
4486 12 : char *str, delim = ',', enc = '"', esc = '\\';
4487 12 : char *delim_str = NULL, *enc_str = NULL, *esc_str = NULL;
4488 12 : int str_len = 0, delim_len = 0, enc_len = 0, esc_len = 0;
4489 :
4490 12 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sss", &str, &str_len, &delim_str, &delim_len,
4491 : &enc_str, &enc_len, &esc_str, &esc_len) == FAILURE) {
4492 0 : return;
4493 : }
4494 :
4495 12 : delim = delim_len ? delim_str[0] : delim;
4496 12 : enc = enc_len ? enc_str[0] : enc;
4497 12 : esc = esc_len ? esc_str[0] : esc;
4498 :
4499 12 : php_fgetcsv(NULL, delim, enc, esc, str_len, str, return_value TSRMLS_CC);
4500 : }
4501 : /* }}} */
4502 :
4503 : /* {{{ proto string str_repeat(string input, int mult)
4504 : Returns the input string repeat mult times */
4505 : PHP_FUNCTION(str_repeat)
4506 161716 : {
4507 : char *input_str; /* Input string */
4508 : int input_len;
4509 : long mult; /* Multiplier */
4510 : char *result; /* Resulting string */
4511 : size_t result_len; /* Length of the resulting string */
4512 :
4513 161716 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &input_str, &input_len, &mult) == FAILURE) {
4514 80 : return;
4515 : }
4516 :
4517 161636 : if (mult < 0) {
4518 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be greater than or equal to 0");
4519 1 : return;
4520 : }
4521 :
4522 : /* Don't waste our time if it's empty */
4523 : /* ... or if the multiplier is zero */
4524 161635 : if (input_len == 0 || mult == 0)
4525 36 : RETURN_EMPTY_STRING();
4526 :
4527 : /* Initialize the result string */
4528 161599 : result_len = input_len * mult;
4529 161599 : result = (char *)safe_emalloc(input_len, mult, 1);
4530 :
4531 : /* Heavy optimization for situations where input string is 1 byte long */
4532 161599 : if (input_len == 1) {
4533 155358 : memset(result, *(input_str), mult);
4534 : } else {
4535 : char *s, *e, *ee;
4536 6241 : int l=0;
4537 6241 : memcpy(result, input_str, input_len);
4538 6241 : s = result;
4539 6241 : e = result + input_len;
4540 6241 : ee = result + result_len;
4541 :
4542 51192 : while (e<ee) {
4543 38710 : l = (e-s) < (ee-e) ? (e-s) : (ee-e);
4544 38710 : memmove(e, s, l);
4545 38710 : e += l;
4546 : }
4547 : }
4548 :
4549 161599 : result[result_len] = '\0';
4550 :
4551 161599 : RETURN_STRINGL(result, result_len, 0);
4552 : }
4553 : /* }}} */
4554 :
4555 : /* {{{ proto mixed count_chars(string input [, int mode])
4556 : Returns info about what characters are used in input */
4557 : PHP_FUNCTION(count_chars)
4558 60 : {
4559 : char *input;
4560 : int chars[256];
4561 60 : long mymode=0;
4562 : unsigned char *buf;
4563 : int len, inx;
4564 : char retstr[256];
4565 60 : int retlen=0;
4566 :
4567 60 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &input, &len, &mymode) == FAILURE) {
4568 11 : return;
4569 : }
4570 :
4571 49 : if (mymode < 0 || mymode > 4) {
4572 7 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown mode");
4573 7 : RETURN_FALSE;
4574 : }
4575 :
4576 42 : buf = (unsigned char *) input;
4577 42 : memset((void*) chars, 0, sizeof(chars));
4578 :
4579 1462 : while (len > 0) {
4580 1378 : chars[*buf]++;
4581 1378 : buf++;
4582 1378 : len--;
4583 : }
4584 :
4585 42 : if (mymode < 3) {
4586 38 : array_init(return_value);
4587 : }
4588 :
4589 10794 : for (inx = 0; inx < 256; inx++) {
4590 10752 : switch (mymode) {
4591 : case 0:
4592 2816 : add_index_long(return_value, inx, chars[inx]);
4593 2816 : break;
4594 : case 1:
4595 6400 : if (chars[inx] != 0) {
4596 180 : add_index_long(return_value, inx, chars[inx]);
4597 : }
4598 6400 : break;
4599 : case 2:
4600 512 : if (chars[inx] == 0) {
4601 475 : add_index_long(return_value, inx, chars[inx]);
4602 : }
4603 512 : break;
4604 : case 3:
4605 512 : if (chars[inx] != 0) {
4606 37 : retstr[retlen++] = inx;
4607 : }
4608 512 : break;
4609 : case 4:
4610 512 : if (chars[inx] == 0) {
4611 475 : retstr[retlen++] = inx;
4612 : }
4613 : break;
4614 : }
4615 : }
4616 :
4617 42 : if (mymode >= 3 && mymode <= 4) {
4618 4 : RETURN_STRINGL(retstr, retlen, 1);
4619 : }
4620 : }
4621 : /* }}} */
4622 :
4623 : /* {{{ php_strnatcmp
4624 : */
4625 : static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
4626 48 : {
4627 : char *s1, *s2;
4628 : int s1_len, s2_len;
4629 :
4630 48 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &s1, &s1_len, &s2, &s2_len) == FAILURE) {
4631 4 : return;
4632 : }
4633 :
4634 44 : RETURN_LONG(strnatcmp_ex(s1, s1_len,
4635 : s2, s2_len,
4636 : fold_case));
4637 : }
4638 : /* }}} */
4639 :
4640 : /* {{{ proto int strnatcmp(string s1, string s2)
4641 : Returns the result of string comparison using 'natural' algorithm */
4642 : PHP_FUNCTION(strnatcmp)
4643 27 : {
4644 27 : php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
4645 27 : }
4646 : /* }}} */
4647 :
4648 : /* {{{ proto array localeconv(void)
4649 : Returns numeric formatting information based on the current locale */
4650 : PHP_FUNCTION(localeconv)
4651 11 : {
4652 : zval *grouping, *mon_grouping;
4653 : int len, i;
4654 :
4655 : /* We don't need no stinkin' parameters... */
4656 11 : if (zend_parse_parameters_none() == FAILURE) {
4657 0 : return;
4658 : }
4659 :
4660 11 : MAKE_STD_ZVAL(grouping);
4661 11 : MAKE_STD_ZVAL(mon_grouping);
4662 :
4663 11 : array_init(return_value);
4664 11 : array_init(grouping);
4665 11 : array_init(mon_grouping);
4666 :
4667 : #ifdef HAVE_LOCALECONV
4668 : {
4669 : struct lconv currlocdata;
4670 :
4671 11 : localeconv_r( &currlocdata );
4672 :
4673 : /* Grab the grouping data out of the array */
4674 11 : len = strlen(currlocdata.grouping);
4675 :
4676 33 : for (i = 0; i < len; i++) {
4677 22 : add_index_long(grouping, i, currlocdata.grouping[i]);
4678 : }
4679 :
4680 : /* Grab the monetary grouping data out of the array */
4681 11 : len = strlen(currlocdata.mon_grouping);
4682 :
4683 31 : for (i = 0; i < len; i++) {
4684 20 : add_index_long(mon_grouping, i, currlocdata.mon_grouping[i]);
4685 : }
4686 :
4687 11 : add_assoc_string(return_value, "decimal_point", currlocdata.decimal_point, 1);
4688 11 : add_assoc_string(return_value, "thousands_sep", currlocdata.thousands_sep, 1);
4689 11 : add_assoc_string(return_value, "int_curr_symbol", currlocdata.int_curr_symbol, 1);
4690 11 : add_assoc_string(return_value, "currency_symbol", currlocdata.currency_symbol, 1);
4691 11 : add_assoc_string(return_value, "mon_decimal_point", currlocdata.mon_decimal_point, 1);
4692 11 : add_assoc_string(return_value, "mon_thousands_sep", currlocdata.mon_thousands_sep, 1);
4693 11 : add_assoc_string(return_value, "positive_sign", currlocdata.positive_sign, 1);
4694 11 : add_assoc_string(return_value, "negative_sign", currlocdata.negative_sign, 1);
4695 11 : add_assoc_long( return_value, "int_frac_digits", currlocdata.int_frac_digits );
4696 11 : add_assoc_long( return_value, "frac_digits", currlocdata.frac_digits );
4697 11 : add_assoc_long( return_value, "p_cs_precedes", currlocdata.p_cs_precedes );
4698 11 : add_assoc_long( return_value, "p_sep_by_space", currlocdata.p_sep_by_space );
4699 11 : add_assoc_long( return_value, "n_cs_precedes", currlocdata.n_cs_precedes );
4700 11 : add_assoc_long( return_value, "n_sep_by_space", currlocdata.n_sep_by_space );
4701 11 : add_assoc_long( return_value, "p_sign_posn", currlocdata.p_sign_posn );
4702 11 : add_assoc_long( return_value, "n_sign_posn", currlocdata.n_sign_posn );
4703 : }
4704 : #else
4705 : /* Ok, it doesn't look like we have locale info floating around, so I guess it
4706 : wouldn't hurt to just go ahead and return the POSIX locale information? */
4707 :
4708 : add_index_long(grouping, 0, -1);
4709 : add_index_long(mon_grouping, 0, -1);
4710 :
4711 : add_assoc_string(return_value, "decimal_point", "\x2E", 1);
4712 : add_assoc_string(return_value, "thousands_sep", "", 1);
4713 : add_assoc_string(return_value, "int_curr_symbol", "", 1);
4714 : add_assoc_string(return_value, "currency_symbol", "", 1);
4715 : add_assoc_string(return_value, "mon_decimal_point", "\x2E", 1);
4716 : add_assoc_string(return_value, "mon_thousands_sep", "", 1);
4717 : add_assoc_string(return_value, "positive_sign", "", 1);
4718 : add_assoc_string(return_value, "negative_sign", "", 1);
4719 : add_assoc_long( return_value, "int_frac_digits", CHAR_MAX );
4720 : add_assoc_long( return_value, "frac_digits", CHAR_MAX );
4721 : add_assoc_long( return_value, "p_cs_precedes", CHAR_MAX );
4722 : add_assoc_long( return_value, "p_sep_by_space", CHAR_MAX );
4723 : add_assoc_long( return_value, "n_cs_precedes", CHAR_MAX );
4724 : add_assoc_long( return_value, "n_sep_by_space", CHAR_MAX );
4725 : add_assoc_long( return_value, "p_sign_posn", CHAR_MAX );
4726 : add_assoc_long( return_value, "n_sign_posn", CHAR_MAX );
4727 : #endif
4728 :
4729 11 : zend_hash_update(Z_ARRVAL_P(return_value), "grouping", 9, &grouping, sizeof(zval *), NULL);
4730 11 : zend_hash_update(Z_ARRVAL_P(return_value), "mon_grouping", 13, &mon_grouping, sizeof(zval *), NULL);
4731 : }
4732 : /* }}} */
4733 :
4734 : /* {{{ proto int strnatcasecmp(string s1, string s2)
4735 : Returns the result of case-insensitive string comparison using 'natural' algorithm */
4736 : PHP_FUNCTION(strnatcasecmp)
4737 21 : {
4738 21 : php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
4739 21 : }
4740 : /* }}} */
4741 :
4742 : /* {{{ proto int substr_count(string haystack, string needle [, int offset [, int length]])
4743 : Returns the number of times a substring occurs in the string */
4744 : PHP_FUNCTION(substr_count)
4745 47 : {
4746 : char *haystack, *needle;
4747 47 : long offset = 0, length = 0;
4748 47 : int ac = ZEND_NUM_ARGS();
4749 47 : int count = 0;
4750 : int haystack_len, needle_len;
4751 : char *p, *endp, cmp;
4752 :
4753 47 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ll", &haystack, &haystack_len, &needle, &needle_len, &offset, &length) == FAILURE) {
4754 6 : return;
4755 : }
4756 :
4757 41 : if (needle_len == 0) {
4758 2 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty substring");
4759 2 : RETURN_FALSE;
4760 : }
4761 :
4762 39 : p = haystack;
4763 39 : endp = p + haystack_len;
4764 :
4765 39 : if (offset < 0) {
4766 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset should be greater than or equal to 0");
4767 1 : RETURN_FALSE;
4768 : }
4769 :
4770 38 : if (offset > haystack_len) {
4771 4 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset value %ld exceeds string length", offset);
4772 4 : RETURN_FALSE;
4773 : }
4774 34 : p += offset;
4775 :
4776 34 : if (ac == 4) {
4777 :
4778 6 : if (length <= 0) {
4779 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length should be greater than 0");
4780 1 : RETURN_FALSE;
4781 : }
4782 5 : if (length > (haystack_len - offset)) {
4783 1 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length value %ld exceeds string length", length);
4784 1 : RETURN_FALSE;
4785 : }
4786 4 : endp = p + length;
4787 : }
4788 :
4789 32 : if (needle_len == 1) {
4790 19 : cmp = needle[0];
4791 :
4792 56 : while ((p = memchr(p, cmp, endp - p))) {
4793 18 : count++;
4794 18 : p++;
4795 : }
4796 : } else {
4797 560 : while ((p = php_memnstr(p, needle, needle_len, endp))) {
4798 534 : p += needle_len;
4799 534 : count++;
4800 : }
4801 : }
4802 :
4803 32 : RETURN_LONG(count);
4804 : }
4805 : /* }}} */
4806 :
4807 : /* {{{ proto string str_pad(string input, int pad_length [, string pad_string [, int pad_type]])
4808 : Returns input string padded on the left or right to specified length with pad_string */
4809 : PHP_FUNCTION(str_pad)
4810 374 : {
4811 : /* Input arguments */
4812 : char *input; /* Input string */
4813 : int input_len;
4814 : long pad_length; /* Length to pad to */
4815 :
4816 : /* Helper variables */
4817 : int num_pad_chars; /* Number of padding characters (total - input size) */
4818 374 : char *result = NULL; /* Resulting string */
4819 374 : int result_len = 0; /* Length of the resulting string */
4820 374 : char *pad_str_val = " "; /* Pointer to padding string */
4821 374 : int pad_str_len = 1; /* Length of the padding string */
4822 374 : long pad_type_val = STR_PAD_RIGHT; /* The padding type value */
4823 374 : int i, left_pad=0, right_pad=0;
4824 :
4825 374 : if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|sl", &input, &input_len, &pad_length,
4826 : &pad_str_val, &pad_str_len, &pad_type_val) == FAILURE) {
4827 23 : return;
4828 : }
4829 :
4830 351 : num_pad_chars = pad_length - input_len;
4831 :
4832 : /* If resulting string turns out to be shorter than input string,
4833 : we simply copy the input and return. */
4834 351 : if (pad_length <= 0 || num_pad_chars <= 0) {
4835 138 : RETURN_STRINGL(input, input_len, 1);
4836 : }
4837 :
4838 213 : if (pad_str_len == 0) {
4839 8 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding string cannot be empty");
4840 8 : return;
4841 : }
4842 :
4843 205 : if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) {
4844 7 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH");
4845 7 : return;
4846 : }
4847 :
4848 198 : result = (char *)emalloc(input_len + num_pad_chars + 1);
4849 :
4850 : /* We need to figure out the left/right padding lengths. */
4851 198 : switch (pad_type_val) {
4852 : case STR_PAD_RIGHT:
4853 125 : left_pad = 0;
4854 125 : right_pad = num_pad_chars;
4855 125 : break;
4856 :
4857 : case STR_PAD_LEFT:
4858 38 : left_pad = num_pad_chars;
4859 38 : right_pad = 0;
4860 38 : break;
4861 :
4862 : case STR_PAD_BOTH:
4863 35 : left_pad = num_pad_chars / 2;
4864 35 : right_pad = num_pad_chars - left_pad;
4865 : break;
4866 : }
4867 :
4868 : /* First we pad on the left. */
4869 660 : for (i = 0; i < left_pad; i++)
4870 462 : result[result_len++] = pad_str_val[i % pad_str_len];
4871 :
4872 : /* Then we copy the input string. */
4873 198 : memcpy(result + result_len, input, input_len);
4874 198 : result_len += input_len;
4875 :
4876 : /* Finally, we pad on the right. */
4877 6298401 : for (i = 0; i < right_pad; i++)
4878 6298203 : result[result_len++] = pad_str_val[i % pad_str_len];
4879 :
4880 198 : result[result_len] = '\0';
4881 :
4882 198 : RETURN_STRINGL(result, result_len, 0);
4883 : }
4884 : /* }}} */
|