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