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.

2878 lines
65 KiB

27 years ago
27 years ago
27 years ago
27 years ago
28 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
26 years ago
27 years ago
27 years ago
26 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
26 years ago
26 years ago
26 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
27 years ago
26 years ago
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP version 4.0 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997, 1998, 1999, 2000 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.02 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://www.php.net/license/2_02.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@fast.no> |
  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_string.h"
  26. #include "php_variables.h"
  27. #ifdef HAVE_LOCALE_H
  28. # include <locale.h>
  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. #define STR_PAD_LEFT 0
  36. #define STR_PAD_RIGHT 1
  37. #define STR_PAD_BOTH 2
  38. void register_string_constants(INIT_FUNC_ARGS)
  39. {
  40. REGISTER_LONG_CONSTANT("STR_PAD_LEFT", STR_PAD_LEFT, CONST_PERSISTENT|CONST_CS);
  41. REGISTER_LONG_CONSTANT("STR_PAD_RIGHT", STR_PAD_RIGHT, CONST_PERSISTENT|CONST_CS);
  42. REGISTER_LONG_CONSTANT("STR_PAD_BOTH", STR_PAD_BOTH, CONST_PERSISTENT|CONST_CS);
  43. }
  44. int php_tag_find(char *tag, int len, char *set);
  45. /* this is read-only, so it's ok */
  46. static char hexconvtab[] = "0123456789abcdef";
  47. static char *php_bin2hex(const unsigned char *old, const size_t oldlen, size_t *newlen)
  48. {
  49. unsigned char *result = NULL;
  50. size_t i, j;
  51. result = (char *) emalloc(oldlen * 2 * sizeof(char));
  52. if(!result) {
  53. return result;
  54. }
  55. for(i = j = 0; i < oldlen; i++) {
  56. result[j++] = hexconvtab[old[i] >> 4];
  57. result[j++] = hexconvtab[old[i] & 15];
  58. }
  59. if(newlen) *newlen = oldlen * 2 * sizeof(char);
  60. return result;
  61. }
  62. /* {{{ proto string bin2hex(string data)
  63. Converts the binary representation of data to hex */
  64. PHP_FUNCTION(bin2hex)
  65. {
  66. zval **data;
  67. char *result;
  68. size_t newlen;
  69. if(ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &data) == FAILURE) {
  70. WRONG_PARAM_COUNT;
  71. }
  72. convert_to_string_ex(data);
  73. result = php_bin2hex((*data)->value.str.val, (*data)->value.str.len, &newlen);
  74. if(!result) {
  75. RETURN_FALSE;
  76. }
  77. RETURN_STRINGL(result, newlen, 0);
  78. }
  79. /* }}} */
  80. /* {{{ proto int strspn(string str, string mask)
  81. Find length of initial segment consisting entirely of characters found in mask */
  82. PHP_FUNCTION(strspn)
  83. {
  84. zval **s1,**s2;
  85. if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
  86. WRONG_PARAM_COUNT;
  87. }
  88. convert_to_string_ex(s1);
  89. convert_to_string_ex(s2);
  90. RETURN_LONG(php_strspn((*s1)->value.str.val, (*s2)->value.str.val,
  91. (*s1)->value.str.val + (*s1)->value.str.len,
  92. (*s2)->value.str.val + (*s2)->value.str.len));
  93. }
  94. /* }}} */
  95. /* {{{ proto int strcspn(string str, string mask)
  96. Find length of initial segment consisting entirely of characters not found in mask */
  97. PHP_FUNCTION(strcspn)
  98. {
  99. zval **s1,**s2;
  100. if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
  101. WRONG_PARAM_COUNT;
  102. }
  103. convert_to_string_ex(s1);
  104. convert_to_string_ex(s2);
  105. RETURN_LONG(php_strcspn((*s1)->value.str.val, (*s2)->value.str.val,
  106. (*s1)->value.str.val + (*s1)->value.str.len,
  107. (*s2)->value.str.val + (*s2)->value.str.len));
  108. }
  109. /* }}} */
  110. PHPAPI void php_trim(zval *str, zval * return_value, int mode)
  111. /* mode 1 : trim left
  112. mode 2 : trim right
  113. mode 3 : trim left and right
  114. */
  115. {
  116. register int i;
  117. int len = str->value.str.len;
  118. int trimmed = 0;
  119. char *c = str->value.str.val;
  120. if (mode & 1) {
  121. for (i = 0; i < len; i++) {
  122. if (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' ||
  123. c[i] == '\t' || c[i] == '\v' || c[i] == '\0') {
  124. trimmed++;
  125. } else {
  126. break;
  127. }
  128. }
  129. len -= trimmed;
  130. c += trimmed;
  131. }
  132. if (mode & 2) {
  133. for (i = len - 1; i >= 0; i--) {
  134. if (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' ||
  135. c[i] == '\t' || c[i] == '\v' || c[i] == '\0') {
  136. len--;
  137. } else {
  138. break;
  139. }
  140. }
  141. }
  142. RETVAL_STRINGL(c, len, 1);
  143. }
  144. /* {{{ proto string rtrim(string str)
  145. An alias for chop */
  146. /* }}} */
  147. /* {{{ proto string chop(string str)
  148. Remove trailing whitespace */
  149. PHP_FUNCTION(chop)
  150. {
  151. zval **str;
  152. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  153. WRONG_PARAM_COUNT;
  154. }
  155. convert_to_string_ex(str);
  156. if ((*str)->type == IS_STRING) {
  157. php_trim(*str, return_value, 2);
  158. return;
  159. }
  160. RETURN_FALSE;
  161. }
  162. /* }}} */
  163. /* {{{ proto string trim(string str)
  164. Strip whitespace from the beginning and end of a string */
  165. PHP_FUNCTION(trim)
  166. {
  167. zval **str;
  168. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  169. WRONG_PARAM_COUNT;
  170. }
  171. convert_to_string_ex(str);
  172. if ((*str)->type == IS_STRING) {
  173. php_trim(*str, return_value, 3);
  174. return;
  175. }
  176. RETURN_FALSE;
  177. }
  178. /* }}} */
  179. /* {{{ proto string ltrim(string str)
  180. Strip whitespace from the beginning of a string */
  181. PHP_FUNCTION(ltrim)
  182. {
  183. zval **str;
  184. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  185. WRONG_PARAM_COUNT;
  186. }
  187. convert_to_string_ex(str);
  188. if ((*str)->type == IS_STRING) {
  189. php_trim(*str, return_value, 1);
  190. return;
  191. }
  192. RETURN_FALSE;
  193. }
  194. /* }}} */
  195. /* {{{ proto string wordwrap(string str[, int width[, string break]])
  196. * wrap buffer to selected number of characters using string break char */
  197. PHP_FUNCTION(wordwrap)
  198. {
  199. pval **ptext, **plinelength, **pbreakchar;
  200. long i=0, l=0, pgr=0, linelength=0, last=0, breakcharlen;
  201. char *text, *breakchar, *newtext;
  202. if (ZEND_NUM_ARGS() < 1 || ZEND_NUM_ARGS() > 3 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &ptext, &plinelength, &pbreakchar) == FAILURE) {
  203. WRONG_PARAM_COUNT;
  204. }
  205. convert_to_string_ex(ptext);
  206. text = (*ptext)->value.str.val;
  207. if (ZEND_NUM_ARGS() > 1) {
  208. convert_to_long_ex(plinelength);
  209. linelength = (*plinelength)->value.lval;
  210. }
  211. else {
  212. linelength = 75;
  213. }
  214. if (ZEND_NUM_ARGS() > 2) {
  215. convert_to_string_ex(pbreakchar);
  216. breakchar = (*pbreakchar)->value.str.val;
  217. breakcharlen = (*pbreakchar)->value.str.len;
  218. }
  219. else {
  220. breakchar = "\n";
  221. breakcharlen = 1;
  222. }
  223. /* Special case for a single-character break as it needs no
  224. additional storage space */
  225. if (breakcharlen == 1) {
  226. while (text[i] != '\0') {
  227. /* prescan line to see if it is greater than linelength */
  228. l = 0;
  229. while (text[i+l] != breakchar[0]) {
  230. if (text[i+l] == '\0') {
  231. l --;
  232. break;
  233. }
  234. l++;
  235. }
  236. if (l > linelength) {
  237. pgr = l;
  238. l = linelength;
  239. /* needs breaking; work backwards to find previous word */
  240. while (l >= 0) {
  241. if (text[i+l] == ' ') {
  242. text[i+l] = breakchar[0];
  243. break;
  244. }
  245. l --;
  246. }
  247. if (l == -1) {
  248. /* couldn't break is backwards, try looking forwards */
  249. l = linelength;
  250. while (l <= pgr) {
  251. if(text[i+l] == ' ') {
  252. text[i+l] = breakchar[0];
  253. break;
  254. }
  255. l ++;
  256. }
  257. }
  258. }
  259. i += l+1;
  260. }
  261. RETVAL_STRINGL(text, strlen(text), 1);
  262. }
  263. else {
  264. /* Multiple character line break */
  265. newtext = emalloc((*ptext)->value.str.len * (breakcharlen+1));
  266. newtext[0] = '\0';
  267. i = 0;
  268. while (text[i] != '\0') {
  269. /* prescan line to see if it is greater than linelength */
  270. l = 0;
  271. while (text[i+l] != '\0') {
  272. if (text[i+l] == breakchar[0]) {
  273. if (breakcharlen == 1 || strncmp(text+i+l, breakchar, breakcharlen)==0)
  274. break;
  275. }
  276. l ++;
  277. }
  278. if (l > linelength) {
  279. pgr = l;
  280. l = linelength;
  281. /* needs breaking; work backwards to find previous word */
  282. while (l >= 0) {
  283. if (text[i+l] == ' ') {
  284. strncat(newtext, text+last, i+l-last);
  285. strcat(newtext, breakchar);
  286. last = i + l + 1;
  287. break;
  288. }
  289. l --;
  290. }
  291. if (l == -1) {
  292. /* couldn't break it backwards, try looking forwards */
  293. l = linelength;
  294. while (l <= pgr) {
  295. if (text[i+l] == ' ') {
  296. strncat(newtext, text+last, i+l-last);
  297. strcat(newtext, breakchar);
  298. last = i + l + 1;
  299. break;
  300. }
  301. l ++;
  302. }
  303. }
  304. i += l+1;
  305. }
  306. else {
  307. i += (l ? l : 1);
  308. }
  309. }
  310. if (i+l > last) {
  311. strcat(newtext, text+last);
  312. }
  313. RETVAL_STRINGL(newtext, strlen(newtext), 1);
  314. efree(newtext);
  315. }
  316. }
  317. /* }}} */
  318. PHPAPI void php_explode(zval *delim, zval *str, zval *return_value, int limit)
  319. {
  320. char *p1, *p2, *endp;
  321. endp = str->value.str.val + str->value.str.len;
  322. p1 = str->value.str.val;
  323. p2 = php_memnstr(str->value.str.val, delim->value.str.val, delim->value.str.len, endp);
  324. if (p2 == NULL) {
  325. add_next_index_stringl(return_value, p1, str->value.str.len, 1);
  326. } else {
  327. do {
  328. add_next_index_stringl(return_value, p1, p2-p1, 1);
  329. p1 = p2 + delim->value.str.len;
  330. } while ((p2 = php_memnstr(p1, delim->value.str.val, delim->value.str.len, endp)) != NULL &&
  331. (limit == -1 || --limit > 1));
  332. if (p1 <= endp)
  333. add_next_index_stringl(return_value, p1, endp-p1, 1);
  334. }
  335. }
  336. /* {{{ proto array explode(string separator, string str [, int limit])
  337. Split a string on string separator and return array of components */
  338. PHP_FUNCTION(explode)
  339. {
  340. zval **str, **delim, **zlimit = NULL;
  341. int limit;
  342. switch (ZEND_NUM_ARGS()) {
  343. case 2:
  344. if (zend_get_parameters_ex(2, &delim, &str) == FAILURE)
  345. WRONG_PARAM_COUNT;
  346. limit=-1;
  347. break;
  348. case 3:
  349. if (zend_get_parameters_ex(3, &delim, &str, &zlimit) == FAILURE)
  350. WRONG_PARAM_COUNT;
  351. convert_to_long_ex(zlimit);
  352. limit = (*zlimit)->value.lval;
  353. break;
  354. default:
  355. WRONG_PARAM_COUNT;
  356. }
  357. convert_to_string_ex(str);
  358. convert_to_string_ex(delim);
  359. if (! (*delim)->value.str.len) {
  360. php_error(E_WARNING,"Empty delimiter");
  361. RETURN_FALSE;
  362. }
  363. if (array_init(return_value) == FAILURE) {
  364. RETURN_FALSE;
  365. }
  366. if(limit==0 || limit==1) {
  367. add_index_stringl(return_value, 0, (*str)->value.str.val, (*str)->value.str.len, 1);
  368. } else {
  369. php_explode(*delim, *str, return_value, limit);
  370. }
  371. }
  372. /* }}} */
  373. /* {{{ proto string join(array src, string glue)
  374. An alias for implode */
  375. /* }}} */
  376. PHPAPI void php_implode(zval *delim, zval *arr, zval *return_value)
  377. {
  378. zval **tmp;
  379. int len = 0, count = 0, target = 0;
  380. HashPosition pos;
  381. /* convert everything to strings, and calculate length */
  382. zend_hash_internal_pointer_reset_ex(arr->value.ht, &pos);
  383. while (zend_hash_get_current_data_ex(arr->value.ht, (void **) &tmp, &pos) == SUCCESS) {
  384. convert_to_string_ex(tmp);
  385. len += (*tmp)->value.str.len;
  386. if (count>0) {
  387. len += delim->value.str.len;
  388. }
  389. count++;
  390. zend_hash_move_forward_ex(arr->value.ht, &pos);
  391. }
  392. /* do it */
  393. return_value->value.str.val = (char *) emalloc(len + 1);
  394. return_value->value.str.val[0] = '\0';
  395. return_value->value.str.val[len] = '\0';
  396. zend_hash_internal_pointer_reset_ex(arr->value.ht, &pos);
  397. while (zend_hash_get_current_data_ex(arr->value.ht, (void **) &tmp, &pos) == SUCCESS) {
  398. count--;
  399. memcpy(return_value->value.str.val + target, (*tmp)->value.str.val,
  400. (*tmp)->value.str.len);
  401. target += (*tmp)->value.str.len;
  402. if (count > 0) {
  403. memcpy(return_value->value.str.val + target, delim->value.str.val,
  404. delim->value.str.len);
  405. target += delim->value.str.len;
  406. }
  407. zend_hash_move_forward_ex(arr->value.ht, &pos);
  408. }
  409. return_value->type = IS_STRING;
  410. return_value->value.str.len = len;
  411. }
  412. /* {{{ proto string implode(array src, string glue)
  413. Join array elements placing glue string between items and return one string */
  414. PHP_FUNCTION(implode)
  415. {
  416. zval **arg1, **arg2, *delim, *arr;
  417. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) {
  418. WRONG_PARAM_COUNT;
  419. }
  420. if ((*arg1)->type == IS_ARRAY && (*arg2)->type == IS_STRING) {
  421. SEPARATE_ZVAL(arg1);
  422. arr = *arg1;
  423. delim = *arg2;
  424. } else if ((*arg2)->type == IS_ARRAY) {
  425. SEPARATE_ZVAL(arg2)
  426. arr = *arg2;
  427. convert_to_string_ex(arg1);
  428. delim = *arg1;
  429. } else {
  430. php_error(E_WARNING, "Bad arguments to %s()",
  431. get_active_function_name());
  432. return;
  433. }
  434. php_implode(delim, arr, return_value);
  435. }
  436. /* }}} */
  437. /* {{{ proto string strtok([string str,] string token)
  438. Tokenize a string */
  439. PHP_FUNCTION(strtok)
  440. {
  441. zval **str, **tok;
  442. char *token = NULL, *tokp=NULL;
  443. char *first = NULL;
  444. int argc;
  445. BLS_FETCH();
  446. argc = ZEND_NUM_ARGS();
  447. if ((argc == 1 && zend_get_parameters_ex(1, &tok) == FAILURE) ||
  448. (argc == 2 && zend_get_parameters_ex(2, &str, &tok) == FAILURE) ||
  449. argc < 1 || argc > 2) {
  450. WRONG_PARAM_COUNT;
  451. }
  452. convert_to_string_ex(tok);
  453. tokp = token = (*tok)->value.str.val;
  454. if (argc == 2) {
  455. convert_to_string_ex(str);
  456. STR_FREE(BG(strtok_string));
  457. BG(strtok_string) = estrndup((*str)->value.str.val,(*str)->value.str.len);
  458. BG(strtok_pos1) = BG(strtok_string);
  459. BG(strtok_pos2) = NULL;
  460. }
  461. if (BG(strtok_pos1) && *BG(strtok_pos1)) {
  462. for ( /* NOP */ ; token && *token; token++) {
  463. BG(strtok_pos2) = strchr(BG(strtok_pos1), (int) *token);
  464. if (!first || (BG(strtok_pos2) && BG(strtok_pos2) < first)) {
  465. first = BG(strtok_pos2);
  466. }
  467. } /* NB: token is unusable now */
  468. BG(strtok_pos2) = first;
  469. if (BG(strtok_pos2)) {
  470. *BG(strtok_pos2) = '\0';
  471. }
  472. RETVAL_STRING(BG(strtok_pos1),1);
  473. #if 0
  474. /* skip 'token' white space for next call to strtok */
  475. while (BG(strtok_pos2) &&
  476. strchr(tokp, *(BG(strtok_pos2)+1))) {
  477. BG(strtok_pos2)++;
  478. }
  479. #endif
  480. if (BG(strtok_pos2))
  481. BG(strtok_pos1) = BG(strtok_pos2) + 1;
  482. else
  483. BG(strtok_pos1) = NULL;
  484. } else {
  485. RETVAL_FALSE;
  486. }
  487. }
  488. /* }}} */
  489. PHPAPI char *php_strtoupper(char *s, size_t len)
  490. {
  491. char *c;
  492. int ch;
  493. size_t i;
  494. c = s;
  495. for (i=0; i<len; i++) {
  496. ch = toupper((unsigned char)*c);
  497. *c++ = ch;
  498. }
  499. return (s);
  500. }
  501. /* {{{ proto string strtoupper(string str)
  502. Make a string uppercase */
  503. PHP_FUNCTION(strtoupper)
  504. {
  505. zval **arg;
  506. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg)) {
  507. WRONG_PARAM_COUNT;
  508. }
  509. convert_to_string_ex(arg);
  510. *return_value = **arg;
  511. zval_copy_ctor(return_value);
  512. php_strtoupper(return_value->value.str.val, return_value->value.str.len);
  513. }
  514. /* }}} */
  515. PHPAPI char *php_strtolower(char *s, size_t len)
  516. {
  517. register int ch;
  518. char *c;
  519. size_t i;
  520. c = s;
  521. for (i=0; i<len; i++) {
  522. ch = tolower((unsigned char)*c);
  523. *c++ = ch;
  524. }
  525. return (s);
  526. }
  527. /* {{{ proto string strtolower(string str)
  528. Make a string lowercase */
  529. PHP_FUNCTION(strtolower)
  530. {
  531. zval **str;
  532. char *ret;
  533. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str)) {
  534. WRONG_PARAM_COUNT;
  535. }
  536. convert_to_string_ex(str);
  537. *return_value = **str;
  538. zval_copy_ctor(return_value);
  539. ret = php_strtolower(return_value->value.str.val, return_value->value.str.len);
  540. }
  541. /* }}} */
  542. PHPAPI char *php_basename(char *s, size_t len)
  543. {
  544. char *ret=NULL, *c, *p=NULL, buf='\0';
  545. c = s + len - 1;
  546. /* strip trailing slashes */
  547. while (*c == '/'
  548. #ifdef PHP_WIN32
  549. || *c == '\\'
  550. #endif
  551. )
  552. c--;
  553. if(c < s+len-1) {
  554. buf = *(c + 1); /* Save overwritten char */
  555. *(c + 1) = '\0'; /* overwrite char */
  556. p = c + 1; /* Save pointer to overwritten char */
  557. }
  558. if ((c = strrchr(s, '/'))
  559. #ifdef PHP_WIN32
  560. || (c = strrchr(s, '\\'))
  561. #endif
  562. ) {
  563. ret = estrdup(c + 1);
  564. } else {
  565. ret = estrdup(s);
  566. }
  567. if(buf) *p = buf;
  568. return (ret);
  569. }
  570. /* {{{ proto string basename(string path)
  571. Return the filename component of the path */
  572. PHP_FUNCTION(basename)
  573. {
  574. zval **str;
  575. char *ret;
  576. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str)) {
  577. WRONG_PARAM_COUNT;
  578. }
  579. convert_to_string_ex(str);
  580. ret = php_basename((*str)->value.str.val,(*str)->value.str.len);
  581. RETVAL_STRING(ret,1)
  582. efree(ret);
  583. }
  584. /* }}} */
  585. PHPAPI void php_dirname(char *str, int len) {
  586. register char *c;
  587. c = str + len - 1;
  588. while (*c == '/'
  589. #ifdef PHP_WIN32
  590. || *c == '\\'
  591. #endif
  592. )
  593. c--; /* strip trailing slashes */
  594. *(c + 1) = '\0';
  595. if ((c = strrchr(str, '/'))
  596. #ifdef PHP_WIN32
  597. || (c = strrchr(str, '\\'))
  598. #endif
  599. )
  600. *c='\0';
  601. else
  602. *str='\0';
  603. }
  604. /* {{{ proto string dirname(string path)
  605. Return the directory name component of the path */
  606. PHP_FUNCTION(dirname)
  607. {
  608. zval **str;
  609. char *ret;
  610. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str)) {
  611. WRONG_PARAM_COUNT;
  612. }
  613. convert_to_string_ex(str);
  614. ret = estrdup((*str)->value.str.val);
  615. php_dirname(ret,(*str)->value.str.len);
  616. if(*ret) {
  617. RETVAL_STRING(ret,1);
  618. } else {
  619. RETVAL_FALSE;
  620. }
  621. efree(ret);
  622. }
  623. /* }}} */
  624. /* case insensitve strstr */
  625. PHPAPI char *php_stristr(unsigned char *s, unsigned char *t,
  626. size_t s_len, size_t t_len)
  627. {
  628. php_strtolower(s, s_len);
  629. php_strtolower(t, t_len);
  630. return php_memnstr(s, t, t_len, s + s_len);
  631. }
  632. PHPAPI size_t php_strspn(char *s1, char *s2, char *s1_end, char *s2_end)
  633. {
  634. register const char *p = s1, *spanp;
  635. register char c = *p;
  636. cont:
  637. for (spanp = s2; p != s1_end && spanp != s2_end;)
  638. if (*spanp++ == c) {
  639. c = *(++p);
  640. goto cont;
  641. }
  642. return (p - s1);
  643. }
  644. PHPAPI size_t php_strcspn(char *s1, char *s2, char *s1_end, char *s2_end)
  645. {
  646. register const char *p, *spanp;
  647. register char c = *s1;
  648. for (p = s1;;) {
  649. spanp = s2;
  650. do {
  651. if (*spanp == c || p == s1_end)
  652. return (p - s1);
  653. } while (spanp++ < s2_end);
  654. c = *(++p);
  655. }
  656. /* NOTREACHED */
  657. }
  658. /* {{{ proto string stristr(string haystack, string needle)
  659. Find first occurrence of a string within another, case insensitive */
  660. PHP_FUNCTION(stristr)
  661. {
  662. zval **haystack, **needle;
  663. char *found = NULL;
  664. int found_offset;
  665. char *haystack_orig;
  666. char needle_char[2];
  667. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) ==
  668. FAILURE) {
  669. WRONG_PARAM_COUNT;
  670. }
  671. SEPARATE_ZVAL(haystack);
  672. SEPARATE_ZVAL(needle);
  673. convert_to_string_ex(haystack);
  674. haystack_orig = estrndup((*haystack)->value.str.val,
  675. (*haystack)->value.str.len);
  676. if ((*needle)->type == IS_STRING) {
  677. if ((*needle)->value.str.len==0) {
  678. php_error(E_WARNING,"Empty delimiter");
  679. efree(haystack_orig);
  680. RETURN_FALSE;
  681. }
  682. found = php_stristr((*haystack)->value.str.val, (*needle)->value.str.val,
  683. (*haystack)->value.str.len, (*needle)->value.str.len);
  684. } else {
  685. convert_to_long_ex(needle);
  686. needle_char[0] = tolower((char) (*needle)->value.lval);
  687. needle_char[1] = '\0';
  688. found = php_stristr((*haystack)->value.str.val, needle_char,
  689. (*haystack)->value.str.len, 1);
  690. }
  691. if (found) {
  692. found_offset = found - (*haystack)->value.str.val;
  693. RETVAL_STRINGL(haystack_orig + found_offset,
  694. (*haystack)->value.str.len - found_offset, 1);
  695. } else {
  696. RETVAL_FALSE;
  697. }
  698. efree(haystack_orig);
  699. }
  700. /* }}} */
  701. /* {{{ proto string strstr(string haystack, string needle)
  702. Find first occurrence of a string within another */
  703. PHP_FUNCTION(strstr)
  704. {
  705. zval **haystack, **needle;
  706. char *haystack_end;
  707. char *found = NULL;
  708. char needle_char[2];
  709. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) ==
  710. FAILURE) {
  711. WRONG_PARAM_COUNT;
  712. }
  713. convert_to_string_ex(haystack);
  714. haystack_end = (*haystack)->value.str.val + (*haystack)->value.str.len;
  715. if ((*needle)->type == IS_STRING) {
  716. if ((*needle)->value.str.len==0) {
  717. php_error(E_WARNING,"Empty delimiter");
  718. RETURN_FALSE;
  719. }
  720. found = php_memnstr((*haystack)->value.str.val, (*needle)->value.str.val,
  721. (*needle)->value.str.len, haystack_end);
  722. } else {
  723. convert_to_long_ex(needle);
  724. needle_char[0] = (char) (*needle)->value.lval;
  725. needle_char[1] = '\0';
  726. found = php_memnstr((*haystack)->value.str.val, needle_char, 1, haystack_end);
  727. }
  728. if (found) {
  729. RETVAL_STRING(found, 1);
  730. } else {
  731. RETVAL_FALSE;
  732. }
  733. }
  734. /* }}} */
  735. /* {{{ proto string strchr(string haystack, string needle)
  736. An alias for strstr */
  737. /* }}} */
  738. /* {{{ proto int strpos(string haystack, string needle [, int offset])
  739. Find position of first occurrence of a string within another */
  740. PHP_FUNCTION(strpos)
  741. {
  742. zval **haystack, **needle, **OFFSET;
  743. int offset = 0;
  744. char *found = NULL;
  745. char *endp;
  746. char *startp;
  747. switch(ZEND_NUM_ARGS()) {
  748. case 2:
  749. if (zend_get_parameters_ex(2, &haystack, &needle) == FAILURE) {
  750. WRONG_PARAM_COUNT;
  751. }
  752. break;
  753. case 3:
  754. if (zend_get_parameters_ex(3, &haystack, &needle, &OFFSET) == FAILURE) {
  755. WRONG_PARAM_COUNT;
  756. }
  757. convert_to_long_ex(OFFSET);
  758. offset = (*OFFSET)->value.lval;
  759. if (offset < 0) {
  760. php_error(E_WARNING,"offset not contained in string");
  761. RETURN_FALSE;
  762. }
  763. break;
  764. default:
  765. WRONG_PARAM_COUNT;
  766. }
  767. convert_to_string_ex(haystack);
  768. if (offset > (*haystack)->value.str.len) {
  769. php_error(E_WARNING,"offset not contained in string");
  770. RETURN_FALSE;
  771. }
  772. startp = (*haystack)->value.str.val;
  773. startp+= offset;
  774. endp = (*haystack)->value.str.val;
  775. endp+= (*haystack)->value.str.len;
  776. if ((*needle)->type == IS_STRING) {
  777. if ((*needle)->value.str.len==0) {
  778. php_error(E_WARNING,"Empty delimiter");
  779. RETURN_FALSE;
  780. }
  781. found = php_memnstr(startp, (*needle)->value.str.val, (*needle)->value.str.len, endp);
  782. } else {
  783. char buf;
  784. convert_to_long_ex(needle);
  785. buf = (char) (*needle)->value.lval;
  786. found = php_memnstr(startp, &buf, 1, endp);
  787. }
  788. if (found) {
  789. RETVAL_LONG(found - (*haystack)->value.str.val);
  790. } else {
  791. RETVAL_FALSE;
  792. }
  793. }
  794. /* }}} */
  795. /* {{{ proto int strrpos(string haystack, string needle)
  796. Find position of last occurrence of a character in a string within another */
  797. PHP_FUNCTION(strrpos)
  798. {
  799. zval **haystack, **needle;
  800. char *found = NULL;
  801. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) == FAILURE) {
  802. WRONG_PARAM_COUNT;
  803. }
  804. convert_to_string_ex(haystack);
  805. if ((*needle)->type == IS_STRING) {
  806. found = strrchr((*haystack)->value.str.val, *(*needle)->value.str.val);
  807. } else {
  808. convert_to_long_ex(needle);
  809. found = strrchr((*haystack)->value.str.val, (char) (*needle)->value.lval);
  810. }
  811. if (found) {
  812. RETVAL_LONG((*haystack)->value.str.len - strlen(found));
  813. } else {
  814. RETVAL_FALSE;
  815. }
  816. }
  817. /* }}} */
  818. /* {{{ proto string strrchr(string haystack, string needle)
  819. Find the last occurrence of a character in a string within another */
  820. PHP_FUNCTION(strrchr)
  821. {
  822. zval **haystack, **needle;
  823. char *found = NULL;
  824. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) ==
  825. FAILURE) {
  826. WRONG_PARAM_COUNT;
  827. }
  828. convert_to_string_ex(haystack);
  829. if ((*needle)->type == IS_STRING) {
  830. found = strrchr((*haystack)->value.str.val, *(*needle)->value.str.val);
  831. } else {
  832. convert_to_long_ex(needle);
  833. found = strrchr((*haystack)->value.str.val, (*needle)->value.lval);
  834. }
  835. if (found) {
  836. RETVAL_STRING(found,1);
  837. } else {
  838. RETVAL_FALSE;
  839. }
  840. }
  841. /* }}} */
  842. static char *php_chunk_split(char *src, int srclen, char *end, int endlen,
  843. int chunklen, int *destlen)
  844. {
  845. char *dest;
  846. char *p, *q;
  847. int chunks; /* complete chunks! */
  848. int restlen;
  849. chunks = srclen / chunklen;
  850. restlen = srclen - chunks * chunklen; /* srclen % chunklen */
  851. dest = emalloc((srclen + (chunks + 1) * endlen + 1) * sizeof(char));
  852. for(p = src, q = dest; p < (src + srclen - chunklen + 1); ) {
  853. memcpy(q, p, chunklen);
  854. q += chunklen;
  855. memcpy(q, end, endlen);
  856. q += endlen;
  857. p += chunklen;
  858. }
  859. if(restlen) {
  860. memcpy(q, p, restlen);
  861. q += restlen;
  862. memcpy(q, end, endlen);
  863. q += endlen;
  864. }
  865. *q = '\0';
  866. if (destlen) {
  867. *destlen = q - dest;
  868. }
  869. return(dest);
  870. }
  871. /* {{{ proto string chunk_split(string str [, int chunklen [, string ending]])
  872. Return split line */
  873. PHP_FUNCTION(chunk_split)
  874. {
  875. zval **p_str, **p_chunklen, **p_ending;
  876. int argc;
  877. char *result;
  878. char *end = "\r\n";
  879. int endlen = 2;
  880. int chunklen = 76;
  881. int result_len;
  882. argc = ZEND_NUM_ARGS();
  883. if (argc < 1 || argc > 3 ||
  884. zend_get_parameters_ex(argc, &p_str, &p_chunklen, &p_ending) == FAILURE) {
  885. WRONG_PARAM_COUNT;
  886. }
  887. switch(argc) {
  888. case 3:
  889. convert_to_string_ex(p_ending);
  890. end = (*p_ending)->value.str.val;
  891. endlen = (*p_ending)->value.str.len;
  892. case 2:
  893. convert_to_long_ex(p_chunklen);
  894. chunklen = (*p_chunklen)->value.lval;
  895. case 1:
  896. convert_to_string_ex(p_str);
  897. }
  898. if(chunklen == 0) {
  899. php_error(E_WARNING, "chunk length is 0");
  900. RETURN_FALSE;
  901. }
  902. result = php_chunk_split((*p_str)->value.str.val, (*p_str)->value.str.len,
  903. end, endlen, chunklen, &result_len);
  904. if(result) {
  905. RETVAL_STRINGL(result, result_len, 0);
  906. } else {
  907. RETURN_FALSE;
  908. }
  909. }
  910. /* }}} */
  911. /* {{{ proto string substr(string str, int start [, int length])
  912. Return part of a string */
  913. PHP_FUNCTION(substr)
  914. {
  915. zval **str, **from, **len;
  916. int argc, l;
  917. int f;
  918. argc = ZEND_NUM_ARGS();
  919. if ((argc == 2 && zend_get_parameters_ex(2, &str, &from) == FAILURE) ||
  920. (argc == 3 && zend_get_parameters_ex(3, &str, &from, &len) == FAILURE) ||
  921. argc < 2 || argc > 3) {
  922. WRONG_PARAM_COUNT;
  923. }
  924. convert_to_string_ex(str);
  925. convert_to_long_ex(from);
  926. f = (*from)->value.lval;
  927. if (argc == 2) {
  928. l = (*str)->value.str.len;
  929. } else {
  930. convert_to_long_ex(len);
  931. l = (*len)->value.lval;
  932. }
  933. /* if "from" position is negative, count start position from the end
  934. * of the string
  935. */
  936. if (f < 0) {
  937. f = (*str)->value.str.len + f;
  938. if (f < 0) {
  939. f = 0;
  940. }
  941. }
  942. /* if "length" position is negative, set it to the length
  943. * needed to stop that many chars from the end of the string
  944. */
  945. if (l < 0) {
  946. l = ((*str)->value.str.len - f) + l;
  947. if (l < 0) {
  948. l = 0;
  949. }
  950. }
  951. if (f >= (int)(*str)->value.str.len) {
  952. RETURN_FALSE;
  953. }
  954. if((f+l) > (int)(*str)->value.str.len) {
  955. l = (int)(*str)->value.str.len - f;
  956. }
  957. RETVAL_STRINGL((*str)->value.str.val + f, l, 1);
  958. }
  959. /* }}} */
  960. /* {{{ proto string substr_replace(string str, string repl, int start [, int length])
  961. Replace part of a string with another string */
  962. PHP_FUNCTION(substr_replace)
  963. {
  964. zval** str;
  965. zval** from;
  966. zval** len;
  967. zval** repl;
  968. char* result;
  969. int result_len;
  970. int argc;
  971. int l;
  972. int f;
  973. argc = ZEND_NUM_ARGS();
  974. if ((argc == 3 && zend_get_parameters_ex(3, &str, &repl, &from) == FAILURE) ||
  975. (argc == 4 && zend_get_parameters_ex(4, &str, &repl, &from, &len) == FAILURE) ||
  976. argc < 3 || argc > 4) {
  977. WRONG_PARAM_COUNT;
  978. }
  979. convert_to_string_ex(str);
  980. convert_to_string_ex(repl);
  981. convert_to_long_ex(from);
  982. f = (*from)->value.lval;
  983. if (argc == 3) {
  984. l = (*str)->value.str.len;
  985. } else {
  986. convert_to_long_ex(len);
  987. l = (*len)->value.lval;
  988. }
  989. /* if "from" position is negative, count start position from the end
  990. * of the string
  991. */
  992. if (f < 0) {
  993. f = (*str)->value.str.len + f;
  994. if (f < 0) {
  995. f = 0;
  996. }
  997. }
  998. /* if "length" position is negative, set it to the length
  999. * needed to stop that many chars from the end of the string
  1000. */
  1001. if (l < 0) {
  1002. l = ((*str)->value.str.len - f) + l;
  1003. if (l < 0) {
  1004. l = 0;
  1005. }
  1006. }
  1007. if (f >= (int)(*str)->value.str.len) {
  1008. RETURN_STRINGL((*str)->value.str.val, (*str)->value.str.len, 1);
  1009. }
  1010. if((f+l) > (int)(*str)->value.str.len) {
  1011. l = (int)(*str)->value.str.len - f;
  1012. }
  1013. result_len = (*str)->value.str.len - l + (*repl)->value.str.len;
  1014. result = (char *)ecalloc(result_len + 1, sizeof(char *));
  1015. memcpy(result, (*str)->value.str.val, f);
  1016. memcpy(&result[f], (*repl)->value.str.val, (*repl)->value.str.len);
  1017. memcpy(&result[f + (*repl)->value.str.len], (*str)->value.str.val + f + l,
  1018. (*str)->value.str.len - f - l);
  1019. RETVAL_STRINGL(result, result_len, 0);
  1020. }
  1021. /* }}} */
  1022. /* {{{ proto string quotemeta(string str)
  1023. Quote meta characters */
  1024. PHP_FUNCTION(quotemeta)
  1025. {
  1026. zval **arg;
  1027. char *str, *old;
  1028. char *old_end;
  1029. char *p, *q;
  1030. char c;
  1031. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
  1032. WRONG_PARAM_COUNT;
  1033. }
  1034. convert_to_string_ex(arg);
  1035. old = (*arg)->value.str.val;
  1036. old_end = (*arg)->value.str.val + (*arg)->value.str.len;
  1037. if (old == old_end) {
  1038. RETURN_FALSE;
  1039. }
  1040. str = emalloc(2 * (*arg)->value.str.len + 1);
  1041. for(p = old, q = str; p != old_end; p++) {
  1042. c = *p;
  1043. switch(c) {
  1044. case '.':
  1045. case '\\':
  1046. case '+':
  1047. case '*':
  1048. case '?':
  1049. case '[':
  1050. case '^':
  1051. case ']':
  1052. case '$':
  1053. case '(':
  1054. case ')':
  1055. *q++ = '\\';
  1056. /* break is missing _intentionally_ */
  1057. default:
  1058. *q++ = c;
  1059. }
  1060. }
  1061. *q = 0;
  1062. RETVAL_STRINGL(erealloc(str, q - str + 1), q - str, 0);
  1063. }
  1064. /* }}} */
  1065. /* {{{ proto int ord(string character)
  1066. Return ASCII value of character */
  1067. PHP_FUNCTION(ord)
  1068. {
  1069. zval **str;
  1070. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  1071. WRONG_PARAM_COUNT;
  1072. }
  1073. convert_to_string_ex(str);
  1074. RETVAL_LONG((unsigned char)(*str)->value.str.val[0]);
  1075. }
  1076. /* }}} */
  1077. /* {{{ proto string chr(int ascii)
  1078. Convert ASCII code to a character */
  1079. PHP_FUNCTION(chr)
  1080. {
  1081. zval **num;
  1082. char temp[2];
  1083. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &num) == FAILURE) {
  1084. WRONG_PARAM_COUNT;
  1085. }
  1086. convert_to_long_ex(num);
  1087. temp[0] = (char) (*num)->value.lval;
  1088. temp[1] = '\0';
  1089. RETVAL_STRINGL(temp, 1,1);
  1090. }
  1091. /* }}} */
  1092. /* {{{ proto string ucfirst(string str)
  1093. Make a string's first character uppercase */
  1094. PHP_FUNCTION(ucfirst)
  1095. {
  1096. zval **arg;
  1097. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &arg) == FAILURE) {
  1098. WRONG_PARAM_COUNT;
  1099. }
  1100. convert_to_string_ex(arg);
  1101. if (!*(*arg)->value.str.val) {
  1102. RETURN_FALSE;
  1103. }
  1104. *return_value=**arg;
  1105. zval_copy_ctor(return_value);
  1106. *return_value->value.str.val = toupper((unsigned char)*return_value->value.str.val);
  1107. }
  1108. /* }}} */
  1109. /* {{{ proto string ucwords(string str)
  1110. Uppercase the first character of every word in a string */
  1111. PHP_FUNCTION(ucwords)
  1112. {
  1113. zval **str;
  1114. register char *r, *r_end;
  1115. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  1116. WRONG_PARAM_COUNT;
  1117. }
  1118. convert_to_string_ex(str);
  1119. if (!Z_STRLEN_PP(str)) {
  1120. RETURN_FALSE;
  1121. }
  1122. *return_value=**str;
  1123. zval_copy_ctor(return_value);
  1124. r=return_value->value.str.val;
  1125. *r=toupper((unsigned char)*r);
  1126. for(r_end = r + return_value->value.str.len - 1 ; r < r_end ; ) {
  1127. if(isspace((int)*r++)) {
  1128. *r=toupper((unsigned char)*r);
  1129. }
  1130. }
  1131. }
  1132. /* }}} */
  1133. PHPAPI char *php_strtr(char *str, int len, char *str_from,
  1134. char *str_to, int trlen)
  1135. {
  1136. int i;
  1137. unsigned char xlat[256];
  1138. if ((trlen < 1) || (len < 1)) {
  1139. return str;
  1140. }
  1141. for (i = 0; i < 256; xlat[i] = i, i++);
  1142. for (i = 0; i < trlen; i++) {
  1143. xlat[(unsigned char) str_from[i]] = str_to[i];
  1144. }
  1145. for (i = 0; i < len; i++) {
  1146. str[i] = xlat[(unsigned char) str[i]];
  1147. }
  1148. return str;
  1149. }
  1150. static void php_strtr_array(zval *return_value,char *str,int slen,HashTable *hash)
  1151. {
  1152. zval *entry;
  1153. char *string_key;
  1154. zval **trans;
  1155. zval ctmp;
  1156. ulong num_key;
  1157. int minlen = 128*1024;
  1158. int maxlen = 0, pos, len, newpos, newlen, found;
  1159. char *newstr, *key;
  1160. HashPosition hpos;
  1161. zend_hash_internal_pointer_reset_ex(hash, &hpos);
  1162. while (zend_hash_get_current_data_ex(hash, (void **)&entry, &hpos) == SUCCESS) {
  1163. switch (zend_hash_get_current_key_ex(hash, &string_key, NULL, &num_key, &hpos)) {
  1164. case HASH_KEY_IS_STRING:
  1165. len = strlen(string_key);
  1166. if (len > maxlen) maxlen = len;
  1167. if (len < minlen) minlen = len;
  1168. efree(string_key);
  1169. break;
  1170. case HASH_KEY_IS_LONG:
  1171. ctmp.type = IS_LONG;
  1172. ctmp.value.lval = num_key;
  1173. convert_to_string(&ctmp);
  1174. len = ctmp.value.str.len;
  1175. zval_dtor(&ctmp);
  1176. if (len > maxlen) maxlen = len;
  1177. if (len < minlen) minlen = len;
  1178. break;
  1179. }
  1180. zend_hash_move_forward_ex(hash, &hpos);
  1181. }
  1182. key = emalloc(maxlen+1);
  1183. newstr = emalloc(8192);
  1184. newlen = 8192;
  1185. newpos = pos = 0;
  1186. while (pos < slen) {
  1187. if ((pos + maxlen) > slen) {
  1188. maxlen = slen - pos;
  1189. }
  1190. found = 0;
  1191. memcpy(key,str+pos,maxlen);
  1192. for (len = maxlen; len >= minlen; len--) {
  1193. key[ len ]=0;
  1194. if (zend_hash_find(hash,key,len+1,(void**)&trans) == SUCCESS) {
  1195. char *tval;
  1196. int tlen;
  1197. zval tmp;
  1198. if ((*trans)->type != IS_STRING) {
  1199. tmp = **trans;
  1200. zval_copy_ctor(&tmp);
  1201. convert_to_string(&tmp);
  1202. tval = tmp.value.str.val;
  1203. tlen = tmp.value.str.len;
  1204. } else {
  1205. tval = (*trans)->value.str.val;
  1206. tlen = (*trans)->value.str.len;
  1207. }
  1208. if ((newpos + tlen + 1) > newlen) {
  1209. newlen = newpos + tlen + 1 + 8192;
  1210. newstr = erealloc(newstr,newlen);
  1211. }
  1212. memcpy(newstr+newpos,tval,tlen);
  1213. newpos += tlen;
  1214. pos += len;
  1215. found = 1;
  1216. if ((*trans)->type != IS_STRING) {
  1217. zval_dtor(&tmp);
  1218. }
  1219. break;
  1220. }
  1221. }
  1222. if (! found) {
  1223. if ((newpos + 1) > newlen) {
  1224. newlen = newpos + 1 + 8192;
  1225. newstr = erealloc(newstr,newlen);
  1226. }
  1227. newstr[ newpos++ ] = str[ pos++ ];
  1228. }
  1229. }
  1230. efree(key);
  1231. newstr[ newpos ] = 0;
  1232. RETURN_STRINGL(newstr,newpos,0);
  1233. }
  1234. /* {{{ proto string strtr(string str, string from, string to)
  1235. Translate characters in str using given translation tables */
  1236. PHP_FUNCTION(strtr)
  1237. { /* strtr(STRING,FROM,TO) */
  1238. zval **str, **from, **to;
  1239. int ac = ZEND_NUM_ARGS();
  1240. if (ac < 2 || ac > 3 || zend_get_parameters_ex(ac, &str, &from, &to) == FAILURE) {
  1241. WRONG_PARAM_COUNT;
  1242. }
  1243. if (ac == 2 && (*from)->type != IS_ARRAY) {
  1244. php_error(E_WARNING,"arg2 must be passed an array");
  1245. RETURN_FALSE;
  1246. }
  1247. convert_to_string_ex(str);
  1248. if (ac == 2) {
  1249. php_strtr_array(return_value,(*str)->value.str.val,(*str)->value.str.len,HASH_OF(*from));
  1250. } else {
  1251. convert_to_string_ex(from);
  1252. convert_to_string_ex(to);
  1253. *return_value=**str;
  1254. zval_copy_ctor(return_value);
  1255. php_strtr(return_value->value.str.val,
  1256. return_value->value.str.len,
  1257. (*from)->value.str.val,
  1258. (*to)->value.str.val,
  1259. MIN((*from)->value.str.len,(*to)->value.str.len));
  1260. }
  1261. }
  1262. /* }}} */
  1263. /* {{{ proto string strrev(string str)
  1264. Reverse a string */
  1265. PHP_FUNCTION(strrev)
  1266. {
  1267. zval **str;
  1268. int i,len;
  1269. char c;
  1270. if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &str)==FAILURE) {
  1271. WRONG_PARAM_COUNT;
  1272. }
  1273. convert_to_string_ex(str);
  1274. *return_value = **str;
  1275. zval_copy_ctor(return_value);
  1276. len = return_value->value.str.len;
  1277. for (i=0; i<len-1-i; i++) {
  1278. c=return_value->value.str.val[i];
  1279. return_value->value.str.val[i] = return_value->value.str.val[len-1-i];
  1280. return_value->value.str.val[len-1-i]=c;
  1281. }
  1282. }
  1283. /* }}} */
  1284. static void php_similar_str(const char *txt1, int len1, const char *txt2,
  1285. int len2, int *pos1, int *pos2, int *max)
  1286. {
  1287. char *p, *q;
  1288. char *end1 = (char *) txt1 + len1;
  1289. char *end2 = (char *) txt2 + len2;
  1290. int l;
  1291. *max = 0;
  1292. for (p = (char *) txt1; p < end1; p++) {
  1293. for (q = (char *) txt2; q < end2; q++) {
  1294. for (l = 0; (p + l < end1) && (q + l < end2) && (p[l] == q[l]);
  1295. l++);
  1296. if (l > *max) {
  1297. *max = l;
  1298. *pos1 = p - txt1;
  1299. *pos2 = q - txt2;
  1300. }
  1301. }
  1302. }
  1303. }
  1304. static int php_similar_char(const char *txt1, int len1,
  1305. const char *txt2, int len2)
  1306. {
  1307. int sum;
  1308. int pos1, pos2, max;
  1309. php_similar_str(txt1, len1, txt2, len2, &pos1, &pos2, &max);
  1310. if ((sum = max)) {
  1311. if (pos1 && pos2)
  1312. sum += php_similar_char(txt1, pos1, txt2, pos2);
  1313. if ((pos1 + max < len1) && (pos2 + max < len2))
  1314. sum += php_similar_char(txt1 + pos1 + max, len1 - pos1 - max,
  1315. txt2 + pos2 + max, len2 - pos2 - max);
  1316. }
  1317. return sum;
  1318. }
  1319. /* {{{ proto int similar_text(string str1, string str2 [, double percent])
  1320. Calculates the similarity between two strings */
  1321. PHP_FUNCTION(similar_text)
  1322. {
  1323. zval **t1, **t2, **percent;
  1324. int ac = ZEND_NUM_ARGS();
  1325. int sim;
  1326. if (ac < 2 || ac > 3 ||
  1327. zend_get_parameters_ex(ac, &t1, &t2, &percent) == FAILURE) {
  1328. WRONG_PARAM_COUNT;
  1329. }
  1330. convert_to_string_ex(t1);
  1331. convert_to_string_ex(t2);
  1332. if (ac > 2) {
  1333. convert_to_double_ex(percent);
  1334. }
  1335. if (((*t1)->value.str.len + (*t2)->value.str.len) == 0) {
  1336. if(ac > 2) {
  1337. (*percent)->value.dval = 0;
  1338. }
  1339. RETURN_LONG(0);
  1340. }
  1341. sim = php_similar_char((*t1)->value.str.val, (*t1)->value.str.len,
  1342. (*t2)->value.str.val, (*t2)->value.str.len);
  1343. if (ac > 2) {
  1344. (*percent)->value.dval = sim * 200.0 / ((*t1)->value.str.len + (*t2)->value.str.len);
  1345. }
  1346. RETURN_LONG(sim);
  1347. }
  1348. /* }}} */
  1349. /* be careful, this edits the string in-place */
  1350. PHPAPI void php_stripslashes(char *str, int *len)
  1351. {
  1352. char *s, *t;
  1353. int l;
  1354. char escape_char='\\';
  1355. PLS_FETCH();
  1356. if (PG(magic_quotes_sybase)) {
  1357. escape_char='\'';
  1358. }
  1359. if (len != NULL) {
  1360. l = *len;
  1361. } else {
  1362. l = strlen(str);
  1363. }
  1364. s = str;
  1365. t = str;
  1366. while (l > 0) {
  1367. if (*t == escape_char) {
  1368. t++; /* skip the slash */
  1369. if (len != NULL)
  1370. (*len)--;
  1371. l--;
  1372. if (l > 0) {
  1373. if(*t=='0') {
  1374. *s++='\0';
  1375. t++;
  1376. } else {
  1377. *s++ = *t++; /* preserve the next character */
  1378. }
  1379. l--;
  1380. }
  1381. } else {
  1382. if (s != t)
  1383. *s++ = *t++;
  1384. else {
  1385. s++;
  1386. t++;
  1387. }
  1388. l--;
  1389. }
  1390. }
  1391. if (s != t) {
  1392. *s = '\0';
  1393. }
  1394. }
  1395. /* {{{ proto string addcslashes(string str, string charlist)
  1396. Escape 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...). */
  1397. PHP_FUNCTION(addcslashes)
  1398. {
  1399. zval **str, **what;
  1400. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &str, &what) == FAILURE) {
  1401. WRONG_PARAM_COUNT;
  1402. }
  1403. convert_to_string_ex(str);
  1404. convert_to_string_ex(what);
  1405. return_value->value.str.val = php_addcslashes((*str)->value.str.val,(*str)->value.str.len,&return_value->value.str.len,0,(*what)->value.str.val,(*what)->value.str.len);
  1406. return_value->type = IS_STRING;
  1407. }
  1408. /* }}} */
  1409. /* {{{ proto string addslashes(string str)
  1410. Escape single quote, double quotes and backslash characters in a string with backslashes */
  1411. PHP_FUNCTION(addslashes)
  1412. {
  1413. zval **str;
  1414. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  1415. WRONG_PARAM_COUNT;
  1416. }
  1417. convert_to_string_ex(str);
  1418. return_value->value.str.val = php_addslashes((*str)->value.str.val,(*str)->value.str.len,&return_value->value.str.len,0);
  1419. return_value->type = IS_STRING;
  1420. }
  1421. /* }}} */
  1422. /* {{{ proto string stripcslashes(string str)
  1423. Strip backslashes from a string. Uses C-style conventions */
  1424. PHP_FUNCTION(stripcslashes)
  1425. {
  1426. zval **str;
  1427. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  1428. WRONG_PARAM_COUNT;
  1429. }
  1430. convert_to_string_ex(str);
  1431. *return_value = **str;
  1432. zval_copy_ctor(return_value);
  1433. php_stripcslashes(return_value->value.str.val,&return_value->value.str.len);
  1434. }
  1435. /* }}} */
  1436. /* {{{ proto string stripslashes(string str)
  1437. Strip backslashes from a string */
  1438. PHP_FUNCTION(stripslashes)
  1439. {
  1440. zval **str;
  1441. if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &str) == FAILURE) {
  1442. WRONG_PARAM_COUNT;
  1443. }
  1444. convert_to_string_ex(str);
  1445. *return_value = **str;
  1446. zval_copy_ctor(return_value);
  1447. php_stripslashes(return_value->value.str.val,&return_value->value.str.len);
  1448. }
  1449. /* }}} */
  1450. #ifndef HAVE_STRERROR
  1451. char *php_strerror(int errnum)
  1452. {
  1453. extern int sys_nerr;
  1454. extern char *sys_errlist[];
  1455. BLS_FETCH();
  1456. if ((unsigned int)errnum < sys_nerr) return(sys_errlist[errnum]);
  1457. (void)sprintf(BG(str_ebuf), "Unknown error: %d", errnum);
  1458. return(BG(str_ebuf));
  1459. }
  1460. #endif
  1461. PHPAPI void php_stripcslashes(char *str, int *len)
  1462. {
  1463. char *source,*target,*end;
  1464. int nlen = *len, i;
  1465. char numtmp[4];
  1466. for (source=str,end=str+nlen,target=str; source<end; source++) {
  1467. if (*source == '\\' && source+1<end) {
  1468. source++;
  1469. switch (*source) {
  1470. case 'n': *target++='\n'; nlen--; break;
  1471. case 'r': *target++='\r'; nlen--; break;
  1472. case 'a': *target++='\a'; nlen--; break;
  1473. case 't': *target++='\t'; nlen--; break;
  1474. case 'v': *target++='\v'; nlen--; break;
  1475. case 'b': *target++='\b'; nlen--; break;
  1476. case 'f': *target++='\f'; nlen--; break;
  1477. case '\\': *target++='\\'; nlen--; break;
  1478. case 'x': if (source+1<end && isxdigit((int)(*(source+1)))) {
  1479. numtmp[0] = *++source;
  1480. if (source+1<end && isxdigit((int)(*(source+1)))) {
  1481. numtmp[1] = *++source;
  1482. numtmp[2] = '\0';
  1483. nlen-=3;
  1484. } else {
  1485. numtmp[1] = '\0';
  1486. nlen-=2;
  1487. }
  1488. *target++=(char)strtol(numtmp, NULL, 16);
  1489. break;
  1490. }
  1491. /* break is left intentionally */
  1492. default: i=0;
  1493. while (source<end && *source>='0' && *source<='7' && i<3) {
  1494. numtmp[i++] = *source++;
  1495. }
  1496. if (i) {
  1497. numtmp[i]='\0';
  1498. *target++=(char)strtol(numtmp, NULL, 8);
  1499. nlen-=i;
  1500. source--;
  1501. } else {
  1502. *target++=*source;
  1503. nlen--;
  1504. }
  1505. }
  1506. } else {
  1507. *target++=*source;
  1508. }
  1509. }
  1510. if(nlen != 0) {
  1511. *target='\0';
  1512. }
  1513. *len = nlen;
  1514. }
  1515. PHPAPI char *php_addcslashes(char *str, int length, int *new_length, int should_free, char *what, int wlength)
  1516. {
  1517. char flags[256];
  1518. char *new_str = emalloc((length?length:(length=strlen(str)))*4+1);
  1519. char *source,*target;
  1520. char *end;
  1521. char c;
  1522. int newlen;
  1523. if (!wlength) {
  1524. wlength = strlen(what);
  1525. }
  1526. if (!length) {
  1527. length = strlen(str);
  1528. }
  1529. memset(flags, '\0', sizeof(flags));
  1530. for (source=what,end=source+wlength; (c=*source) || source<end; source++) {
  1531. if (source+3<end && *(source+1) == '.' && *(source+2) == '.' && (unsigned char)*(source+3)>=(unsigned char)c) {
  1532. memset(flags+c, 1, (unsigned char)*(source+3)-(unsigned char)c+1);
  1533. source+=3;
  1534. } else
  1535. flags[(unsigned char)c]=1;
  1536. }
  1537. for (source=str,end=source+length,target=new_str; (c=*source) || source<end; source++) {
  1538. if (flags[(unsigned char)c]) {
  1539. if ((unsigned char)c<32 || (unsigned char)c>126) {
  1540. *target++ = '\\';
  1541. switch (c) {
  1542. case '\n': *target++ = 'n'; break;
  1543. case '\t': *target++ = 't'; break;
  1544. case '\r': *target++ = 'r'; break;
  1545. case '\a': *target++ = 'a'; break;
  1546. case '\v': *target++ = 'v'; break;
  1547. case '\b': *target++ = 'b'; break;
  1548. case '\f': *target++ = 'f'; break;
  1549. default: target += sprintf(target, "%03o", (unsigned char)c);
  1550. }
  1551. continue;
  1552. }
  1553. *target++ = '\\';
  1554. }
  1555. *target++ = c;
  1556. }
  1557. *target = 0;
  1558. newlen = target-new_str;
  1559. if (target-new_str<length*4) {
  1560. new_str = erealloc(new_str, newlen+1);
  1561. }
  1562. if (new_length) {
  1563. *new_length = newlen;
  1564. }
  1565. if (should_free) {
  1566. STR_FREE(str);
  1567. }
  1568. return new_str;
  1569. }
  1570. PHPAPI char *php_addslashes(char *str, int length, int *new_length, int should_free)
  1571. {
  1572. /* maximum string length, worst case situation */
  1573. char *new_str;
  1574. char *source,*target;
  1575. char *end;
  1576. char c;
  1577. PLS_FETCH();
  1578. if (!str) {
  1579. *new_length = 0;
  1580. return str;
  1581. }
  1582. new_str = (char *) emalloc((length?length:(length=strlen(str)))*2+1);
  1583. for (source=str,end=source+length,target=new_str; source<end; source++) {
  1584. c = *source;
  1585. switch(c) {
  1586. case '\0':
  1587. *target++ = '\\';
  1588. *target++ = '0';
  1589. break;
  1590. case '\'':
  1591. if (PG(magic_quotes_sybase)) {
  1592. *target++ = '\'';
  1593. *target++ = '\'';
  1594. break;
  1595. }
  1596. /* break is missing *intentionally* */
  1597. case '\"':
  1598. case '\\':
  1599. if (!PG(magic_quotes_sybase)) {
  1600. *target++ = '\\';
  1601. }
  1602. /* break is missing *intentionally* */
  1603. default:
  1604. *target++ = c;
  1605. break;
  1606. }
  1607. }
  1608. *target = 0;
  1609. if (new_length) {
  1610. *new_length = target - new_str;
  1611. }
  1612. if (should_free) {
  1613. STR_FREE(str);
  1614. }
  1615. return new_str;
  1616. }
  1617. #define _HEB_BLOCK_TYPE_ENG 1
  1618. #define _HEB_BLOCK_TYPE_HEB 2
  1619. #define isheb(c) (((((unsigned char) c)>=224) && (((unsigned char) c)<=250)) ? 1 : 0)
  1620. #define _isblank(c) (((((unsigned char) c)==' ' || ((unsigned char) c)=='\t')) ? 1 : 0)
  1621. #define _isnewline(c) (((((unsigned char) c)=='\n' || ((unsigned char) c)=='\r')) ? 1 : 0)
  1622. PHPAPI void php_char_to_str(char *str,uint len,char from,char *to,int to_len,zval *result)
  1623. {
  1624. int char_count=0;
  1625. char *source,*target,*tmp,*source_end=str+len, *tmp_end=NULL;
  1626. for (source=str; source<source_end; source++) {
  1627. if (*source==from) {
  1628. char_count++;
  1629. }
  1630. }
  1631. result->type = IS_STRING;
  1632. if (char_count==0) {
  1633. result->value.str.val = estrndup(str,len);
  1634. result->value.str.len = len;
  1635. return;
  1636. }
  1637. result->value.str.len = len+char_count*(to_len-1);
  1638. result->value.str.val = target = (char *) emalloc(result->value.str.len+1);
  1639. for (source=str; source<source_end; source++) {
  1640. if (*source==from) {
  1641. for (tmp=to,tmp_end=tmp+to_len; tmp<tmp_end; tmp++) {
  1642. *target = *tmp;
  1643. target++;
  1644. }
  1645. } else {
  1646. *target = *source;
  1647. target++;
  1648. }
  1649. }
  1650. *target = 0;
  1651. }
  1652. PHPAPI inline char *
  1653. php_memnstr(char *haystack, char *needle, int needle_len, char *end)
  1654. {
  1655. char *p = haystack;
  1656. char *s = NULL;
  1657. for(; p <= end - needle_len &&
  1658. (s = memchr(p, *needle, end - p - needle_len + 1)); p = s + 1) {
  1659. if(memcmp(s, needle, needle_len) == 0)
  1660. return s;
  1661. }
  1662. return NULL;
  1663. }
  1664. PHPAPI char *php_str_to_str(char *haystack, int length,
  1665. char *needle, int needle_len, char *str, int str_len, int *_new_length)
  1666. {
  1667. char *p, *q;
  1668. char *r, *s;
  1669. char *end = haystack + length;
  1670. char *result;
  1671. char *off;
  1672. result = emalloc(length);
  1673. /* we jump through haystack searching for the needle. hurray! */
  1674. for(p = haystack, q = result;
  1675. (r = php_memnstr(p, needle, needle_len, end));) {
  1676. /* this ain't optimal. you could call it `efficient memory usage' */
  1677. off = erealloc(result, (q - result) + (r - p) + (str_len) + 1);
  1678. if(off != result) {
  1679. if(!off) {
  1680. goto finish;
  1681. }
  1682. q += off - result;
  1683. result = off;
  1684. }
  1685. memcpy(q, p, r - p);
  1686. q += r - p;
  1687. memcpy(q, str, str_len);
  1688. q += str_len;
  1689. p = r + needle_len;
  1690. }
  1691. /* if there is a rest, copy it */
  1692. if((end - p) > 0) {
  1693. s = (q) + (end - p);
  1694. off = erealloc(result, s - result + 1);
  1695. if(off != result) {
  1696. if(!off) {
  1697. goto finish;
  1698. }
  1699. q += off - result;
  1700. result = off;
  1701. s = q + (end - p);
  1702. }
  1703. memcpy(q, p, end - p);
  1704. q = s;
  1705. }
  1706. finish:
  1707. *q = '\0';
  1708. if(_new_length) *_new_length = q - result;
  1709. return result;
  1710. }
  1711. /* {{{ proto string str_replace(string needle, string str, string haystack)
  1712. Replace all occurrences of needle in haystack with str */
  1713. PHP_FUNCTION(str_replace)
  1714. {
  1715. zval **haystack, **needle, **str;
  1716. char *result;
  1717. int len = 0;
  1718. if(ZEND_NUM_ARGS() != 3 ||
  1719. zend_get_parameters_ex(3, &needle, &str, &haystack) == FAILURE) {
  1720. WRONG_PARAM_COUNT;
  1721. }
  1722. convert_to_string_ex(haystack);
  1723. convert_to_string_ex(needle);
  1724. convert_to_string_ex(str);
  1725. if((*haystack)->value.str.len == 0) {
  1726. RETURN_STRING(empty_string,1);
  1727. }
  1728. if((*needle)->value.str.len == 1) {
  1729. php_char_to_str((*haystack)->value.str.val,
  1730. (*haystack)->value.str.len,
  1731. (*needle)->value.str.val[0],
  1732. (*str)->value.str.val,
  1733. (*str)->value.str.len,
  1734. return_value);
  1735. return;
  1736. }
  1737. if((*needle)->value.str.len == 0) {
  1738. php_error(E_WARNING, "The length of the needle must not be 0");
  1739. RETURN_FALSE;
  1740. }
  1741. result = php_str_to_str((*haystack)->value.str.val, (*haystack)->value.str.len,
  1742. (*needle)->value.str.val, (*needle)->value.str.len,
  1743. (*str)->value.str.val, (*str)->value.str.len, &len);
  1744. RETURN_STRINGL(result, len, 0);
  1745. }
  1746. /* }}} */
  1747. /* Converts Logical Hebrew text (Hebrew Windows style) to Visual text
  1748. * Cheers/complaints/flames - Zeev Suraski <zeev@php.net>
  1749. */
  1750. static void php_hebrev(INTERNAL_FUNCTION_PARAMETERS,int convert_newlines)
  1751. {
  1752. zval **str,**max_chars_per_line;
  1753. char *heb_str,*tmp,*target,*opposite_target,*broken_str;
  1754. int block_start, block_end, block_type, block_length, i;
  1755. int block_ended;
  1756. long max_chars=0;
  1757. int begin,end,char_count,orig_begin;
  1758. switch(ZEND_NUM_ARGS()) {
  1759. case 1:
  1760. if (zend_get_parameters_ex(1, &str)==FAILURE) {
  1761. RETURN_FALSE;
  1762. }
  1763. break;
  1764. case 2:
  1765. if (zend_get_parameters_ex(2, &str, &max_chars_per_line)==FAILURE) {
  1766. RETURN_FALSE;
  1767. }
  1768. convert_to_long_ex(max_chars_per_line);
  1769. max_chars = (*max_chars_per_line)->value.lval;
  1770. break;
  1771. default:
  1772. WRONG_PARAM_COUNT;
  1773. break;
  1774. }
  1775. convert_to_string_ex(str);
  1776. if ((*str)->value.str.len==0) {
  1777. RETURN_FALSE;
  1778. }
  1779. tmp = (*str)->value.str.val;
  1780. block_start=block_end=0;
  1781. block_ended=0;
  1782. heb_str = (char *) emalloc((*str)->value.str.len+1);
  1783. target = heb_str+(*str)->value.str.len;
  1784. opposite_target = heb_str;
  1785. *target = 0;
  1786. target--;
  1787. block_length=0;
  1788. if (isheb(*tmp)) {
  1789. block_type = _HEB_BLOCK_TYPE_HEB;
  1790. } else {
  1791. block_type = _HEB_BLOCK_TYPE_ENG;
  1792. }
  1793. do {
  1794. if (block_type==_HEB_BLOCK_TYPE_HEB) {
  1795. while((isheb((int)*(tmp+1)) || _isblank((int)*(tmp+1)) || ispunct((int)*(tmp+1)) || (int)*(tmp+1)=='\n' ) && block_end<(*str)->value.str.len-1) {
  1796. tmp++;
  1797. block_end++;
  1798. block_length++;
  1799. }
  1800. for (i=block_start; i<=block_end; i++) {
  1801. *target = (*str)->value.str.val[i];
  1802. switch (*target) {
  1803. case '(':
  1804. *target = ')';
  1805. break;
  1806. case ')':
  1807. *target = '(';
  1808. break;
  1809. default:
  1810. break;
  1811. }
  1812. target--;
  1813. }
  1814. block_type = _HEB_BLOCK_TYPE_ENG;
  1815. } else {
  1816. while(!isheb(*(tmp+1)) && (int)*(tmp+1)!='\n' && block_end<(*str)->value.str.len-1) {
  1817. tmp++;
  1818. block_end++;
  1819. block_length++;
  1820. }
  1821. while ((_isblank((int)*tmp) || ispunct((int)*tmp)) && *tmp!='/' && *tmp!='-' && block_end>block_start) {
  1822. tmp--;
  1823. block_end--;
  1824. }
  1825. for (i=block_end; i>=block_start; i--) {
  1826. *target = (*str)->value.str.val[i];
  1827. target--;
  1828. }
  1829. block_type = _HEB_BLOCK_TYPE_HEB;
  1830. }
  1831. block_start=block_end+1;
  1832. } while(block_end<(*str)->value.str.len-1);
  1833. broken_str = (char *) emalloc((*str)->value.str.len+1);
  1834. begin=end=(*str)->value.str.len-1;
  1835. target = broken_str;
  1836. while (1) {
  1837. char_count=0;
  1838. while ((!max_chars || char_count<max_chars) && begin>0) {
  1839. char_count++;
  1840. begin--;
  1841. if (begin<=0 || _isnewline(heb_str[begin])) {
  1842. while(begin>0 && _isnewline(heb_str[begin-1])) {
  1843. begin--;
  1844. char_count++;
  1845. }
  1846. break;
  1847. }
  1848. }
  1849. if (char_count==max_chars) { /* try to avoid breaking words */
  1850. int new_char_count=char_count, new_begin=begin;
  1851. while (new_char_count>0) {
  1852. if (_isblank(heb_str[new_begin]) || _isnewline(heb_str[new_begin])) {
  1853. break;
  1854. }
  1855. new_begin++;
  1856. new_char_count--;
  1857. }
  1858. if (new_char_count>0) {
  1859. char_count=new_char_count;
  1860. begin=new_begin;
  1861. }
  1862. }
  1863. orig_begin=begin;
  1864. if (_isblank(heb_str[begin])) {
  1865. heb_str[begin]='\n';
  1866. }
  1867. while (begin<=end && _isnewline(heb_str[begin])) { /* skip leading newlines */
  1868. begin++;
  1869. }
  1870. for (i=begin; i<=end; i++) { /* copy content */
  1871. *target = heb_str[i];
  1872. target++;
  1873. }
  1874. for (i=orig_begin; i<=end && _isnewline(heb_str[i]); i++) {
  1875. *target = heb_str[i];
  1876. target++;
  1877. }
  1878. begin=orig_begin;
  1879. if (begin<=0) {
  1880. *target = 0;
  1881. break;
  1882. }
  1883. begin--;
  1884. end=begin;
  1885. }
  1886. efree(heb_str);
  1887. if (convert_newlines) {
  1888. php_char_to_str(broken_str,(*str)->value.str.len,'\n',"<br>\n",5,return_value);
  1889. efree(broken_str);
  1890. } else {
  1891. return_value->value.str.val = broken_str;
  1892. return_value->value.str.len = (*str)->value.str.len;
  1893. return_value->type = IS_STRING;
  1894. }
  1895. }
  1896. /* {{{ proto string hebrev(string str [, int max_chars_per_line])
  1897. Convert logical Hebrew text to visual text */
  1898. PHP_FUNCTION(hebrev)
  1899. {
  1900. php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU,0);
  1901. }
  1902. /* }}} */
  1903. /* {{{ proto string hebrevc(string str [, int max_chars_per_line])
  1904. Convert logical Hebrew text to visual text with newline conversion */
  1905. PHP_FUNCTION(hebrevc)
  1906. {
  1907. php_hebrev(INTERNAL_FUNCTION_PARAM_PASSTHRU,1);
  1908. }
  1909. /* }}} */
  1910. /* {{{ proto string nl2br(string str)
  1911. Converts newlines to HTML line breaks */
  1912. PHP_FUNCTION(nl2br)
  1913. {
  1914. zval **str;
  1915. if (ZEND_NUM_ARGS()!=1 || zend_get_parameters_ex(1, &str)==FAILURE) {
  1916. WRONG_PARAM_COUNT;
  1917. }
  1918. convert_to_string_ex(str);
  1919. php_char_to_str((*str)->value.str.val,(*str)->value.str.len,'\n',"<br>\n",5,return_value);
  1920. }
  1921. /* }}} */
  1922. /* {{{ proto string strip_tags(string str [, string allowable_tags])
  1923. Strips HTML and PHP tags from a string */
  1924. PHP_FUNCTION(strip_tags)
  1925. {
  1926. char *buf;
  1927. zval **str, **allow=NULL;
  1928. char *allowed_tags=NULL;
  1929. int allowed_tags_len=0;
  1930. switch(ZEND_NUM_ARGS()) {
  1931. case 1:
  1932. if(zend_get_parameters_ex(1, &str)==FAILURE) {
  1933. RETURN_FALSE;
  1934. }
  1935. break;
  1936. case 2:
  1937. if(zend_get_parameters_ex(2, &str, &allow)==FAILURE) {
  1938. RETURN_FALSE;
  1939. }
  1940. convert_to_string_ex(allow);
  1941. allowed_tags = (*allow)->value.str.val;
  1942. allowed_tags_len = (*allow)->value.str.len;
  1943. break;
  1944. default:
  1945. WRONG_PARAM_COUNT;
  1946. break;
  1947. }
  1948. convert_to_string_ex(str);
  1949. buf = estrndup((*str)->value.str.val,(*str)->value.str.len);
  1950. php_strip_tags(buf, (*str)->value.str.len, 0, allowed_tags, allowed_tags_len);
  1951. RETURN_STRING(buf, 0);
  1952. }
  1953. /* }}} */
  1954. /* {{{ proto string setlocale(string category, string locale)
  1955. Set locale information */
  1956. PHP_FUNCTION(setlocale)
  1957. {
  1958. zval **pcategory, **plocale;
  1959. zval *category, *locale;
  1960. int cat;
  1961. char *loc, *retval;
  1962. BLS_FETCH();
  1963. if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &pcategory, &plocale)==FAILURE)
  1964. WRONG_PARAM_COUNT;
  1965. #ifdef HAVE_SETLOCALE
  1966. convert_to_string_ex(pcategory);
  1967. convert_to_string_ex(plocale);
  1968. category = *pcategory;
  1969. locale = *plocale;
  1970. if (!strcasecmp ("LC_ALL", category->value.str.val))
  1971. cat = LC_ALL;
  1972. else if (!strcasecmp ("LC_COLLATE", category->value.str.val))
  1973. cat = LC_COLLATE;
  1974. else if (!strcasecmp ("LC_CTYPE", category->value.str.val))
  1975. cat = LC_CTYPE;
  1976. #ifdef LC_MESSAGES
  1977. else if (!strcasecmp ("LC_MESSAGES", category->value.str.val))
  1978. cat = LC_MESSAGES;
  1979. #endif
  1980. else if (!strcasecmp ("LC_MONETARY", category->value.str.val))
  1981. cat = LC_MONETARY;
  1982. else if (!strcasecmp ("LC_NUMERIC", category->value.str.val))
  1983. cat = LC_NUMERIC;
  1984. else if (!strcasecmp ("LC_TIME", category->value.str.val))
  1985. cat = LC_TIME;
  1986. else {
  1987. php_error(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->value.str.val);
  1988. RETURN_FALSE;
  1989. }
  1990. if (!strcmp ("0", locale->value.str.val))
  1991. loc = NULL;
  1992. else
  1993. loc = locale->value.str.val;
  1994. retval = setlocale (cat, loc);
  1995. if (retval) {
  1996. /* Remember if locale was changed */
  1997. if (loc) {
  1998. STR_FREE(BG(locale_string));
  1999. BG(locale_string) = estrdup(retval);
  2000. }
  2001. RETVAL_STRING(retval,1);
  2002. return;
  2003. }
  2004. #endif
  2005. RETURN_FALSE;
  2006. }
  2007. /* }}} */
  2008. /* {{{ proto void parse_str(string encoded_string)
  2009. Parses GET/POST/COOKIE data and sets global variables. */
  2010. PHP_FUNCTION(parse_str)
  2011. {
  2012. zval **arg;
  2013. char *res = NULL;
  2014. PLS_FETCH();
  2015. SLS_FETCH();
  2016. if (zend_get_parameters_ex(1, &arg) == FAILURE) {
  2017. WRONG_PARAM_COUNT;
  2018. }
  2019. convert_to_string_ex(arg);
  2020. if ((*arg)->value.str.val && *(*arg)->value.str.val) {
  2021. res = estrndup((*arg)->value.str.val,(*arg)->value.str.len);
  2022. }
  2023. php_treat_data(PARSE_STRING, res ELS_CC PLS_CC SLS_CC);
  2024. }
  2025. /* }}} */
  2026. #define PHP_TAG_BUF_SIZE 1023
  2027. /* Check if tag is in a set of tags
  2028. *
  2029. * states:
  2030. *
  2031. * 0 start tag
  2032. * 1 first non-whitespace char seen
  2033. */
  2034. int php_tag_find(char *tag, int len, char *set) {
  2035. char c, *n, *t;
  2036. int state=0, done=0;
  2037. char *norm = emalloc(len+1);
  2038. n = norm;
  2039. t = tag;
  2040. c = tolower(*t);
  2041. /*
  2042. normalize the tag removing leading and trailing whitespace
  2043. and turn any <a whatever...> into just <a> and any </tag>
  2044. into <tag>
  2045. */
  2046. if (!len) {
  2047. return 0;
  2048. }
  2049. while(!done) {
  2050. switch(c) {
  2051. case '<':
  2052. *(n++) = c;
  2053. break;
  2054. case '>':
  2055. done =1;
  2056. break;
  2057. default:
  2058. if(!isspace((int)c)) {
  2059. if(state==0) {
  2060. state=1;
  2061. if(c!='/') *(n++) = c;
  2062. } else {
  2063. *(n++) = c;
  2064. }
  2065. } else {
  2066. if(state==1) done=1;
  2067. }
  2068. break;
  2069. }
  2070. c = tolower(*(++t));
  2071. }
  2072. *(n++) = '>';
  2073. *n = '\0';
  2074. if(strstr(set,norm)) {
  2075. done=1;
  2076. } else {
  2077. done=0;
  2078. }
  2079. efree(norm);
  2080. return done;
  2081. }
  2082. /* A simple little state-machine to strip out html and php tags
  2083. State 0 is the output state, State 1 means we are inside a
  2084. normal html tag and state 2 means we are inside a php tag.
  2085. The state variable is passed in to allow a function like fgetss
  2086. to maintain state across calls to the function.
  2087. lc holds the last significant character read and br is a bracket
  2088. counter.
  2089. When an allow string is passed in we keep track of the string
  2090. in state 1 and when the tag is closed check it against the
  2091. allow string to see if we should allow it.
  2092. */
  2093. PHPAPI void php_strip_tags(char *rbuf, int len, int state, char *allow, int allow_len)
  2094. {
  2095. char *tbuf, *buf, *p, *tp, *rp, c, lc;
  2096. int br, i=0;
  2097. buf = estrndup(rbuf,len);
  2098. c = *buf;
  2099. lc = '\0';
  2100. p = buf;
  2101. rp = rbuf;
  2102. br = 0;
  2103. if(allow) {
  2104. php_strtolower(allow, allow_len);
  2105. tbuf = emalloc(PHP_TAG_BUF_SIZE+1);
  2106. tp = tbuf;
  2107. } else {
  2108. tbuf = tp = NULL;
  2109. }
  2110. while(i<len) {
  2111. switch (c) {
  2112. case '<':
  2113. if (state == 0) {
  2114. lc = '<';
  2115. state = 1;
  2116. if(allow) {
  2117. *(tp++) = '<';
  2118. }
  2119. }
  2120. break;
  2121. case '(':
  2122. if (state == 2) {
  2123. if (lc != '\"') {
  2124. lc = '(';
  2125. br++;
  2126. }
  2127. } else if (state == 0) {
  2128. *(rp++) = c;
  2129. }
  2130. break;
  2131. case ')':
  2132. if (state == 2) {
  2133. if (lc != '\"') {
  2134. lc = ')';
  2135. br--;
  2136. }
  2137. } else if (state == 0) {
  2138. *(rp++) = c;
  2139. }
  2140. break;
  2141. case '>':
  2142. if (state == 1) {
  2143. lc = '>';
  2144. state = 0;
  2145. if(allow) {
  2146. *(tp++) = '>';
  2147. *tp='\0';
  2148. if(php_tag_find(tbuf, tp-tbuf, allow)) {
  2149. memcpy(rp,tbuf,tp-tbuf);
  2150. rp += tp-tbuf;
  2151. }
  2152. tp = tbuf;
  2153. }
  2154. } else if (state == 2) {
  2155. if (!br && lc != '\"' && *(p-1)=='?') {
  2156. state = 0;
  2157. }
  2158. }
  2159. break;
  2160. case '\"':
  2161. if (state == 2) {
  2162. if (lc == '\"') {
  2163. lc = '\0';
  2164. } else if (lc != '\\') {
  2165. lc = '\"';
  2166. }
  2167. } else if (state == 0) {
  2168. *(rp++) = c;
  2169. } else if (allow && state == 1) {
  2170. *(tp++) = c;
  2171. }
  2172. break;
  2173. case '?':
  2174. if (state==1 && *(p-1)=='<') {
  2175. br=0;
  2176. state=2;
  2177. break;
  2178. }
  2179. /* fall-through */
  2180. default:
  2181. if (state == 0) {
  2182. *(rp++) = c;
  2183. } else if(allow && state == 1) {
  2184. *(tp++) = c;
  2185. if( (tp-tbuf)>=PHP_TAG_BUF_SIZE ) { /* no buffer overflows */
  2186. tp = tbuf;
  2187. }
  2188. }
  2189. break;
  2190. }
  2191. c = *(++p);
  2192. i++;
  2193. }
  2194. *rp = '\0';
  2195. efree(buf);
  2196. if(allow) efree(tbuf);
  2197. }
  2198. /* {{{ proto string str_repeat(string input, int mult)
  2199. Returns the input string repeat mult times */
  2200. PHP_FUNCTION(str_repeat)
  2201. {
  2202. zval **input_str; /* Input string */
  2203. zval **mult; /* Multiplier */
  2204. char *result; /* Resulting string */
  2205. int result_len; /* Length of the resulting string */
  2206. int i;
  2207. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &input_str, &mult) == FAILURE) {
  2208. WRONG_PARAM_COUNT;
  2209. }
  2210. /* Make sure we're dealing with proper types */
  2211. convert_to_string_ex(input_str);
  2212. convert_to_long_ex(mult);
  2213. if ((*mult)->value.lval < 1) {
  2214. php_error(E_WARNING, "Second argument to %s() has to be greater than 0",
  2215. get_active_function_name());
  2216. return;
  2217. }
  2218. /* Don't waste our time if it's empty */
  2219. if ((*input_str)->value.str.len == 0)
  2220. RETURN_STRINGL(empty_string, 0, 1);
  2221. /* Initialize the result string */
  2222. result_len = (*input_str)->value.str.len * (*mult)->value.lval;
  2223. result = (char *)emalloc(result_len + 1);
  2224. /* Copy the input string into the result as many times as necessary */
  2225. for (i=0; i<(*mult)->value.lval; i++) {
  2226. memcpy(result + (*input_str)->value.str.len * i,
  2227. (*input_str)->value.str.val,
  2228. (*input_str)->value.str.len);
  2229. }
  2230. result[result_len] = '\0';
  2231. RETURN_STRINGL(result, result_len, 0);
  2232. }
  2233. /* }}} */
  2234. /* {{{ proto mixed count_chars(string input [, int mode])
  2235. Returns info about what characters are used in input */
  2236. PHP_FUNCTION(count_chars)
  2237. {
  2238. zval **input, **mode;
  2239. int chars[256];
  2240. int ac=ZEND_NUM_ARGS();
  2241. int mymode=0;
  2242. unsigned char *buf;
  2243. int len, inx;
  2244. char retstr[256];
  2245. int retlen=0;
  2246. if (ac < 1 || ac > 2 || zend_get_parameters_ex(ac, &input, &mode) == FAILURE) {
  2247. WRONG_PARAM_COUNT;
  2248. }
  2249. convert_to_string_ex(input);
  2250. if (ac == 2) {
  2251. convert_to_long_ex(mode);
  2252. mymode = (*mode)->value.lval;
  2253. if (mymode < 0 || mymode > 4) {
  2254. php_error(E_WARNING, "unknown mode");
  2255. RETURN_FALSE;
  2256. }
  2257. }
  2258. len = (*input)->value.str.len;
  2259. buf = (unsigned char *) (*input)->value.str.val;
  2260. memset((void*) chars,0,sizeof(chars));
  2261. while (len > 0) {
  2262. chars[*buf]++;
  2263. buf++;
  2264. len--;
  2265. }
  2266. if (mymode < 3) {
  2267. array_init(return_value);
  2268. }
  2269. for (inx=0; inx < 255; inx++) {
  2270. switch (mymode) {
  2271. case 0:
  2272. add_index_long(return_value,inx,chars[inx]);
  2273. break;
  2274. case 1:
  2275. if (chars[inx] != 0) {
  2276. add_index_long(return_value,inx,chars[inx]);
  2277. }
  2278. break;
  2279. case 2:
  2280. if (chars[inx] == 0) {
  2281. add_index_long(return_value,inx,chars[inx]);
  2282. }
  2283. break;
  2284. case 3:
  2285. if (chars[inx] != 0) {
  2286. retstr[retlen++] = inx;
  2287. }
  2288. break;
  2289. case 4:
  2290. if (chars[inx] == 0) {
  2291. retstr[retlen++] = inx;
  2292. }
  2293. break;
  2294. }
  2295. }
  2296. if (mymode >= 3 && mymode <= 4) {
  2297. RETURN_STRINGL(retstr,retlen,1);
  2298. }
  2299. }
  2300. /* }}} */
  2301. static void php_strnatcmp(INTERNAL_FUNCTION_PARAMETERS, int fold_case)
  2302. {
  2303. zval **s1, **s2;
  2304. if (ZEND_NUM_ARGS()!=2 || zend_get_parameters_ex(2, &s1, &s2) == FAILURE) {
  2305. WRONG_PARAM_COUNT;
  2306. }
  2307. convert_to_string_ex(s1);
  2308. convert_to_string_ex(s2);
  2309. RETURN_LONG(strnatcmp_ex((*s1)->value.str.val, (*s1)->value.str.len,
  2310. (*s2)->value.str.val, (*s2)->value.str.len,
  2311. fold_case));
  2312. }
  2313. /* {{{ proto int strnatcmp(string s1, string s2)
  2314. Returns the result of string comparison using 'natural' algorithm */
  2315. PHP_FUNCTION(strnatcmp)
  2316. {
  2317. php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
  2318. }
  2319. /* }}} */
  2320. /* {{{ proto int strnatcasecmp(string s1, string s2)
  2321. Returns the result of case-insensitive string comparison using 'natural' algorithm */
  2322. PHP_FUNCTION(strnatcasecmp)
  2323. {
  2324. php_strnatcmp(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
  2325. }
  2326. /* }}} */
  2327. /* {{{ proto int substr_count(string haystack, string needle)
  2328. Returns the number of times a substring occurs in the string. */
  2329. PHP_FUNCTION(substr_count)
  2330. {
  2331. zval **haystack, **needle;
  2332. int i, length, count = 0;
  2333. char *p, *endp, cmp;
  2334. if (ZEND_NUM_ARGS() != 2 || zend_get_parameters_ex(2, &haystack, &needle) == FAILURE) {
  2335. WRONG_PARAM_COUNT;
  2336. }
  2337. convert_to_string_ex(haystack);
  2338. convert_to_string_ex(needle);
  2339. if ((*needle)->value.str.len == 0) {
  2340. php_error(E_WARNING, "Empty substring");
  2341. RETURN_FALSE;
  2342. } else if ((*needle)->value.str.len == 1) {
  2343. /* Special optimized case to avoid calls to php_memnstr(). */
  2344. for (i = 0, p = (*haystack)->value.str.val,
  2345. length = (*haystack)->value.str.len, cmp = (*needle)->value.str.val[0];
  2346. i < length; i++) {
  2347. if (p[i] == cmp) {
  2348. count++;
  2349. }
  2350. }
  2351. } else {
  2352. p = (*haystack)->value.str.val;
  2353. endp = p + (*haystack)->value.str.len;
  2354. while (p <= endp) {
  2355. if( (p = php_memnstr(p, (*needle)->value.str.val, (*needle)->value.str.len, endp)) != NULL ) {
  2356. p += (*needle)->value.str.len;
  2357. count++;
  2358. } else {
  2359. break;
  2360. }
  2361. }
  2362. }
  2363. RETURN_LONG(count);
  2364. }
  2365. /* }}} */
  2366. /* {{{ proto string str_pad(string input, int pad_length [, string pad_string [, int pad_type]])
  2367. Returns input string padded on the left or right to specified length with pad_string */
  2368. PHP_FUNCTION(str_pad)
  2369. {
  2370. /* Input arguments */
  2371. zval **input, /* Input string */
  2372. **pad_length, /* Length to pad to */
  2373. **pad_string, /* Padding string */
  2374. **pad_type; /* Padding type (left/right/both) */
  2375. /* Helper variables */
  2376. int num_pad_chars; /* Number of padding characters (total - input size) */
  2377. char *result = NULL; /* Resulting string */
  2378. int result_len = 0; /* Length of the resulting string */
  2379. char *pad_str_val = " "; /* Pointer to padding string */
  2380. int pad_str_len = 1; /* Length of the padding string */
  2381. int pad_type_val = STR_PAD_RIGHT; /* The padding type value */
  2382. int i, left_pad=0, right_pad=0;
  2383. if (ZEND_NUM_ARGS() < 2 || ZEND_NUM_ARGS() > 4 ||
  2384. zend_get_parameters_ex(ZEND_NUM_ARGS(), &input, &pad_length, &pad_string, &pad_type) == FAILURE) {
  2385. WRONG_PARAM_COUNT;
  2386. }
  2387. /* Perform initial conversion to expected data types. */
  2388. convert_to_string_ex(input);
  2389. convert_to_long_ex(pad_length);
  2390. num_pad_chars = Z_LVAL_PP(pad_length) - Z_STRLEN_PP(input);
  2391. /* If resulting string turns out to be shorter than input string,
  2392. we simply copy the input and return. */
  2393. if (num_pad_chars < 0) {
  2394. *return_value = **input;
  2395. zval_copy_ctor(return_value);
  2396. return;
  2397. }
  2398. /* Setup the padding string values if specified. */
  2399. if (ZEND_NUM_ARGS() > 2) {
  2400. convert_to_string_ex(pad_string);
  2401. if (Z_STRLEN_PP(pad_string) == 0) {
  2402. php_error(E_WARNING, "Padding string cannot be empty in %s()",
  2403. get_active_function_name());
  2404. return;
  2405. }
  2406. pad_str_val = Z_STRVAL_PP(pad_string);
  2407. pad_str_len = Z_STRLEN_PP(pad_string);
  2408. if (ZEND_NUM_ARGS() > 3) {
  2409. convert_to_long_ex(pad_type);
  2410. pad_type_val = Z_LVAL_PP(pad_type);
  2411. if (pad_type_val < STR_PAD_LEFT || pad_type_val > STR_PAD_BOTH) {
  2412. php_error(E_WARNING, "Padding type has to be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH in %s()", get_active_function_name());
  2413. return;
  2414. }
  2415. }
  2416. }
  2417. result = (char *)emalloc(Z_STRLEN_PP(input) + num_pad_chars + 1);
  2418. /* We need to figure out the left/right padding lengths. */
  2419. switch (pad_type_val) {
  2420. case STR_PAD_RIGHT:
  2421. left_pad = 0;
  2422. right_pad = num_pad_chars;
  2423. break;
  2424. case STR_PAD_LEFT:
  2425. left_pad = num_pad_chars;
  2426. right_pad = 0;
  2427. break;
  2428. case STR_PAD_BOTH:
  2429. left_pad = num_pad_chars / 2;
  2430. right_pad = num_pad_chars - left_pad;
  2431. break;
  2432. }
  2433. /* First we pad on the left. */
  2434. for (i = 0; i < left_pad; i++)
  2435. result[result_len++] = pad_str_val[i % pad_str_len];
  2436. /* Then we copy the input string. */
  2437. memcpy(result + result_len, Z_STRVAL_PP(input), Z_STRLEN_PP(input));
  2438. result_len += Z_STRLEN_PP(input);
  2439. /* Finally, we pad on the right. */
  2440. for (i = 0; i < right_pad; i++)
  2441. result[result_len++] = pad_str_val[i % pad_str_len];
  2442. result[result_len] = '\0';
  2443. RETURN_STRINGL(result, result_len, 0);
  2444. }
  2445. /* }}} */
  2446. /* {{{ proto mixed sscanf(string str, string format [, string ...])
  2447. Implements an ANSI C compatible sscanf */
  2448. PHP_FUNCTION(sscanf)
  2449. {
  2450. zval **format;
  2451. zval **literal;
  2452. int result;
  2453. zval ***args;
  2454. int argCount;
  2455. argCount = ZEND_NUM_ARGS();
  2456. if (argCount < 2) {
  2457. WRONG_PARAM_COUNT;
  2458. }
  2459. args = (zval ***)emalloc(argCount * sizeof(zval **));
  2460. if (!args || (zend_get_parameters_array_ex(argCount,args) == FAILURE)) {
  2461. efree( args );
  2462. WRONG_PARAM_COUNT;
  2463. }
  2464. literal = args[0];
  2465. format = args[1];
  2466. convert_to_string_ex( format );
  2467. convert_to_string_ex( literal );
  2468. result = php_sscanf_internal( (*literal)->value.str.val,
  2469. (*format)->value.str.val,
  2470. argCount,args,
  2471. 2,&return_value);
  2472. efree(args);
  2473. if (SCAN_ERROR_WRONG_PARAM_COUNT == result) {
  2474. WRONG_PARAM_COUNT;
  2475. }
  2476. }
  2477. /* }}} */
  2478. /*
  2479. * Local variables:
  2480. * tab-width: 4
  2481. * c-basic-offset: 4
  2482. * End:
  2483. */