PageRenderTime 38ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/2.1/Source/ExtSupport/PHP4/Variables.cpp

#
C++ | 3574 lines | 2902 code | 469 blank | 203 comment | 661 complexity | ccf186d0a57acaa894deee49e80d345c MD5 | raw file
Possible License(s): CPL-1.0, GPL-2.0, CC-BY-SA-3.0, MPL-2.0-no-copyleft-exception, Apache-2.0
  1. //
  2. // ExtSupport.PHP4 - substitute for php4ts.dll
  3. //
  4. // Variables.cpp
  5. // - contains definitions of variables related functions
  6. //
  7. #include "stdafx.h"
  8. #include "Variables.h"
  9. #include "Helpers.h"
  10. #include "ExtSupport.h"
  11. #include "Memory.h"
  12. #include "Errors.h"
  13. #include "Hash.h"
  14. #include "Resources.h"
  15. #include "TsrmLs.h"
  16. #include "Request.h"
  17. #include "Constants.h"
  18. #include "Unsupported.h"
  19. #include "Spprintf.h"
  20. #include "Parameters.h"
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <limits.h>
  24. #include <math.h>
  25. using namespace System;
  26. using namespace PHP::ExtManager;
  27. #pragma unmanaged
  28. static inline char *
  29. zend_str_tolower_dup(const char *source, unsigned int length)
  30. {
  31. return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
  32. }
  33. char *empty_string = ""; /* in order to save emalloc() and efree() time for
  34. * empty strings (usually used to denote empty
  35. * return values in failed functions).
  36. * The macro STR_FREE() will not efree() it.
  37. */
  38. #define LONG_SIGN_MASK (1L << (8*sizeof(long)-1))
  39. #define zend_strtod(str, endptr) strtod(str, endptr)
  40. zval zval_used_for_init = { NULL, IS_NULL, 0, 1 };
  41. zend_utility_values zend_uv = { ".php", 4, 1 };
  42. // copied from zend_API.c and slightly modified
  43. #define zendi_convert_scalar_to_number(op, holder, result) \
  44. if (op==result) { \
  45. convert_scalar_to_number(op TSRMLS_CC); \
  46. } else { \
  47. switch ((op)->type) { \
  48. case IS_STRING: \
  49. { \
  50. switch (((holder).type=is_numeric_string((op)->value.str.val, (op)->value.str.len, &(holder).value.lval, &(holder).value.dval, 1))) { \
  51. case IS_DOUBLE: \
  52. case IS_LONG: \
  53. break; \
  54. default: \
  55. (holder).value.lval = strtol((op)->value.str.val, NULL, 10); \
  56. (holder).type = IS_LONG; \
  57. break; \
  58. } \
  59. (op) = &(holder); \
  60. break; \
  61. } \
  62. case IS_BOOL: \
  63. case IS_RESOURCE: \
  64. (holder).value.lval = (op)->value.lval; \
  65. (holder).type = IS_LONG; \
  66. (op) = &(holder); \
  67. break; \
  68. case IS_NULL: \
  69. (holder).value.lval = 0; \
  70. (holder).type = IS_LONG; \
  71. (op) = &(holder); \
  72. break; \
  73. } \
  74. }
  75. // copied from zend_API.c
  76. #define DVAL_TO_LVAL(d, l) (l) = (d) > LONG_MAX ? (unsigned long) (d) : (long) (d)
  77. // copied from zend_API.c
  78. #define zendi_convert_to_long(op, holder, result) \
  79. if (op==result) { \
  80. convert_to_long(op); \
  81. } else if ((op)->type != IS_LONG) { \
  82. switch ((op)->type) { \
  83. case IS_NULL: \
  84. (holder).value.lval = 0; \
  85. break; \
  86. case IS_DOUBLE: \
  87. DVAL_TO_LVAL((op)->value.dval, (holder).value.lval); \
  88. break; \
  89. case IS_STRING: \
  90. (holder).value.lval = strtol((op)->value.str.val, NULL, 10); \
  91. break; \
  92. case IS_ARRAY: \
  93. (holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \
  94. break; \
  95. case IS_OBJECT: \
  96. (holder).value.lval = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0); \
  97. break; \
  98. case IS_BOOL: \
  99. case IS_RESOURCE: \
  100. (holder).value.lval = (op)->value.lval; \
  101. break; \
  102. default: \
  103. zend_error(E_WARNING, "Cannot convert to ordinal value"); \
  104. (holder).value.lval = 0; \
  105. break; \
  106. } \
  107. (holder).type = IS_LONG; \
  108. (op) = &(holder); \
  109. }
  110. // copied from zend_API.c
  111. #define zendi_convert_to_boolean(op, holder, result) \
  112. if (op==result) { \
  113. convert_to_boolean(op); \
  114. } else if ((op)->type != IS_BOOL) { \
  115. switch ((op)->type) { \
  116. case IS_NULL: \
  117. (holder).value.lval = 0; \
  118. break; \
  119. case IS_RESOURCE: \
  120. case IS_LONG: \
  121. (holder).value.lval = ((op)->value.lval ? 1 : 0); \
  122. break; \
  123. case IS_DOUBLE: \
  124. (holder).value.lval = ((op)->value.dval ? 1 : 0); \
  125. break; \
  126. case IS_STRING: \
  127. if ((op)->value.str.len == 0 \
  128. || ((op)->value.str.len==1 && (op)->value.str.val[0]=='0')) { \
  129. (holder).value.lval = 0; \
  130. } else { \
  131. (holder).value.lval = 1; \
  132. } \
  133. break; \
  134. case IS_ARRAY: \
  135. (holder).value.lval = (zend_hash_num_elements((op)->value.ht)?1:0); \
  136. break; \
  137. case IS_OBJECT: \
  138. (holder).value.lval = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0); \
  139. break; \
  140. default: \
  141. (holder).value.lval = 0; \
  142. break; \
  143. } \
  144. (holder).type = IS_BOOL; \
  145. (op) = &(holder); \
  146. }
  147. // copied from zend_API.c and beautified
  148. ZEND_API char *zend_zval_type_name(zval *arg)
  149. {
  150. switch (arg->type)
  151. {
  152. case IS_NULL: return "null";
  153. case IS_LONG: return "integer";
  154. case IS_DOUBLE: return "double";
  155. case IS_STRING: return "string";
  156. case IS_ARRAY: return "array";
  157. case IS_OBJECT: return "object";
  158. case IS_BOOL: return "boolean";
  159. case IS_RESOURCE: return "resource";
  160. default: return "unknown";
  161. }
  162. }
  163. // copied from zend_variables.c, slightly modified and beautified
  164. #ifdef PHP4TS
  165. ZEND_API int _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
  166. {
  167. switch (zvalue->type)
  168. {
  169. case IS_RESOURCE: {
  170. TSRMLS_FETCH();
  171. _zend_list_addref(zvalue->value.lval, tsrm_ls);
  172. }
  173. break;
  174. case IS_BOOL:
  175. case IS_LONG:
  176. case IS_NULL: break;
  177. case IS_CONSTANT:
  178. case IS_STRING: if (zvalue->value.str.val)
  179. {
  180. if (zvalue->value.str.len==0)
  181. {
  182. zvalue->value.str.val = empty_string;
  183. return SUCCESS;
  184. }
  185. }
  186. CHECK_ZVAL_STRING_REL(zvalue);
  187. zvalue->value.str.val = (char *)estrndup_rel(zvalue->value.str.val, zvalue->value.str.len);
  188. break;
  189. case IS_ARRAY:
  190. case IS_CONSTANT_ARRAY:
  191. {
  192. zval *tmp;
  193. HashTable *original_ht = zvalue->value.ht;
  194. TSRMLS_FETCH();
  195. if (zvalue->value.ht == &EG(symbol_table)) return SUCCESS;
  196. ALLOC_HASHTABLE_REL(zvalue->value.ht);
  197. zend_hash_init(zvalue->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
  198. zend_hash_copy(zvalue->value.ht, original_ht, (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *));
  199. }
  200. break;
  201. case IS_OBJECT: {
  202. zval *tmp;
  203. HashTable *original_ht = Z_OBJPROP_P(zvalue);
  204. TSRMLS_FETCH();
  205. if (original_ht == &EG(symbol_table)) return SUCCESS; /* do nothing */
  206. ALLOC_HASHTABLE_REL(Z_OBJPROP_P(zvalue));
  207. zend_hash_init(Z_OBJPROP_P(zvalue), 0, NULL, ZVAL_PTR_DTOR, 0);
  208. zend_hash_copy(Z_OBJPROP_P(zvalue), original_ht,
  209. (copy_ctor_func_t)zval_add_ref, (void *) &tmp, sizeof(zval *));
  210. }
  211. break;
  212. }
  213. return SUCCESS;
  214. }
  215. #elif defined(PHP5TS)
  216. ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC)
  217. {
  218. switch (zvalue->type) {
  219. case IS_RESOURCE: {
  220. TSRMLS_FETCH();
  221. zend_list_addref(zvalue->value.lval);
  222. }
  223. break;
  224. case IS_BOOL:
  225. case IS_LONG:
  226. case IS_NULL:
  227. break;
  228. case IS_CONSTANT:
  229. case IS_STRING:
  230. CHECK_ZVAL_STRING_REL(zvalue);
  231. zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len);
  232. break;
  233. case IS_ARRAY:
  234. case IS_CONSTANT_ARRAY: {
  235. zval *tmp;
  236. HashTable *original_ht = zvalue->value.ht;
  237. HashTable *tmp_ht = NULL;
  238. TSRMLS_FETCH();
  239. if (zvalue->value.ht == &EG(symbol_table)) {
  240. return; /* do nothing */
  241. }
  242. ALLOC_HASHTABLE_REL(tmp_ht);
  243. zend_hash_init(tmp_ht, zend_hash_num_elements(original_ht), NULL, ZVAL_PTR_DTOR, 0);
  244. zend_hash_copy(tmp_ht, original_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
  245. zvalue->value.ht = tmp_ht;
  246. }
  247. break;
  248. case IS_OBJECT:
  249. {
  250. TSRMLS_FETCH();
  251. Z_OBJ_HT_P(zvalue)->add_ref(zvalue TSRMLS_CC);
  252. }
  253. break;
  254. }
  255. }
  256. #endif
  257. #pragma managed
  258. // copied from zend_variables.c, slightly modified and beautified
  259. #ifdef PHP4TS
  260. ZEND_API void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC)
  261. {
  262. if (zvalue->type == IS_LONG) return;
  263. switch (zvalue->type & ~IS_CONSTANT_INDEX)
  264. {
  265. case IS_STRING:
  266. case IS_CONSTANT: CHECK_ZVAL_STRING_REL(zvalue);
  267. STR_FREE_REL(zvalue->value.str.val);
  268. break;
  269. case IS_ARRAY:
  270. case IS_CONSTANT_ARRAY:
  271. {
  272. TSRMLS_FETCH();
  273. if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table)))
  274. {
  275. zend_hash_destroy(zvalue->value.ht);
  276. FREE_HASHTABLE(zvalue->value.ht);
  277. }
  278. }
  279. break;
  280. case IS_OBJECT: {
  281. TSRMLS_FETCH();
  282. zend_hash_destroy(Z_OBJPROP_P(zvalue));
  283. FREE_HASHTABLE(Z_OBJPROP_P(zvalue));
  284. }
  285. break;
  286. case IS_RESOURCE: {
  287. // NEVER DESTROY RESOURCES LIKE THIS - causes many problems
  288. // destroy resource
  289. //if (Request::GetCurrentRequest()->DontDestroyResources == false)
  290. //{
  291. // TSRMLS_FETCH();
  292. // _zend_list_delete(zvalue->value.lval, tsrm_ls);
  293. //}
  294. }
  295. break;
  296. case IS_LONG: case IS_DOUBLE:
  297. case IS_BOOL: case IS_NULL:
  298. default:
  299. return;
  300. }
  301. }
  302. #elif defined(PHP5TS)
  303. ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC)
  304. {
  305. switch (zvalue->type & ~IS_CONSTANT_INDEX) {
  306. case IS_STRING:
  307. case IS_CONSTANT:
  308. CHECK_ZVAL_STRING_REL(zvalue);
  309. STR_FREE_REL(zvalue->value.str.val);
  310. break;
  311. case IS_ARRAY:
  312. case IS_CONSTANT_ARRAY: {
  313. TSRMLS_FETCH();
  314. if (zvalue->value.ht && (zvalue->value.ht != &EG(symbol_table))) {
  315. zend_hash_destroy(zvalue->value.ht);
  316. FREE_HASHTABLE(zvalue->value.ht);
  317. }
  318. }
  319. break;
  320. case IS_OBJECT:
  321. {
  322. TSRMLS_FETCH();
  323. Z_OBJ_HT_P(zvalue)->del_ref(zvalue TSRMLS_CC);
  324. }
  325. break;
  326. case IS_RESOURCE:
  327. {
  328. // NEVER DESTROY RESOURCES LIKE THIS - causes many problems
  329. // destroy resource
  330. //if (Request::GetCurrentRequest()->DontDestroyResources == false)
  331. //{
  332. //TSRMLS_FETCH();
  333. ///* destroy resource */
  334. //zend_list_delete(zvalue->value.lval);
  335. //}
  336. }
  337. break;
  338. case IS_LONG:
  339. case IS_DOUBLE:
  340. case IS_BOOL:
  341. case IS_NULL:
  342. default:
  343. return;
  344. break;
  345. }
  346. }
  347. #endif
  348. #pragma unmanaged
  349. // copied from zend_variables.c and beautified
  350. ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC)
  351. {
  352. switch (zvalue->type & ~IS_CONSTANT_INDEX)
  353. {
  354. case IS_STRING:
  355. case IS_CONSTANT:
  356. CHECK_ZVAL_STRING_REL(zvalue);
  357. if (zvalue->value.str.val != empty_string) free(zvalue->value.str.val);
  358. break;
  359. case IS_ARRAY:
  360. case IS_CONSTANT_ARRAY:
  361. case IS_OBJECT:
  362. case IS_RESOURCE:
  363. zend_error(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
  364. break;
  365. case IS_LONG:
  366. case IS_DOUBLE:
  367. case IS_BOOL:
  368. case IS_NULL:
  369. default:
  370. break;
  371. }
  372. }
  373. // copied from zend_execute.h, slightly modified and beautified
  374. static inline void safe_free_zval_ptr(zval *p)
  375. {
  376. TSRMLS_FETCH();
  377. if (p != EG(uninitialized_zval_ptr))
  378. {
  379. FREE_ZVAL(p);
  380. }
  381. }
  382. // copied from zend_execute_API.c, slightly modified and beautified
  383. ZEND_API void _zval_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC)
  384. {
  385. (*zval_ptr)->refcount--;
  386. if ((*zval_ptr)->refcount == 0)
  387. {
  388. zval_dtor(*zval_ptr);
  389. safe_free_zval_ptr(*zval_ptr);
  390. }
  391. else if (((*zval_ptr)->refcount == 1) && ((*zval_ptr)->type != IS_OBJECT))
  392. {
  393. (*zval_ptr)->is_ref = 0;
  394. }
  395. }
  396. // copied from zend_execute_API.c, slightly modified and beautified
  397. ZEND_API void _zval_internal_ptr_dtor(zval **zval_ptr ZEND_FILE_LINE_DC)
  398. {
  399. (*zval_ptr)->refcount--;
  400. if ((*zval_ptr)->refcount == 0)
  401. {
  402. zval_internal_dtor(*zval_ptr);
  403. free(*zval_ptr);
  404. }
  405. else if ((*zval_ptr)->refcount == 1) (*zval_ptr)->is_ref = 0;
  406. }
  407. // copied from zend_variables.c
  408. ZEND_API void zval_add_ref(zval **p)
  409. {
  410. (*p)->refcount++;
  411. }
  412. // copied from zend_operators.c, slightly modified and beautified
  413. #ifdef PHP4TS
  414. ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC)
  415. {
  416. switch (op->type)
  417. {
  418. case IS_STRING:
  419. {
  420. char *strval;
  421. strval = op->value.str.val;
  422. switch ((op->type = is_numeric_string(strval, op->value.str.len, &op->value.lval, &op->value.dval, 1)))
  423. {
  424. case IS_DOUBLE:
  425. case IS_LONG:
  426. break;
  427. default:
  428. op->value.lval = strtol(op->value.str.val, NULL, 10);
  429. op->type = IS_LONG;
  430. break;
  431. }
  432. STR_FREE(strval);
  433. break;
  434. }
  435. case IS_BOOL: op->type = IS_LONG;
  436. break;
  437. case IS_RESOURCE: _zend_list_delete(op->value.lval, tsrm_ls);
  438. op->type = IS_LONG;
  439. break;
  440. case IS_NULL: op->type = IS_LONG;
  441. op->value.lval = 0;
  442. break;
  443. }
  444. }
  445. // copied from zend_operators.c and beautified
  446. static void convert_scalar_to_array(zval *op, int type)
  447. {
  448. zval *entry;
  449. ALLOC_ZVAL(entry);
  450. *entry = *op;
  451. INIT_PZVAL(entry);
  452. switch (type)
  453. {
  454. case IS_ARRAY:
  455. ALLOC_HASHTABLE(op->value.ht);
  456. zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
  457. zend_hash_index_update(op->value.ht, 0, (void *) &entry, sizeof(zval *), NULL);
  458. op->type = IS_ARRAY;
  459. break;
  460. case IS_OBJECT:
  461. ALLOC_HASHTABLE(Z_OBJPROP_P(op));
  462. zend_hash_init(Z_OBJPROP_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
  463. zend_hash_update(Z_OBJPROP_P(op), "scalar", sizeof("scalar"), (void *)&entry, sizeof(zval *), NULL);
  464. Z_OBJCE_P(op) = &zend_standard_class_def;
  465. Z_TYPE_P(op) = IS_OBJECT;
  466. break;
  467. }
  468. }
  469. // copied from zend_operators.c, slightly modified and beautified
  470. ZEND_API void convert_to_array(zval *op)
  471. {
  472. TSRMLS_FETCH();
  473. switch(op->type)
  474. {
  475. case IS_ARRAY: return;
  476. /* OBJECTS_OPTIMIZE */
  477. case IS_OBJECT:
  478. op->type = IS_ARRAY;
  479. op->value.ht = Z_OBJPROP_P(op);
  480. return;
  481. case IS_NULL: ALLOC_HASHTABLE(op->value.ht);
  482. zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
  483. op->type = IS_ARRAY;
  484. break;
  485. default: convert_scalar_to_array(op, IS_ARRAY);
  486. break;
  487. }
  488. }
  489. // copied from zend_operators.c and beautified
  490. ZEND_API void convert_to_boolean(zval *op)
  491. {
  492. char *strval;
  493. int tmp;
  494. switch (op->type)
  495. {
  496. case IS_BOOL:
  497. break;
  498. case IS_NULL:
  499. op->value.lval = 0;
  500. break;
  501. case IS_RESOURCE:
  502. {
  503. TSRMLS_FETCH();
  504. zend_list_delete(op->value.lval);
  505. }
  506. /* break missing intentionally */
  507. case IS_LONG:
  508. op->value.lval = (op->value.lval ? 1 : 0);
  509. break;
  510. case IS_DOUBLE:
  511. op->value.lval = (op->value.dval ? 1 : 0);
  512. break;
  513. case IS_STRING:
  514. strval = op->value.str.val;
  515. if (op->value.str.len == 0 || (op->value.str.len == 1 && op->value.str.val[0] == '0')) op->value.lval = 0;
  516. else op->value.lval = 1;
  517. STR_FREE(strval);
  518. break;
  519. case IS_ARRAY:
  520. tmp = (zend_hash_num_elements(op->value.ht) ? 1 : 0);
  521. zval_dtor(op);
  522. op->value.lval = tmp;
  523. break;
  524. case IS_OBJECT:
  525. tmp = (zend_hash_num_elements(Z_OBJPROP_P(op)) ? 1 : 0);
  526. zval_dtor(op);
  527. op->value.lval = tmp;
  528. break;
  529. default:
  530. zval_dtor(op);
  531. op->value.lval = 0;
  532. break;
  533. }
  534. op->type = IS_BOOL;
  535. }
  536. // copied from zend_operators.c and beautified
  537. ZEND_API void convert_to_double(zval *op)
  538. {
  539. char *strval;
  540. double tmp;
  541. switch (op->type)
  542. {
  543. case IS_NULL:
  544. op->value.dval = 0.0;
  545. break;
  546. case IS_RESOURCE:
  547. {
  548. TSRMLS_FETCH();
  549. zend_list_delete(op->value.lval);
  550. }
  551. /* break missing intentionally */
  552. case IS_BOOL:
  553. case IS_LONG:
  554. op->value.dval = (double)op->value.lval;
  555. break;
  556. case IS_DOUBLE:
  557. break;
  558. case IS_STRING:
  559. strval = op->value.str.val;
  560. op->value.dval = strtod(strval, NULL);
  561. STR_FREE(strval);
  562. break;
  563. case IS_ARRAY:
  564. tmp = (zend_hash_num_elements(op->value.ht) ? 1 : 0);
  565. zval_dtor(op);
  566. op->value.dval = tmp;
  567. break;
  568. case IS_OBJECT:
  569. tmp = (zend_hash_num_elements(Z_OBJPROP_P(op))? 1 : 0);
  570. zval_dtor(op);
  571. op->value.dval = tmp;
  572. break;
  573. default:
  574. zend_error(E_WARNING, "Cannot convert to real value (type=%d)", op->type);
  575. zval_dtor(op);
  576. op->value.dval = 0;
  577. break;
  578. }
  579. op->type = IS_DOUBLE;
  580. }
  581. // copied from zend_operators.c and beautified
  582. ZEND_API void convert_to_long(zval *op)
  583. {
  584. convert_to_long_base(op, 10);
  585. }
  586. // copied from zend_operators.c and beautified
  587. ZEND_API void convert_to_long_base(zval *op, int base)
  588. {
  589. char *strval;
  590. long tmp;
  591. switch (op->type)
  592. {
  593. case IS_NULL:
  594. op->value.lval = 0;
  595. break;
  596. case IS_RESOURCE:
  597. {
  598. TSRMLS_FETCH();
  599. zend_list_delete(op->value.lval);
  600. }
  601. /* break missing intentionally */
  602. case IS_BOOL:
  603. case IS_LONG:
  604. break;
  605. case IS_DOUBLE:
  606. DVAL_TO_LVAL(op->value.dval, op->value.lval);
  607. break;
  608. case IS_STRING:
  609. strval = op->value.str.val;
  610. op->value.lval = strtol(strval, NULL, base);
  611. STR_FREE(strval);
  612. break;
  613. case IS_ARRAY:
  614. tmp = (zend_hash_num_elements(op->value.ht) ? 1 : 0);
  615. zval_dtor(op);
  616. op->value.lval = tmp;
  617. break;
  618. case IS_OBJECT:
  619. tmp = (zend_hash_num_elements(Z_OBJPROP_P(op))?1:0);
  620. zval_dtor(op);
  621. op->value.lval = tmp;
  622. break;
  623. default:
  624. zend_error(E_WARNING, "Cannot convert to ordinal value");
  625. zval_dtor(op);
  626. op->value.lval = 0;
  627. break;
  628. }
  629. op->type = IS_LONG;
  630. }
  631. // copied from zend_operators.c and beautified
  632. ZEND_API void convert_to_null(zval *op)
  633. {
  634. zval_dtor(op);
  635. op->type = IS_NULL;
  636. }
  637. // copied from zend_operators.c, slightly modified and beautified
  638. ZEND_API void convert_to_object(zval *op)
  639. {
  640. switch (op->type)
  641. {
  642. /* OBJECTS_FIXME */
  643. case IS_ARRAY:
  644. Z_TYPE_P(op) = IS_OBJECT;
  645. Z_OBJPROP_P(op) = op->value.ht;
  646. Z_OBJCE_P(op) = &zend_standard_class_def;
  647. return;
  648. case IS_OBJECT:
  649. return;
  650. /* OBJECTS_FIXME */
  651. case IS_NULL:
  652. ALLOC_HASHTABLE(Z_OBJPROP_P(op));
  653. zend_hash_init(Z_OBJPROP_P(op), 0, NULL, ZVAL_PTR_DTOR, 0);
  654. Z_OBJCE_P(op) = &zend_standard_class_def;
  655. Z_TYPE_P(op) = IS_OBJECT;
  656. break;
  657. default:
  658. convert_scalar_to_array(op, IS_OBJECT);
  659. break;
  660. }
  661. }
  662. // copied from zend_operators.c, slightly modified and beautified
  663. ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
  664. {
  665. long lval;
  666. double dval;
  667. TSRMLS_FETCH();
  668. switch (op->type)
  669. {
  670. case IS_NULL: op->value.str.val = empty_string;
  671. op->value.str.len = 0;
  672. break;
  673. case IS_STRING: break;
  674. case IS_BOOL: if (op->value.lval)
  675. {
  676. op->value.str.val = estrndup_rel("1", 1);
  677. op->value.str.len = 1;
  678. }
  679. else
  680. {
  681. op->value.str.val = empty_string;
  682. op->value.str.len = 0;
  683. }
  684. break;
  685. case IS_RESOURCE:
  686. {
  687. long tmp = op->value.lval;
  688. _zend_list_delete(op->value.lval, tsrm_ls);
  689. op->value.str.val = (char *)emalloc(sizeof("Resource id #") - 1 + MAX_LENGTH_OF_LONG);
  690. op->value.str.len = sprintf(op->value.str.val, "Resource id #%ld", tmp);
  691. break;
  692. }
  693. case IS_LONG: lval = op->value.lval;
  694. op->value.str.val = (char *) emalloc_rel(MAX_LENGTH_OF_LONG + 1);
  695. op->value.str.len = zend_sprintf(op->value.str.val, "%ld", lval); /* SAFE */
  696. break;
  697. case IS_DOUBLE: {
  698. dval = op->value.dval;
  699. op->value.str.val = (char *)emalloc_rel(MAX_LENGTH_OF_DOUBLE + EG_precision + 1);
  700. op->value.str.len = zend_sprintf(op->value.str.val, "%.*G", (int)EG_precision, dval); /* SAFE */
  701. /* %G already handles removing trailing zeros from the fractional part, yay */
  702. break;
  703. }
  704. case IS_ARRAY: zval_dtor(op);
  705. op->value.str.val = estrndup_rel("Array", sizeof("Array") - 1);
  706. op->value.str.len = sizeof("Array") - 1;
  707. zend_error(E_NOTICE, "Array to string conversion");
  708. break;
  709. case IS_OBJECT: zval_dtor(op);
  710. op->value.str.val = estrndup_rel("Object", sizeof("Object") - 1);
  711. op->value.str.len = sizeof("Object") - 1;
  712. zend_error(E_NOTICE, "Object to string conversion");
  713. break;
  714. default: zval_dtor(op);
  715. ZVAL_BOOL(op, 0);
  716. break;
  717. }
  718. op->type = IS_STRING;
  719. }
  720. #elif defined(PHP5TS)
  721. #define convert_object_to_type(op, ctype, conv_func) \
  722. if (Z_OBJ_HT_P(op)->cast_object) { \
  723. zval dst; \
  724. if (Z_OBJ_HT_P(op)->cast_object(op, &dst, ctype TSRMLS_CC) == FAILURE) { \
  725. zend_error(E_RECOVERABLE_ERROR, \
  726. "Object of class %s could not be converted to %s", Z_OBJCE_P(op)->name, \
  727. zend_get_type_by_const(ctype)); \
  728. } else { \
  729. zval_dtor(op); \
  730. Z_TYPE_P(op) = ctype; \
  731. op->value = dst.value; \
  732. } \
  733. } else { \
  734. if(Z_OBJ_HT_P(op)->get) { \
  735. zval *newop = Z_OBJ_HT_P(op)->get(op TSRMLS_CC); \
  736. if(Z_TYPE_P(newop) != IS_OBJECT) { \
  737. /* for safety - avoid loop */ \
  738. zval_dtor(op); \
  739. *op = *newop; \
  740. FREE_ZVAL(newop); \
  741. conv_func(op); \
  742. } \
  743. } \
  744. }
  745. /* Argument parsing API -- andrei */
  746. ZEND_API char *zend_get_type_by_const(int type)
  747. {
  748. switch(type) {
  749. case IS_BOOL:
  750. return "boolean";
  751. case IS_LONG:
  752. return "integer";
  753. case IS_DOUBLE:
  754. return "double";
  755. case IS_STRING:
  756. return "string";
  757. case IS_OBJECT:
  758. return "object";
  759. case IS_RESOURCE:
  760. return "resource";
  761. case IS_NULL:
  762. return "null";
  763. case IS_ARRAY:
  764. return "array";
  765. default:
  766. return "unknown";
  767. }
  768. }
  769. ZEND_API void convert_to_long(zval *op)
  770. {
  771. if ((op)->type != IS_LONG) {
  772. convert_to_long_base(op, 10);
  773. }
  774. }
  775. ZEND_API void convert_to_long_base(zval *op, int base)
  776. {
  777. char *strval;
  778. long tmp;
  779. switch (op->type) {
  780. case IS_NULL:
  781. op->value.lval = 0;
  782. break;
  783. case IS_RESOURCE: {
  784. TSRMLS_FETCH();
  785. zend_list_delete(op->value.lval);
  786. }
  787. /* break missing intentionally */
  788. case IS_BOOL:
  789. case IS_LONG:
  790. break;
  791. case IS_DOUBLE:
  792. DVAL_TO_LVAL(op->value.dval, op->value.lval);
  793. break;
  794. case IS_STRING:
  795. strval = op->value.str.val;
  796. op->value.lval = strtol(strval, NULL, base);
  797. STR_FREE(strval);
  798. break;
  799. case IS_ARRAY:
  800. tmp = (zend_hash_num_elements(op->value.ht)?1:0);
  801. zval_dtor(op);
  802. op->value.lval = tmp;
  803. break;
  804. case IS_OBJECT:
  805. {
  806. int retval = 1;
  807. TSRMLS_FETCH();
  808. convert_object_to_type(op, IS_LONG, convert_to_long);
  809. if (op->type == IS_LONG) {
  810. return;
  811. }
  812. if (EG(ze1_compatibility_mode)) {
  813. HashTable *ht = Z_OBJPROP_P(op);
  814. if (ht) {
  815. retval = (zend_hash_num_elements(ht)?1:0);
  816. }
  817. } else {
  818. zend_error(E_NOTICE, "Object of class %s could not be converted to int", Z_OBJCE_P(op)->name);
  819. }
  820. zval_dtor(op);
  821. ZVAL_LONG(op, retval);
  822. return;
  823. }
  824. default:
  825. zend_error(E_WARNING, "Cannot convert to ordinal value");
  826. zval_dtor(op);
  827. op->value.lval = 0;
  828. break;
  829. }
  830. op->type = IS_LONG;
  831. }
  832. ZEND_API void convert_to_double(zval *op)
  833. {
  834. char *strval;
  835. double tmp;
  836. switch (op->type) {
  837. case IS_NULL:
  838. op->value.dval = 0.0;
  839. break;
  840. case IS_RESOURCE: {
  841. TSRMLS_FETCH();
  842. zend_list_delete(op->value.lval);
  843. }
  844. /* break missing intentionally */
  845. case IS_BOOL:
  846. case IS_LONG:
  847. op->value.dval = (double) op->value.lval;
  848. break;
  849. case IS_DOUBLE:
  850. break;
  851. case IS_STRING:
  852. strval = op->value.str.val;
  853. op->value.dval = zend_strtod(strval, NULL);
  854. STR_FREE(strval);
  855. break;
  856. case IS_ARRAY:
  857. tmp = (zend_hash_num_elements(op->value.ht)?1:0);
  858. zval_dtor(op);
  859. op->value.dval = tmp;
  860. break;
  861. case IS_OBJECT:
  862. {
  863. double retval = 1.0;
  864. TSRMLS_FETCH();
  865. convert_object_to_type(op, IS_DOUBLE, convert_to_double);
  866. if (op->type == IS_DOUBLE) {
  867. return;
  868. }
  869. if (EG(ze1_compatibility_mode)) {
  870. HashTable *ht = Z_OBJPROP_P(op);
  871. if (ht) {
  872. retval = (zend_hash_num_elements(ht)?1.0:0.0);
  873. }
  874. } else {
  875. zend_error(E_NOTICE, "Object of class %s could not be converted to double", Z_OBJCE_P(op)->name);
  876. }
  877. zval_dtor(op);
  878. ZVAL_DOUBLE(op, retval);
  879. break;
  880. }
  881. default:
  882. zend_error(E_WARNING, "Cannot convert to real value (type=%d)", op->type);
  883. zval_dtor(op);
  884. op->value.dval = 0;
  885. break;
  886. }
  887. op->type = IS_DOUBLE;
  888. }
  889. ZEND_API void convert_to_null(zval *op)
  890. {
  891. if (Z_TYPE_P(op) == IS_OBJECT) {
  892. if (Z_OBJ_HT_P(op)->cast_object) {
  893. zval *org;
  894. TSRMLS_FETCH();
  895. ALLOC_ZVAL(org);
  896. *org = *op;
  897. if (Z_OBJ_HT_P(op)->cast_object(org, op, IS_NULL TSRMLS_CC) == SUCCESS) {
  898. zval_dtor(org);
  899. return;
  900. }
  901. *op = *org;
  902. FREE_ZVAL(org);
  903. }
  904. }
  905. zval_dtor(op);
  906. Z_TYPE_P(op) = IS_NULL;
  907. }
  908. ZEND_API void convert_to_boolean(zval *op)
  909. {
  910. char *strval;
  911. int tmp;
  912. switch (op->type) {
  913. case IS_BOOL:
  914. break;
  915. case IS_NULL:
  916. op->value.lval = 0;
  917. break;
  918. case IS_RESOURCE: {
  919. TSRMLS_FETCH();
  920. zend_list_delete(op->value.lval);
  921. }
  922. /* break missing intentionally */
  923. case IS_LONG:
  924. op->value.lval = (op->value.lval ? 1 : 0);
  925. break;
  926. case IS_DOUBLE:
  927. op->value.lval = (op->value.dval ? 1 : 0);
  928. break;
  929. case IS_STRING:
  930. strval = op->value.str.val;
  931. if (op->value.str.len == 0
  932. || (op->value.str.len==1 && op->value.str.val[0]=='0')) {
  933. op->value.lval = 0;
  934. } else {
  935. op->value.lval = 1;
  936. }
  937. STR_FREE(strval);
  938. break;
  939. case IS_ARRAY:
  940. tmp = (zend_hash_num_elements(op->value.ht)?1:0);
  941. zval_dtor(op);
  942. op->value.lval = tmp;
  943. break;
  944. case IS_OBJECT:
  945. {
  946. zend_bool retval = 1;
  947. TSRMLS_FETCH();
  948. convert_object_to_type(op, IS_BOOL, convert_to_boolean);
  949. if (op->type == IS_BOOL) {
  950. return;
  951. }
  952. if (EG(ze1_compatibility_mode)) {
  953. HashTable *ht = Z_OBJPROP_P(op);
  954. if (ht) {
  955. retval = (zend_hash_num_elements(ht)?1:0);
  956. }
  957. }
  958. zval_dtor(op);
  959. ZVAL_BOOL(op, retval);
  960. break;
  961. }
  962. default:
  963. zval_dtor(op);
  964. op->value.lval = 0;
  965. break;
  966. }
  967. op->type = IS_BOOL;
  968. }
  969. ZEND_API void _convert_to_string(zval *op ZEND_FILE_LINE_DC)
  970. {
  971. long lval;
  972. double dval;
  973. switch (op->type) {
  974. case IS_NULL:
  975. op->value.str.val = STR_EMPTY_ALLOC();
  976. op->value.str.len = 0;
  977. break;
  978. case IS_STRING:
  979. break;
  980. case IS_BOOL:
  981. if (op->value.lval) {
  982. op->value.str.val = estrndup_rel("1", 1);
  983. op->value.str.len = 1;
  984. } else {
  985. op->value.str.val = STR_EMPTY_ALLOC();
  986. op->value.str.len = 0;
  987. }
  988. break;
  989. case IS_RESOURCE: {
  990. long tmp = op->value.lval;
  991. TSRMLS_FETCH();
  992. zend_list_delete(op->value.lval);
  993. op->value.str.len = zend_spprintf(&op->value.str.val, 0, "Resource id #%ld", tmp);
  994. break;
  995. }
  996. case IS_LONG:
  997. lval = op->value.lval;
  998. op->value.str.len = zend_spprintf(&op->value.str.val, 0, "%ld", lval); /* SAFE */
  999. break;
  1000. case IS_DOUBLE: {
  1001. TSRMLS_FETCH();
  1002. dval = op->value.dval;
  1003. op->value.str.len = zend_spprintf(&op->value.str.val, 0, "%.*G", (int) EG(precision), dval); /* SAFE */
  1004. /* %G already handles removing trailing zeros from the fractional part, yay */
  1005. break;
  1006. }
  1007. case IS_ARRAY:
  1008. zend_error(E_NOTICE, "Array to string conversion");
  1009. zval_dtor(op);
  1010. op->value.str.val = estrndup_rel("Array", sizeof("Array")-1);
  1011. op->value.str.len = sizeof("Array")-1;
  1012. break;
  1013. case IS_OBJECT: {
  1014. TSRMLS_FETCH();
  1015. convert_object_to_type(op, IS_STRING, convert_to_string);
  1016. if (op->type == IS_STRING) {
  1017. return;
  1018. }
  1019. zend_error(E_NOTICE, "Object of class %s to string conversion", Z_OBJCE_P(op)->name);
  1020. zval_dtor(op);
  1021. op->value.str.val = estrndup_rel("Object", sizeof("Object")-1);
  1022. op->value.str.len = sizeof("Object")-1;
  1023. break;
  1024. }
  1025. default:
  1026. zval_dtor(op);
  1027. ZVAL_BOOL(op, 0);
  1028. break;
  1029. }
  1030. op->type = IS_STRING;
  1031. }
  1032. static void convert_scalar_to_array(zval *op, int type)
  1033. {
  1034. zval *entry;
  1035. ALLOC_ZVAL(entry);
  1036. *entry = *op;
  1037. INIT_PZVAL(entry);
  1038. switch (type) {
  1039. case IS_ARRAY:
  1040. ALLOC_HASHTABLE(op->value.ht);
  1041. zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
  1042. zend_hash_index_update(op->value.ht, 0, (void *) &entry, sizeof(zval *), NULL);
  1043. op->type = IS_ARRAY;
  1044. break;
  1045. case IS_OBJECT:
  1046. {
  1047. /* OBJECTS_OPTIMIZE */
  1048. TSRMLS_FETCH();
  1049. object_init(op);
  1050. zend_hash_update(Z_OBJPROP_P(op), "scalar", sizeof("scalar"), (void *) &entry, sizeof(zval *), NULL);
  1051. }
  1052. break;
  1053. }
  1054. }
  1055. ZEND_API void convert_to_array(zval *op)
  1056. {
  1057. TSRMLS_FETCH();
  1058. switch (op->type) {
  1059. case IS_ARRAY:
  1060. return;
  1061. break;
  1062. /* OBJECTS_OPTIMIZE */
  1063. case IS_OBJECT:
  1064. {
  1065. zval *tmp;
  1066. HashTable *ht;
  1067. ALLOC_HASHTABLE(ht);
  1068. zend_hash_init(ht, 0, NULL, ZVAL_PTR_DTOR, 0);
  1069. if (Z_OBJ_HT_P(op)->get_properties) {
  1070. HashTable *obj_ht = Z_OBJ_HT_P(op)->get_properties(op TSRMLS_CC);
  1071. if(obj_ht) {
  1072. zend_hash_copy(ht, obj_ht, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
  1073. }
  1074. } else {
  1075. convert_object_to_type(op, IS_ARRAY, convert_to_array);
  1076. if (op->type == IS_ARRAY) {
  1077. zend_hash_destroy(ht);
  1078. FREE_HASHTABLE(ht);
  1079. return;
  1080. }
  1081. }
  1082. zval_dtor(op);
  1083. op->type = IS_ARRAY;
  1084. op->value.ht = ht;
  1085. }
  1086. return;
  1087. case IS_NULL:
  1088. ALLOC_HASHTABLE(op->value.ht);
  1089. zend_hash_init(op->value.ht, 0, NULL, ZVAL_PTR_DTOR, 0);
  1090. op->type = IS_ARRAY;
  1091. break;
  1092. default:
  1093. convert_scalar_to_array(op, IS_ARRAY);
  1094. break;
  1095. }
  1096. }
  1097. ZEND_API void convert_to_object(zval *op)
  1098. {
  1099. switch (op->type) {
  1100. case IS_ARRAY:
  1101. {
  1102. /* OBJECTS_OPTIMIZE */
  1103. TSRMLS_FETCH();
  1104. object_and_properties_init(op, &zend_standard_class_def, op->value.ht);
  1105. return;
  1106. break;
  1107. }
  1108. case IS_OBJECT:
  1109. return;
  1110. case IS_NULL:
  1111. {
  1112. /* OBJECTS_OPTIMIZE */
  1113. TSRMLS_FETCH();
  1114. object_init(op);
  1115. break;
  1116. }
  1117. default:
  1118. convert_scalar_to_array(op, IS_OBJECT);
  1119. break;
  1120. }
  1121. }
  1122. ZEND_API void convert_scalar_to_number(zval *op TSRMLS_DC)
  1123. {
  1124. switch (op->type) {
  1125. case IS_STRING:
  1126. {
  1127. char *strval;
  1128. strval = op->value.str.val;
  1129. if ((op->type=is_numeric_string(strval, op->value.str.len, &op->value.lval, &op->value.dval, 1)) == 0) {
  1130. op->value.lval = 0;
  1131. op->type = IS_LONG;
  1132. }
  1133. STR_FREE(strval);
  1134. break;
  1135. }
  1136. case IS_BOOL:
  1137. op->type = IS_LONG;
  1138. break;
  1139. case IS_RESOURCE:
  1140. zend_list_delete(op->value.lval);
  1141. op->type = IS_LONG;
  1142. break;
  1143. case IS_OBJECT:
  1144. convert_to_long_base(op, 10);
  1145. break;
  1146. case IS_NULL:
  1147. op->type = IS_LONG;
  1148. op->value.lval = 0;
  1149. break;
  1150. }
  1151. }
  1152. #endif
  1153. // copied from zend_strtod.c
  1154. ZEND_API double zend_hex_strtod(const char *str, char **endptr)
  1155. {
  1156. const char *s = str;
  1157. char c;
  1158. int any = 0;
  1159. double value = 0;
  1160. if (*s == '0' && (s[1] == 'x' || s[1] == 'X')) {
  1161. s += 2;
  1162. }
  1163. while ((c = *s++)) {
  1164. if (c >= '0' && c <= '9') {
  1165. c -= '0';
  1166. } else if (c >= 'A' && c <= 'F') {
  1167. c -= 'A' - 10;
  1168. } else if (c >= 'a' && c <= 'f') {
  1169. c -= 'a' - 10;
  1170. } else {
  1171. break;
  1172. }
  1173. any = 1;
  1174. value = value * 16 + c;
  1175. }
  1176. if (endptr != NULL) {
  1177. *endptr = (char *)(any ? s - 1 : str);
  1178. }
  1179. return value;
  1180. }
  1181. ZEND_API double zend_oct_strtod(const char *str, char **endptr)
  1182. {
  1183. const char *s = str;
  1184. char c;
  1185. double value = 0;
  1186. int any = 0;
  1187. /* skip leading zero */
  1188. s++;
  1189. while ((c = *s++)) {
  1190. if (c < '0' || c > '7') {
  1191. /* break and return the current value if the number is not well-formed
  1192. * that's what Linux strtol() does
  1193. */
  1194. break;
  1195. }
  1196. value = value * 8 + c - '0';
  1197. any = 1;
  1198. }
  1199. if (endptr != NULL) {
  1200. *endptr = (char *)(any ? s - 1 : str);
  1201. }
  1202. return value;
  1203. }
  1204. // copied from zend_operators.c and beautified
  1205. ZEND_API long zend_atol(const char *str, int str_len)
  1206. {
  1207. long retval;
  1208. if (!str_len) {
  1209. str_len = strlen(str);
  1210. }
  1211. retval = strtol(str, NULL, 0);
  1212. if (str_len>0) {
  1213. switch (str[str_len-1]) {
  1214. case 'g':
  1215. case 'G':
  1216. retval *= 1024;
  1217. /* break intentionally missing */
  1218. case 'm':
  1219. case 'M':
  1220. retval *= 1024;
  1221. /* break intentionally missing */
  1222. case 'k':
  1223. case 'K':
  1224. retval *= 1024;
  1225. break;
  1226. }
  1227. }
  1228. return retval;
  1229. }
  1230. ZEND_API int zend_atoi(const char *str, int str_len)
  1231. {
  1232. int retval;
  1233. if (!str_len) str_len = strlen(str);
  1234. retval = strtol(str, NULL, 0);
  1235. if (str_len > 0)
  1236. {
  1237. switch (str[str_len-1])
  1238. {
  1239. case 'k':
  1240. case 'K': retval *= 1024;
  1241. break;
  1242. case 'm':
  1243. case 'M': retval *= 1048576;
  1244. break;
  1245. }
  1246. }
  1247. return retval;
  1248. }
  1249. // copied from zend_operators.c and beautified
  1250. ZEND_API void zend_str_tolower(char *str, unsigned int length)
  1251. {
  1252. register char *p = str, *end = p + length;
  1253. while (p < end)
  1254. {
  1255. if (*p >= 'A' && *p <= 'Z') *p = (*p)+32;
  1256. p++;
  1257. }
  1258. }
  1259. // copied from zend_operators.c and beautified
  1260. ZEND_API char *zend_str_tolower_copy(char *dest, const char *source, unsigned int length)
  1261. {
  1262. register unsigned char *str = (unsigned char *)source;
  1263. register unsigned char *result = (unsigned char *)dest;
  1264. register unsigned char *end = str + length;
  1265. while (str < end) *result++ = tolower((int)*str++);
  1266. *result = *end;
  1267. return dest;
  1268. }
  1269. // copied from zend_operators.c and beautified
  1270. ZEND_API int zend_binary_strcmp(char *s1, uint len1, char *s2, uint len2)
  1271. {
  1272. int retval;
  1273. retval = memcmp(s1, s2, MIN(len1, len2));
  1274. if (!retval) return (len1 - len2);
  1275. else return retval;
  1276. }
  1277. // copied from zend_operators.c and beautified
  1278. ZEND_API int zend_binary_strncmp(char *s1, uint len1, char *s2, uint len2, uint length)
  1279. {
  1280. int retval;
  1281. retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
  1282. if (!retval) return (MIN(length, len1) - MIN(length, len2));
  1283. else return retval;
  1284. }
  1285. // copied from zend_operators.c and beautified
  1286. ZEND_API int zend_binary_strcasecmp(char *s1, uint len1, char *s2, uint len2)
  1287. {
  1288. int len;
  1289. int c1, c2;
  1290. len = MIN(len1, len2);
  1291. while (len--)
  1292. {
  1293. c1 = tolower(*s1++);
  1294. c2 = tolower(*s2++);
  1295. if (c1 != c2) return c1 - c2;
  1296. }
  1297. return len1 - len2;
  1298. }
  1299. // copied from zend_operators.c and beautified
  1300. ZEND_API int zend_binary_strncasecmp(char *s1, uint len1, char *s2, uint len2, uint length)
  1301. {
  1302. int len;
  1303. int c1, c2;
  1304. len = MIN(length, MIN(len1, len2));
  1305. while (len--)
  1306. {
  1307. c1 = tolower(*s1++);
  1308. c2 = tolower(*s2++);
  1309. if (c1 != c2) return c1 - c2;
  1310. }
  1311. return MIN(length, len1) - MIN(length, len2);
  1312. }
  1313. // copied from zend_operators.c and beautified
  1314. ZEND_API int zend_binary_zval_strcmp(zval *s1, zval *s2)
  1315. {
  1316. return zend_binary_strcmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len);
  1317. }
  1318. // copied from zend_operators.c and beautified
  1319. ZEND_API int zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3)
  1320. {
  1321. return zend_binary_strncmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len, s3->value.lval);
  1322. }
  1323. // copied from zend_operators.c and beautified
  1324. ZEND_API int zend_binary_zval_strcasecmp(zval *s1, zval *s2)
  1325. {
  1326. return zend_binary_strcasecmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len);
  1327. }
  1328. // copied from zend_operators.c and beautified
  1329. ZEND_API int zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3)
  1330. {
  1331. return zend_binary_strncasecmp(s1->value.str.val, s1->value.str.len, s2->value.str.val, s2->value.str.len, s3->value.lval);
  1332. }
  1333. // copied from zend_operators.c, slightly modified and beautified
  1334. ZEND_API void zendi_smart_strcmp(zval *result, zval *s1, zval *s2)
  1335. {
  1336. int ret1, ret2;
  1337. long lval1, lval2;
  1338. double dval1, dval2;
  1339. if ((ret1 = is_numeric_string(s1->value.str.val, s1->value.str.len, &lval1, &dval1, 0)) &&
  1340. (ret2 = is_numeric_string(s2->value.str.val, s2->value.str.len, &lval2, &dval2, 0)))
  1341. {
  1342. if (ret1 == IS_DOUBLE || ret2 == IS_DOUBLE)
  1343. {
  1344. if (ret1 != IS_DOUBLE) dval1 = strtod(s1->value.str.val, NULL);
  1345. else if (ret2 != IS_DOUBLE) dval2 = strtod(s2->value.str.val, NULL);
  1346. result->value.dval = dval1 - dval2;
  1347. result->value.lval = ZEND_NORMALIZE_BOOL(result->value.dval);
  1348. result->type = IS_LONG;
  1349. }
  1350. else
  1351. {
  1352. /* they both have to be long's */
  1353. result->value.lval = lval1 - lval2;
  1354. result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval);
  1355. result->type = IS_LONG;
  1356. }
  1357. }
  1358. else
  1359. {
  1360. result->value.lval = zend_binary_zval_strcmp(s1, s2);
  1361. result->value.lval = ZEND_NORMALIZE_BOOL(result->value.lval);
  1362. result->type = IS_LONG;
  1363. }
  1364. return;
  1365. }
  1366. // copied from zend_operators.c, slightly modified and beautified
  1367. int hash_zval_compare_function(const zval **z1, const zval **z2 TSRMLS_DC)
  1368. {
  1369. zval result;
  1370. if (compare_function(&result, (zval *)*z1, (zval *)*z2 TSRMLS_CC) == FAILURE) return 1;
  1371. return result.value.lval;
  1372. }
  1373. // copied from zend_operators.c and beautified
  1374. ZEND_API void zend_compare_symbol_tables(zval *result, HashTable *ht1, HashTable *ht2 TSRMLS_DC)
  1375. {
  1376. result->type = IS_LONG;
  1377. result->value.lval = zend_hash_compare(ht1, ht2, (compare_func_t)hash_zval_compare_function, 0 TSRMLS_CC);
  1378. }
  1379. // copied from zend_operators.c and beautified
  1380. ZEND_API void zend_compare_arrays(zval *result, zval *a1, zval *a2 TSRMLS_DC)
  1381. {
  1382. zend_compare_symbol_tables(result, a1->value.ht, a2->value.ht TSRMLS_CC);
  1383. }
  1384. // copied from zend_operators.c
  1385. ZEND_API int zend_compare_symbol_tables_i(HashTable *ht1, HashTable *ht2 TSRMLS_DC)
  1386. {
  1387. return zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0 TSRMLS_CC);
  1388. }
  1389. // copied from zend_operators.c and beautified
  1390. ZEND_API void zend_compare_objects(zval *result, zval *o1, zval *o2 TSRMLS_DC)
  1391. {
  1392. /* OBJECTS_FIXME */
  1393. if (Z_OBJCE_P(o1) != Z_OBJCE_P(o2))
  1394. {
  1395. result->value.lval = 1; /* Comparing objects of different types is pretty much meaningless */
  1396. result->type = IS_LONG;
  1397. return;
  1398. }
  1399. zend_compare_symbol_tables(result, Z_OBJPROP_P(o1), Z_OBJPROP_P(o2) TSRMLS_CC);
  1400. }
  1401. // copied from zend_operators.c and beautified
  1402. ZEND_API int string_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1403. {
  1404. zval op1_copy, op2_copy;
  1405. int use_copy1, use_copy2;
  1406. zend_make_printable_zval(op1, &op1_copy, &use_copy1);
  1407. zend_make_printable_zval(op2, &op2_copy, &use_copy2);
  1408. if (use_copy1) op1 = &op1_copy;
  1409. if (use_copy2) op2 = &op2_copy;
  1410. result->value.lval = zend_binary_zval_strcmp(op1, op2);
  1411. result->type = IS_LONG;
  1412. if (use_copy1) zval_dtor(op1);
  1413. if (use_copy2) zval_dtor(op2);
  1414. return SUCCESS;
  1415. }
  1416. // copied from zend_operators.c and beautified
  1417. ZEND_API int string_locale_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1418. {
  1419. zval op1_copy, op2_copy;
  1420. int use_copy1, use_copy2;
  1421. zend_make_printable_zval(op1, &op1_copy, &use_copy1);
  1422. zend_make_printable_zval(op2, &op2_copy, &use_copy2);
  1423. if (use_copy1) op1 = &op1_copy;
  1424. if (use_copy2) op2 = &op2_copy;
  1425. result->value.lval = strcoll(op1->value.str.val, op2->value.str.val);
  1426. result->type = IS_LONG;
  1427. if (use_copy1) zval_dtor(op1);
  1428. if (use_copy2) zval_dtor(op2);
  1429. return SUCCESS;
  1430. }
  1431. // copied from zend_operators.c and beautified
  1432. ZEND_API int numeric_compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1433. {
  1434. zval op1_copy, op2_copy;
  1435. op1_copy = *op1;
  1436. zval_copy_ctor(&op1_copy);
  1437. op2_copy = *op2;
  1438. zval_copy_ctor(&op2_copy);
  1439. convert_to_double(&op1_copy);
  1440. convert_to_double(&op2_copy);
  1441. result->value.lval = ZEND_NORMALIZE_BOOL(op1_copy.value.dval - op2_copy.value.dval);
  1442. result->type = IS_LONG;
  1443. return SUCCESS;
  1444. }
  1445. // copied from zend_operators.c and beautified
  1446. ZEND_API int compare_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1447. {
  1448. zval op1_copy, op2_copy;
  1449. if ((op1->type == IS_NULL && op2->type == IS_STRING) ||
  1450. (op2->type == IS_NULL && op1->type == IS_STRING))
  1451. {
  1452. if (op1->type == IS_NULL)
  1453. {
  1454. result->type = IS_LONG;
  1455. result->value.lval = zend_binary_strcmp("", 0, op2->value.str.val, op2->value.str.len);
  1456. return SUCCESS;
  1457. }
  1458. else
  1459. {
  1460. result->type = IS_LONG;
  1461. result->value.lval = zend_binary_strcmp(op1->value.str.val, op1->value.str.len, "", 0);
  1462. return SUCCESS;
  1463. }
  1464. }
  1465. if (op1->type == IS_STRING && op2->type == IS_STRING)
  1466. {
  1467. zendi_smart_strcmp(result, op1, op2);
  1468. return SUCCESS;
  1469. }
  1470. if (op1->type == IS_BOOL || op2->type == IS_BOOL ||
  1471. op1->type == IS_NULL || op2->type == IS_NULL)
  1472. {
  1473. zendi_convert_to_boolean(op1, op1_copy, result);
  1474. zendi_convert_to_boolean(op2, op2_copy, result);
  1475. result->type = IS_LONG;
  1476. result->value.lval = ZEND_NORMALIZE_BOOL(op1->value.lval - op2->value.lval);
  1477. return SUCCESS;
  1478. }
  1479. zendi_convert_scalar_to_number(op1, op1_copy, result);
  1480. zendi_convert_scalar_to_number(op2, op2_copy, result);
  1481. if (op1->type == IS_LONG && op2->type == IS_LONG) {
  1482. result->type = IS_LONG;
  1483. result->value.lval = op1->value.lval > op2->value.lval ? 1 : (op1->value.lval < op2->value.lval ? -1 : 0);
  1484. return SUCCESS;
  1485. }
  1486. if ((op1->type == IS_DOUBLE || op1->type == IS_LONG) &&
  1487. (op2->type == IS_DOUBLE || op2->type == IS_LONG))
  1488. {
  1489. result->value.dval = (op1->type == IS_LONG ? (double) op1->value.lval : op1->value.dval) -
  1490. (op2->type == IS_LONG ? (double) op2->value.lval : op2->value.dval);
  1491. result->value.lval = ZEND_NORMALIZE_BOOL(result->value.dval);
  1492. result->type = IS_LONG;
  1493. return SUCCESS;
  1494. }
  1495. if (op1->type == IS_ARRAY && op2->type == IS_ARRAY)
  1496. {
  1497. zend_compare_arrays(result, op1, op2 TSRMLS_CC);
  1498. return SUCCESS;
  1499. }
  1500. if (op1->type == IS_OBJECT && op2->type == IS_OBJECT)
  1501. {
  1502. zend_compare_objects(result, op1, op2 TSRMLS_CC);
  1503. return SUCCESS;
  1504. }
  1505. if (op1->type == IS_ARRAY)
  1506. {
  1507. result->value.lval = 1;
  1508. result->type = IS_LONG;
  1509. return SUCCESS;
  1510. }
  1511. if (op2->type == IS_ARRAY)
  1512. {
  1513. result->value.lval = -1;
  1514. result->type = IS_LONG;
  1515. return SUCCESS;
  1516. }
  1517. if (op1->type == IS_OBJECT)
  1518. {
  1519. result->value.lval = 1;
  1520. result->type = IS_LONG;
  1521. return SUCCESS;
  1522. }
  1523. if (op2->type == IS_OBJECT)
  1524. {
  1525. result->value.lval = -1;
  1526. result->type = IS_LONG;
  1527. return SUCCESS;
  1528. }
  1529. ZVAL_BOOL(result, 0);
  1530. return FAILURE;
  1531. }
  1532. // copied from zend_operators.c and beautified
  1533. ZEND_API void zend_make_printable_zval(zval *expr, zval *expr_copy, int *use_copy)
  1534. {
  1535. if (expr->type == IS_STRING)
  1536. {
  1537. *use_copy = 0;
  1538. return;
  1539. }
  1540. switch (expr->type)
  1541. {
  1542. case IS_NULL:
  1543. expr_copy->value.str.len = 0;
  1544. expr_copy->value.str.val = empty_string;
  1545. break;
  1546. case IS_BOOL:
  1547. if (expr->value.lval)
  1548. {
  1549. expr_copy->value.str.len = 1;
  1550. expr_copy->value.str.val = estrndup("1", 1);
  1551. }
  1552. else
  1553. {
  1554. expr_copy->value.str.len = 0;
  1555. expr_copy->value.str.val = empty_string;
  1556. }
  1557. break;
  1558. case IS_RESOURCE:
  1559. expr_copy->value.str.val = (char *)emalloc(sizeof("Resource id #") -1 + MAX_LENGTH_OF_LONG);
  1560. expr_copy->value.str.len = sprintf(expr_copy->value.str.val, "Resource id #%ld", expr->value.lval);
  1561. break;
  1562. case IS_ARRAY:
  1563. expr_copy->value.str.len = sizeof("Array") - 1;
  1564. expr_copy->value.str.val = estrndup("Array", expr_copy->value.str.len);
  1565. break;
  1566. case IS_OBJECT:
  1567. expr_copy->value.str.len = sizeof("Object") - 1;
  1568. expr_copy->value.str.val = estrndup("Object", expr_copy->value.str.len);
  1569. break;
  1570. case IS_DOUBLE:
  1571. *expr_copy = *expr;
  1572. zval_copy_ctor(expr_copy);
  1573. zend_locale_sprintf_double(expr_copy ZEND_FILE_LINE_CC);
  1574. break;
  1575. default:
  1576. *expr_copy = *expr;
  1577. zval_copy_ctor(expr_copy);
  1578. convert_to_string(expr_copy);
  1579. break;
  1580. }
  1581. expr_copy->type = IS_STRING;
  1582. *use_copy = 1;
  1583. }
  1584. // copied from zend_operators.c and beautified
  1585. #ifdef PHP4TS
  1586. ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC)
  1587. {
  1588. double dval = op->value.dval;
  1589. TSRMLS_FETCH();
  1590. op->value.str.val = (char *)emalloc_rel(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
  1591. sprintf(op->value.str.val, "%.*G", (int)EG(precision), dval);
  1592. op->value.str.len = strlen(op->value.str.val);
  1593. if (EG(float_separator)[0] != '.')
  1594. {
  1595. char *p = op->value.str.val;
  1596. if ((p = strchr(p, '.'))) *p = EG(float_separator)[0];
  1597. }
  1598. }
  1599. #elif defined(PHP5TS)
  1600. ZEND_API void zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC)
  1601. {
  1602. TSRMLS_FETCH();
  1603. op->value.str.len = zend_spprintf(&op->value.str.val, 0, "%.*G", (int) EG(precision), (double)op->value.dval);
  1604. }
  1605. #endif
  1606. // copied from strlcpy.c and slightly modified
  1607. /*
  1608. * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  1609. * All rights reserved.
  1610. *
  1611. * Redistribution and use in source and binary forms, with or without
  1612. * modification, are permitted provided that the following conditions
  1613. * are met:
  1614. * 1. Redistributions of source code must retain the above copyright
  1615. * notice, this list of conditions and the following disclaimer.
  1616. * 2. Redistributions in binary form must reproduce the above copyright
  1617. * notice, this list of conditions and the following disclaimer in the
  1618. * documentation and/or other materials provided with the distribution.
  1619. * 3. The name of the author may not be used to endorse or promote products
  1620. * derived from this software without specific prior written permission.
  1621. *
  1622. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  1623. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  1624. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  1625. * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  1626. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  1627. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  1628. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  1629. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  1630. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  1631. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  1632. */
  1633. /*
  1634. * Copy src to string dst of size siz. At most siz-1 characters
  1635. * will be copied. Always NUL terminates (unless siz == 0).
  1636. * Returns strlen(src); if retval >= siz, truncation occurred.
  1637. */
  1638. ZEND_API size_t php_strlcpy(char *dst, const char *src, size_t siz)
  1639. {
  1640. register char *d = dst;
  1641. register const char *s = src;
  1642. register size_t n = siz;
  1643. /* Copy as many bytes as will fit */
  1644. if (n != 0 && --n != 0) {
  1645. do {
  1646. if ((*d++ = *s++) == 0)
  1647. break;
  1648. } while (--n != 0);
  1649. }
  1650. /* Not enough room in dst, add NUL and traverse rest of src */
  1651. if (n == 0) {
  1652. if (siz != 0)
  1653. *d = '\0'; /* NUL-terminate dst */
  1654. while (*s++)
  1655. ;
  1656. }
  1657. return(s - src - 1); /* count does not include NUL */
  1658. }
  1659. // copied from zend_operators.c and beautified
  1660. ZEND_API int bitwise_and_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1661. {
  1662. zval op1_copy, op2_copy;
  1663. if (op1->type == IS_STRING && op2->type == IS_STRING)
  1664. {
  1665. zval *longer, *shorter;
  1666. char *result_str;
  1667. int i, result_len;
  1668. if (op1->value.str.len >= op2->value.str.len)
  1669. {
  1670. longer = op1;
  1671. shorter = op2;
  1672. }
  1673. else
  1674. {
  1675. longer = op2;
  1676. shorter = op1;
  1677. }
  1678. result->type = IS_STRING;
  1679. result_len = shorter->value.str.len;
  1680. result_str = estrndup(shorter->value.str.val, shorter->value.str.len);
  1681. for (i = 0; i < shorter->value.str.len; i++)
  1682. {
  1683. result_str[i] &= longer->value.str.val[i];
  1684. }
  1685. if (result == op1)
  1686. {
  1687. STR_FREE(result->value.str.val);
  1688. }
  1689. result->value.str.val = result_str;
  1690. result->value.str.len = result_len;
  1691. return SUCCESS;
  1692. }
  1693. zendi_convert_to_long(op1, op1_copy, result);
  1694. zendi_convert_to_long(op2, op2_copy, result);
  1695. result->type = IS_LONG;
  1696. result->value.lval = op1->value.lval & op2->value.lval;
  1697. return SUCCESS;
  1698. }
  1699. // copied from zend_operators.c and beautified
  1700. ZEND_API int bitwise_not_function(zval *result, zval *op1 TSRMLS_DC)
  1701. {
  1702. zval op1_copy = *op1;
  1703. op1 = &op1_copy;
  1704. if (op1->type == IS_DOUBLE)
  1705. {
  1706. op1->value.lval = (long)op1->value.dval;
  1707. op1->type = IS_LONG;
  1708. }
  1709. if (op1->type == IS_LONG)
  1710. {
  1711. result->value.lval = ~op1->value.lval;
  1712. result->type = IS_LONG;
  1713. return SUCCESS;
  1714. }
  1715. if (op1->type == IS_STRING)
  1716. {
  1717. int i;
  1718. result->type = IS_STRING;
  1719. result->value.str.val = estrndup(op1->value.str.val, op1->value.str.len);
  1720. result->value.str.len = op1->value.str.len;
  1721. for (i = 0; i < op1->value.str.len; i++)
  1722. {
  1723. result->value.str.val[i] = ~op1->value.str.val[i];
  1724. }
  1725. return SUCCESS;
  1726. }
  1727. zend_error(E_ERROR, "Unsupported operand types");
  1728. return FAILURE; /* unknown datatype */
  1729. }
  1730. // copied from zend_operators.c and beautified
  1731. ZEND_API int bitwise_or_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1732. {
  1733. zval op1_copy, op2_copy;
  1734. if (op1->type == IS_STRING && op2->type == IS_STRING)
  1735. {
  1736. zval *longer, *shorter;
  1737. char *result_str;
  1738. int i, result_len;
  1739. if (op1->value.str.len >= op2->value.str.len)
  1740. {
  1741. longer = op1;
  1742. shorter = op2;
  1743. }
  1744. else
  1745. {
  1746. longer = op2;
  1747. shorter = op1;
  1748. }
  1749. result->type = IS_STRING;
  1750. result_len = longer->value.str.len;
  1751. result_str = estrndup(longer->value.str.val, longer->value.str.len);
  1752. for (i = 0; i < shorter->value.str.len; i++)
  1753. {
  1754. result_str[i] |= shorter->value.str.val[i];
  1755. }
  1756. if (result == op1)
  1757. {
  1758. STR_FREE(result->value.str.val);
  1759. }
  1760. result->value.str.val = result_str;
  1761. result->value.str.len = result_len;
  1762. return SUCCESS;
  1763. }
  1764. zendi_convert_to_long(op1, op1_copy, result);
  1765. zendi_convert_to_long(op2, op2_copy, result);
  1766. result->type = IS_LONG;
  1767. result->value.lval = op1->value.lval | op2->value.lval;
  1768. return SUCCESS;
  1769. }
  1770. // copied from zend_operators.c and beautified
  1771. ZEND_API int bitwise_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1772. {
  1773. zval op1_copy, op2_copy;
  1774. if (op1->type == IS_STRING && op2->type == IS_STRING)
  1775. {
  1776. zval *longer, *shorter;
  1777. char *result_str;
  1778. int i, result_len;
  1779. if (op1->value.str.len >= op2->value.str.len)
  1780. {
  1781. longer = op1;
  1782. shorter = op2;
  1783. }
  1784. else
  1785. {
  1786. longer = op2;
  1787. shorter = op1;
  1788. }
  1789. result->type = IS_STRING;
  1790. result_len = shorter->value.str.len;
  1791. result_str = estrndup(shorter->value.str.val, shorter->value.str.len);
  1792. for (i = 0; i < shorter->value.str.len; i++)
  1793. {
  1794. result_str[i] ^= longer->value.str.val[i];
  1795. }
  1796. if (result == op1)
  1797. {
  1798. STR_FREE(result->value.str.val);
  1799. }
  1800. result->value.str.val = result_str;
  1801. result->value.str.len = result_len;
  1802. return SUCCESS;
  1803. }
  1804. zendi_convert_to_long(op1, op1_copy, result);
  1805. zendi_convert_to_long(op2, op2_copy, result);
  1806. result->type = IS_LONG;
  1807. result->value.lval = op1->value.lval ^ op2->value.lval;
  1808. return SUCCESS;
  1809. }
  1810. // copied from zend_operators.c
  1811. ZEND_API int boolean_not_function(zval *result, zval *op1 TSRMLS_DC)
  1812. {
  1813. zval op1_copy;
  1814. zendi_convert_to_boolean(op1, op1_copy, result);
  1815. result->type = IS_BOOL;
  1816. result->value.lval = !op1->value.lval;
  1817. return SUCCESS;
  1818. }
  1819. // copied from zend_operators.c
  1820. ZEND_API int boolean_xor_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  1821. {
  1822. zval op1_copy, op2_copy;
  1823. result->type = IS_BOOL;
  1824. zendi_convert_to_boolean(op1, op1_copy, result);
  1825. zendi_convert_to_boolean(op2, op2_copy, result);
  1826. result->value.lval = op1->value.lval ^ op2->value.lval;
  1827. return SUCCESS;
  1828. }
  1829. // copied from zend_operators.c and beautified
  1830. ZEND_API int add_char_to_string(zval *result, zval *op1, zval *op2)
  1831. {
  1832. result->value.str.len = op1->value.str.len + 1;
  1833. result->value.str.val = (char *)erealloc(op1->value.str.val, result->value.str.len+1);
  1834. result->value.str.val[result->value.str.len - 1] = (char)op2->value.lval;
  1835. result->value.str.val[result->value.str.len] = 0;
  1836. result->type = IS_STRING;
  1837. return SUCCESS;
  1838. }
  1839. // copied from zend_operators.c and beautified
  1840. ZEND_API int add_string_to_string(zval *result, zval *op1, zval *op2)
  1841. {
  1842. int length = op1->value.str.len + op2->value.str.len;
  1843. if (op1->value.str.val == empty_string)
  1844. {
  1845. result->value.str.val = (char *)emalloc(length+1);
  1846. }
  1847. else
  1848. {
  1849. result->value.str.val = (char *)erealloc(op1->value.str.val, length+1);
  1850. }
  1851. memcpy(result->value.str.val + op1->value.str.len, op2->value.str.val, op2->value.str.len);
  1852. result->value.str.val[length] = 0;
  1853. result->value.str.len = length;
  1854. result->type = IS_STRING;
  1855. return SUCCESS;
  1856. }
  1857. // copied from zend_operators.c
  1858. ZEND_API int zval_is_true(zval *op)
  1859. {
  1860. convert_to_boolean(op);
  1861. return (op->value.lval ? 1 : 0);
  1862. }
  1863. // copied from zend_execute_API.c and beautified
  1864. ZEND_API int zval_update_constant(zval **pp, void *arg TSRMLS_DC)
  1865. {
  1866. zval *p = *pp;
  1867. zend_bool inline_change = (zend_bool)(unsigned long)arg;
  1868. zval const_value;
  1869. if (p->type == IS_CONSTANT)
  1870. {
  1871. int refcount;
  1872. SEPARATE_ZVAL(pp);
  1873. p = *pp;
  1874. refcount = p->refcount;
  1875. if (!zend_get_constant(p->value.str.val, p->value.str.len, &const_value TSRMLS_CC))
  1876. {
  1877. zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'",
  1878. p->value.str.val, p->value.str.val);
  1879. p->type = IS_STRING;
  1880. if (!inline_change) zval_copy_ctor(p);
  1881. }
  1882. else
  1883. {
  1884. if (inline_change) STR_FREE(p->value.str.val);
  1885. *p = const_value;
  1886. }
  1887. INIT_PZVAL(p);
  1888. p->refcount = refcount;
  1889. }
  1890. else if (p->type == IS_CONSTANT_ARRAY)
  1891. {
  1892. zval **element, *new_val;
  1893. char *str_index;
  1894. uint str_index_len;
  1895. ulong num_index;
  1896. SEPARATE_ZVAL(pp);
  1897. p = *pp;
  1898. p->type = IS_ARRAY;
  1899. /* First go over the array and see if there are any constant indices */
  1900. zend_hash_internal_pointer_reset(p->value.ht);
  1901. while (zend_hash_get_current_data(p->value.ht, (void **) &element) == SUCCESS)
  1902. {
  1903. if (!(Z_TYPE_PP(element) & IS_CONSTANT_INDEX))
  1904. {
  1905. zend_hash_move_forward(p->value.ht);
  1906. continue;
  1907. }
  1908. Z_TYPE_PP(element) &= ~IS_CONSTANT_INDEX;
  1909. if (zend_hash_get_current_key_ex(p->value.ht, &str_index, &str_index_len, &num_index,
  1910. 0, NULL) != HASH_KEY_IS_STRING)
  1911. {
  1912. zend_hash_move_forward(p->value.ht);
  1913. continue;
  1914. }
  1915. if (!zend_get_constant(str_index, str_index_len-1, &const_value TSRMLS_CC))
  1916. {
  1917. zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", str_index, str_index);
  1918. zend_hash_move_forward(p->value.ht);
  1919. continue;
  1920. }
  1921. if (const_value.type == IS_STRING && const_value.value.str.len == str_index_len-1 &&
  1922. !strncmp(const_value.value.str.val, str_index, str_index_len))
  1923. {
  1924. /* constant value is the same as its name */
  1925. zval_dtor(&const_value);
  1926. zend_hash_move_forward(p->value.ht);
  1927. continue;
  1928. }
  1929. ALLOC_ZVAL(new_val);
  1930. *new_val = **element;
  1931. zval_copy_ctor(new_val);
  1932. new_val->refcount = 1;
  1933. new_val->is_ref = 0;
  1934. /* preserve this bit for inheritance */
  1935. Z_TYPE_PP(element) |= IS_CONSTANT_INDEX;
  1936. switch (const_value.type)
  1937. {
  1938. case IS_STRING:
  1939. zend_hash_update(p->value.ht, const_value.value.str.val, const_value.value.str.len+1,
  1940. &new_val, sizeof(zval *), NULL);
  1941. break;
  1942. case IS_LONG:
  1943. zend_hash_index_update(p->value.ht, const_value.value.lval, &new_val, sizeof(zval *), NULL);
  1944. break;
  1945. }
  1946. zend_hash_del(p->value.ht, str_index, str_index_len);
  1947. zval_dtor(&const_value);
  1948. }
  1949. zend_hash_apply_with_argument(p->value.ht, (apply_func_arg_t)zval_update_constant, (void *)1 TSRMLS_CC);
  1950. }
  1951. return 0;
  1952. }
  1953. // copied from zend_execute.h and beautified
  1954. static inline int i_zend_is_true(zval *op)
  1955. {
  1956. int result;
  1957. switch (op->type)
  1958. {
  1959. case IS_NULL:
  1960. result = 0;
  1961. break;
  1962. case IS_LONG:
  1963. case IS_BOOL:
  1964. case IS_RESOURCE:
  1965. result = (op->value.lval ? 1 : 0);
  1966. break;
  1967. case IS_DOUBLE:
  1968. result = (op->value.dval ? 1 : 0);
  1969. break;
  1970. case IS_STRING:
  1971. if (op->value.str.len == 0 || (op->value.str.len == 1 && op->value.str.val[0] == '0'))
  1972. {
  1973. result = 0;
  1974. }
  1975. else
  1976. {
  1977. result = 1;
  1978. }
  1979. break;
  1980. case IS_ARRAY:
  1981. result = (zend_hash_num_elements(op->value.ht) ? 1 : 0);
  1982. break;
  1983. case IS_OBJECT:
  1984. /* OBJ-TBI */
  1985. result = 1;
  1986. break;
  1987. default:
  1988. result = 0;
  1989. break;
  1990. }
  1991. return result;
  1992. }
  1993. // copied from zend_execute_API.c
  1994. ZEND_API int zend_is_true(zval *op)
  1995. {
  1996. return i_zend_is_true(op);
  1997. }
  1998. // copied from zend_operators.c and beautified
  1999. ZEND_API double zend_string_to_double(const char *number, zend_uint length)
  2000. {
  2001. double divisor = 10.0;
  2002. double result = 0.0;
  2003. double exponent;
  2004. const char *end = number + length;
  2005. const char *digit = number;
  2006. if (!length) return result;
  2007. while (digit < end)
  2008. {
  2009. if (*digit <= '9' && *digit >= '0')
  2010. {
  2011. result *= 10;
  2012. result += *digit - '0';
  2013. }
  2014. else if (*digit == '.')
  2015. {
  2016. digit++;
  2017. break;
  2018. }
  2019. else if (toupper(*digit) == 'E')
  2020. {
  2021. exponent = (double)atoi(digit + 1);
  2022. result *= pow(10.0, exponent);
  2023. return result;
  2024. }
  2025. else return result;
  2026. digit++;
  2027. }
  2028. while (digit < end)
  2029. {
  2030. if (*digit <= '9' && *digit >= '0')
  2031. {
  2032. result += (*digit - '0') / divisor;
  2033. divisor *= 10;
  2034. }
  2035. else if (toupper(*digit) == 'E')
  2036. {
  2037. exponent = (double)atoi(digit + 1);
  2038. result *= pow(10.0, exponent);
  2039. return result;
  2040. }
  2041. else return result;
  2042. digit++;
  2043. }
  2044. return result;
  2045. }
  2046. // copied from zend_operators.c and beautified
  2047. ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2048. {
  2049. zval op1_copy, op2_copy;
  2050. int use_copy1, use_copy2;
  2051. zend_make_printable_zval(op1, &op1_copy, &use_copy1);
  2052. zend_make_printable_zval(op2, &op2_copy, &use_copy2);
  2053. if (use_copy1) op1 = &op1_copy;
  2054. if (use_copy2) op2 = &op2_copy;
  2055. if (result == op1)
  2056. {
  2057. /* special case, perform operations on result */
  2058. uint res_len = op1->value.str.len + op2->value.str.len;
  2059. if (result->value.str.len == 0)
  2060. {
  2061. /* handle empty_string */
  2062. STR_FREE(result->value.str.val);
  2063. result->value.str.val = (char *)emalloc(res_len + 1);
  2064. }
  2065. else result->value.str.val = (char *)erealloc(result->value.str.val, res_len + 1);
  2066. memcpy(result->value.str.val + result->value.str.len, op2->value.str.val, op2->value.str.len);
  2067. result->value.str.val[res_len] = 0;
  2068. result->value.str.len = res_len;
  2069. }
  2070. else
  2071. {
  2072. result->value.str.len = op1->value.str.len + op2->value.str.len;
  2073. result->value.str.val = (char *)emalloc(result->value.str.len + 1);
  2074. memcpy(result->value.str.val, op1->value.str.val, op1->value.str.len);
  2075. memcpy(result->value.str.val + op1->value.str.len, op2->value.str.val, op2->value.str.len);
  2076. result->value.str.val[result->value.str.len] = 0;
  2077. result->type = IS_STRING;
  2078. }
  2079. if (use_copy1) zval_dtor(op1);
  2080. if (use_copy2) zval_dtor(op2);
  2081. return SUCCESS;
  2082. }
  2083. // copied from zend_operators.c and beautified
  2084. ZEND_API int add_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2085. {
  2086. zval op1_copy, op2_copy;
  2087. if (op1->type == IS_ARRAY && op2->type == IS_ARRAY)
  2088. {
  2089. zval *tmp;
  2090. if (result == op1 && result == op2)
  2091. {
  2092. /* $a += $a */
  2093. return SUCCESS;
  2094. }
  2095. if (result != op1)
  2096. {
  2097. *result = *op1;
  2098. zval_copy_ctor(result);
  2099. }
  2100. zend_hash_merge(result->value.ht, op2->value.ht, (void (*)(void *pData))zval_add_ref,
  2101. (void *)&tmp, sizeof(zval *), 0);
  2102. return SUCCESS;
  2103. }
  2104. zendi_convert_scalar_to_number(op1, op1_copy, result);
  2105. zendi_convert_scalar_to_number(op2, op2_copy, result);
  2106. if (op1->type == IS_LONG && op2->type == IS_LONG)
  2107. {
  2108. long lval = op1->value.lval + op2->value.lval;
  2109. /* check for overflow by comparing sign bits */
  2110. if ((op1->value.lval & LONG_SIGN_MASK) == (op2->value.lval & LONG_SIGN_MASK)
  2111. && (op1->value.lval & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK))
  2112. {
  2113. result->value.dval = (double)op1->value.lval + (double)op2->value.lval;
  2114. result->type = IS_DOUBLE;
  2115. }
  2116. else
  2117. {
  2118. result->value.lval = lval;
  2119. result->type = IS_LONG;
  2120. }
  2121. return SUCCESS;
  2122. }
  2123. if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
  2124. || (op1->type == IS_LONG && op2->type == IS_DOUBLE))
  2125. {
  2126. result->value.dval = (op1->type == IS_LONG ?
  2127. (((double) op1->value.lval) + op2->value.dval) :
  2128. (op1->value.dval + ((double) op2->value.lval)));
  2129. result->type = IS_DOUBLE;
  2130. return SUCCESS;
  2131. }
  2132. if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE)
  2133. {
  2134. result->type = IS_DOUBLE;
  2135. result->value.dval = op1->value.dval + op2->value.dval;
  2136. return SUCCESS;
  2137. }
  2138. zend_error(E_ERROR, "Unsupported operand types");
  2139. return FAILURE; /* unknown datatype */
  2140. }
  2141. // copied from zend_operators.c and beautified
  2142. ZEND_API int sub_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2143. {
  2144. zval op1_copy, op2_copy;
  2145. zendi_convert_scalar_to_number(op1, op1_copy, result);
  2146. zendi_convert_scalar_to_number(op2, op2_copy, result);
  2147. if (op1->type == IS_LONG && op2->type == IS_LONG)
  2148. {
  2149. long lval = op1->value.lval - op2->value.lval;
  2150. /* check for overflow by comparing sign bits */
  2151. if ((op1->value.lval & LONG_SIGN_MASK) != (op2->value.lval & LONG_SIGN_MASK)
  2152. && (op1->value.lval & LONG_SIGN_MASK) != (lval & LONG_SIGN_MASK))
  2153. {
  2154. result->value.dval = (double)op1->value.lval - (double)op2->value.lval;
  2155. result->type = IS_DOUBLE;
  2156. }
  2157. else
  2158. {
  2159. result->value.lval = lval;
  2160. result->type = IS_LONG;
  2161. }
  2162. return SUCCESS;
  2163. }
  2164. if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
  2165. || (op1->type == IS_LONG && op2->type == IS_DOUBLE))
  2166. {
  2167. result->value.dval = (op1->type == IS_LONG ?
  2168. (((double) op1->value.lval) - op2->value.dval) :
  2169. (op1->value.dval - ((double) op2->value.lval)));
  2170. result->type = IS_DOUBLE;
  2171. return SUCCESS;
  2172. }
  2173. if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE)
  2174. {
  2175. result->type = IS_DOUBLE;
  2176. result->value.dval = op1->value.dval - op2->value.dval;
  2177. return SUCCESS;
  2178. }
  2179. zend_error(E_ERROR, "Unsupported operand types");
  2180. return FAILURE; /* unknown datatype */
  2181. }
  2182. // copied from zend_operators.c and beautified
  2183. ZEND_API int decrement_function(zval *op1)
  2184. {
  2185. long lval;
  2186. double dval;
  2187. switch (op1->type)
  2188. {
  2189. case IS_LONG:
  2190. if (op1->value.lval == LONG_MIN)
  2191. {
  2192. double d = (double)op1->value.lval;
  2193. ZVAL_DOUBLE(op1, d-1);
  2194. }
  2195. else op1->value.lval--;
  2196. break;
  2197. case IS_DOUBLE:
  2198. op1->value.dval = op1->value.dval - 1;
  2199. break;
  2200. case IS_STRING: /* Like perl we only support string increment */
  2201. if (op1->value.str.len == 0)
  2202. {
  2203. /* consider as 0 */
  2204. STR_FREE(op1->value.str.val);
  2205. op1->value.lval = -1;
  2206. op1->type = IS_LONG;
  2207. break;
  2208. }
  2209. switch (is_numeric_string(op1->value.str.val, op1->value.str.len, &lval, &dval, 0))
  2210. {
  2211. case IS_LONG:
  2212. STR_FREE(op1->value.str.val);
  2213. if (lval == LONG_MIN)
  2214. {
  2215. double d = (double)lval;
  2216. ZVAL_DOUBLE(op1, d - 1);
  2217. }
  2218. else
  2219. {
  2220. op1->value.lval = lval - 1;
  2221. op1->type = IS_LONG;
  2222. }
  2223. break;
  2224. case IS_DOUBLE:
  2225. STR_FREE(op1->value.str.val);
  2226. op1->value.dval = dval - 1;
  2227. op1->type = IS_DOUBLE;
  2228. break;
  2229. }
  2230. break;
  2231. default:
  2232. return FAILURE;
  2233. }
  2234. return SUCCESS;
  2235. }
  2236. #define LOWER_CASE 1
  2237. #define UPPER_CASE 2
  2238. #define NUMERIC 3
  2239. // copied from zend_operators.c and beautified
  2240. static void increment_string(zval *str)
  2241. {
  2242. int carry = 0;
  2243. int pos = str->value.str.len - 1;
  2244. char *s = str->value.str.val;
  2245. char *t;
  2246. int last = 0; /* Shut up the compiler warning */
  2247. int ch;
  2248. if (str->value.str.len == 0)
  2249. {
  2250. STR_FREE(str->value.str.val);
  2251. str->value.str.val = estrndup("1", sizeof("1") - 1);
  2252. str->value.str.len = 1;
  2253. return;
  2254. }
  2255. while (pos >= 0)
  2256. {
  2257. ch = s[pos];
  2258. if (ch >= 'a' && ch <= 'z')
  2259. {
  2260. if (ch == 'z')
  2261. {
  2262. s[pos] = 'a';
  2263. carry = 1;
  2264. }
  2265. else
  2266. {
  2267. s[pos]++;
  2268. carry = 0;
  2269. }
  2270. last = LOWER_CASE;
  2271. }
  2272. else if (ch >= 'A' && ch <= 'Z')
  2273. {
  2274. if (ch == 'Z')
  2275. {
  2276. s[pos] = 'A';
  2277. carry = 1;
  2278. }
  2279. else
  2280. {
  2281. s[pos]++;
  2282. carry = 0;
  2283. }
  2284. last = UPPER_CASE;
  2285. }
  2286. else if (ch >= '0' && ch <= '9')
  2287. {
  2288. if (ch == '9')
  2289. {
  2290. s[pos] = '0';
  2291. carry = 1;
  2292. }
  2293. else
  2294. {
  2295. s[pos]++;
  2296. carry = 0;
  2297. }
  2298. last = NUMERIC;
  2299. }
  2300. else
  2301. {
  2302. carry = 0;
  2303. break;
  2304. }
  2305. if (carry == 0) break;
  2306. pos--;
  2307. }
  2308. if (carry)
  2309. {
  2310. t = (char *)emalloc(str->value.str.len + 1 + 1);
  2311. memcpy(t + 1, str->value.str.val, str->value.str.len);
  2312. str->value.str.len++;
  2313. t[str->value.str.len] = '\0';
  2314. switch (last)
  2315. {
  2316. case NUMERIC:
  2317. t[0] = '1';
  2318. break;
  2319. case UPPER_CASE:
  2320. t[0] = 'A';
  2321. break;
  2322. case LOWER_CASE:
  2323. t[0] = 'a';
  2324. break;
  2325. }
  2326. STR_FREE(str->value.str.val);
  2327. str->value.str.val = t;
  2328. }
  2329. }
  2330. // copied from zend_operators.c and beautified
  2331. ZEND_API int increment_function(zval *op1)
  2332. {
  2333. switch (op1->type)
  2334. {
  2335. case IS_LONG:
  2336. if (op1->value.lval == LONG_MAX)
  2337. {
  2338. /* switch to double */
  2339. double d = (double)op1->value.lval;
  2340. ZVAL_DOUBLE(op1, d + 1);
  2341. }
  2342. else op1->value.lval++;
  2343. break;
  2344. case IS_DOUBLE:
  2345. op1->value.dval = op1->value.dval + 1;
  2346. break;
  2347. case IS_NULL:
  2348. op1->value.lval = 1;
  2349. op1->type = IS_LONG;
  2350. break;
  2351. case IS_STRING:
  2352. {
  2353. long lval;
  2354. double dval;
  2355. char *strval = op1->value.str.val;
  2356. switch (is_numeric_string(strval, op1->value.str.len, &lval, &dval, 0))
  2357. {
  2358. case IS_LONG:
  2359. if (lval == LONG_MAX)
  2360. {
  2361. /* switch to double */
  2362. double d = (double)lval;
  2363. ZVAL_DOUBLE(op1, d+1);
  2364. }
  2365. else
  2366. {
  2367. op1->value.lval = lval + 1;
  2368. op1->type = IS_LONG;
  2369. }
  2370. efree(strval); /* should never be empty_string */
  2371. break;
  2372. case IS_DOUBLE:
  2373. op1->value.dval = dval + 1;
  2374. op1->type = IS_DOUBLE;
  2375. efree(strval); /* should never be empty_string */
  2376. break;
  2377. default:
  2378. /* Perl style string increment */
  2379. increment_string(op1);
  2380. break;
  2381. }
  2382. }
  2383. break;
  2384. default:
  2385. return FAILURE;
  2386. }
  2387. return SUCCESS;
  2388. }
  2389. // copied from zend_operators.c and beautified
  2390. ZEND_API int div_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2391. {
  2392. zval op1_copy, op2_copy;
  2393. zendi_convert_scalar_to_number(op1, op1_copy, result);
  2394. zendi_convert_scalar_to_number(op2, op2_copy, result);
  2395. if ((op2->type == IS_LONG && op2->value.lval == 0) || (op2->type == IS_DOUBLE && op2->value.dval == 0.0))
  2396. {
  2397. zend_error(E_WARNING, "Division by zero");
  2398. ZVAL_BOOL(result, 0);
  2399. return FAILURE; /* division by zero */
  2400. }
  2401. if (op1->type == IS_LONG && op2->type == IS_LONG)
  2402. {
  2403. if (op1->value.lval % op2->value.lval == 0)
  2404. {
  2405. /* integer */
  2406. result->type = IS_LONG;
  2407. result->value.lval = op1->value.lval / op2->value.lval;
  2408. }
  2409. else
  2410. {
  2411. result->type = IS_DOUBLE;
  2412. result->value.dval = ((double)op1->value.lval) / op2->value.lval;
  2413. }
  2414. return SUCCESS;
  2415. }
  2416. if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
  2417. || (op1->type == IS_LONG && op2->type == IS_DOUBLE))
  2418. {
  2419. result->value.dval = (op1->type == IS_LONG ?
  2420. (((double)op1->value.lval) / op2->value.dval) :
  2421. (op1->value.dval / ((double)op2->value.lval)));
  2422. result->type = IS_DOUBLE;
  2423. return SUCCESS;
  2424. }
  2425. if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE)
  2426. {
  2427. result->type = IS_DOUBLE;
  2428. result->value.dval = op1->value.dval / op2->value.dval;
  2429. return SUCCESS;
  2430. }
  2431. zend_error(E_ERROR, "Unsupported operand types");
  2432. return FAILURE; /* unknown datatype */
  2433. }
  2434. // copied from zend_operators.c and beautified
  2435. ZEND_API int mod_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2436. {
  2437. zval op1_copy, op2_copy;
  2438. zendi_convert_to_long(op1, op1_copy, result);
  2439. zendi_convert_to_long(op2, op2_copy, result);
  2440. if (op2->value.lval == 0)
  2441. {
  2442. ZVAL_BOOL(result, 0);
  2443. return FAILURE; /* modulus by zero */
  2444. }
  2445. result->type = IS_LONG;
  2446. result->value.lval = op1->value.lval % op2->value.lval;
  2447. return SUCCESS;
  2448. }
  2449. // copied from zend_operators.c and beautified
  2450. ZEND_API int mul_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2451. {
  2452. zval op1_copy, op2_copy;
  2453. zendi_convert_scalar_to_number(op1, op1_copy, result);
  2454. zendi_convert_scalar_to_number(op2, op2_copy, result);
  2455. if (op1->type == IS_LONG && op2->type == IS_LONG)
  2456. {
  2457. long lval = op1->value.lval * op2->value.lval;
  2458. /* check for overflow by applying the reverse calculation */
  2459. if (op1->value.lval != 0 && lval / op1->value.lval != op2->value.lval)
  2460. {
  2461. result->value.dval = (double) op1->value.lval * (double) op2->value.lval;
  2462. result->type = IS_DOUBLE;
  2463. }
  2464. else
  2465. {
  2466. result->value.lval = lval;
  2467. result->type = IS_LONG;
  2468. }
  2469. return SUCCESS;
  2470. }
  2471. if ((op1->type == IS_DOUBLE && op2->type == IS_LONG)
  2472. || (op1->type == IS_LONG && op2->type == IS_DOUBLE))
  2473. {
  2474. result->value.dval = (op1->type == IS_LONG ?
  2475. (((double) op1->value.lval) * op2->value.dval) :
  2476. (op1->value.dval * ((double) op2->value.lval)));
  2477. result->type = IS_DOUBLE;
  2478. return SUCCESS;
  2479. }
  2480. if (op1->type == IS_DOUBLE && op2->type == IS_DOUBLE)
  2481. {
  2482. result->type = IS_DOUBLE;
  2483. result->value.dval = op1->value.dval * op2->value.dval;
  2484. return SUCCESS;
  2485. }
  2486. zend_error(E_ERROR, "Unsupported operand types");
  2487. return FAILURE; /* unknown datatype */
  2488. }
  2489. // copied from zend_operators.c
  2490. ZEND_API int shift_left_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2491. {
  2492. zval op1_copy, op2_copy;
  2493. zendi_convert_to_long(op1, op1_copy, result);
  2494. zendi_convert_to_long(op2, op2_copy, result);
  2495. result->value.lval = op1->value.lval << op2->value.lval;
  2496. result->type = IS_LONG;
  2497. return SUCCESS;
  2498. }
  2499. // copied from zend_operators.c
  2500. ZEND_API int shift_right_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2501. {
  2502. zval op1_copy, op2_copy;
  2503. zendi_convert_to_long(op1, op1_copy, result);
  2504. zendi_convert_to_long(op2, op2_copy, result);
  2505. result->value.lval = op1->value.lval >> op2->value.lval;
  2506. result->type = IS_LONG;
  2507. return SUCCESS;
  2508. }
  2509. // copied from zend_operators.c and beautified
  2510. static int hash_zval_identical_function(const zval **z1, const zval **z2)
  2511. {
  2512. zval result;
  2513. TSRMLS_FETCH();
  2514. /* is_identical_function() returns 1 in case of identity and 0 in case
  2515. * of a difference;
  2516. * whereas this comparison function is expected to return 0 on identity,
  2517. * and non zero otherwise.
  2518. */
  2519. if (is_identical_function(&result, (zval *)*z1, (zval *)*z2 TSRMLS_CC) == FAILURE)
  2520. {
  2521. return 1;
  2522. }
  2523. return !result.value.lval;
  2524. }
  2525. // copied from zend_operators.c and beautified
  2526. ZEND_API int is_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2527. {
  2528. result->type = IS_BOOL;
  2529. if (op1->type != op2->type)
  2530. {
  2531. result->value.lval = 0;
  2532. return SUCCESS;
  2533. }
  2534. switch (op1->type)
  2535. {
  2536. case IS_NULL:
  2537. result->value.lval = (op2->type==IS_NULL);
  2538. break;
  2539. case IS_BOOL:
  2540. case IS_LONG:
  2541. case IS_RESOURCE:
  2542. result->value.lval = (op1->value.lval == op2->value.lval);
  2543. break;
  2544. case IS_DOUBLE:
  2545. result->value.lval = (op1->value.dval == op2->value.dval);
  2546. break;
  2547. case IS_STRING:
  2548. if ((op1->value.str.len == op2->value.str.len)
  2549. && (!memcmp(op1->value.str.val, op2->value.str.val, op1->value.str.len)))
  2550. {
  2551. result->value.lval = 1;
  2552. }
  2553. else result->value.lval = 0;
  2554. break;
  2555. case IS_ARRAY:
  2556. if (zend_hash_compare(op1->value.ht, op2->value.ht,
  2557. (compare_func_t)hash_zval_identical_function, 1 TSRMLS_CC) == 0)
  2558. {
  2559. result->value.lval = 1;
  2560. }
  2561. else result->value.lval = 0;
  2562. break;
  2563. case IS_OBJECT:
  2564. /* OBJECTS_FIXME */
  2565. if (Z_OBJCE_P(op1) != Z_OBJCE_P(op2)) result->value.lval = 0;
  2566. else
  2567. {
  2568. if (zend_hash_compare(Z_OBJPROP_P(op1), Z_OBJPROP_P(op2),
  2569. (compare_func_t)hash_zval_identical_function, 1 TSRMLS_CC) == 0) result->value.lval = 1;
  2570. else result->value.lval = 0;
  2571. }
  2572. break;
  2573. default:
  2574. ZVAL_BOOL(result, 0);
  2575. return FAILURE;
  2576. }
  2577. return SUCCESS;
  2578. }
  2579. // copied from zend_operators.c and beautified
  2580. ZEND_API int is_not_identical_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2581. {
  2582. result->type = IS_BOOL;
  2583. if (is_identical_function(result, op1, op2 TSRMLS_CC) == FAILURE) return FAILURE;
  2584. result->value.lval = !result->value.lval;
  2585. return SUCCESS;
  2586. }
  2587. // copied from zend_operators.c and beautified
  2588. ZEND_API int is_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2589. {
  2590. if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) return FAILURE;
  2591. convert_to_boolean(result);
  2592. if (result->value.lval == 0) result->value.lval = 1;
  2593. else result->value.lval = 0;
  2594. return SUCCESS;
  2595. }
  2596. // copied from zend_operators.c and beautified
  2597. ZEND_API int is_not_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2598. {
  2599. if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) return FAILURE;
  2600. convert_to_boolean(result);
  2601. if (result->value.lval) result->value.lval = 1;
  2602. else result->value.lval = 0;
  2603. return SUCCESS;
  2604. }
  2605. // copied from zend_operators.c and beautified
  2606. ZEND_API int is_smaller_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2607. {
  2608. if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) return FAILURE;
  2609. if (result->type == IS_LONG)
  2610. {
  2611. result->type = IS_BOOL;
  2612. if (result->value.lval < 0) result->value.lval = 1;
  2613. else result->value.lval = 0;
  2614. return SUCCESS;
  2615. }
  2616. if (result->type == IS_DOUBLE)
  2617. {
  2618. result->type = IS_BOOL;
  2619. if (result->value.dval < 0) result->value.lval = 1;
  2620. else result->value.lval = 0;
  2621. return SUCCESS;
  2622. }
  2623. zend_error(E_ERROR, "Unsupported operand types");
  2624. return FAILURE;
  2625. }
  2626. // copied from zend_operators.c and beautified
  2627. ZEND_API int is_smaller_or_equal_function(zval *result, zval *op1, zval *op2 TSRMLS_DC)
  2628. {
  2629. if (compare_function(result, op1, op2 TSRMLS_CC) == FAILURE) return FAILURE;
  2630. if (result->type == IS_LONG)
  2631. {
  2632. result->type = IS_BOOL;
  2633. if (result->value.lval <= 0) result->value.lval = 1;
  2634. else result->value.lval = 0;
  2635. return SUCCESS;
  2636. }
  2637. if (result->type == IS_DOUBLE)
  2638. {
  2639. result->type = IS_BOOL;
  2640. if (result->value.dval <= 0) result->value.lval = 1;
  2641. else result->value.lval = 0;
  2642. return SUCCESS;
  2643. }
  2644. zend_error(E_ERROR, "Unsupported operand types");
  2645. return FAILURE;
  2646. }
  2647. // copied from zend_operators.c and beautified
  2648. ZEND_API void multi_convert_to_long_ex(int argc, ...)
  2649. {
  2650. zval **arg;
  2651. va_list ap;
  2652. va_start(ap, argc);
  2653. while (argc--)
  2654. {
  2655. arg = va_arg(ap, zval **);
  2656. convert_to_long_ex(arg);
  2657. }
  2658. va_end(ap);
  2659. }
  2660. // copied from zend_operators.c and beautified
  2661. ZEND_API void multi_convert_to_double_ex(int argc, ...)
  2662. {
  2663. zval **arg;
  2664. va_list ap;
  2665. va_start(ap, argc);
  2666. while (argc--)
  2667. {
  2668. arg = va_arg(ap, zval **);
  2669. convert_to_double_ex(arg);
  2670. }
  2671. va_end(ap);
  2672. }
  2673. // copied from zend_operators.c and beautified
  2674. ZEND_API void multi_convert_to_string_ex(int argc, ...)
  2675. {
  2676. zval **arg;
  2677. va_list ap;
  2678. va_start(ap, argc);
  2679. while (argc--)
  2680. {
  2681. arg = va_arg(ap, zval **);
  2682. convert_to_string_ex(arg);
  2683. }
  2684. va_end(ap);
  2685. }
  2686. // copied from zend_opcode.c and beautified
  2687. ZEND_API void *get_binary_op(int opcode)
  2688. {
  2689. switch (opcode)
  2690. {
  2691. case ZEND_ADD:
  2692. case ZEND_ASSIGN_ADD:
  2693. return (void *)add_function;
  2694. break;
  2695. case ZEND_SUB:
  2696. case ZEND_ASSIGN_SUB:
  2697. return (void *)sub_function;
  2698. break;
  2699. case ZEND_MUL:
  2700. case ZEND_ASSIGN_MUL:
  2701. return (void *)mul_function;
  2702. break;
  2703. case ZEND_DIV:
  2704. case ZEND_ASSIGN_DIV:
  2705. return (void *)div_function;
  2706. break;
  2707. case ZEND_MOD:
  2708. case ZEND_ASSIGN_MOD:
  2709. return (void *)mod_function;
  2710. break;
  2711. case ZEND_SL:
  2712. case ZEND_ASSIGN_SL:
  2713. return (void *)shift_left_function;
  2714. break;
  2715. case ZEND_SR:
  2716. case ZEND_ASSIGN_SR:
  2717. return (void *)shift_right_function;
  2718. break;
  2719. case ZEND_CONCAT:
  2720. case ZEND_ASSIGN_CONCAT:
  2721. return (void *)concat_function;
  2722. break;
  2723. case ZEND_IS_IDENTICAL:
  2724. return (void *)is_identical_function;
  2725. break;
  2726. case ZEND_IS_NOT_IDENTICAL:
  2727. return (void *)is_not_identical_function;
  2728. break;
  2729. case ZEND_IS_EQUAL:
  2730. return (void *)is_equal_function;
  2731. break;
  2732. case ZEND_IS_NOT_EQUAL:
  2733. return (void *)is_not_equal_function;
  2734. break;
  2735. case ZEND_IS_SMALLER:
  2736. return (void *)is_smaller_function;
  2737. break;
  2738. case ZEND_IS_SMALLER_OR_EQUAL:
  2739. return (void *)is_smaller_or_equal_function;
  2740. break;
  2741. case ZEND_BW_OR:
  2742. case ZEND_ASSIGN_BW_OR:
  2743. return (void *)bitwise_or_function;
  2744. break;
  2745. case ZEND_BW_AND:
  2746. case ZEND_ASSIGN_BW_AND:
  2747. return (void *)bitwise_and_function;
  2748. break;
  2749. case ZEND_BW_XOR:
  2750. case ZEND_ASSIGN_BW_XOR:
  2751. return (void *)bitwise_xor_function;
  2752. break;
  2753. default:
  2754. return NULL;
  2755. break;
  2756. }
  2757. }
  2758. // copied from zend_opcode.c and beautified
  2759. ZEND_API unary_op_type get_unary_op(int opcode)
  2760. {
  2761. switch (opcode)
  2762. {
  2763. case ZEND_BW_NOT:
  2764. return (unary_op_type)bitwise_not_function;
  2765. break;
  2766. case ZEND_BOOL_NOT:
  2767. return (unary_op_type)boolean_not_function;
  2768. break;
  2769. default:
  2770. return (unary_op_type) NULL;
  2771. break;
  2772. }
  2773. }
  2774. // copied from php_variables.c and beautified
  2775. void _php_import_environment_variables(zval *array_ptr TSRMLS_DC)
  2776. {
  2777. //char **env, *p, *t;
  2778. //for (env = environ; env != NULL && *env != NULL; env++)
  2779. //{
  2780. // p = strchr(*env, '=');
  2781. // if (!p) continue; /* malformed entry? */
  2782. // t = estrndup(*env, p - *env);
  2783. // php_register_variable(t, p + 1, array_ptr TSRMLS_CC);
  2784. // efree(t);
  2785. //}
  2786. }
  2787. ZEND_API void (*php_import_environment_variables)(zval *array_ptr TSRMLS_DC) = _php_import_environment_variables;
  2788. #ifdef PHP4TS
  2789. // copied from zend_operators.c
  2790. ZEND_API zend_bool zend_is_callable(zval *callable, zend_bool syntax_only, char **callable_name)
  2791. {
  2792. char *lcname;
  2793. int retval = 0;
  2794. TSRMLS_FETCH();
  2795. switch (Z_TYPE_P(callable))
  2796. {
  2797. case IS_STRING:
  2798. {
  2799. if (callable_name) *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
  2800. if (syntax_only) return 1;
  2801. lcname = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
  2802. zend_str_tolower(lcname, Z_STRLEN_P(callable));
  2803. if (zend_hash_exists(EG(function_table), lcname, Z_STRLEN_P(callable) + 1)) retval = 1;
  2804. efree(lcname);
  2805. break;
  2806. }
  2807. case IS_ARRAY:
  2808. {
  2809. zval **method;
  2810. zval **obj;
  2811. zend_class_entry *ce = NULL;
  2812. char callable_name_len;
  2813. if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2 &&
  2814. zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj) == SUCCESS &&
  2815. zend_hash_index_find(Z_ARRVAL_P(callable), 1, (void **) &method) == SUCCESS &&
  2816. (Z_TYPE_PP(obj) == IS_OBJECT || Z_TYPE_PP(obj) == IS_STRING) &&
  2817. Z_TYPE_PP(method) == IS_STRING)
  2818. {
  2819. if (Z_TYPE_PP(obj) == IS_STRING)
  2820. {
  2821. if (callable_name)
  2822. {
  2823. char *ptr;
  2824. callable_name_len = Z_STRLEN_PP(obj) + Z_STRLEN_PP(method) + sizeof("::");
  2825. ptr = *callable_name = (char *)emalloc(callable_name_len);
  2826. memcpy(ptr, Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
  2827. ptr += Z_STRLEN_PP(obj);
  2828. memcpy(ptr, "::", sizeof("::") - 1);
  2829. ptr += sizeof("::") - 1;
  2830. memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
  2831. }
  2832. if (syntax_only) return 1;
  2833. lcname = estrndup(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
  2834. zend_str_tolower(lcname, Z_STRLEN_PP(obj));
  2835. zend_hash_find(EG(class_table), lcname, Z_STRLEN_PP(obj) + 1, (void**)&ce);
  2836. efree(lcname);
  2837. }
  2838. else
  2839. {
  2840. ce = Z_OBJCE_PP(obj);
  2841. if (callable_name)
  2842. {
  2843. char *ptr;
  2844. callable_name_len = ce->name_length + Z_STRLEN_PP(method) + sizeof("::");
  2845. ptr = *callable_name = (char *)emalloc(callable_name_len);
  2846. memcpy(ptr, ce->name, ce->name_length);
  2847. ptr += ce->name_length;
  2848. memcpy(ptr, "::", sizeof("::") - 1);
  2849. ptr += sizeof("::") - 1;
  2850. memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
  2851. }
  2852. if (syntax_only) return 1;
  2853. }
  2854. if (ce)
  2855. {
  2856. lcname = estrndup(Z_STRVAL_PP(method), Z_STRLEN_PP(method));
  2857. zend_str_tolower(lcname, Z_STRLEN_PP(method));
  2858. if (zend_hash_exists(&ce->function_table, lcname, Z_STRLEN_PP(method) + 1))
  2859. {
  2860. retval = 1;
  2861. }
  2862. efree(lcname);
  2863. }
  2864. }
  2865. else if (callable_name) *callable_name = estrndup("Array", sizeof("Array")-1);
  2866. }
  2867. break;
  2868. default:
  2869. if (callable_name)
  2870. {
  2871. zval expr_copy;
  2872. int use_copy;
  2873. zend_make_printable_zval(callable, &expr_copy, &use_copy);
  2874. *callable_name = estrndup(Z_STRVAL(expr_copy), Z_STRLEN(expr_copy));
  2875. zval_dtor(&expr_copy);
  2876. }
  2877. break;
  2878. }
  2879. return retval;
  2880. }
  2881. #elif defined PHP5TS
  2882. //Copied from zend_api.c
  2883. static int zend_is_callable_check_func(int check_flags, zval ***zobj_ptr_ptr, zend_class_entry *ce_org, zval *callable, zend_class_entry **ce_ptr, zend_function **fptr_ptr TSRMLS_DC)
  2884. {
  2885. int retval;
  2886. char *lcname, *lmname, *colon;
  2887. int clen, mlen;
  2888. zend_function *fptr;
  2889. zend_class_entry **pce;
  2890. HashTable *ftable;
  2891. *ce_ptr = NULL;
  2892. *fptr_ptr = NULL;
  2893. if ((colon = strstr(Z_STRVAL_P(callable), "::")) != NULL) {
  2894. clen = colon - Z_STRVAL_P(callable);
  2895. mlen = Z_STRLEN_P(callable) - clen - 2;
  2896. lcname = zend_str_tolower_dup(Z_STRVAL_P(callable), clen);
  2897. /* caution: lcname is not '\0' terminated */
  2898. if (clen == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self") - 1) == 0) {
  2899. *ce_ptr = EG(scope);
  2900. } else if (clen == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent") - 1) == 0 && EG(active_op_array)->scope) {
  2901. *ce_ptr = EG(scope) ? EG(scope)->parent : NULL;
  2902. } else if (zend_lookup_class(Z_STRVAL_P(callable), clen, &pce TSRMLS_CC) == SUCCESS) {
  2903. *ce_ptr = *pce;
  2904. }
  2905. efree(lcname);
  2906. if (!*ce_ptr) {
  2907. return 0;
  2908. }
  2909. ftable = &(*ce_ptr)->function_table;
  2910. if (ce_org && !instanceof_function(ce_org, *ce_ptr TSRMLS_CC)) {
  2911. return 0;
  2912. }
  2913. lmname = zend_str_tolower_dup(Z_STRVAL_P(callable) + clen + 2, mlen);
  2914. } else {
  2915. mlen = Z_STRLEN_P(callable);
  2916. lmname = zend_str_tolower_dup(Z_STRVAL_P(callable), mlen);
  2917. if (ce_org) {
  2918. ftable = &ce_org->function_table;
  2919. *ce_ptr = ce_org;
  2920. } else {
  2921. ftable = EG(function_table);
  2922. }
  2923. }
  2924. retval = zend_hash_find(ftable, lmname, mlen+1, (void**)&fptr) == SUCCESS ? 1 : 0;
  2925. if (!retval) {
  2926. if (*zobj_ptr_ptr && *ce_ptr && (*ce_ptr)->__call != 0) {
  2927. retval = (*ce_ptr)->__call != NULL;
  2928. *fptr_ptr = (*ce_ptr)->__call;
  2929. }
  2930. } else {
  2931. *fptr_ptr = fptr;
  2932. if (*ce_ptr) {
  2933. if (!*zobj_ptr_ptr && !(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
  2934. if ((check_flags & IS_CALLABLE_CHECK_IS_STATIC) != 0) {
  2935. retval = 0;
  2936. } else {
  2937. if (EG(This) && instanceof_function(Z_OBJCE_P(EG(This)), *ce_ptr TSRMLS_CC)) {
  2938. *zobj_ptr_ptr = &EG(This);
  2939. zend_error(E_STRICT, "Non-static method %s::%s() cannot be called statically, assuming $this from compatible context %s", (*ce_ptr)->name, fptr->common.function_name, Z_OBJCE_P(EG(This))->name);
  2940. } else {
  2941. zend_error(E_STRICT, "Non-static method %s::%s() cannot be called statically", (*ce_ptr)->name, fptr->common.function_name);
  2942. }
  2943. }
  2944. }
  2945. if (retval && (check_flags & IS_CALLABLE_CHECK_NO_ACCESS) == 0) {
  2946. if (fptr->op_array.fn_flags & ZEND_ACC_PRIVATE) {
  2947. if (!zend_check_private(fptr, *zobj_ptr_ptr ? Z_OBJCE_PP(*zobj_ptr_ptr) : EG(scope), lmname, mlen TSRMLS_CC)) {
  2948. retval = 0;
  2949. }
  2950. } else if ((fptr->common.fn_flags & ZEND_ACC_PROTECTED)) {
  2951. if (!zend_check_protected(fptr->common.scope, EG(scope))) {
  2952. retval = 0;
  2953. }
  2954. }
  2955. }
  2956. }
  2957. }
  2958. efree(lmname);
  2959. return retval;
  2960. }
  2961. //Copied from zend_api.c (php4ts)
  2962. ZEND_API zend_bool zend_is_callable_ex(zval *callable, uint check_flags, char **callable_name, int *callable_name_len, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zval ***zobj_ptr_ptr TSRMLS_DC)
  2963. {
  2964. char *lcname;
  2965. zend_bool retval = 0;
  2966. int callable_name_len_local;
  2967. zend_class_entry *ce_local, **pce;
  2968. zend_function *fptr_local;
  2969. zval **zobj_ptr_local;
  2970. if (callable_name) {
  2971. *callable_name = NULL;
  2972. }
  2973. if (callable_name_len == NULL) {
  2974. callable_name_len = &callable_name_len_local;
  2975. }
  2976. if (ce_ptr == NULL) {
  2977. ce_ptr = &ce_local;
  2978. }
  2979. if (fptr_ptr == NULL) {
  2980. fptr_ptr = &fptr_local;
  2981. }
  2982. if (zobj_ptr_ptr == NULL) {
  2983. zobj_ptr_ptr = &zobj_ptr_local;
  2984. }
  2985. *ce_ptr = NULL;
  2986. *fptr_ptr = NULL;
  2987. *zobj_ptr_ptr = NULL;
  2988. switch (Z_TYPE_P(callable)) {
  2989. case IS_STRING:
  2990. if (callable_name) {
  2991. *callable_name = estrndup(Z_STRVAL_P(callable), Z_STRLEN_P(callable));
  2992. *callable_name_len = Z_STRLEN_P(callable);
  2993. }
  2994. if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
  2995. return 1;
  2996. }
  2997. retval = zend_is_callable_check_func(check_flags|IS_CALLABLE_CHECK_IS_STATIC, zobj_ptr_ptr, NULL, callable, ce_ptr, fptr_ptr TSRMLS_CC);
  2998. break;
  2999. case IS_ARRAY:
  3000. {
  3001. zend_class_entry *ce = NULL;
  3002. zval **method;
  3003. zval **obj;
  3004. if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2 &&
  3005. zend_hash_index_find(Z_ARRVAL_P(callable), 0, (void **) &obj) == SUCCESS &&
  3006. zend_hash_index_find(Z_ARRVAL_P(callable), 1, (void **) &method) == SUCCESS &&
  3007. (Z_TYPE_PP(obj) == IS_OBJECT || Z_TYPE_PP(obj) == IS_STRING) &&
  3008. Z_TYPE_PP(method) == IS_STRING) {
  3009. if (Z_TYPE_PP(obj) == IS_STRING) {
  3010. if (callable_name) {
  3011. char *ptr;
  3012. *callable_name_len = Z_STRLEN_PP(obj) + Z_STRLEN_PP(method) + sizeof("::") - 1;
  3013. ptr = *callable_name = (char *)emalloc(*callable_name_len + 1);
  3014. memcpy(ptr, Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
  3015. ptr += Z_STRLEN_PP(obj);
  3016. memcpy(ptr, "::", sizeof("::") - 1);
  3017. ptr += sizeof("::") - 1;
  3018. memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
  3019. }
  3020. if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
  3021. return 1;
  3022. }
  3023. lcname = zend_str_tolower_dup(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj));
  3024. if (Z_STRLEN_PP(obj) == sizeof("self") - 1 && memcmp(lcname, "self", sizeof("self")) == 0 && EG(active_op_array)) {
  3025. ce = EG(active_op_array)->scope;
  3026. } else if (Z_STRLEN_PP(obj) == sizeof("parent") - 1 && memcmp(lcname, "parent", sizeof("parent")) == 0 && EG(active_op_array) && EG(active_op_array)->scope) {
  3027. ce = EG(active_op_array)->scope->parent;
  3028. } else if (zend_lookup_class(Z_STRVAL_PP(obj), Z_STRLEN_PP(obj), &pce TSRMLS_CC) == SUCCESS) {
  3029. ce = *pce;
  3030. }
  3031. efree(lcname);
  3032. } else {
  3033. ce = Z_OBJCE_PP(obj); /* TBFixed: what if it's overloaded? */
  3034. *zobj_ptr_ptr = obj;
  3035. if (callable_name) {
  3036. char *ptr;
  3037. *callable_name_len = ce->name_length + Z_STRLEN_PP(method) + sizeof("::") - 1;
  3038. ptr = *callable_name = (char *)emalloc(*callable_name_len + 1);
  3039. memcpy(ptr, ce->name, ce->name_length);
  3040. ptr += ce->name_length;
  3041. memcpy(ptr, "::", sizeof("::") - 1);
  3042. ptr += sizeof("::") - 1;
  3043. memcpy(ptr, Z_STRVAL_PP(method), Z_STRLEN_PP(method) + 1);
  3044. }
  3045. if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
  3046. *ce_ptr = ce;
  3047. return 1;
  3048. }
  3049. }
  3050. if (ce) {
  3051. retval = zend_is_callable_check_func(check_flags, zobj_ptr_ptr, ce, *method, ce_ptr, fptr_ptr TSRMLS_CC);
  3052. }
  3053. } else if (callable_name) {
  3054. *callable_name = estrndup("Array", sizeof("Array")-1);
  3055. *callable_name_len = sizeof("Array") - 1;
  3056. }
  3057. *ce_ptr = ce;
  3058. }
  3059. break;
  3060. default:
  3061. if (callable_name) {
  3062. zval expr_copy;
  3063. int use_copy;
  3064. zend_make_printable_zval(callable, &expr_copy, &use_copy);
  3065. *callable_name = estrndup(Z_STRVAL(expr_copy), Z_STRLEN(expr_copy));
  3066. *callable_name_len = Z_STRLEN(expr_copy);
  3067. zval_dtor(&expr_copy);
  3068. }
  3069. break;
  3070. }
  3071. return retval;
  3072. }
  3073. ZEND_API zend_bool zend_is_callable(zval *callable, uint check_flags, char **callable_name TSRMLS_DC)
  3074. {
  3075. return zend_is_callable_ex(callable, check_flags, callable_name, NULL, NULL, NULL, NULL TSRMLS_CC);
  3076. }
  3077. // copied from zend_operators.c
  3078. ZEND_API zend_bool instanceof_function_ex(zend_class_entry *instance_ce, zend_class_entry *ce, zend_bool interfaces_only TSRMLS_DC)
  3079. {
  3080. zend_uint i;
  3081. for (i=0; i<instance_ce->num_interfaces; i++) {
  3082. if (instanceof_function(instance_ce->interfaces[i], ce TSRMLS_CC)) {
  3083. return 1;
  3084. }
  3085. }
  3086. if (!interfaces_only) {
  3087. while (instance_ce) {
  3088. if (instance_ce == ce) {
  3089. return 1;
  3090. }
  3091. instance_ce = instance_ce->parent;
  3092. }
  3093. }
  3094. return 0;
  3095. }
  3096. // copied from zend_operators.c
  3097. ZEND_API zend_bool instanceof_function(zend_class_entry *instance_ce, zend_class_entry *ce TSRMLS_DC)
  3098. {
  3099. return instanceof_function_ex(instance_ce, ce, 0 TSRMLS_CC);
  3100. }
  3101. // copied from zend_execute_api.c
  3102. ZEND_API void zend_rebuild_symbol_table(TSRMLS_D)
  3103. {
  3104. }
  3105. #endif