PageRenderTime 71ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 2ms

/ext/standard/string.c

https://github.com/php/php-src
C | 6197 lines | 5022 code | 692 blank | 483 comment | 1234 complexity | 36aa99423264fce3e37fb1a5d0ece920 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Copyright (c) The PHP Group |
  4. +----------------------------------------------------------------------+
  5. | This source file is subject to version 3.01 of the PHP license, |
  6. | that is bundled with this package in the file LICENSE, and is |
  7. | available through the world-wide-web at the following url: |
  8. | https://www.php.net/license/3_01.txt |
  9. | If you did not receive a copy of the PHP license and are unable to |
  10. | obtain it through the world-wide-web, please send a note to |
  11. | license@php.net so we can mail you a copy immediately. |
  12. +----------------------------------------------------------------------+
  13. | Authors: Rasmus Lerdorf <rasmus@php.net> |
  14. | Stig Sæther Bakken <ssb@php.net> |
  15. | Zeev Suraski <zeev@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include <stdio.h>
  19. #include "php.h"
  20. #include "php_rand.h"
  21. #include "php_string.h"
  22. #include "php_variables.h"
  23. #include <locale.h>
  24. #ifdef HAVE_LANGINFO_H
  25. # include <langinfo.h>
  26. #endif
  27. #ifdef HAVE_LIBINTL
  28. # include <libintl.h> /* For LC_MESSAGES */
  29. #endif
  30. #include "scanf.h"
  31. #include "zend_API.h"
  32. #include "zend_execute.h"
  33. #include "php_globals.h"
  34. #include "basic_functions.h"
  35. #include "zend_smart_str.h"
  36. #include <Zend/zend_exceptions.h>
  37. #ifdef ZTS
  38. #include "TSRM.h"
  39. #endif
  40. /* For str_getcsv() support */
  41. #include "ext/standard/file.h"
  42. /* For php_next_utf8_char() */
  43. #include "ext/standard/html.h"
  44. #ifdef __SSE2__
  45. #include <emmintrin.h>
  46. #endif
  47. #define STR_PAD_LEFT 0
  48. #define STR_PAD_RIGHT 1
  49. #define STR_PAD_BOTH 2
  50. #define PHP_PATHINFO_DIRNAME 1
  51. #define PHP_PATHINFO_BASENAME 2
  52. #define PHP_PATHINFO_EXTENSION 4
  53. #define PHP_PATHINFO_FILENAME 8
  54. #define PHP_PATHINFO_ALL (PHP_PATHINFO_DIRNAME | PHP_PATHINFO_BASENAME | PHP_PATHINFO_EXTENSION | PHP_PATHINFO_FILENAME)
  55. #define STR_STRSPN 0
  56. #define STR_STRCSPN 1
  57. /* {{{ register_string_constants */
  58. void register_string_constants(INIT_FUNC_ARGS)
  59. {
  60. REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_CS | CONST_PERSISTENT);
  61. REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_CS | CONST_PERSISTENT);
  62. REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_CS | CONST_PERSISTENT);
  63. REGISTER_LONG_CONSTANT("PATHINFO_DIRNAME", PHP_PATHINFO_DIRNAME, CONST_CS | CONST_PERSISTENT);
  64. REGISTER_LONG_CONSTANT("PATHINFO_BASENAME", PHP_PATHINFO_BASENAME, CONST_CS | CONST_PERSISTENT);
  65. REGISTER_LONG_CONSTANT("PATHINFO_EXTENSION", PHP_PATHINFO_EXTENSION, CONST_CS | CONST_PERSISTENT);
  66. REGISTER_LONG_CONSTANT("PATHINFO_FILENAME", PHP_PATHINFO_FILENAME, CONST_CS | CONST_PERSISTENT);
  67. REGISTER_LONG_CONSTANT("PATHINFO_ALL", PHP_PATHINFO_ALL, CONST_CS | CONST_PERSISTENT);
  68. /* If last members of struct lconv equal CHAR_MAX, no grouping is done */
  69. REGISTER_LONG_CONSTANT("CHAR_MAX", CHAR_MAX, CONST_CS | CONST_PERSISTENT);
  70. REGISTER_LONG_CONSTANT("LC_CTYPE", LC_CTYPE, CONST_CS | CONST_PERSISTENT);
  71. REGISTER_LONG_CONSTANT("LC_NUMERIC", LC_NUMERIC, CONST_CS | CONST_PERSISTENT);
  72. REGISTER_LONG_CONSTANT("LC_TIME", LC_TIME, CONST_CS | CONST_PERSISTENT);
  73. REGISTER_LONG_CONSTANT("LC_COLLATE", LC_COLLATE, CONST_CS | CONST_PERSISTENT);
  74. REGISTER_LONG_CONSTANT("LC_MONETARY", LC_MONETARY, CONST_CS | CONST_PERSISTENT);
  75. REGISTER_LONG_CONSTANT("LC_ALL", LC_ALL, CONST_CS | CONST_PERSISTENT);
  76. # ifdef LC_MESSAGES
  77. REGISTER_LONG_CONSTANT("LC_MESSAGES", LC_MESSAGES, CONST_CS | CONST_PERSISTENT);
  78. # endif
  79. }
  80. /* }}} */
  81. int php_tag_find(char *tag, size_t len, const char *set);
  82. /* this is read-only, so it's ok */
  83. ZEND_SET_ALIGNED(16, static const char hexconvtab[]) = "0123456789abcdef";
  84. /* localeconv mutex */
  85. #ifdef ZTS
  86. static MUTEX_T locale_mutex = NULL;
  87. #endif
  88. /* {{{ php_bin2hex */
  89. static zend_string *php_bin2hex(const unsigned char *old, const size_t oldlen)
  90. {
  91. zend_string *result;
  92. size_t i, j;
  93. result = zend_string_safe_alloc(oldlen, 2 * sizeof(char), 0, 0);
  94. for (i = j = 0; i < oldlen; i++) {
  95. ZSTR_VAL(result)[j++] = hexconvtab[old[i] >> 4];
  96. ZSTR_VAL(result)[j++] = hexconvtab[old[i] & 15];
  97. }
  98. ZSTR_VAL(result)[j] = '\0';
  99. return result;
  100. }
  101. /* }}} */
  102. /* {{{ php_hex2bin */
  103. static zend_string *php_hex2bin(const unsigned char *old, const size_t oldlen)
  104. {
  105. size_t target_length = oldlen >> 1;
  106. zend_string *str = zend_string_alloc(target_length, 0);
  107. unsigned char *ret = (unsigned char *)ZSTR_VAL(str);
  108. size_t i, j;
  109. for (i = j = 0; i < target_length; i++) {
  110. unsigned char c = old[j++];
  111. unsigned char l = c & ~0x20;
  112. int is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
  113. unsigned char d;
  114. /* basically (c >= '0' && c <= '9') || (l >= 'A' && l <= 'F') */
  115. if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
  116. d = (l - 0x10 - 0x27 * is_letter) << 4;
  117. } else {
  118. zend_string_efree(str);
  119. return NULL;
  120. }
  121. c = old[j++];
  122. l = c & ~0x20;
  123. is_letter = ((unsigned int) ((l - 'A') ^ (l - 'F' - 1))) >> (8 * sizeof(unsigned int) - 1);
  124. if (EXPECTED((((c ^ '0') - 10) >> (8 * sizeof(unsigned int) - 1)) | is_letter)) {
  125. d |= l - 0x10 - 0x27 * is_letter;
  126. } else {
  127. zend_string_efree(str);
  128. return NULL;
  129. }
  130. ret[i] = d;
  131. }
  132. ret[i] = '\0';
  133. return str;
  134. }
  135. /* }}} */
  136. /* {{{ localeconv_r
  137. * glibc's localeconv is not reentrant, so lets make it so ... sorta */
  138. PHPAPI struct lconv *localeconv_r(struct lconv *out)
  139. {
  140. #ifdef ZTS
  141. tsrm_mutex_lock( locale_mutex );
  142. #endif
  143. /* cur->locinfo is struct __crt_locale_info which implementation is
  144. hidden in vc14. TODO revisit this and check if a workaround available
  145. and needed. */
  146. #if defined(PHP_WIN32) && _MSC_VER < 1900 && defined(ZTS)
  147. {
  148. /* Even with the enabled per thread locale, localeconv
  149. won't check any locale change in the master thread. */
  150. _locale_t cur = _get_current_locale();
  151. *out = *cur->locinfo->lconv;
  152. _free_locale(cur);
  153. }
  154. #else
  155. /* localeconv doesn't return an error condition */
  156. *out = *localeconv();
  157. #endif
  158. #ifdef ZTS
  159. tsrm_mutex_unlock( locale_mutex );
  160. #endif
  161. return out;
  162. }
  163. /* }}} */
  164. #ifdef ZTS
  165. /* {{{ PHP_MINIT_FUNCTION */
  166. PHP_MINIT_FUNCTION(localeconv)
  167. {
  168. locale_mutex = tsrm_mutex_alloc();
  169. return SUCCESS;
  170. }
  171. /* }}} */
  172. /* {{{ PHP_MSHUTDOWN_FUNCTION */
  173. PHP_MSHUTDOWN_FUNCTION(localeconv)
  174. {
  175. tsrm_mutex_free( locale_mutex );
  176. locale_mutex = NULL;
  177. return SUCCESS;
  178. }
  179. /* }}} */
  180. #endif
  181. /* {{{ Converts the binary representation of data to hex */
  182. PHP_FUNCTION(bin2hex)
  183. {
  184. zend_string *result;
  185. zend_string *data;
  186. ZEND_PARSE_PARAMETERS_START(1, 1)
  187. Z_PARAM_STR(data)
  188. ZEND_PARSE_PARAMETERS_END();
  189. result = php_bin2hex((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data));
  190. RETURN_STR(result);
  191. }
  192. /* }}} */
  193. /* {{{ Converts the hex representation of data to binary */
  194. PHP_FUNCTION(hex2bin)
  195. {
  196. zend_string *result, *data;
  197. ZEND_PARSE_PARAMETERS_START(1, 1)
  198. Z_PARAM_STR(data)
  199. ZEND_PARSE_PARAMETERS_END();
  200. if (ZSTR_LEN(data) % 2 != 0) {
  201. php_error_docref(NULL, E_WARNING, "Hexadecimal input string must have an even length");
  202. RETURN_FALSE;
  203. }
  204. result = php_hex2bin((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data));
  205. if (!result) {
  206. php_error_docref(NULL, E_WARNING, "Input string must be hexadecimal string");
  207. RETURN_FALSE;
  208. }
  209. RETVAL_STR(result);
  210. }
  211. /* }}} */
  212. static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /* {{{ */
  213. {
  214. zend_string *s11, *s22;
  215. zend_long start = 0, len = 0;
  216. bool len_is_null = 1;
  217. ZEND_PARSE_PARAMETERS_START(2, 4)
  218. Z_PARAM_STR(s11)
  219. Z_PARAM_STR(s22)
  220. Z_PARAM_OPTIONAL
  221. Z_PARAM_LONG(start)
  222. Z_PARAM_LONG_OR_NULL(len, len_is_null)
  223. ZEND_PARSE_PARAMETERS_END();
  224. size_t remain_len = ZSTR_LEN(s11);
  225. if (start < 0) {
  226. start += remain_len;
  227. if (start < 0) {
  228. start = 0;
  229. }
  230. } else if ((size_t) start > remain_len) {
  231. start = remain_len;
  232. }
  233. remain_len -= start;
  234. if (!len_is_null) {
  235. if (len < 0) {
  236. len += remain_len;
  237. if (len < 0) {
  238. len = 0;
  239. }
  240. } else if ((size_t) len > remain_len) {
  241. len = remain_len;
  242. }
  243. } else {
  244. len = remain_len;
  245. }
  246. if (len == 0) {
  247. RETURN_LONG(0);
  248. }
  249. if (behavior == STR_STRSPN) {
  250. RETURN_LONG(php_strspn(ZSTR_VAL(s11) + start /*str1_start*/,
  251. ZSTR_VAL(s22) /*str2_start*/,
  252. ZSTR_VAL(s11) + start + len /*str1_end*/,
  253. ZSTR_VAL(s22) + ZSTR_LEN(s22) /*str2_end*/));
  254. } else {
  255. ZEND_ASSERT(behavior == STR_STRCSPN);
  256. RETURN_LONG(php_strcspn(ZSTR_VAL(s11) + start /*str1_start*/,
  257. ZSTR_VAL(s22) /*str2_start*/,
  258. ZSTR_VAL(s11) + start + len /*str1_end*/,
  259. ZSTR_VAL(s22) + ZSTR_LEN(s22) /*str2_end*/));
  260. }
  261. }
  262. /* }}} */
  263. /* {{{ 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) */
  264. PHP_FUNCTION(strspn)
  265. {
  266. php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRSPN);
  267. }
  268. /* }}} */
  269. /* {{{ 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) */
  270. PHP_FUNCTION(strcspn)
  271. {
  272. php_spn_common_handler(INTERNAL_FUNCTION_PARAM_PASSTHRU, STR_STRCSPN);
  273. }
  274. /* }}} */
  275. /* {{{ PHP_MINIT_FUNCTION(nl_langinfo) */
  276. #if HAVE_NL_LANGINFO
  277. PHP_MINIT_FUNCTION(nl_langinfo)
  278. {
  279. #define REGISTER_NL_LANGINFO_CONSTANT(x) REGISTER_LONG_CONSTANT(#x, x, CONST_CS | CONST_PERSISTENT)
  280. #ifdef ABDAY_1
  281. REGISTER_NL_LANGINFO_CONSTANT(ABDAY_1);
  282. REGISTER_NL_LANGINFO_CONSTANT(ABDAY_2);
  283. REGISTER_NL_LANGINFO_CONSTANT(ABDAY_3);
  284. REGISTER_NL_LANGINFO_CONSTANT(ABDAY_4);
  285. REGISTER_NL_LANGINFO_CONSTANT(ABDAY_5);
  286. REGISTER_NL_LANGINFO_CONSTANT(ABDAY_6);
  287. REGISTER_NL_LANGINFO_CONSTANT(ABDAY_7);
  288. #endif
  289. #ifdef DAY_1
  290. REGISTER_NL_LANGINFO_CONSTANT(DAY_1);
  291. REGISTER_NL_LANGINFO_CONSTANT(DAY_2);
  292. REGISTER_NL_LANGINFO_CONSTANT(DAY_3);
  293. REGISTER_NL_LANGINFO_CONSTANT(DAY_4);
  294. REGISTER_NL_LANGINFO_CONSTANT(DAY_5);
  295. REGISTER_NL_LANGINFO_CONSTANT(DAY_6);
  296. REGISTER_NL_LANGINFO_CONSTANT(DAY_7);
  297. #endif
  298. #ifdef ABMON_1
  299. REGISTER_NL_LANGINFO_CONSTANT(ABMON_1);
  300. REGISTER_NL_LANGINFO_CONSTANT(ABMON_2);
  301. REGISTER_NL_LANGINFO_CONSTANT(ABMON_3);
  302. REGISTER_NL_LANGINFO_CONSTANT(ABMON_4);
  303. REGISTER_NL_LANGINFO_CONSTANT(ABMON_5);
  304. REGISTER_NL_LANGINFO_CONSTANT(ABMON_6);
  305. REGISTER_NL_LANGINFO_CONSTANT(ABMON_7);
  306. REGISTER_NL_LANGINFO_CONSTANT(ABMON_8);
  307. REGISTER_NL_LANGINFO_CONSTANT(ABMON_9);
  308. REGISTER_NL_LANGINFO_CONSTANT(ABMON_10);
  309. REGISTER_NL_LANGINFO_CONSTANT(ABMON_11);
  310. REGISTER_NL_LANGINFO_CONSTANT(ABMON_12);
  311. #endif
  312. #ifdef MON_1
  313. REGISTER_NL_LANGINFO_CONSTANT(MON_1);
  314. REGISTER_NL_LANGINFO_CONSTANT(MON_2);
  315. REGISTER_NL_LANGINFO_CONSTANT(MON_3);
  316. REGISTER_NL_LANGINFO_CONSTANT(MON_4);
  317. REGISTER_NL_LANGINFO_CONSTANT(MON_5);
  318. REGISTER_NL_LANGINFO_CONSTANT(MON_6);
  319. REGISTER_NL_LANGINFO_CONSTANT(MON_7);
  320. REGISTER_NL_LANGINFO_CONSTANT(MON_8);
  321. REGISTER_NL_LANGINFO_CONSTANT(MON_9);
  322. REGISTER_NL_LANGINFO_CONSTANT(MON_10);
  323. REGISTER_NL_LANGINFO_CONSTANT(MON_11);
  324. REGISTER_NL_LANGINFO_CONSTANT(MON_12);
  325. #endif
  326. #ifdef AM_STR
  327. REGISTER_NL_LANGINFO_CONSTANT(AM_STR);
  328. #endif
  329. #ifdef PM_STR
  330. REGISTER_NL_LANGINFO_CONSTANT(PM_STR);
  331. #endif
  332. #ifdef D_T_FMT
  333. REGISTER_NL_LANGINFO_CONSTANT(D_T_FMT);
  334. #endif
  335. #ifdef D_FMT
  336. REGISTER_NL_LANGINFO_CONSTANT(D_FMT);
  337. #endif
  338. #ifdef T_FMT
  339. REGISTER_NL_LANGINFO_CONSTANT(T_FMT);
  340. #endif
  341. #ifdef T_FMT_AMPM
  342. REGISTER_NL_LANGINFO_CONSTANT(T_FMT_AMPM);
  343. #endif
  344. #ifdef ERA
  345. REGISTER_NL_LANGINFO_CONSTANT(ERA);
  346. #endif
  347. #ifdef ERA_YEAR
  348. REGISTER_NL_LANGINFO_CONSTANT(ERA_YEAR);
  349. #endif
  350. #ifdef ERA_D_T_FMT
  351. REGISTER_NL_LANGINFO_CONSTANT(ERA_D_T_FMT);
  352. #endif
  353. #ifdef ERA_D_FMT
  354. REGISTER_NL_LANGINFO_CONSTANT(ERA_D_FMT);
  355. #endif
  356. #ifdef ERA_T_FMT
  357. REGISTER_NL_LANGINFO_CONSTANT(ERA_T_FMT);
  358. #endif
  359. #ifdef ALT_DIGITS
  360. REGISTER_NL_LANGINFO_CONSTANT(ALT_DIGITS);
  361. #endif
  362. #ifdef INT_CURR_SYMBOL
  363. REGISTER_NL_LANGINFO_CONSTANT(INT_CURR_SYMBOL);
  364. #endif
  365. #ifdef CURRENCY_SYMBOL
  366. REGISTER_NL_LANGINFO_CONSTANT(CURRENCY_SYMBOL);
  367. #endif
  368. #ifdef CRNCYSTR
  369. REGISTER_NL_LANGINFO_CONSTANT(CRNCYSTR);
  370. #endif
  371. #ifdef MON_DECIMAL_POINT
  372. REGISTER_NL_LANGINFO_CONSTANT(MON_DECIMAL_POINT);
  373. #endif
  374. #ifdef MON_THOUSANDS_SEP
  375. REGISTER_NL_LANGINFO_CONSTANT(MON_THOUSANDS_SEP);
  376. #endif
  377. #ifdef MON_GROUPING
  378. REGISTER_NL_LANGINFO_CONSTANT(MON_GROUPING);
  379. #endif
  380. #ifdef POSITIVE_SIGN
  381. REGISTER_NL_LANGINFO_CONSTANT(POSITIVE_SIGN);
  382. #endif
  383. #ifdef NEGATIVE_SIGN
  384. REGISTER_NL_LANGINFO_CONSTANT(NEGATIVE_SIGN);
  385. #endif
  386. #ifdef INT_FRAC_DIGITS
  387. REGISTER_NL_LANGINFO_CONSTANT(INT_FRAC_DIGITS);
  388. #endif
  389. #ifdef FRAC_DIGITS
  390. REGISTER_NL_LANGINFO_CONSTANT(FRAC_DIGITS);
  391. #endif
  392. #ifdef P_CS_PRECEDES
  393. REGISTER_NL_LANGINFO_CONSTANT(P_CS_PRECEDES);
  394. #endif
  395. #ifdef P_SEP_BY_SPACE
  396. REGISTER_NL_LANGINFO_CONSTANT(P_SEP_BY_SPACE);
  397. #endif
  398. #ifdef N_CS_PRECEDES
  399. REGISTER_NL_LANGINFO_CONSTANT(N_CS_PRECEDES);
  400. #endif
  401. #ifdef N_SEP_BY_SPACE
  402. REGISTER_NL_LANGINFO_CONSTANT(N_SEP_BY_SPACE);
  403. #endif
  404. #ifdef P_SIGN_POSN
  405. REGISTER_NL_LANGINFO_CONSTANT(P_SIGN_POSN);
  406. #endif
  407. #ifdef N_SIGN_POSN
  408. REGISTER_NL_LANGINFO_CONSTANT(N_SIGN_POSN);
  409. #endif
  410. #ifdef DECIMAL_POINT
  411. REGISTER_NL_LANGINFO_CONSTANT(DECIMAL_POINT);
  412. #endif
  413. #ifdef RADIXCHAR
  414. REGISTER_NL_LANGINFO_CONSTANT(RADIXCHAR);
  415. #endif
  416. #ifdef THOUSANDS_SEP
  417. REGISTER_NL_LANGINFO_CONSTANT(THOUSANDS_SEP);
  418. #endif
  419. #ifdef THOUSEP
  420. REGISTER_NL_LANGINFO_CONSTANT(THOUSEP);
  421. #endif
  422. #ifdef GROUPING
  423. REGISTER_NL_LANGINFO_CONSTANT(GROUPING);
  424. #endif
  425. #ifdef YESEXPR
  426. REGISTER_NL_LANGINFO_CONSTANT(YESEXPR);
  427. #endif
  428. #ifdef NOEXPR
  429. REGISTER_NL_LANGINFO_CONSTANT(NOEXPR);
  430. #endif
  431. #ifdef YESSTR
  432. REGISTER_NL_LANGINFO_CONSTANT(YESSTR);
  433. #endif
  434. #ifdef NOSTR
  435. REGISTER_NL_LANGINFO_CONSTANT(NOSTR);
  436. #endif
  437. #ifdef CODESET
  438. REGISTER_NL_LANGINFO_CONSTANT(CODESET);
  439. #endif
  440. #undef REGISTER_NL_LANGINFO_CONSTANT
  441. return SUCCESS;
  442. }
  443. /* }}} */
  444. /* {{{ Query language and locale information */
  445. PHP_FUNCTION(nl_langinfo)
  446. {
  447. zend_long item;
  448. char *value;
  449. ZEND_PARSE_PARAMETERS_START(1, 1)
  450. Z_PARAM_LONG(item)
  451. ZEND_PARSE_PARAMETERS_END();
  452. switch(item) { /* {{{ */
  453. #ifdef ABDAY_1
  454. case ABDAY_1:
  455. case ABDAY_2:
  456. case ABDAY_3:
  457. case ABDAY_4:
  458. case ABDAY_5:
  459. case ABDAY_6:
  460. case ABDAY_7:
  461. #endif
  462. #ifdef DAY_1
  463. case DAY_1:
  464. case DAY_2:
  465. case DAY_3:
  466. case DAY_4:
  467. case DAY_5:
  468. case DAY_6:
  469. case DAY_7:
  470. #endif
  471. #ifdef ABMON_1
  472. case ABMON_1:
  473. case ABMON_2:
  474. case ABMON_3:
  475. case ABMON_4:
  476. case ABMON_5:
  477. case ABMON_6:
  478. case ABMON_7:
  479. case ABMON_8:
  480. case ABMON_9:
  481. case ABMON_10:
  482. case ABMON_11:
  483. case ABMON_12:
  484. #endif
  485. #ifdef MON_1
  486. case MON_1:
  487. case MON_2:
  488. case MON_3:
  489. case MON_4:
  490. case MON_5:
  491. case MON_6:
  492. case MON_7:
  493. case MON_8:
  494. case MON_9:
  495. case MON_10:
  496. case MON_11:
  497. case MON_12:
  498. #endif
  499. #ifdef AM_STR
  500. case AM_STR:
  501. #endif
  502. #ifdef PM_STR
  503. case PM_STR:
  504. #endif
  505. #ifdef D_T_FMT
  506. case D_T_FMT:
  507. #endif
  508. #ifdef D_FMT
  509. case D_FMT:
  510. #endif
  511. #ifdef T_FMT
  512. case T_FMT:
  513. #endif
  514. #ifdef T_FMT_AMPM
  515. case T_FMT_AMPM:
  516. #endif
  517. #ifdef ERA
  518. case ERA:
  519. #endif
  520. #ifdef ERA_YEAR
  521. case ERA_YEAR:
  522. #endif
  523. #ifdef ERA_D_T_FMT
  524. case ERA_D_T_FMT:
  525. #endif
  526. #ifdef ERA_D_FMT
  527. case ERA_D_FMT:
  528. #endif
  529. #ifdef ERA_T_FMT
  530. case ERA_T_FMT:
  531. #endif
  532. #ifdef ALT_DIGITS
  533. case ALT_DIGITS:
  534. #endif
  535. #ifdef INT_CURR_SYMBOL
  536. case INT_CURR_SYMBOL:
  537. #endif
  538. #ifdef CURRENCY_SYMBOL
  539. case CURRENCY_SYMBOL:
  540. #endif
  541. #ifdef CRNCYSTR
  542. case CRNCYSTR:
  543. #endif
  544. #ifdef MON_DECIMAL_POINT
  545. case MON_DECIMAL_POINT:
  546. #endif
  547. #ifdef MON_THOUSANDS_SEP
  548. case MON_THOUSANDS_SEP:
  549. #endif
  550. #ifdef MON_GROUPING
  551. case MON_GROUPING:
  552. #endif
  553. #ifdef POSITIVE_SIGN
  554. case POSITIVE_SIGN:
  555. #endif
  556. #ifdef NEGATIVE_SIGN
  557. case NEGATIVE_SIGN:
  558. #endif
  559. #ifdef INT_FRAC_DIGITS
  560. case INT_FRAC_DIGITS:
  561. #endif
  562. #ifdef FRAC_DIGITS
  563. case FRAC_DIGITS:
  564. #endif
  565. #ifdef P_CS_PRECEDES
  566. case P_CS_PRECEDES:
  567. #endif
  568. #ifdef P_SEP_BY_SPACE
  569. case P_SEP_BY_SPACE:
  570. #endif
  571. #ifdef N_CS_PRECEDES
  572. case N_CS_PRECEDES:
  573. #endif
  574. #ifdef N_SEP_BY_SPACE
  575. case N_SEP_BY_SPACE:
  576. #endif
  577. #ifdef P_SIGN_POSN
  578. case P_SIGN_POSN:
  579. #endif
  580. #ifdef N_SIGN_POSN
  581. case N_SIGN_POSN:
  582. #endif
  583. #ifdef DECIMAL_POINT
  584. case DECIMAL_POINT:
  585. #elif defined(RADIXCHAR)
  586. case RADIXCHAR:
  587. #endif
  588. #ifdef THOUSANDS_SEP
  589. case THOUSANDS_SEP:
  590. #elif defined(THOUSEP)
  591. case THOUSEP:
  592. #endif
  593. #ifdef GROUPING
  594. case GROUPING:
  595. #endif
  596. #ifdef YESEXPR
  597. case YESEXPR:
  598. #endif
  599. #ifdef NOEXPR
  600. case NOEXPR:
  601. #endif
  602. #ifdef YESSTR
  603. case YESSTR:
  604. #endif
  605. #ifdef NOSTR
  606. case NOSTR:
  607. #endif
  608. #ifdef CODESET
  609. case CODESET:
  610. #endif
  611. break;
  612. default:
  613. php_error_docref(NULL, E_WARNING, "Item '" ZEND_LONG_FMT "' is not valid", item);
  614. RETURN_FALSE;
  615. }
  616. /* }}} */
  617. value = nl_langinfo(item);
  618. if (value == NULL) {
  619. RETURN_FALSE;
  620. } else {
  621. RETURN_STRING(value);
  622. }
  623. }
  624. #endif
  625. /* }}} */
  626. /* {{{ Compares two strings using the current locale */
  627. PHP_FUNCTION(strcoll)
  628. {
  629. zend_string *s1, *s2;
  630. ZEND_PARSE_PARAMETERS_START(2, 2)
  631. Z_PARAM_STR(s1)
  632. Z_PARAM_STR(s2)
  633. ZEND_PARSE_PARAMETERS_END();
  634. RETURN_LONG(strcoll((const char *) ZSTR_VAL(s1),
  635. (const char *) ZSTR_VAL(s2)));
  636. }
  637. /* }}} */
  638. /* {{{ php_charmask
  639. * Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
  640. * it needs to be incrementing.
  641. * Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
  642. */
  643. static inline int php_charmask(const unsigned char *input, size_t len, char *mask)
  644. {
  645. const unsigned char *end;
  646. unsigned char c;
  647. int result = SUCCESS;
  648. memset(mask, 0, 256);
  649. for (end = input+len; input < end; input++) {
  650. c=*input;
  651. if ((input+3 < end) && input[1] == '.' && input[2] == '.'
  652. && input[3] >= c) {
  653. memset(mask+c, 1, input[3] - c + 1);
  654. input+=3;
  655. } else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
  656. /* Error, try to be as helpful as possible:
  657. (a range ending/starting with '.' won't be captured here) */
  658. if (end-len >= input) { /* there was no 'left' char */
  659. php_error_docref(NULL, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
  660. result = FAILURE;
  661. continue;
  662. }
  663. if (input+2 >= end) { /* there is no 'right' char */
  664. php_error_docref(NULL, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
  665. result = FAILURE;
  666. continue;
  667. }
  668. if (input[-1] > input[2]) { /* wrong order */
  669. php_error_docref(NULL, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
  670. result = FAILURE;
  671. continue;
  672. }
  673. /* FIXME: better error (a..b..c is the only left possibility?) */
  674. php_error_docref(NULL, E_WARNING, "Invalid '..'-range");
  675. result = FAILURE;
  676. continue;
  677. } else {
  678. mask[c]=1;
  679. }
  680. }
  681. return result;
  682. }
  683. /* }}} */
  684. /* {{{ php_trim_int()
  685. * mode 1 : trim left
  686. * mode 2 : trim right
  687. * mode 3 : trim left and right
  688. * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
  689. */
  690. static zend_always_inline zend_string *php_trim_int(zend_string *str, const char *what, size_t what_len, int mode)
  691. {
  692. const char *start = ZSTR_VAL(str);
  693. const char *end = start + ZSTR_LEN(str);
  694. char mask[256];
  695. if (what) {
  696. if (what_len == 1) {
  697. char p = *what;
  698. if (mode & 1) {
  699. while (start != end) {
  700. if (*start == p) {
  701. start++;
  702. } else {
  703. break;
  704. }
  705. }
  706. }
  707. if (mode & 2) {
  708. while (start != end) {
  709. if (*(end-1) == p) {
  710. end--;
  711. } else {
  712. break;
  713. }
  714. }
  715. }
  716. } else {
  717. php_charmask((const unsigned char *) what, what_len, mask);
  718. if (mode & 1) {
  719. while (start != end) {
  720. if (mask[(unsigned char)*start]) {
  721. start++;
  722. } else {
  723. break;
  724. }
  725. }
  726. }
  727. if (mode & 2) {
  728. while (start != end) {
  729. if (mask[(unsigned char)*(end-1)]) {
  730. end--;
  731. } else {
  732. break;
  733. }
  734. }
  735. }
  736. }
  737. } else {
  738. if (mode & 1) {
  739. while (start != end) {
  740. unsigned char c = (unsigned char)*start;
  741. if (c <= ' ' &&
  742. (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) {
  743. start++;
  744. } else {
  745. break;
  746. }
  747. }
  748. }
  749. if (mode & 2) {
  750. while (start != end) {
  751. unsigned char c = (unsigned char)*(end-1);
  752. if (c <= ' ' &&
  753. (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\0')) {
  754. end--;
  755. } else {
  756. break;
  757. }
  758. }
  759. }
  760. }
  761. if (ZSTR_LEN(str) == end - start) {
  762. return zend_string_copy(str);
  763. } else if (end - start == 0) {
  764. return ZSTR_EMPTY_ALLOC();
  765. } else {
  766. return zend_string_init(start, end - start, 0);
  767. }
  768. }
  769. /* }}} */
  770. /* {{{ php_trim_int()
  771. * mode 1 : trim left
  772. * mode 2 : trim right
  773. * mode 3 : trim left and right
  774. * what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
  775. */
  776. PHPAPI zend_string *php_trim(zend_string *str, const char *what, size_t what_len, int mode)
  777. {
  778. return php_trim_int(str, what, what_len, mode);
  779. }
  780. /* }}} */
  781. /* {{{ php_do_trim
  782. * Base for trim(), rtrim() and ltrim() functions.
  783. */
  784. static zend_always_inline void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
  785. {
  786. zend_string *str;
  787. zend_string *what = NULL;
  788. ZEND_PARSE_PARAMETERS_START(1, 2)
  789. Z_PARAM_STR(str)
  790. Z_PARAM_OPTIONAL
  791. Z_PARAM_STR(what)
  792. ZEND_PARSE_PARAMETERS_END();
  793. ZVAL_STR(return_value, php_trim_int(str, (what ? ZSTR_VAL(what) : NULL), (what ? ZSTR_LEN(what) : 0), mode));
  794. }
  795. /* }}} */
  796. /* {{{ Strips whitespace from the beginning and end of a string */
  797. PHP_FUNCTION(trim)
  798. {
  799. php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3);
  800. }
  801. /* }}} */
  802. /* {{{ Removes trailing whitespace */
  803. PHP_FUNCTION(rtrim)
  804. {
  805. php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 2);
  806. }
  807. /* }}} */
  808. /* {{{ Strips whitespace from the beginning of a string */
  809. PHP_FUNCTION(ltrim)
  810. {
  811. php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  812. }
  813. /* }}} */
  814. /* {{{ Wraps buffer to selected number of characters using string break char */
  815. PHP_FUNCTION(wordwrap)
  816. {
  817. zend_string *text;
  818. char *breakchar = "\n";
  819. size_t newtextlen, chk, breakchar_len = 1;
  820. size_t alloced;
  821. zend_long current = 0, laststart = 0, lastspace = 0;
  822. zend_long linelength = 75;
  823. bool docut = 0;
  824. zend_string *newtext;
  825. ZEND_PARSE_PARAMETERS_START(1, 4)
  826. Z_PARAM_STR(text)
  827. Z_PARAM_OPTIONAL
  828. Z_PARAM_LONG(linelength)
  829. Z_PARAM_STRING(breakchar, breakchar_len)
  830. Z_PARAM_BOOL(docut)
  831. ZEND_PARSE_PARAMETERS_END();
  832. if (ZSTR_LEN(text) == 0) {
  833. RETURN_EMPTY_STRING();
  834. }
  835. if (breakchar_len == 0) {
  836. zend_argument_value_error(3, "cannot be empty");
  837. RETURN_THROWS();
  838. }
  839. if (linelength == 0 && docut) {
  840. zend_argument_value_error(4, "cannot be true when argument #2 ($width) is 0");
  841. RETURN_THROWS();
  842. }
  843. /* Special case for a single-character break as it needs no
  844. additional storage space */
  845. if (breakchar_len == 1 && !docut) {
  846. newtext = zend_string_init(ZSTR_VAL(text), ZSTR_LEN(text), 0);
  847. laststart = lastspace = 0;
  848. for (current = 0; current < (zend_long)ZSTR_LEN(text); current++) {
  849. if (ZSTR_VAL(text)[current] == breakchar[0]) {
  850. laststart = lastspace = current + 1;
  851. } else if (ZSTR_VAL(text)[current] == ' ') {
  852. if (current - laststart >= linelength) {
  853. ZSTR_VAL(newtext)[current] = breakchar[0];
  854. laststart = current + 1;
  855. }
  856. lastspace = current;
  857. } else if (current - laststart >= linelength && laststart != lastspace) {
  858. ZSTR_VAL(newtext)[lastspace] = breakchar[0];
  859. laststart = lastspace + 1;
  860. }
  861. }
  862. RETURN_NEW_STR(newtext);
  863. } else {
  864. /* Multiple character line break or forced cut */
  865. if (linelength > 0) {
  866. chk = (size_t)(ZSTR_LEN(text)/linelength + 1);
  867. newtext = zend_string_safe_alloc(chk, breakchar_len, ZSTR_LEN(text), 0);
  868. alloced = ZSTR_LEN(text) + chk * breakchar_len + 1;
  869. } else {
  870. chk = ZSTR_LEN(text);
  871. alloced = ZSTR_LEN(text) * (breakchar_len + 1) + 1;
  872. newtext = zend_string_safe_alloc(ZSTR_LEN(text), breakchar_len + 1, 0, 0);
  873. }
  874. /* now keep track of the actual new text length */
  875. newtextlen = 0;
  876. laststart = lastspace = 0;
  877. for (current = 0; current < (zend_long)ZSTR_LEN(text); current++) {
  878. if (chk == 0) {
  879. alloced += (size_t) (((ZSTR_LEN(text) - current + 1)/linelength + 1) * breakchar_len) + 1;
  880. newtext = zend_string_extend(newtext, alloced, 0);
  881. chk = (size_t) ((ZSTR_LEN(text) - current)/linelength) + 1;
  882. }
  883. /* when we hit an existing break, copy to new buffer, and
  884. * fix up laststart and lastspace */
  885. if (ZSTR_VAL(text)[current] == breakchar[0]
  886. && current + breakchar_len < ZSTR_LEN(text)
  887. && !strncmp(ZSTR_VAL(text) + current, breakchar, breakchar_len)) {
  888. memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart + breakchar_len);
  889. newtextlen += current - laststart + breakchar_len;
  890. current += breakchar_len - 1;
  891. laststart = lastspace = current + 1;
  892. chk--;
  893. }
  894. /* if it is a space, check if it is at the line boundary,
  895. * copy and insert a break, or just keep track of it */
  896. else if (ZSTR_VAL(text)[current] == ' ') {
  897. if (current - laststart >= linelength) {
  898. memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
  899. newtextlen += current - laststart;
  900. memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
  901. newtextlen += breakchar_len;
  902. laststart = current + 1;
  903. chk--;
  904. }
  905. lastspace = current;
  906. }
  907. /* if we are cutting, and we've accumulated enough
  908. * characters, and we haven't see a space for this line,
  909. * copy and insert a break. */
  910. else if (current - laststart >= linelength
  911. && docut && laststart >= lastspace) {
  912. memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
  913. newtextlen += current - laststart;
  914. memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
  915. newtextlen += breakchar_len;
  916. laststart = lastspace = current;
  917. chk--;
  918. }
  919. /* if the current word puts us over the linelength, copy
  920. * back up until the last space, insert a break, and move
  921. * up the laststart */
  922. else if (current - laststart >= linelength
  923. && laststart < lastspace) {
  924. memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, lastspace - laststart);
  925. newtextlen += lastspace - laststart;
  926. memcpy(ZSTR_VAL(newtext) + newtextlen, breakchar, breakchar_len);
  927. newtextlen += breakchar_len;
  928. laststart = lastspace = lastspace + 1;
  929. chk--;
  930. }
  931. }
  932. /* copy over any stragglers */
  933. if (laststart != current) {
  934. memcpy(ZSTR_VAL(newtext) + newtextlen, ZSTR_VAL(text) + laststart, current - laststart);
  935. newtextlen += current - laststart;
  936. }
  937. ZSTR_VAL(newtext)[newtextlen] = '\0';
  938. /* free unused memory */
  939. newtext = zend_string_truncate(newtext, newtextlen, 0);
  940. RETURN_NEW_STR(newtext);
  941. }
  942. }
  943. /* }}} */
  944. /* {{{ php_explode */
  945. PHPAPI void php_explode(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
  946. {
  947. const char *p1 = ZSTR_VAL(str);
  948. const char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
  949. const char *p2 = php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
  950. zval tmp;
  951. if (p2 == NULL) {
  952. ZVAL_STR_COPY(&tmp, str);
  953. zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
  954. } else {
  955. zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
  956. ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
  957. do {
  958. ZEND_HASH_FILL_GROW();
  959. ZEND_HASH_FILL_SET_STR(zend_string_init_fast(p1, p2 - p1));
  960. ZEND_HASH_FILL_NEXT();
  961. p1 = p2 + ZSTR_LEN(delim);
  962. p2 = php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
  963. } while (p2 != NULL && --limit > 1);
  964. if (p1 <= endp) {
  965. ZEND_HASH_FILL_GROW();
  966. ZEND_HASH_FILL_SET_STR(zend_string_init_fast(p1, endp - p1));
  967. ZEND_HASH_FILL_NEXT();
  968. }
  969. } ZEND_HASH_FILL_END();
  970. }
  971. }
  972. /* }}} */
  973. /* {{{ php_explode_negative_limit */
  974. PHPAPI void php_explode_negative_limit(const zend_string *delim, zend_string *str, zval *return_value, zend_long limit)
  975. {
  976. #define EXPLODE_ALLOC_STEP 64
  977. const char *p1 = ZSTR_VAL(str);
  978. const char *endp = ZSTR_VAL(str) + ZSTR_LEN(str);
  979. const char *p2 = php_memnstr(ZSTR_VAL(str), ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
  980. zval tmp;
  981. if (p2 == NULL) {
  982. /*
  983. do nothing since limit <= -1, thus if only one chunk - 1 + (limit) <= 0
  984. by doing nothing we return empty array
  985. */
  986. } else {
  987. size_t allocated = EXPLODE_ALLOC_STEP, found = 0;
  988. zend_long i, to_return;
  989. const char **positions = emalloc(allocated * sizeof(char *));
  990. positions[found++] = p1;
  991. do {
  992. if (found >= allocated) {
  993. allocated = found + EXPLODE_ALLOC_STEP;/* make sure we have enough memory */
  994. positions = erealloc(ZEND_VOIDP(positions), allocated*sizeof(char *));
  995. }
  996. positions[found++] = p1 = p2 + ZSTR_LEN(delim);
  997. p2 = php_memnstr(p1, ZSTR_VAL(delim), ZSTR_LEN(delim), endp);
  998. } while (p2 != NULL);
  999. to_return = limit + found;
  1000. /* limit is at least -1 therefore no need of bounds checking : i will be always less than found */
  1001. for (i = 0; i < to_return; i++) { /* this checks also for to_return > 0 */
  1002. ZVAL_STRINGL(&tmp, positions[i], (positions[i+1] - ZSTR_LEN(delim)) - positions[i]);
  1003. zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
  1004. }
  1005. efree((void *)positions);
  1006. }
  1007. #undef EXPLODE_ALLOC_STEP
  1008. }
  1009. /* }}} */
  1010. /* {{{ 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. */
  1011. PHP_FUNCTION(explode)
  1012. {
  1013. zend_string *str, *delim;
  1014. zend_long limit = ZEND_LONG_MAX; /* No limit */
  1015. zval tmp;
  1016. ZEND_PARSE_PARAMETERS_START(2, 3)
  1017. Z_PARAM_STR(delim)
  1018. Z_PARAM_STR(str)
  1019. Z_PARAM_OPTIONAL
  1020. Z_PARAM_LONG(limit)
  1021. ZEND_PARSE_PARAMETERS_END();
  1022. if (ZSTR_LEN(delim) == 0) {
  1023. zend_argument_value_error(1, "cannot be empty");
  1024. RETURN_THROWS();
  1025. }
  1026. array_init(return_value);
  1027. if (ZSTR_LEN(str) == 0) {
  1028. if (limit >= 0) {
  1029. ZVAL_EMPTY_STRING(&tmp);
  1030. zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
  1031. }
  1032. return;
  1033. }
  1034. if (limit > 1) {
  1035. php_explode(delim, str, return_value, limit);
  1036. } else if (limit < 0) {
  1037. php_explode_negative_limit(delim, str, return_value, limit);
  1038. } else {
  1039. ZVAL_STR_COPY(&tmp, str);
  1040. zend_hash_index_add_new(Z_ARRVAL_P(return_value), 0, &tmp);
  1041. }
  1042. }
  1043. /* }}} */
  1044. /* {{{ An alias for implode */
  1045. /* }}} */
  1046. /* {{{ php_implode */
  1047. PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return_value)
  1048. {
  1049. zval *tmp;
  1050. int numelems;
  1051. zend_string *str;
  1052. char *cptr;
  1053. size_t len = 0;
  1054. struct {
  1055. zend_string *str;
  1056. zend_long lval;
  1057. } *strings, *ptr;
  1058. ALLOCA_FLAG(use_heap)
  1059. numelems = zend_hash_num_elements(pieces);
  1060. if (numelems == 0) {
  1061. RETURN_EMPTY_STRING();
  1062. } else if (numelems == 1) {
  1063. /* loop to search the first not undefined element... */
  1064. ZEND_HASH_FOREACH_VAL(pieces, tmp) {
  1065. RETURN_STR(zval_get_string(tmp));
  1066. } ZEND_HASH_FOREACH_END();
  1067. }
  1068. ptr = strings = do_alloca((sizeof(*strings)) * numelems, use_heap);
  1069. ZEND_HASH_FOREACH_VAL(pieces, tmp) {
  1070. if (EXPECTED(Z_TYPE_P(tmp) == IS_STRING)) {
  1071. ptr->str = Z_STR_P(tmp);
  1072. len += ZSTR_LEN(ptr->str);
  1073. ptr->lval = 0;
  1074. ptr++;
  1075. } else if (UNEXPECTED(Z_TYPE_P(tmp) == IS_LONG)) {
  1076. zend_long val = Z_LVAL_P(tmp);
  1077. ptr->str = NULL;
  1078. ptr->lval = val;
  1079. ptr++;
  1080. if (val <= 0) {
  1081. len++;
  1082. }
  1083. while (val) {
  1084. val /= 10;
  1085. len++;
  1086. }
  1087. } else {
  1088. ptr->str = zval_get_string_func(tmp);
  1089. len += ZSTR_LEN(ptr->str);
  1090. ptr->lval = 1;
  1091. ptr++;
  1092. }
  1093. } ZEND_HASH_FOREACH_END();
  1094. /* numelems cannot be 0, we checked above */
  1095. str = zend_string_safe_alloc(numelems - 1, ZSTR_LEN(glue), len, 0);
  1096. cptr = ZSTR_VAL(str) + ZSTR_LEN(str);
  1097. *cptr = 0;
  1098. while (1) {
  1099. ptr--;
  1100. if (EXPECTED(ptr->str)) {
  1101. cptr -= ZSTR_LEN(ptr->str);
  1102. memcpy(cptr, ZSTR_VAL(ptr->str), ZSTR_LEN(ptr->str));
  1103. if (ptr->lval) {
  1104. zend_string_release_ex(ptr->str, 0);
  1105. }
  1106. } else {
  1107. char *oldPtr = cptr;
  1108. char oldVal = *cptr;
  1109. cptr = zend_print_long_to_buf(cptr, ptr->lval);
  1110. *oldPtr = oldVal;
  1111. }
  1112. if (ptr == strings) {
  1113. break;
  1114. }
  1115. cptr -= ZSTR_LEN(glue);
  1116. memcpy(cptr, ZSTR_VAL(glue), ZSTR_LEN(glue));
  1117. }
  1118. free_alloca(strings, use_heap);
  1119. RETURN_NEW_STR(str);
  1120. }
  1121. /* }}} */
  1122. /* {{{ Joins array elements placing glue string between items and return one string */
  1123. PHP_FUNCTION(implode)
  1124. {
  1125. zend_string *arg1_str = NULL;
  1126. HashTable *arg1_array = NULL;
  1127. zend_array *pieces = NULL;
  1128. ZEND_PARSE_PARAMETERS_START(1, 2)
  1129. Z_PARAM_ARRAY_HT_OR_STR(arg1_array, arg1_str)
  1130. Z_PARAM_OPTIONAL
  1131. Z_PARAM_ARRAY_HT_OR_NULL(pieces)
  1132. ZEND_PARSE_PARAMETERS_END();
  1133. if (pieces == NULL) {
  1134. if (arg1_array == NULL) {
  1135. zend_type_error("%s(): Argument #1 ($pieces) must be of type array, string given", get_active_function_name());
  1136. RETURN_THROWS();
  1137. }
  1138. arg1_str = ZSTR_EMPTY_ALLOC();
  1139. pieces = arg1_array;
  1140. } else {
  1141. if (arg1_str == NULL) {
  1142. zend_argument_type_error(1, "must be of type string, array given");
  1143. RETURN_THROWS();
  1144. }
  1145. }
  1146. php_implode(arg1_str, pieces, return_value);
  1147. }
  1148. /* }}} */
  1149. #define STRTOK_TABLE(p) BG(strtok_table)[(unsigned char) *p]
  1150. /* {{{ Tokenize a string */
  1151. PHP_FUNCTION(strtok)
  1152. {
  1153. zend_string *str, *tok = NULL;
  1154. char *token;
  1155. char *token_end;
  1156. char *p;
  1157. char *pe;
  1158. size_t skipped = 0;
  1159. ZEND_PARSE_PARAMETERS_START(1, 2)
  1160. Z_PARAM_STR(str)
  1161. Z_PARAM_OPTIONAL
  1162. Z_PARAM_STR_OR_NULL(tok)
  1163. ZEND_PARSE_PARAMETERS_END();
  1164. if (!tok) {
  1165. tok = str;
  1166. } else {
  1167. if (BG(strtok_string)) {
  1168. zend_string_release(BG(strtok_string));
  1169. }
  1170. BG(strtok_string) = zend_string_copy(str);
  1171. BG(strtok_last) = ZSTR_VAL(str);
  1172. BG(strtok_len) = ZSTR_LEN(str);
  1173. }
  1174. if (!BG(strtok_string)) {
  1175. /* String to tokenize not set. */
  1176. // TODO: Should this warn?
  1177. RETURN_FALSE;
  1178. }
  1179. p = BG(strtok_last); /* Where we start to search */
  1180. pe = ZSTR_VAL(BG(strtok_string)) + BG(strtok_len);
  1181. if (p >= pe) {
  1182. /* Reached the end of the string. */
  1183. RETURN_FALSE;
  1184. }
  1185. token = ZSTR_VAL(tok);
  1186. token_end = token + ZSTR_LEN(tok);
  1187. while (token < token_end) {
  1188. STRTOK_TABLE(token++) = 1;
  1189. }
  1190. /* Skip leading delimiters */
  1191. while (STRTOK_TABLE(p)) {
  1192. if (++p >= pe) {
  1193. /* no other chars left */
  1194. goto return_false;
  1195. }
  1196. skipped++;
  1197. }
  1198. /* We know at this place that *p is no delimiter, so skip it */
  1199. while (++p < pe) {
  1200. if (STRTOK_TABLE(p)) {
  1201. goto return_token;
  1202. }
  1203. }
  1204. if (p - BG(strtok_last)) {
  1205. return_token:
  1206. RETVAL_STRINGL(BG(strtok_last) + skipped, (p - BG(strtok_last)) - skipped);
  1207. BG(strtok_last) = p + 1;
  1208. } else {
  1209. return_false:
  1210. RETVAL_FALSE;
  1211. zend_string_release(BG(strtok_string));
  1212. BG(strtok_string) = NULL;
  1213. }
  1214. /* Restore table -- usually faster then memset'ing the table on every invocation */
  1215. token = ZSTR_VAL(tok);
  1216. while (token < token_end) {
  1217. STRTOK_TABLE(token++) = 0;
  1218. }
  1219. }
  1220. /* }}} */
  1221. /* {{{ php_strtoupper */
  1222. PHPAPI char *php_strtoupper(char *s, size_t len)
  1223. {
  1224. unsigned char *c;
  1225. const unsigned char *e;
  1226. c = (unsigned char *)s;
  1227. e = (unsigned char *)c+len;
  1228. while (c < e) {
  1229. *c = toupper(*c);
  1230. c++;
  1231. }
  1232. return s;
  1233. }
  1234. /* }}} */
  1235. /* {{{ php_string_toupper */
  1236. PHPAPI zend_string *php_string_toupper(zend_string *s)
  1237. {
  1238. unsigned char *c;
  1239. const unsigned char *e;
  1240. if (EXPECTED(!BG(ctype_string))) {
  1241. return zend_string_toupper(s);
  1242. }
  1243. c = (unsigned char *)ZSTR_VAL(s);
  1244. e = c + ZSTR_LEN(s);
  1245. while (c < e) {
  1246. if (islower(*c)) {
  1247. unsigned char *r;
  1248. zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
  1249. if (c != (unsigned char*)ZSTR_VAL(s)) {
  1250. memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
  1251. }
  1252. r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
  1253. while (c < e) {
  1254. *r = toupper(*c);
  1255. r++;
  1256. c++;
  1257. }
  1258. *r = '\0';
  1259. return res;
  1260. }
  1261. c++;
  1262. }
  1263. return zend_string_copy(s);
  1264. }
  1265. /* }}} */
  1266. /* {{{ Makes a string uppercase */
  1267. PHP_FUNCTION(strtoupper)
  1268. {
  1269. zend_string *arg;
  1270. ZEND_PARSE_PARAMETERS_START(1, 1)
  1271. Z_PARAM_STR(arg)
  1272. ZEND_PARSE_PARAMETERS_END();
  1273. RETURN_STR(php_string_toupper(arg));
  1274. }
  1275. /* }}} */
  1276. /* {{{ php_strtolower */
  1277. PHPAPI char *php_strtolower(char *s, size_t len)
  1278. {
  1279. unsigned char *c;
  1280. const unsigned char *e;
  1281. c = (unsigned char *)s;
  1282. e = c+len;
  1283. while (c < e) {
  1284. *c = tolower(*c);
  1285. c++;
  1286. }
  1287. return s;
  1288. }
  1289. /* }}} */
  1290. /* {{{ php_string_tolower */
  1291. PHPAPI zend_string *php_string_tolower(zend_string *s)
  1292. {
  1293. if (EXPECTED(!BG(ctype_string))) {
  1294. return zend_string_tolower(s);
  1295. }
  1296. unsigned char *c = (unsigned char *)ZSTR_VAL(s);
  1297. const unsigned char *e = c + ZSTR_LEN(s);
  1298. while (c < e) {
  1299. if (isupper(*c)) {
  1300. unsigned char *r;
  1301. zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0);
  1302. if (c != (unsigned char*)ZSTR_VAL(s)) {
  1303. memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s));
  1304. }
  1305. r = c + (ZSTR_VAL(res) - ZSTR_VAL(s));
  1306. while (c < e) {
  1307. *r = tolower(*c);
  1308. r++;
  1309. c++;
  1310. }
  1311. *r = '\0';
  1312. return res;
  1313. }
  1314. c++;
  1315. }
  1316. return zend_string_copy(s);
  1317. }
  1318. /* }}} */
  1319. /* {{{ Makes a string lowercase */
  1320. PHP_FUNCTION(strtolower)
  1321. {
  1322. zend_string *str;
  1323. ZEND_PARSE_PARAMETERS_START(1, 1)
  1324. Z_PARAM_STR(str)
  1325. ZEND_PARSE_PARAMETERS_END();
  1326. RETURN_STR(php_string_tolower(str));
  1327. }
  1328. /* }}} */
  1329. #if defined(PHP_WIN32)
  1330. static bool _is_basename_start(const char *start, const char *pos)
  1331. {
  1332. if (pos - start >= 1
  1333. && *(pos-1) != '/'
  1334. && *(pos-1) != '\\') {
  1335. if (pos - start == 1) {
  1336. return 1;
  1337. } else if (*(pos-2) == '/' || *(pos-2) == '\\') {
  1338. return 1;
  1339. } else if (*(pos-2) == ':'
  1340. && _is_basename_start(start, pos - 2)) {
  1341. return 1;
  1342. }
  1343. }
  1344. return 0;
  1345. }
  1346. #endif
  1347. /* {{{ php_basename */
  1348. PHPAPI zend_string *php_basename(const char *s, size_t len, const char *suffix, size_t suffix_len)
  1349. {
  1350. const char *basename_start;
  1351. const char *basename_end;
  1352. if (CG(ascii_compatible_locale)) {
  1353. basename_end = s + len - 1;
  1354. /* Strip trailing slashes */
  1355. while (basename_end >= s
  1356. #if defined(PHP_WIN32)
  1357. && (*basename_end == '/'
  1358. || *basename_end == '\\'
  1359. || (*basename_end == ':'
  1360. && _is_basename_start(s, basename_end)))) {
  1361. #else
  1362. && *basename_end == '/') {
  1363. #endif
  1364. basename_end--;
  1365. }
  1366. if (basename_end < s) {
  1367. return ZSTR_EMPTY_ALLOC();
  1368. }
  1369. /* Extract filename */
  1370. basename_start = basename_end;
  1371. basename_end++;
  1372. while (basename_start > s
  1373. #if defined(PHP_WIN32)
  1374. && *(basename_start-1) != '/'
  1375. && *(basename_start-1) != '\\') {
  1376. if (*(basename_start-1) == ':' &&
  1377. _is_basename_start(s, basename_start - 1)) {
  1378. break;
  1379. }
  1380. #else
  1381. && *(basename_start-1) != '/') {
  1382. #endif
  1383. basename_start--;
  1384. }
  1385. } else {
  1386. /* State 0 is directly after a directory separator (or at the start of the string).
  1387. * State 1 is everything else. */
  1388. int state = 0;
  1389. basename_start = s;
  1390. basename_end = s;
  1391. while (len > 0) {
  1392. int inc_len = (*s == '\0' ? 1 : php_mblen(s, len));
  1393. switch (inc_len) {
  1394. case 0:
  1395. goto quit_loop;
  1396. case 1:
  1397. #if defined(PHP_WIN32)
  1398. if (*s == '/' || *s == '\\') {
  1399. #else
  1400. if (*s == '/') {
  1401. #endif
  1402. if (state == 1) {
  1403. state = 0;
  1404. basename_end = s;
  1405. }
  1406. #if defined(PHP_WIN32)
  1407. /* Catch relative paths in c:file.txt style. They're not to confuse
  1408. with the NTFS streams. This part ensures also, that no drive
  1409. letter traversing happens. */
  1410. } else if ((*s == ':' && (s - basename_start == 1))) {
  1411. if (state == 0) {
  1412. basename_start = s;
  1413. state = 1;
  1414. } else {
  1415. basename_end = s;
  1416. state = 0;
  1417. }
  1418. #endif
  1419. } else {
  1420. if (state == 0) {
  1421. basename_start = s;
  1422. state = 1;
  1423. }
  1424. }
  1425. break;
  1426. default:
  1427. if (inc_len < 0) {
  1428. /* If character is invalid, treat it like other non-significant characters. */
  1429. inc_len = 1;
  1430. php_mb_reset();
  1431. }
  1432. if (state == 0) {
  1433. basename_start = s;
  1434. state = 1;
  1435. }
  1436. break;
  1437. }
  1438. s += inc_len;
  1439. len -= inc_len;
  1440. }
  1441. quit_loop:
  1442. if (state == 1) {
  1443. basename_end = s;
  1444. }
  1445. }
  1446. if (suffix != NULL && suffix_len < (size_t)(basename_end - basename_start) &&
  1447. memcmp(basename_end - suffix_len, suffix, suffix_len) == 0) {
  1448. basename_end -= suffix_len;
  1449. }
  1450. return zend_string_init(basename_start, basename_end - basename_start, 0);
  1451. }
  1452. /* }}} */
  1453. /* {{{ Returns the filename component of the path */
  1454. PHP_FUNCTION(basename)
  1455. {
  1456. char *string, *suffix = NULL;
  1457. size_t string_len, suffix_len = 0;
  1458. ZEND_PARSE_PARAMETERS_START(1, 2)
  1459. Z_PARAM_STRING(string, string_len)
  1460. Z_PARAM_OPTIONAL
  1461. Z_PARAM_STRING(suffix, suffix_len)
  1462. ZEND_PARSE_PARAMETERS_END();
  1463. RETURN_STR(php_basename(string, string_len, suffix, suffix_len));
  1464. }
  1465. /* }}} */
  1466. /* {{{ php_dirname
  1467. Returns directory name component of path */
  1468. PHPAPI size_t php_dirname(char *path, size_t len)
  1469. {
  1470. return zend_dirname(path, len);
  1471. }
  1472. /* }}} */
  1473. /* {{{ Returns the directory name component of the path */
  1474. PHP_FUNCTION(dirname)
  1475. {
  1476. char *str;
  1477. size_t str_len;
  1478. zend_string *ret;
  1479. zend_long levels = 1;
  1480. ZEND_PARSE_PARAMETERS_START(1, 2)
  1481. Z_PARAM_STRING(str, str_len)
  1482. Z_PARAM_OPTIONAL
  1483. Z_PARAM_LONG(levels)
  1484. ZEND_PARSE_PARAMETERS_END();
  1485. ret = zend_string_init(str, str_len, 0);
  1486. if (levels == 1) {
  1487. /* Default case */
  1488. #ifdef PHP_WIN32
  1489. ZSTR_LEN(ret) = php_win32_ioutil_dirname(ZSTR_VAL(ret), str_len);
  1490. #else
  1491. ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len);
  1492. #endif
  1493. } else if (levels < 1) {
  1494. zend_argument_value_error(2, "must be greater than or equal to 1");
  1495. zend_string_efree(ret);
  1496. RETURN_THROWS();
  1497. } else {
  1498. /* Some levels up */
  1499. do {
  1500. #ifdef PHP_WIN32
  1501. ZSTR_LEN(ret) = php_win32_ioutil_dirname(ZSTR_VAL(ret), str_len = ZSTR_LEN(ret));
  1502. #else
  1503. ZSTR_LEN(ret) = zend_dirname(ZSTR_VAL(ret), str_len = ZSTR_LEN(ret));
  1504. #endif
  1505. } while (ZSTR_LEN(ret) < str_len && --levels);
  1506. }
  1507. RETURN_NEW_STR(ret);
  1508. }
  1509. /* }}} */
  1510. /* {{{ Returns information about a certain string */
  1511. PHP_FUNCTION(pathinfo)
  1512. {
  1513. zval tmp;
  1514. char *path, *dirname;
  1515. size_t path_len;
  1516. int have_basename;
  1517. zend_long opt = PHP_PATHINFO_ALL;
  1518. zend_string *ret = NULL;
  1519. ZEND_PARSE_PARAMETERS_START(1, 2)
  1520. Z_PARAM_STRING(path, path_len)
  1521. Z_PARAM_OPTIONAL
  1522. Z_PARAM_LONG(opt)
  1523. ZEND_PARSE_PARAMETERS_END();
  1524. have_basename = ((opt & PHP_PATHINFO_BASENAME) == PHP_PATHINFO_BASENAME);
  1525. array_init(&tmp);
  1526. if ((opt & PHP_PATHINFO_DIRNAME) == PHP_PATHINFO_DIRNAME) {
  1527. dirname = estrndup(path, path_len);
  1528. php_dirname(dirname, path_len);
  1529. if (*dirname) {
  1530. add_assoc_string(&tmp, "dirname", dirname);
  1531. }
  1532. efree(dirname);
  1533. }
  1534. if (have_basename) {
  1535. ret = php_basename(path, path_len, NULL, 0);
  1536. add_assoc_str(&tmp, "basename", zend_string_copy(ret));
  1537. }
  1538. if ((opt & PHP_PATHINFO_EXTENSION) == PHP_PATHINFO_EXTENSION) {
  1539. const char *p;
  1540. ptrdiff_t idx;
  1541. if (!have_basename) {
  1542. ret = php_basename(path, path_len, NULL, 0);
  1543. }
  1544. p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
  1545. if (p) {
  1546. idx = p - ZSTR_VAL(ret);
  1547. add_assoc_stringl(&tmp, "extension", ZSTR_VAL(ret) + idx + 1, ZSTR_LEN(ret) - idx - 1);
  1548. }
  1549. }
  1550. if ((opt & PHP_PATHINFO_FILENAME) == PHP_PATHINFO_FILENAME) {
  1551. const char *p;
  1552. ptrdiff_t idx;
  1553. /* Have we already looked up the basename? */
  1554. if (!have_basename && !ret) {
  1555. ret = php_basename(path, path_len, NULL, 0);
  1556. }
  1557. p = zend_memrchr(ZSTR_VAL(ret), '.', ZSTR_LEN(ret));
  1558. idx = p ? (p - ZSTR_VAL(ret)) : (ptrdiff_t)ZSTR_LEN(ret);
  1559. add_assoc_stringl(&tmp, "filename", ZSTR_VAL(ret), idx);
  1560. }
  1561. if (ret) {
  1562. zend_string_release_ex(ret, 0);
  1563. }
  1564. if (opt == PHP_PATHINFO_ALL) {
  1565. RETURN_COPY_VALUE(&tmp);
  1566. } else {
  1567. zval *element;
  1568. if ((element = zend_hash_get_current_data(Z_ARRVAL(tmp))) != NULL) {
  1569. RETVAL_COPY_DEREF(element);
  1570. } else {
  1571. RETVAL_EMPTY_STRING();
  1572. }
  1573. zval_ptr_dtor(&tmp);
  1574. }
  1575. }
  1576. /* }}} */
  1577. /* {{{ php_stristr
  1578. case insensitive strstr */
  1579. PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
  1580. {
  1581. php_strtolower(s, s_len);
  1582. php_strtolower(t, t_len);
  1583. return (char*)php_memnstr(s, t, t_len, s + s_len);
  1584. }
  1585. /* }}} */
  1586. /* {{{ php_strspn */
  1587. PHPAPI size_t php_strspn(const char *s1, const char *s2, const char *s1_end, const char *s2_end)
  1588. {
  1589. const char *p = s1, *spanp;
  1590. char c = *p;
  1591. cont:
  1592. for (spanp = s2; p != s1_end && spanp != s2_end;) {
  1593. if (*spanp++ == c) {
  1594. c = *(++p);
  1595. goto cont;
  1596. }
  1597. }
  1598. return (p - s1);
  1599. }
  1600. /* }}} */
  1601. /* {{{ php_strcspn */
  1602. PHPAPI size_t php_strcspn(const char *s1, const char *s2, const char *s1_end, const char *s2_end)
  1603. {
  1604. const char *p, *spanp;
  1605. char c = *s1;
  1606. for (p = s1;;) {
  1607. spanp = s2;
  1608. do {
  1609. if (*spanp == c || p == s1_end) {
  1610. return p - s1;
  1611. }
  1612. } while (spanp++ < (s2_end - 1));
  1613. c = *++p;
  1614. }
  1615. /* NOTREACHED */
  1616. }
  1617. /* }}} */
  1618. /* {{{ Finds first occurrence of a string within another, case insensitive */
  1619. PHP_FUNCTION(stristr)
  1620. {
  1621. zend_string *haystack, *needle;
  1622. const char *found = NULL;
  1623. size_t found_offset;
  1624. char *haystack_dup;
  1625. char *orig_needle;
  1626. bool part = 0;
  1627. ZEND_PARSE_PARAMETERS_START(2, 3)
  1628. Z_PARAM_STR(haystack)
  1629. Z_PARAM_STR(needle)
  1630. Z_PARAM_OPTIONAL
  1631. Z_PARAM_BOOL(part)
  1632. ZEND_PARSE_PARAMETERS_END();
  1633. haystack_dup = estrndup(ZSTR_VAL(haystack), ZSTR_LEN(haystack));
  1634. orig_needle = estrndup(ZSTR_VAL(needle), ZSTR_LEN(needle));
  1635. found = php_stristr(haystack_dup, orig_needle, ZSTR_LEN(haystack), ZSTR_LEN(needle));
  1636. efree(orig_needle);
  1637. if (found) {
  1638. found_offset = found - haystack_dup;
  1639. if (part) {
  1640. RETVAL_STRINGL(ZSTR_VAL(haystack), found_offset);
  1641. } else {
  1642. RETVAL_STRINGL(ZSTR_VAL(haystack) + found_offset, ZSTR_LEN(haystack) - found_offset);
  1643. }
  1644. } else {
  1645. RETVAL_FALSE;
  1646. }
  1647. efree(haystack_dup);
  1648. }
  1649. /* }}} */
  1650. /* {{{ Finds first occurrence of a string within another */
  1651. PHP_FUNCTION(strstr)
  1652. {
  1653. zend_string *haystack, *needle;
  1654. const char *found = NULL;
  1655. zend_long found_offset;
  1656. bool part = 0;
  1657. ZEND_PARSE_PARAMETERS_START(2, 3)
  1658. Z_PARAM_STR(haystack)
  1659. Z_PARAM_STR(needle)
  1660. Z_PARAM_OPTIONAL
  1661. Z_PARAM_BOOL(part)
  1662. ZEND_PARSE_PARAMETERS_END();
  1663. found = php_memnstr(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle), ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
  1664. if (found) {
  1665. found_offset = found - ZSTR_VAL(haystack);
  1666. if (part) {
  1667. RETURN_STRINGL(ZSTR_VAL(haystack), found_offset);
  1668. } else {
  1669. RETURN_STRINGL(found, ZSTR_LEN(haystack) - found_offset);
  1670. }
  1671. }
  1672. RETURN_FALSE;
  1673. }
  1674. /* }}} */
  1675. /* {{{ Checks if a string contains another */
  1676. PHP_FUNCTION(str_contains)
  1677. {
  1678. zend_string *haystack, *needle;
  1679. ZEND_PARSE_PARAMETERS_START(2, 2)
  1680. Z_PARAM_STR(haystack)
  1681. Z_PARAM_STR(needle)
  1682. ZEND_PARSE_PARAMETERS_END();
  1683. RETURN_BOOL(php_memnstr(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle), ZSTR_VAL(haystack) + ZSTR_LEN(haystack)));
  1684. }
  1685. /* }}} */
  1686. /* {{{ Checks if haystack starts with needle */
  1687. PHP_FUNCTION(str_starts_with)
  1688. {
  1689. zend_string *haystack, *needle;
  1690. ZEND_PARSE_PARAMETERS_START(2, 2)
  1691. Z_PARAM_STR(haystack)
  1692. Z_PARAM_STR(needle)
  1693. ZEND_PARSE_PARAMETERS_END();
  1694. if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
  1695. RETURN_FALSE;
  1696. }
  1697. RETURN_BOOL(memcmp(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
  1698. }
  1699. /* }}} */
  1700. /* {{{ Checks if haystack ends with needle */
  1701. PHP_FUNCTION(str_ends_with)
  1702. {
  1703. zend_string *haystack, *needle;
  1704. ZEND_PARSE_PARAMETERS_START(2, 2)
  1705. Z_PARAM_STR(haystack)
  1706. Z_PARAM_STR(needle)
  1707. ZEND_PARSE_PARAMETERS_END();
  1708. if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
  1709. RETURN_FALSE;
  1710. }
  1711. RETURN_BOOL(memcmp(
  1712. ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - ZSTR_LEN(needle),
  1713. ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
  1714. }
  1715. /* }}} */
  1716. /* {{{ An alias for strstr */
  1717. /* }}} */
  1718. /* {{{ Finds position of first occurrence of a string within another */
  1719. PHP_FUNCTION(strpos)
  1720. {
  1721. zend_string *haystack, *needle;
  1722. const char *found = NULL;
  1723. zend_long offset = 0;
  1724. ZEND_PARSE_PARAMETERS_START(2, 3)
  1725. Z_PARAM_STR(haystack)
  1726. Z_PARAM_STR(needle)
  1727. Z_PARAM_OPTIONAL
  1728. Z_PARAM_LONG(offset)
  1729. ZEND_PARSE_PARAMETERS_END();
  1730. if (offset < 0) {
  1731. offset += (zend_long)ZSTR_LEN(haystack);
  1732. }
  1733. if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
  1734. zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
  1735. RETURN_THROWS();
  1736. }
  1737. found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
  1738. ZSTR_VAL(needle), ZSTR_LEN(needle),
  1739. ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
  1740. if (found) {
  1741. RETURN_LONG(found - ZSTR_VAL(haystack));
  1742. } else {
  1743. RETURN_FALSE;
  1744. }
  1745. }
  1746. /* }}} */
  1747. /* {{{ Finds position of first occurrence of a string within another, case insensitive */
  1748. PHP_FUNCTION(stripos)
  1749. {
  1750. const char *found = NULL;
  1751. zend_string *haystack, *needle;
  1752. zend_long offset = 0;
  1753. zend_string *needle_dup = NULL, *haystack_dup;
  1754. ZEND_PARSE_PARAMETERS_START(2, 3)
  1755. Z_PARAM_STR(haystack)
  1756. Z_PARAM_STR(needle)
  1757. Z_PARAM_OPTIONAL
  1758. Z_PARAM_LONG(offset)
  1759. ZEND_PARSE_PARAMETERS_END();
  1760. if (offset < 0) {
  1761. offset += (zend_long)ZSTR_LEN(haystack);
  1762. }
  1763. if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
  1764. zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
  1765. RETURN_THROWS();
  1766. }
  1767. if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
  1768. RETURN_FALSE;
  1769. }
  1770. haystack_dup = php_string_tolower(haystack);
  1771. needle_dup = php_string_tolower(needle);
  1772. found = (char*)php_memnstr(ZSTR_VAL(haystack_dup) + offset,
  1773. ZSTR_VAL(needle_dup), ZSTR_LEN(needle_dup), ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack));
  1774. if (found) {
  1775. RETVAL_LONG(found - ZSTR_VAL(haystack_dup));
  1776. } else {
  1777. RETVAL_FALSE;
  1778. }
  1779. zend_string_release_ex(haystack_dup, 0);
  1780. zend_string_release_ex(needle_dup, 0);
  1781. }
  1782. /* }}} */
  1783. /* {{{ Finds position of last occurrence of a string within another string */
  1784. PHP_FUNCTION(strrpos)
  1785. {
  1786. zend_string *needle;
  1787. zend_string *haystack;
  1788. zend_long offset = 0;
  1789. const char *p, *e, *found;
  1790. ZEND_PARSE_PARAMETERS_START(2, 3)
  1791. Z_PARAM_STR(haystack)
  1792. Z_PARAM_STR(needle)
  1793. Z_PARAM_OPTIONAL
  1794. Z_PARAM_LONG(offset)
  1795. ZEND_PARSE_PARAMETERS_END();
  1796. if (offset >= 0) {
  1797. if ((size_t)offset > ZSTR_LEN(haystack)) {
  1798. zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
  1799. RETURN_THROWS();
  1800. }
  1801. p = ZSTR_VAL(haystack) + (size_t)offset;
  1802. e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
  1803. } else {
  1804. if (offset < -ZEND_LONG_MAX || (size_t)(-offset) > ZSTR_LEN(haystack)) {
  1805. zend_argument_value_error(3, "must be contained in argument #1 ($haystack)");
  1806. RETURN_THROWS();
  1807. }
  1808. p = ZSTR_VAL(haystack);
  1809. if ((size_t)-offset < ZSTR_LEN(needle)) {
  1810. e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);
  1811. } else {
  1812. e = ZSTR_VAL(haystack) + ZSTR_LEN(haystack) + offset + ZSTR_LEN(needle);
  1813. }
  1814. }
  1815. if ((found = zend_memnrstr(p, ZSTR_VAL(needle), ZSTR_LEN(needle), e))) {
  1816. RETURN_LONG(found - ZSTR_VAL(haystack));

Large files files are truncated, but you can click here to view the full file