xml/cxmllibrary/src/tinytree/src/tree.c
branchRCL_3
changeset 20 889504eac4fb
equal deleted inserted replaced
19:6bcc0aa4be39 20:889504eac4fb
       
     1 /*
       
     2 * Copyright (c) 2000 - 2001 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of the License "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description: 
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include <xml/cxml/nw_tinytree.h>
       
    20 #include "cxml_vector.h"
       
    21 
       
    22 NW_TinyTree_t*
       
    23 NW_TinyTree_new(){
       
    24   NW_TinyTree_t* tree = (NW_TinyTree_t*) NW_Mem_Malloc (sizeof(NW_TinyTree_t));
       
    25   if (tree != NULL){
       
    26     tree->tree = NULL;
       
    27     tree->root_index = 0;
       
    28     tree->ebuffer = NULL;
       
    29     tree->context = NULL;
       
    30   }
       
    31   return tree;
       
    32 }
       
    33 
       
    34 NW_Status_t
       
    35 NW_TinyTree_construct(NW_TinyTree_t *tree,
       
    36                       CXML_Vector_Metric_t initialNodeCount,
       
    37                       void *buffer,
       
    38                       NW_TinyTree_Offset_t buffsz,
       
    39                       void *context,
       
    40                       NW_Bool freeBuff){
       
    41 
       
    42   NW_ASSERT(tree != NULL);
       
    43 
       
    44   tree->tree =
       
    45   NW_TinyTree_TreeVector_Construct (sizeof(NW_TinyTree_Node_t),
       
    46                               initialNodeCount,
       
    47                               tree);
       
    48   if(tree->tree == NULL) {
       
    49     return NW_STAT_OUT_OF_MEMORY;
       
    50   }
       
    51 
       
    52   /* Make the supplied buffer the first ebuffer segment */
       
    53   tree->ebuffer = NW_TinyTree_EBuffer_Construct((NW_Uint8*) buffer, 
       
    54                                           buffsz, 
       
    55                                           NW_TINY_TREE_BLOCK_SIZE_DEFAULT,
       
    56                                           freeBuff);
       
    57   if(tree->ebuffer == NULL){
       
    58     NW_TinyTree_TreeVector_Destruct(tree->tree);
       
    59     tree->tree = NULL;
       
    60     return NW_STAT_OUT_OF_MEMORY;
       
    61   }
       
    62 
       
    63   /* Init the rest of the tree */
       
    64   tree->root_index = 0;
       
    65   tree->context = context;
       
    66   return NW_STAT_SUCCESS;
       
    67 }
       
    68 
       
    69 void
       
    70 NW_TinyTree_destruct(NW_TinyTree_t *tree)
       
    71 {
       
    72   if (tree != NULL){
       
    73     if (tree->tree != NULL) {
       
    74       NW_TinyTree_TreeVector_Destruct (tree->tree);
       
    75     }
       
    76     if (tree->ebuffer != NULL){
       
    77       NW_TinyTree_EBuffer_Destruct (tree->ebuffer);
       
    78     }
       
    79     tree->tree = NULL;
       
    80     tree->root_index = 0;
       
    81     tree->ebuffer = NULL;
       
    82     tree->context = NULL;
       
    83   }
       
    84 }
       
    85 
       
    86 static 
       
    87 NW_TinyTree_Node_t*
       
    88 NW_TinyTree_appendNodeAt(NW_TinyTree_t *tree, 
       
    89                          NW_TinyTree_Node_t *node, 
       
    90                          NW_TinyTree_Index_t index){
       
    91   NW_TinyTree_TreeNode_t* sentinel;
       
    92 	NW_TinyTree_Node_t* retNode = NULL;
       
    93 
       
    94 
       
    95   NW_ASSERT(tree != NULL);
       
    96   NW_ASSERT(tree->tree != NULL);
       
    97   NW_ASSERT(node != NULL);
       
    98 
       
    99 	sentinel = (NW_TinyTree_TreeNode_t*) NW_Mem_Malloc(sizeof(NW_TinyTree_TreeNode_t));
       
   100 	if(sentinel == NULL){
       
   101 		return NULL;
       
   102 	}
       
   103   sentinel->flags = TNODE_FLAG_TREE;
       
   104   sentinel->tree = tree;
       
   105 
       
   106   /* Add the new element at the specified index */
       
   107   retNode = (NW_TinyTree_Node_t*)
       
   108          CXML_Vector_InsertAt(tree->tree->vector, (void*)node, index, sentinel);
       
   109            NW_Mem_Free(sentinel);
       
   110 	return retNode;
       
   111 }
       
   112 
       
   113 /* Add a node, appending storage to the tree vector.
       
   114  * The appended node is created as an orphan and needs to be attached
       
   115  * to the tree somewhere.
       
   116  */
       
   117 
       
   118 static
       
   119 NW_TinyTree_Node_t*
       
   120 NW_TinyTree_appendNode(NW_TinyTree_t *tree, 
       
   121                        NW_TinyTree_Node_t *node){
       
   122 
       
   123   NW_ASSERT(tree != NULL);
       
   124   NW_ASSERT(node != NULL);
       
   125 
       
   126   /* Add the new element */
       
   127 
       
   128   return NW_TinyTree_appendNodeAt(tree, node, CXML_Vector_AtEnd);
       
   129 }
       
   130 
       
   131 
       
   132 /* Get the node at a given index */
       
   133 
       
   134 static
       
   135 NW_TinyTree_Node_t*
       
   136 NW_TinyTree_getNode(NW_TinyTree_t *tree, 
       
   137                     NW_TinyTree_Index_t index){
       
   138 
       
   139   NW_ASSERT(tree != NULL);
       
   140   NW_ASSERT(tree->tree != NULL);
       
   141   NW_ASSERT(tree->tree->vector != NULL);
       
   142   NW_ASSERT(index > 0);
       
   143   
       
   144   return (NW_TinyTree_Node_t*)
       
   145     CXML_Vector_ElementAt(tree->tree->vector, (CXML_Vector_Metric_t)index);
       
   146 }
       
   147 
       
   148 /*
       
   149 * Create an unattached node which references the source buffer at offset.
       
   150 */
       
   151 
       
   152 NW_TinyTree_Node_t*
       
   153 NW_TinyTree_createNode(NW_TinyTree_t* tree, 
       
   154                        NW_TinyTree_Offset_t offset){
       
   155   
       
   156   NW_TinyTree_Node_t node;
       
   157 
       
   158   NW_ASSERT(tree != NULL);
       
   159   NW_ASSERT(tree->tree != NULL);
       
   160   /* The root must have been set before creating any new nodes */
       
   161   NW_ASSERT(tree->root_index == 1);
       
   162 
       
   163   /* Initialize a node on the stack */
       
   164   node.source_offset = offset;
       
   165   node.flags = 0;
       
   166   node.first_child = 0;
       
   167   node.next_sibling = 0; 
       
   168   node.tree = tree;
       
   169   node.token = 0;
       
   170   /* Copy this into the tree */
       
   171   return NW_TinyTree_appendNode(tree, &node);
       
   172 }
       
   173 
       
   174 /* 
       
   175 * Create a root node which references the source buffer at offset. 
       
   176 * Returns a pointer to the root node.
       
   177 */
       
   178 
       
   179 NW_TinyTree_Node_t*
       
   180 NW_TinyTree_setRoot(NW_TinyTree_t *tree, 
       
   181                     NW_TinyTree_Offset_t offset){
       
   182   
       
   183   NW_TinyTree_Node_t root_node;
       
   184   
       
   185   NW_ASSERT(tree != NULL);
       
   186   NW_ASSERT(tree->tree != NULL);
       
   187   /* The root must not have set been already */
       
   188   NW_ASSERT(tree->root_index == 0);
       
   189 
       
   190   tree->root_index = 1;
       
   191   root_node.source_offset = offset;
       
   192   root_node.flags = TNODE_FLAG_ROOT;
       
   193   root_node.first_child = 0;
       
   194   root_node.next_sibling = 0;
       
   195   root_node.tree = tree;
       
   196   root_node.token = 0;
       
   197   /* TODO: make this a dummy element! */
       
   198   if (NW_TinyTree_appendNodeAt(tree, &root_node, 0) == NULL) {
       
   199     return NULL;
       
   200   }
       
   201 
       
   202   return NW_TinyTree_appendNodeAt(tree, &root_node, tree->root_index);
       
   203 }
       
   204 
       
   205 /*
       
   206 * Get the root node of the tree.
       
   207 */
       
   208 
       
   209 NW_TinyTree_Node_t*
       
   210 NW_TinyTree_getRoot(NW_TinyTree_t *tree){
       
   211 
       
   212   NW_ASSERT(tree != NULL);
       
   213   /* Return NULL if not set */
       
   214   if(tree->root_index == 0)
       
   215     return NULL;
       
   216   return NW_TinyTree_getNode(tree, tree->root_index);
       
   217 }
       
   218 
       
   219 NW_TinyTree_Node_t*
       
   220 NW_TinyTree_findNextSibling(NW_TinyTree_Node_t *node){
       
   221 
       
   222   NW_ASSERT(node != NULL);
       
   223 
       
   224   if (((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING)
       
   225       || (node->next_sibling == 0)) {
       
   226     return NULL;
       
   227   }
       
   228   
       
   229   return node->next_sibling;
       
   230 }
       
   231 
       
   232 /* Find last sibling address */
       
   233 
       
   234 NW_TinyTree_Node_t*
       
   235 NW_TinyTree_findLastSibling(NW_TinyTree_Node_t *node)
       
   236 {
       
   237   NW_TinyTree_Node_t* sibling = node;
       
   238 
       
   239   NW_ASSERT(node != NULL);
       
   240 
       
   241   while (((sibling->flags & TNODE_FLAG_LASTSIBLING) != TNODE_FLAG_LASTSIBLING)
       
   242          && (sibling->next_sibling != 0)) {
       
   243     sibling = sibling->next_sibling;
       
   244   }
       
   245 
       
   246   /* Because the array always starts with the tree node, no node ever has index 0 */
       
   247   if(sibling == node)
       
   248     return NULL;
       
   249   
       
   250   return sibling;
       
   251 }
       
   252 
       
   253 NW_TinyTree_Node_t*
       
   254 NW_TinyTree_findFirstChild(NW_TinyTree_Node_t *node)
       
   255 {
       
   256   NW_ASSERT(node != NULL);
       
   257   return node->first_child;
       
   258 }
       
   259 
       
   260 
       
   261 /*
       
   262 * Find a node's last child
       
   263 */
       
   264 
       
   265 NW_TinyTree_Node_t*
       
   266 NW_TinyTree_findLastChild(NW_TinyTree_Node_t* node){
       
   267   
       
   268   NW_TinyTree_Node_t* first;
       
   269   NW_TinyTree_Node_t* last;
       
   270 
       
   271   NW_ASSERT(node != NULL);
       
   272 
       
   273   first = NW_TinyTree_findFirstChild(node);
       
   274 
       
   275   if(first == NULL){
       
   276     return NULL; /* No children */
       
   277   }
       
   278 
       
   279   last = NW_TinyTree_findLastSibling(first);
       
   280 
       
   281   if(last == NULL){ /* No siblings, only child */
       
   282     return first;
       
   283   }
       
   284 
       
   285   return last;
       
   286 }
       
   287 
       
   288 /* 
       
   289 * Get a node's parent
       
   290 */
       
   291 
       
   292 NW_TinyTree_Node_t* 
       
   293 NW_TinyTree_findParent(NW_TinyTree_Node_t *node)
       
   294 {
       
   295  
       
   296   NW_TinyTree_Node_t *last_sibling;
       
   297 
       
   298   NW_ASSERT(node != NULL);
       
   299 
       
   300   /* Is this the root node ? */
       
   301   if((node->flags & TNODE_FLAG_ROOT) == TNODE_FLAG_ROOT)
       
   302     return NULL;
       
   303   
       
   304   /* Is next sibling zero ? */
       
   305   if (node->next_sibling == 0)
       
   306     return NULL;
       
   307 
       
   308   /* The next sibling index of the last sibling points back to parent */
       
   309 
       
   310   last_sibling = NW_TinyTree_findLastSibling(node);
       
   311 
       
   312   if (last_sibling == NULL){
       
   313     last_sibling = node;  /* No siblings */
       
   314   }
       
   315 
       
   316   return last_sibling->next_sibling;
       
   317 }
       
   318 
       
   319 
       
   320 /*
       
   321 * Attach a node as a sibling after another node.
       
   322 */
       
   323 
       
   324 NW_Status_t 
       
   325 NW_TinyTree_attachAfter(NW_TinyTree_Node_t *node, 
       
   326                         NW_TinyTree_Node_t *sibling)
       
   327 {
       
   328   NW_ASSERT(node != NULL);
       
   329   NW_ASSERT(sibling != NULL);
       
   330 
       
   331   if((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING){
       
   332     node->flags &= ~TNODE_FLAG_LASTSIBLING; 
       
   333     sibling->flags |= TNODE_FLAG_LASTSIBLING;
       
   334   }
       
   335   
       
   336   sibling->next_sibling = node->next_sibling;
       
   337   node->next_sibling = sibling;
       
   338   return NW_STAT_SUCCESS;
       
   339 }
       
   340 
       
   341 NW_TinyTree_Node_t*
       
   342 NW_TinyTree_findPreviousSibling(NW_TinyTree_Node_t *node){
       
   343 
       
   344   NW_TinyTree_Node_t *sibling;
       
   345   NW_TinyTree_Node_t *parent; 
       
   346 
       
   347   NW_ASSERT(node != NULL);
       
   348 
       
   349   /* First find the parent */
       
   350   parent = NW_TinyTree_findParent(node);
       
   351 
       
   352   if(parent == NULL)
       
   353     return NULL;
       
   354 
       
   355   /* Then get first child */
       
   356   sibling = NW_TinyTree_findFirstChild(parent);
       
   357   NW_ASSERT(sibling != NULL);
       
   358   if(sibling == node)
       
   359     return NULL; /* Only child */
       
   360 
       
   361   /* Find a sibling whose next_sibling points to me */
       
   362   while(sibling->next_sibling != node){ 
       
   363     NW_ASSERT(sibling->next_sibling != NULL);
       
   364     sibling = sibling->next_sibling;
       
   365   }
       
   366   return sibling;
       
   367 }
       
   368 
       
   369 /*
       
   370 * Attach a node as a sibling before another node.
       
   371 */
       
   372 
       
   373 NW_Status_t 
       
   374 NW_TinyTree_attachBefore(NW_TinyTree_Node_t *node, 
       
   375                          NW_TinyTree_Node_t *sibling)
       
   376 {
       
   377   NW_TinyTree_Node_t *previous = NW_TinyTree_findPreviousSibling(node);
       
   378 
       
   379   NW_ASSERT(node != NULL);
       
   380   NW_ASSERT(sibling != NULL);
       
   381 
       
   382   /* Has a previous sibling, insert after */
       
   383   if(previous != NULL){
       
   384     NW_TinyTree_attachAfter(previous, sibling);
       
   385     return NW_STAT_SUCCESS;
       
   386   }
       
   387 
       
   388   /*Otherwise, insert as first child */
       
   389   previous = NW_TinyTree_findParent(node);
       
   390   if(previous == NULL)
       
   391      return NW_STAT_FAILURE; /* TODO: return a more descriptive error status */
       
   392 
       
   393   previous->first_child = sibling;
       
   394   /*lint -e{794} Conceivable use of null pointer */
       
   395   sibling->next_sibling = node;
       
   396   
       
   397   return NW_STAT_SUCCESS;
       
   398 }
       
   399 
       
   400 /*
       
   401 * Attach a child (as last child) to a node 
       
   402 */
       
   403 
       
   404 NW_Status_t
       
   405 NW_TinyTree_attachChild(NW_TinyTree_Node_t *node, 
       
   406                         NW_TinyTree_Node_t *child)
       
   407 {
       
   408   NW_TinyTree_Node_t *last_child = NW_TinyTree_findLastChild(node);
       
   409   
       
   410   NW_ASSERT(node != NULL);
       
   411   NW_ASSERT(child != NULL);
       
   412 
       
   413   /* If there are no children, attach as first child */
       
   414   if(last_child == NULL){
       
   415     node->first_child = child;
       
   416     /* Point child's next_sibling back to parent and set LASTSIBLING flag */
       
   417     child->next_sibling = node;
       
   418     child->flags |= TNODE_FLAG_LASTSIBLING;
       
   419     return NW_STAT_SUCCESS;
       
   420   }
       
   421   /* Else attach as sibling to last child */
       
   422   else{
       
   423     return NW_TinyTree_attachAfter(last_child, child);
       
   424   }
       
   425 }
       
   426 
       
   427 NW_Status_t
       
   428 NW_TinyTree_deleteNode(NW_TinyTree_Node_t *node)
       
   429 {
       
   430   NW_ASSERT(node != NULL);
       
   431 
       
   432   /* If not the root node, then adjust parent or sibling indexes */
       
   433   if((node->flags & TNODE_FLAG_ROOT)!= TNODE_FLAG_ROOT){
       
   434     NW_TinyTree_Node_t *previous_sibling;
       
   435     previous_sibling = NW_TinyTree_findPreviousSibling(node);
       
   436     /* If we are first child, modify parent's first_child index */
       
   437     if(previous_sibling == NULL){
       
   438       NW_TinyTree_Node_t *parent = NW_TinyTree_findParent(node);
       
   439       NW_ASSERT(parent != NULL);
       
   440       /* If also last child (i.e. only child) */
       
   441       if((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING){
       
   442         /* Zero the parent's child index */
       
   443         parent->first_child = 0;
       
   444       }
       
   445       /* Not only child */
       
   446       else{
       
   447         /* Move parent child offset to my next sibling */
       
   448         parent->first_child = node->next_sibling;
       
   449       }
       
   450     }
       
   451     /* Not the first child */
       
   452     else {
       
   453       /* Adjust previous sibling next_sibling index */
       
   454       previous_sibling->next_sibling = node->next_sibling;
       
   455       if((node->flags & TNODE_FLAG_LASTSIBLING) == TNODE_FLAG_LASTSIBLING){
       
   456         previous_sibling->flags |= TNODE_FLAG_LASTSIBLING;
       
   457       }
       
   458     }
       
   459   }
       
   460   
       
   461  /* Note that we don't actually remove the node from the tree vector
       
   462   * since this may cause other nodes to be moved, invalidating any
       
   463   * references to them.
       
   464   */
       
   465 
       
   466   return NW_STAT_SUCCESS;
       
   467 }
       
   468 
       
   469 NW_Status_t
       
   470 NW_TinyTree_setContext(NW_TinyTree_t *tree, 
       
   471                        void *context){
       
   472   NW_ASSERT(tree != NULL);
       
   473   tree->context = context;
       
   474   return NW_STAT_SUCCESS;
       
   475 }
       
   476 
       
   477 void*
       
   478 NW_TinyTree_getContext(NW_TinyTree_t *tree){
       
   479   NW_ASSERT(tree != NULL);
       
   480   return tree->context;
       
   481 }
       
   482 
       
   483 NW_Uint16 
       
   484 NW_TinyTree_Node_getFlags(NW_TinyTree_Node_t *node){
       
   485   NW_ASSERT(node != NULL);
       
   486   return node->flags;
       
   487 }
       
   488 
       
   489 NW_Status_t
       
   490 NW_TinyTree_Node_setUserFlags(NW_TinyTree_Node_t *node, 
       
   491                               NW_Uint16 flags){
       
   492   NW_ASSERT(node != NULL);
       
   493   node->flags &= ~TNODE_USR_FLAGS; /*Zero user flags */
       
   494   node->flags |= (flags & TNODE_USR_FLAGS);
       
   495   return NW_STAT_SUCCESS;
       
   496 }
       
   497 
       
   498 NW_TinyTree_Offset_t
       
   499 NW_TinyTree_Node_getSourceOffset(NW_TinyTree_Node_t *node){
       
   500   NW_ASSERT(node != NULL);
       
   501 
       
   502   return node->source_offset;
       
   503 }
       
   504 
       
   505 void *
       
   506 NW_TinyTree_Node_getSourceAddress(NW_TinyTree_t *tree, 
       
   507                                   NW_TinyTree_Node_t* node){
       
   508 
       
   509   NW_ASSERT(node != NULL);
       
   510   NW_ASSERT(tree != NULL);
       
   511  
       
   512   /*lint -e{794} Conceivable use of null pointer */
       
   513   return (void *)(NW_TinyTree_EBuffer_AddressAt(tree->ebuffer, 
       
   514 						node->source_offset));
       
   515 }
       
   516 
       
   517 
       
   518 NW_Status_t
       
   519 NW_TinyTree_Node_GetSegmentAndOffset(NW_TinyTree_t* tree,
       
   520                                      NW_TinyTree_Node_t* node,
       
   521                                      NW_Uint8** segment,             
       
   522                                      NW_TinyTree_Offset_t* segSize, 
       
   523                                      NW_TinyTree_Offset_t* offset) {
       
   524   NW_ASSERT(tree != NULL);
       
   525   NW_ASSERT(node != NULL);
       
   526   
       
   527   return NW_TinyTree_EBuffer_GetSegmentAndOffset(tree->ebuffer, 
       
   528                                                  node->source_offset,
       
   529                                                  segment,
       
   530                                                  segSize,
       
   531                                                  offset);
       
   532 }
       
   533 
       
   534 NW_Status_t
       
   535 NW_TinyTree_GetSourceOffset(NW_TinyTree_t* tree,
       
   536                             NW_Uint8*  segmentAddr,         
       
   537                             NW_TinyTree_Offset_t  offset,
       
   538                             NW_TinyTree_Offset_t* index){
       
   539   NW_ASSERT(tree != NULL);
       
   540 
       
   541   return NW_TinyTree_EBuffer_GetIndex(tree->ebuffer, segmentAddr, offset, index);
       
   542 }
       
   543 
       
   544 
       
   545 
       
   546 NW_Uint8*
       
   547 NW_TinyTree_GetWritableBlock(NW_TinyTree_t* tree,
       
   548                              NW_TinyTree_Offset_t      size,
       
   549                              NW_TinyTree_Offset_t    * source_offset){  /* OUT */
       
   550 
       
   551   return NW_TinyTree_EBuffer_GetWritableBlock(tree->ebuffer, size, source_offset);
       
   552 
       
   553 }
       
   554 
       
   555 NW_TinyTree_t*
       
   556 NW_TinyTree_Node_findTreeOld(NW_TinyTree_Node_t *node)
       
   557 {
       
   558   NW_TinyTree_Node_t *parent = NW_TinyTree_findParent(node);
       
   559   NW_ASSERT(node != NULL);
       
   560 
       
   561   // find rootNode 
       
   562   while (parent != NULL)
       
   563   {
       
   564     node = parent;
       
   565     parent = NW_TinyTree_findParent(parent);
       
   566   }
       
   567   // root node should be next to sentinal tree node 
       
   568   while(node != NULL){
       
   569     if((node->flags & TNODE_FLAG_TREE) == TNODE_FLAG_TREE){
       
   570       return ((NW_TinyTree_TreeNode_t*)node)->tree;
       
   571     }
       
   572     --node;
       
   573   }
       
   574   // Not reached 
       
   575   NW_ASSERT(0);
       
   576   return NULL;
       
   577 }
       
   578 
       
   579 EXPORT_C NW_TinyTree_t*
       
   580 NW_TinyTree_Node_findTree(NW_TinyTree_Node_t *node)
       
   581     {
       
   582     if (!node->tree)
       
   583         {
       
   584         return NW_TinyTree_Node_findTreeOld(node);
       
   585         }
       
   586     else
       
   587         {
       
   588         return node->tree;
       
   589         }
       
   590         
       
   591     }
       
   592 
       
   593 /*
       
   594 * Create a new node as a child of an existing node. The child
       
   595 * references the source buffer at offset. The new child node is
       
   596 * returned.  
       
   597 */
       
   598 
       
   599 NW_TinyTree_Node_t*
       
   600 NW_TinyTree_createChild(NW_TinyTree_t *tree, 
       
   601                         NW_TinyTree_Node_t *parent, 
       
   602                         NW_TinyTree_Offset_t offset){
       
   603 
       
   604   NW_TinyTree_Node_t *child = NW_TinyTree_createNode(tree, offset);
       
   605 
       
   606   if (child != NULL){
       
   607     NW_TinyTree_attachChild(parent, child);
       
   608   }
       
   609   
       
   610   return child;
       
   611 }
       
   612 
       
   613 /*
       
   614 * Create a new node as an immediate sibling to an existing node. The
       
   615 * child references the source buffer at offset. The new child node is
       
   616 * returned.  
       
   617 */
       
   618 NW_TinyTree_Node_t*
       
   619 NW_TinyTree_createSibling(NW_TinyTree_t *tree, 
       
   620                           NW_TinyTree_Node_t *node, 
       
   621                           NW_TinyTree_Offset_t offset)
       
   622 {
       
   623   NW_TinyTree_Node_t *sibling = NW_TinyTree_createNode(tree, offset);
       
   624   NW_TinyTree_attachAfter(node, sibling);
       
   625   return sibling;
       
   626 }
       
   627 
       
   628 void
       
   629 NW_TinyTree_recurse(NW_TinyTree_t* tree,
       
   630                     NW_TinyTree_Node_t* start_node, 
       
   631                     void (*Node_CB) (NW_TinyTree_t*, NW_TinyTree_Node_t *, void *),
       
   632                     void * context)
       
   633 {
       
   634   NW_TinyTree_Node_t *child;
       
   635   
       
   636   (*(Node_CB)) (tree, start_node, context);
       
   637   if((child = NW_TinyTree_findFirstChild(start_node)) != 0){
       
   638     NW_TinyTree_recurse(tree, child, Node_CB, context);
       
   639     while((child = NW_TinyTree_findNextSibling(child)) != 0){
       
   640       NW_TinyTree_recurse(tree, child, Node_CB, context);
       
   641     }
       
   642   }
       
   643 }
       
   644 
       
   645 /* Initialize a node iterator with a start node */
       
   646 
       
   647 void
       
   648 NW_TinyTree_NodeIterator_init(NW_TinyTree_Node_t* start_node, 
       
   649                               NW_TinyTree_NodeIterator_t* iterator)
       
   650 {
       
   651   iterator->start_node = start_node; 
       
   652   iterator->traversal_node = NULL;
       
   653 }
       
   654 
       
   655 /* 
       
   656 * Iterate through a subtree returning each node exactly once.
       
   657 * The algorithm follows the toplogical ordering of the tree (if there is
       
   658 * an edge from v0 to v1, always visit v0 before v1). It's equivalent to 
       
   659 * solving a labyrinth by keeping your right hand on the wall!
       
   660 */
       
   661 
       
   662 NW_TinyTree_Node_t*
       
   663 NW_TinyTree_NodeIterator_iterate(NW_TinyTree_NodeIterator_t *iterator){
       
   664   
       
   665   NW_TinyTree_Node_t* node;
       
   666 
       
   667   if(iterator->start_node == NULL)
       
   668     return NULL;
       
   669 
       
   670   if(iterator->traversal_node == NULL){
       
   671     node = iterator->start_node;
       
   672     if(iterator->start_node->first_child != 0){
       
   673       iterator->traversal_node = iterator->start_node->first_child;
       
   674     }
       
   675     else{
       
   676       iterator->start_node = NULL;
       
   677     }
       
   678     return node;
       
   679   }
       
   680 
       
   681   node = iterator->traversal_node;
       
   682   
       
   683   /* First try to move down */
       
   684   if(iterator->traversal_node->first_child != 0){
       
   685     iterator->traversal_node = iterator->traversal_node->first_child;
       
   686     return node;
       
   687   }
       
   688 
       
   689   /* If you can't move down, move right */
       
   690 
       
   691   if((iterator->traversal_node->flags & TNODE_FLAG_LASTSIBLING) != TNODE_FLAG_LASTSIBLING){
       
   692     iterator->traversal_node = iterator->traversal_node->next_sibling;
       
   693     return node;
       
   694   }
       
   695 
       
   696   /* If you can't move right, move back up */
       
   697   /* TODO:  some other expression here */
       
   698   while(node != NULL){
       
   699     iterator->traversal_node = iterator->traversal_node->next_sibling;
       
   700     /* If you reached the start, quit */
       
   701     if(iterator->traversal_node == iterator->start_node){
       
   702       iterator->start_node = NULL;
       
   703       return node;
       
   704     }
       
   705     /* Otherwise, try to move right */
       
   706     if((iterator->traversal_node->flags & TNODE_FLAG_LASTSIBLING) != TNODE_FLAG_LASTSIBLING){
       
   707       iterator->traversal_node = iterator->traversal_node->next_sibling;
       
   708       return node;
       
   709     }
       
   710     /* Otherwise, continue to move up */
       
   711   }
       
   712   return NULL;
       
   713 }
       
   714 
       
   715 /* Iterate the siblings of a node */ 
       
   716 
       
   717 NW_TinyTree_Node_t*
       
   718 NW_TinyTree_NodeIterator_iterateSiblings(NW_TinyTree_NodeIterator_t *iterator){
       
   719   if((iterator->start_node->flags & TNODE_FLAG_LASTSIBLING)== TNODE_FLAG_LASTSIBLING)
       
   720     return NULL;
       
   721   else{
       
   722     iterator->start_node = iterator->start_node->next_sibling;
       
   723     return iterator->start_node;
       
   724   }
       
   725 }
       
   726 
       
   727 
       
   728 
       
   729 
       
   730