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