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