You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4903 lines
118 KiB

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