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