+/* {{{ zval *http_exception_wrap(zval *, zval *, zend_class_entry *) */
+zval *_http_exception_wrap(zval *old_exception, zval *new_exception, zend_class_entry *ce TSRMLS_DC)
+{
+ int inner = 1;
+ char *message;
+ zval *sub_exception, *tmp_exception;
+
+ if (!new_exception) {
+ MAKE_STD_ZVAL(new_exception);
+ object_init_ex(new_exception, ce);
+
+ zend_update_property(ce, new_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
+ copy_bt_args(old_exception, new_exception TSRMLS_CC);
+
+ sub_exception = old_exception;
+
+ while ((sub_exception = zend_read_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(sub_exception) == IS_OBJECT) {
+ ++inner;
+ }
+
+ spprintf(&message, 0, "Exception caused by %d inner exception(s)", inner);
+ zend_update_property_string(ZEND_EXCEPTION_GET_DEFAULT(), new_exception, "message", lenof("message"), message TSRMLS_CC);
+ efree(message);
+ } else {
+ sub_exception = new_exception;
+ tmp_exception = new_exception;
+
+ while ((tmp_exception = zend_read_property(Z_OBJCE_P(tmp_exception), tmp_exception, "innerException", lenof("innerException"), 0 TSRMLS_CC)) && Z_TYPE_P(tmp_exception) == IS_OBJECT) {
+ sub_exception = tmp_exception;
+ }
+
+ zend_update_property(Z_OBJCE_P(sub_exception), sub_exception, "innerException", lenof("innerException"), old_exception TSRMLS_CC);
+ copy_bt_args(old_exception, new_exception TSRMLS_CC);
+ copy_bt_args(old_exception, sub_exception TSRMLS_CC);
+ }
+#if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 3
+ Z_ADDREF_P(old_exception);
+ zend_exception_set_previous(new_exception, old_exception TSRMLS_CC);
+#endif
+ zval_ptr_dtor(&old_exception);
+ return new_exception;