/** Free just the containing structure, leaving the nodes */ GhtErr ght_nodelist_free_shallow(GhtNodeList *nl) { if ( nl->nodes ) ght_free(nl->nodes); ght_free(nl); return GHT_OK; }
GhtErr ght_reader_free(GhtReader *reader) { if ( reader->type == GHT_IO_FILE ) { if ( reader->file ) fclose(reader->file); if ( reader->filename ) ght_free(reader->filename); } ght_free(reader); return GHT_OK; }
GhtErr ght_hash_free(GhtHash *hash) { assert(hash != NULL); ght_free(hash); return GHT_OK; }
GhtErr ght_node_set_hash(GhtNode *node, GhtHash *hash) { if ( node->hash ) ght_free(node->hash); node->hash = hash; return GHT_OK; }
/* Setup/teardown for this suite */ static int init_suite(void) { GhtErr result; char *xmlstr = file_to_str("test/data/simple-schema.xml"); result = ght_schema_from_xml_str(xmlstr, &schema); ght_free(xmlstr); return result; }
GhtErr ght_writer_free(GhtWriter *writer) { if ( ! writer ) return GHT_ERROR; if ( writer->type == GHT_IO_MEM ) { bytebuffer_destroy(writer->bytebuffer); } else if ( writer->type == GHT_IO_FILE ) { if ( writer->file ) fclose(writer->file); if ( writer->filename ) ght_free(writer->filename); } ght_free(writer); return GHT_OK; }
static int clean_suite(void) { if ( schema ) ght_schema_free(schema); if ( xmlstr ) ght_free(xmlstr); return 0; }
static void test_schema_xml() { char *mystr, *str; GhtErr result; GhtSchema *myschema = NULL; size_t schema_size; result = ght_schema_to_xml_str(schema, &str, &schema_size); CU_ASSERT_EQUAL(result, GHT_OK); result = ght_schema_from_xml_str(str, &myschema); CU_ASSERT_EQUAL(result, GHT_OK); result = ght_schema_to_xml_str(myschema, &mystr, &schema_size); CU_ASSERT_EQUAL(result, GHT_OK); CU_ASSERT_STRING_EQUAL(str, mystr); ght_free(str); ght_free(mystr); ght_schema_free(myschema); }
GhtErr ght_node_free(GhtNode *node) { int i; const int deep = 1; assert(node != NULL); if ( node->attributes ) GHT_TRY(ght_attribute_free(node->attributes)); if ( node->children ) GHT_TRY(ght_nodelist_free_deep(node->children)); if ( node->hash ) GHT_TRY(ght_hash_free(node->hash)); ght_free(node); return GHT_OK; }
GhtErr ght_node_delete_attribute(GhtNode *node, const GhtDimension *dim) { GhtAttribute *attr = node->attributes; GhtAttribute *attr_prev; /* No attributes, noop */ if ( ! attr ) return GHT_OK; /* Roll forward until we find a match */ while( attr->dim != dim ) { if ( attr->next ) { attr_prev = attr; attr = attr->next; } /* No attributes matches dimension */ else { return GHT_ERROR; } } /* Handle first attribute in list specially */ if ( attr == node->attributes ) { if ( attr->next ) node->attributes = attr->next; else node->attributes = NULL; } else { attr_prev->next = attr->next; } ght_free(attr); return GHT_OK; }
/** * Recursive function, walk down from parent node, looking for * appropriate insertion point for node_to_insert. If duplicates, * and duplicate leaf, insert as hash-less "attribute only" node. * ["abcdefg", "abcdeff", "abcdddd", "abbbeee"] becomes * "ab"->["c"->["d"->["ddd","ef"->["g","f"]]],"b"] */ GhtErr ght_node_insert_node(GhtNode *node, GhtNode *node_to_insert, GhtDuplicates duplicates) { GhtHash *node_leaf, *node_to_insert_leaf; GhtErr err; GhtHashMatch matchtype; /* NULL hash implies this node is a faux node for duplicate points */ if ( ! node->hash ) return GHT_INCOMPLETE; /* matchtype in (GHT_NONE, GHT_GLOBAL, GHT_SAME, GHT_CHILD, GHT_SPLIT) */ /* NONE and GLOBAL come back with GHT_ERROR, so we don't handle them yet */ GHT_TRY(ght_hash_leaf_parts(node->hash, node_to_insert->hash, GHT_MAX_HASH_LENGTH, &matchtype, &node_leaf, &node_to_insert_leaf)); /* Insert node is child of node, either explicitly, or implicitly for */ /* the "" hash which serves as a master parent */ /* "abcdef" is a GHT_CHILD or "abc", and gets added as "def" */ if ( matchtype == GHT_CHILD || matchtype == GHT_GLOBAL ) { int i; ght_node_set_hash(node_to_insert, ght_strdup(node_to_insert_leaf)); for ( i = 0; i < ght_node_num_children(node); i++ ) { err = ght_node_insert_node(node->children->nodes[i], node_to_insert, duplicates); /* Node added to one of the children */ if ( err == GHT_OK ) return GHT_OK; } /* Node didn't fit any of the children, so add it at this level */ return ght_node_add_child(node, node_to_insert); } if ( matchtype == GHT_SAME ) { /* New node is duplicate of this node. We insert an */ /* empty node (no hash) underneath, to hang attributes off of */ /* and use this node as the parent */ if ( duplicates ) { /* If this is the first duplicate, add a copy of the parent */ /* To serve as a proxy leaf for this value */ if ( ( ! node->children ) || ( node->children->num_nodes == 0 ) ) { GhtNode *parent_leaf; GHT_TRY(ght_node_new(&parent_leaf)); GHT_TRY(ght_node_transfer_attributes(node, parent_leaf)); GHT_TRY(ght_node_add_child(node, parent_leaf)); } /* Add the new node under the parent, stripping the hash */ ght_free(node_to_insert->hash); node_to_insert->hash = NULL; GHT_TRY(ght_node_add_child(node, node_to_insert)); return GHT_OK; } else { /* For now, we just skip duplicates. */ /* In future, average / median the duplicates onto parent here? */ return GHT_OK; } } /* "abcdef" and "abcghi" need to GHT_SPLIT, into "abc"->["def", "ghi"] */ if ( matchtype == GHT_SPLIT ) { /* We need a new node to hold that part of the parent that is not shared */ GhtNode *another_node_to_insert; GHT_TRY(ght_node_new_from_hash(node_leaf, &another_node_to_insert)); /* Move attributes to the new child */ GHT_TRY(ght_node_transfer_attributes(node, another_node_to_insert)); /* Any children of the parent need to move down the tree with the unique part of the hash */ if ( node->children ) { another_node_to_insert->children = node->children; node->children = NULL; } /* Null-terminate parent hash at end of shared part */ *node_leaf = '\0'; /* Pull the non-shared part of insert node hash to the front */ memmove(node_to_insert->hash, node_to_insert_leaf, strlen(node_to_insert_leaf)+1); /* Add the unique portion of the parent to the parent */ GHT_TRY(ght_node_add_child(node, another_node_to_insert)); /* Add the unique portion of the insert node to the parent */ GHT_TRY(ght_node_add_child(node, node_to_insert)); /* Done! */ return GHT_OK; } /* Don't get here */ return GHT_ERROR; }