mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
implement clone functionality to fix segfault
DomNode->clone() creates new doc proxy if document is cloned remove printf from xpath fix remaining invalid object state issues
This commit is contained in:
parent
0ecd198dc5
commit
ec2ea131fb
6 changed files with 170 additions and 129 deletions
|
@ -268,33 +268,35 @@ zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object TS
|
||||||
|
|
||||||
intern = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
|
intern = (dom_object *)zend_object_store_get_object(object TSRMLS_CC);
|
||||||
objmap = (dom_nnodemap_object *)intern->ptr;
|
objmap = (dom_nnodemap_object *)intern->ptr;
|
||||||
if (objmap->ht == NULL) {
|
if (objmap != NULL) {
|
||||||
if (objmap->nodetype == DOM_NODESET) {
|
if (objmap->ht == NULL) {
|
||||||
nodeht = HASH_OF(objmap->baseobjptr);
|
if (objmap->nodetype == DOM_NODESET) {
|
||||||
zend_hash_internal_pointer_reset(nodeht);
|
nodeht = HASH_OF(objmap->baseobjptr);
|
||||||
if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
|
zend_hash_internal_pointer_reset(nodeht);
|
||||||
curattr = *entry;
|
if (zend_hash_get_current_data(nodeht, (void **) &entry)==SUCCESS) {
|
||||||
curattr->refcount++;
|
curattr = *entry;
|
||||||
}
|
curattr->refcount++;
|
||||||
} else {
|
|
||||||
nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
|
|
||||||
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
|
|
||||||
if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
|
|
||||||
curnode = (xmlNodePtr) nodep->properties;
|
|
||||||
} else {
|
|
||||||
curnode = (xmlNodePtr) nodep->children;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
|
nodep = (xmlNode *)dom_object_get_node(objmap->baseobj);
|
||||||
nodep = xmlDocGetRootElement((xmlDoc *) nodep);
|
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
|
||||||
|
if (objmap->nodetype == XML_ATTRIBUTE_NODE) {
|
||||||
|
curnode = (xmlNodePtr) nodep->properties;
|
||||||
|
} else {
|
||||||
|
curnode = (xmlNodePtr) nodep->children;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
nodep = nodep->children;
|
if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
|
||||||
|
nodep = xmlDocGetRootElement((xmlDoc *) nodep);
|
||||||
|
} else {
|
||||||
|
nodep = nodep->children;
|
||||||
|
}
|
||||||
|
curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0);
|
||||||
}
|
}
|
||||||
curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &curindex, 0);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
curnode = php_dom_libxml_hash_iter(objmap->ht, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (curnode) {
|
if (curnode) {
|
||||||
|
|
|
@ -61,17 +61,20 @@ int dom_namednodemap_length_read(dom_object *obj, zval **retval TSRMLS_DC)
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
objmap = (dom_nnodemap_object *)obj->ptr;
|
objmap = (dom_nnodemap_object *)obj->ptr;
|
||||||
if (objmap->ht) {
|
|
||||||
count = xmlHashSize(objmap->ht);
|
if (objmap != NULL) {
|
||||||
} else {
|
if (objmap->ht) {
|
||||||
nodep = dom_object_get_node(objmap->baseobj);
|
count = xmlHashSize(objmap->ht);
|
||||||
if (nodep) {
|
} else {
|
||||||
curnode = nodep->properties;
|
nodep = dom_object_get_node(objmap->baseobj);
|
||||||
if (curnode) {
|
if (nodep) {
|
||||||
count++;
|
curnode = nodep->properties;
|
||||||
while (curnode->next != NULL) {
|
if (curnode) {
|
||||||
count++;
|
count++;
|
||||||
curnode = curnode->next;
|
while (curnode->next != NULL) {
|
||||||
|
count++;
|
||||||
|
curnode = curnode->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,17 +113,20 @@ PHP_FUNCTION(dom_namednodemap_get_named_item)
|
||||||
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
||||||
|
|
||||||
objmap = (dom_nnodemap_object *)intern->ptr;
|
objmap = (dom_nnodemap_object *)intern->ptr;
|
||||||
if (objmap->ht) {
|
|
||||||
if (objmap->nodetype == XML_ENTITY_NODE) {
|
if (objmap != NULL) {
|
||||||
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, named);
|
if (objmap->ht) {
|
||||||
|
if (objmap->nodetype == XML_ENTITY_NODE) {
|
||||||
|
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, named);
|
||||||
|
} else {
|
||||||
|
notep = (xmlNotation *)xmlHashLookup(objmap->ht, named);
|
||||||
|
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
notep = (xmlNotation *)xmlHashLookup(objmap->ht, named);
|
nodep = dom_object_get_node(objmap->baseobj);
|
||||||
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
|
if (nodep) {
|
||||||
}
|
itemnode = (xmlNodePtr)xmlHasProp(nodep, named);
|
||||||
} else {
|
}
|
||||||
nodep = dom_object_get_node(objmap->baseobj);
|
|
||||||
if (nodep) {
|
|
||||||
itemnode = (xmlNodePtr)xmlHasProp(nodep, named);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,26 +184,27 @@ PHP_FUNCTION(dom_namednodemap_item)
|
||||||
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
||||||
|
|
||||||
objmap = (dom_nnodemap_object *)intern->ptr;
|
objmap = (dom_nnodemap_object *)intern->ptr;
|
||||||
if (objmap->ht) {
|
|
||||||
if (objmap->nodetype == XML_ENTITY_NODE) {
|
if (objmap != NULL) {
|
||||||
itemnode = php_dom_libxml_hash_iter(objmap->ht, index);
|
if (objmap->ht) {
|
||||||
} else {
|
if (objmap->nodetype == XML_ENTITY_NODE) {
|
||||||
itemnode = php_dom_libxml_notation_iter(objmap->ht, index);
|
itemnode = php_dom_libxml_hash_iter(objmap->ht, index);
|
||||||
}
|
} else {
|
||||||
} else {
|
itemnode = php_dom_libxml_notation_iter(objmap->ht, index);
|
||||||
nodep = dom_object_get_node(objmap->baseobj);
|
}
|
||||||
if (nodep) {
|
} else {
|
||||||
curnode = (xmlNodePtr)nodep->properties;
|
nodep = dom_object_get_node(objmap->baseobj);
|
||||||
count = 0;
|
if (nodep) {
|
||||||
while (count < index && curnode != NULL) {
|
curnode = (xmlNodePtr)nodep->properties;
|
||||||
count++;
|
count = 0;
|
||||||
curnode = (xmlNodePtr)curnode->next;
|
while (count < index && curnode != NULL) {
|
||||||
|
count++;
|
||||||
|
curnode = (xmlNodePtr)curnode->next;
|
||||||
|
}
|
||||||
|
itemnode = curnode;
|
||||||
}
|
}
|
||||||
itemnode = curnode;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
RETURN_NULL();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemnode) {
|
if (itemnode) {
|
||||||
|
@ -232,17 +239,20 @@ PHP_FUNCTION(dom_namednodemap_get_named_item_ns)
|
||||||
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
||||||
|
|
||||||
objmap = (dom_nnodemap_object *)intern->ptr;
|
objmap = (dom_nnodemap_object *)intern->ptr;
|
||||||
if (objmap->ht) {
|
|
||||||
if (objmap->nodetype == XML_ENTITY_NODE) {
|
if (objmap != NULL) {
|
||||||
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, named);
|
if (objmap->ht) {
|
||||||
|
if (objmap->nodetype == XML_ENTITY_NODE) {
|
||||||
|
itemnode = (xmlNodePtr)xmlHashLookup(objmap->ht, named);
|
||||||
|
} else {
|
||||||
|
notep = (xmlNotation *)xmlHashLookup(objmap->ht, named);
|
||||||
|
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
notep = (xmlNotation *)xmlHashLookup(objmap->ht, named);
|
nodep = dom_object_get_node(objmap->baseobj);
|
||||||
itemnode = create_notation(notep->name, notep->PublicID, notep->SystemID);
|
if (nodep) {
|
||||||
}
|
itemnode = (xmlNodePtr)xmlHasNsProp(nodep, named, uri);
|
||||||
} else {
|
}
|
||||||
nodep = dom_object_get_node(objmap->baseobj);
|
|
||||||
if (nodep) {
|
|
||||||
itemnode = (xmlNodePtr)xmlHasNsProp(nodep, named, uri);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1291,9 +1291,13 @@ PHP_FUNCTION(dom_node_clone_node)
|
||||||
|
|
||||||
node = xmlDocCopyNode(n, n->doc, recursive);
|
node = xmlDocCopyNode(n, n->doc, recursive);
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* When deep is false Element nodes still require the attributes
|
/* When deep is false Element nodes still require the attributes
|
||||||
Following taken from libxml as xmlDocCopyNode doesnt do this */
|
Following taken from libxml as xmlDocCopyNode doesnt do this */
|
||||||
if (node && n->type == XML_ELEMENT_NODE && recursive == 0) {
|
if (n->type == XML_ELEMENT_NODE && recursive == 0) {
|
||||||
if (n->nsDef != NULL) {
|
if (n->nsDef != NULL) {
|
||||||
node->nsDef = xmlCopyNamespaceList(n->nsDef);
|
node->nsDef = xmlCopyNamespaceList(n->nsDef);
|
||||||
}
|
}
|
||||||
|
@ -1319,8 +1323,9 @@ PHP_FUNCTION(dom_node_clone_node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node) {
|
/* If document cloned we want a new document proxy */
|
||||||
RETURN_FALSE;
|
if (node->doc != n->doc) {
|
||||||
|
intern = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
DOM_RET_OBJ(rv, node, &ret, intern);
|
DOM_RET_OBJ(rv, node, &ret, intern);
|
||||||
|
|
|
@ -55,31 +55,33 @@ int dom_nodelist_length_read(dom_object *obj, zval **retval TSRMLS_DC)
|
||||||
HashTable *nodeht;
|
HashTable *nodeht;
|
||||||
|
|
||||||
objmap = (dom_nnodemap_object *)obj->ptr;
|
objmap = (dom_nnodemap_object *)obj->ptr;
|
||||||
if (objmap->ht) {
|
if (objmap != NULL) {
|
||||||
count = xmlHashSize(objmap->ht);
|
if (objmap->ht) {
|
||||||
} else {
|
count = xmlHashSize(objmap->ht);
|
||||||
if (objmap->nodetype == DOM_NODESET) {
|
|
||||||
nodeht = HASH_OF(objmap->baseobjptr);
|
|
||||||
count = zend_hash_num_elements(nodeht);
|
|
||||||
} else {
|
} else {
|
||||||
nodep = dom_object_get_node(objmap->baseobj);
|
if (objmap->nodetype == DOM_NODESET) {
|
||||||
if (nodep) {
|
nodeht = HASH_OF(objmap->baseobjptr);
|
||||||
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
|
count = zend_hash_num_elements(nodeht);
|
||||||
curnode = nodep->children;
|
} else {
|
||||||
if (curnode) {
|
nodep = dom_object_get_node(objmap->baseobj);
|
||||||
count++;
|
if (nodep) {
|
||||||
while (curnode->next != NULL) {
|
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
|
||||||
|
curnode = nodep->children;
|
||||||
|
if (curnode) {
|
||||||
count++;
|
count++;
|
||||||
curnode = curnode->next;
|
while (curnode->next != NULL) {
|
||||||
|
count++;
|
||||||
|
curnode = curnode->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
|
|
||||||
nodep = xmlDocGetRootElement((xmlDoc *) nodep);
|
|
||||||
} else {
|
} else {
|
||||||
nodep = nodep->children;
|
if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
|
||||||
|
nodep = xmlDocGetRootElement((xmlDoc *) nodep);
|
||||||
|
} else {
|
||||||
|
nodep = nodep->children;
|
||||||
|
}
|
||||||
|
curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &count, -1);
|
||||||
}
|
}
|
||||||
curnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &count, -1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,43 +120,43 @@ PHP_FUNCTION(dom_nodelist_item)
|
||||||
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
intern = (dom_object *)zend_object_store_get_object(id TSRMLS_CC);
|
||||||
|
|
||||||
objmap = (dom_nnodemap_object *)intern->ptr;
|
objmap = (dom_nnodemap_object *)intern->ptr;
|
||||||
if (objmap->ht) {
|
if (objmap != NULL) {
|
||||||
if (objmap->nodetype == XML_ENTITY_NODE) {
|
if (objmap->ht) {
|
||||||
itemnode = php_dom_libxml_hash_iter(objmap->ht, index);
|
if (objmap->nodetype == XML_ENTITY_NODE) {
|
||||||
} else {
|
itemnode = php_dom_libxml_hash_iter(objmap->ht, index);
|
||||||
itemnode = php_dom_libxml_notation_iter(objmap->ht, index);
|
} else {
|
||||||
}
|
itemnode = php_dom_libxml_notation_iter(objmap->ht, index);
|
||||||
} else {
|
|
||||||
if (objmap->nodetype == DOM_NODESET) {
|
|
||||||
nodeht = HASH_OF(objmap->baseobjptr);
|
|
||||||
if (zend_hash_index_find(nodeht, index, (void **) &entry)==SUCCESS) {
|
|
||||||
*return_value = **entry;
|
|
||||||
zval_copy_ctor(return_value);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nodep = dom_object_get_node(objmap->baseobj);
|
if (objmap->nodetype == DOM_NODESET) {
|
||||||
if (nodep) {
|
nodeht = HASH_OF(objmap->baseobjptr);
|
||||||
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
|
if (zend_hash_index_find(nodeht, index, (void **) &entry)==SUCCESS) {
|
||||||
curnode = nodep->children;
|
*return_value = **entry;
|
||||||
while (count < index && curnode != NULL) {
|
zval_copy_ctor(return_value);
|
||||||
count++;
|
return;
|
||||||
curnode = curnode->next;
|
}
|
||||||
}
|
} else {
|
||||||
itemnode = curnode;
|
nodep = dom_object_get_node(objmap->baseobj);
|
||||||
} else {
|
if (nodep) {
|
||||||
if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
|
if (objmap->nodetype == XML_ATTRIBUTE_NODE || objmap->nodetype == XML_ELEMENT_NODE) {
|
||||||
nodep = xmlDocGetRootElement((xmlDoc *) nodep);
|
curnode = nodep->children;
|
||||||
|
while (count < index && curnode != NULL) {
|
||||||
|
count++;
|
||||||
|
curnode = curnode->next;
|
||||||
|
}
|
||||||
|
itemnode = curnode;
|
||||||
} else {
|
} else {
|
||||||
nodep = nodep->children;
|
if (nodep->type == XML_DOCUMENT_NODE || nodep->type == XML_HTML_DOCUMENT_NODE) {
|
||||||
|
nodep = xmlDocGetRootElement((xmlDoc *) nodep);
|
||||||
|
} else {
|
||||||
|
nodep = nodep->children;
|
||||||
|
}
|
||||||
|
itemnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &count, index);
|
||||||
}
|
}
|
||||||
itemnode = dom_get_elements_by_tag_name_ns_raw(nodep, objmap->ns, objmap->local, &count, index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
RETURN_NULL();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemnode) {
|
if (itemnode) {
|
||||||
|
|
|
@ -338,6 +338,7 @@ PHP_MINIT_FUNCTION(dom)
|
||||||
dom_object_handlers.read_property = dom_read_property;
|
dom_object_handlers.read_property = dom_read_property;
|
||||||
dom_object_handlers.write_property = dom_write_property;
|
dom_object_handlers.write_property = dom_write_property;
|
||||||
dom_object_handlers.get_property_ptr_ptr = NULL;
|
dom_object_handlers.get_property_ptr_ptr = NULL;
|
||||||
|
dom_object_handlers.clone_obj = zend_objects_store_clone_obj;
|
||||||
|
|
||||||
zend_hash_init(&classes, 0, NULL, NULL, 1);
|
zend_hash_init(&classes, 0, NULL, NULL, 1);
|
||||||
|
|
||||||
|
@ -720,13 +721,6 @@ void node_list_unlink(xmlNodePtr node TSRMLS_DC)
|
||||||
}
|
}
|
||||||
/* }}} end node_list_unlink */
|
/* }}} end node_list_unlink */
|
||||||
|
|
||||||
/* {{{ dom_objects_clone */
|
|
||||||
void dom_objects_clone(void *object, void **object_clone TSRMLS_DC)
|
|
||||||
{
|
|
||||||
/* TODO */
|
|
||||||
}
|
|
||||||
/* }}} */
|
|
||||||
|
|
||||||
#if defined(LIBXML_XPATH_ENABLED)
|
#if defined(LIBXML_XPATH_ENABLED)
|
||||||
/* {{{ dom_xpath_objects_free_storage */
|
/* {{{ dom_xpath_objects_free_storage */
|
||||||
void dom_xpath_objects_free_storage(void *object TSRMLS_DC)
|
void dom_xpath_objects_free_storage(void *object TSRMLS_DC)
|
||||||
|
@ -821,6 +815,36 @@ static dom_object* dom_objects_set_class(zend_class_entry *class_type TSRMLS_DC)
|
||||||
return intern;
|
return intern;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* {{{ dom_objects_clone */
|
||||||
|
void dom_objects_clone(void *object, void **object_clone TSRMLS_DC)
|
||||||
|
{
|
||||||
|
dom_object *intern = (dom_object *) object;
|
||||||
|
dom_object *clone;
|
||||||
|
xmlNodePtr node;
|
||||||
|
xmlNodePtr cloned_node;
|
||||||
|
|
||||||
|
clone = dom_objects_set_class(intern->std.ce TSRMLS_CC);
|
||||||
|
|
||||||
|
if (instanceof_function(intern->std.ce, dom_node_class_entry TSRMLS_CC)) {
|
||||||
|
node = (xmlNodePtr)dom_object_get_node((dom_object *) object);
|
||||||
|
if (node != NULL) {
|
||||||
|
cloned_node = xmlDocCopyNode(node, node->doc, 1);
|
||||||
|
if (cloned_node != NULL) {
|
||||||
|
/* If we cloned a document then we must create new doc proxy */
|
||||||
|
if (cloned_node->doc == node->doc) {
|
||||||
|
clone->document = intern->document;
|
||||||
|
}
|
||||||
|
php_libxml_increment_doc_ref((php_libxml_node_object *)clone, cloned_node->doc TSRMLS_CC);
|
||||||
|
php_libxml_increment_node_ptr((php_libxml_node_object *)clone, cloned_node, NULL TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*object_clone = (void *) clone;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ dom_objects_new */
|
/* {{{ dom_objects_new */
|
||||||
zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC)
|
zend_object_value dom_objects_new(zend_class_entry *class_type TSRMLS_DC)
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,8 +85,6 @@ int dom_xpath_document_read(dom_object *obj, zval **retval TSRMLS_DC)
|
||||||
|
|
||||||
if (ctx) {
|
if (ctx) {
|
||||||
docp = (xmlDocPtr) ctx->doc;
|
docp = (xmlDocPtr) ctx->doc;
|
||||||
} else {
|
|
||||||
printf("NONE");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ALLOC_ZVAL(*retval);
|
ALLOC_ZVAL(*retval);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue