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