cbf_tree.c

Go to the documentation of this file.
00001 /**********************************************************************
00002  * cbf_tree -- handle cbf nodes                                       *
00003  *                                                                    *
00004  * Version 0.6 13 January 1999                                        *
00005  *                                                                    *
00006  *            Paul Ellis (ellis@ssrl.slac.stanford.edu) and           *
00007  *         Herbert J. Bernstein (yaya@bernstein-plus-sons.com)        *
00008  **********************************************************************/
00009   
00010 /**********************************************************************
00011  *                               NOTICE                               *
00012  * Creative endeavors depend on the lively exchange of ideas. There   *
00013  * are laws and customs which establish rights and responsibilities   *
00014  * for authors and the users of what authors create.  This notice     *
00015  * is not intended to prevent you from using the software and         *
00016  * documents in this package, but to ensure that there are no         *
00017  * misunderstandings about terms and conditions of such use.          *
00018  *                                                                    *
00019  * Please read the following notice carefully.  If you do not         *
00020  * understand any portion of this notice, please seek appropriate     *
00021  * professional legal advice before making use of the software and    *
00022  * documents included in this software package.  In addition to       *
00023  * whatever other steps you may be obliged to take to respect the     *
00024  * intellectual property rights of the various parties involved, if   *
00025  * you do make use of the software and documents in this package,     *
00026  * please give credit where credit is due by citing this package,     *
00027  * its authors and the URL or other source from which you obtained    *
00028  * it, or equivalent primary references in the literature with the    *
00029  * same authors.                                                      *
00030  *                                                                    *
00031  * Some of the software and documents included within this software   *
00032  * package are the intellectual property of various parties, and      *
00033  * placement in this package does not in any way imply that any       *
00034  * such rights have in any way been waived or diminished.             *
00035  *                                                                    *
00036  * With respect to any software or documents for which a copyright    *
00037  * exists, ALL RIGHTS ARE RESERVED TO THE OWNERS OF SUCH COPYRIGHT.   *
00038  *                                                                    *
00039  * Even though the authors of the various documents and software      *
00040  * found here have made a good faith effort to ensure that the        *
00041  * documents are correct and that the software performs according     *
00042  * to its documentation, and we would greatly appreciate hearing of   *
00043  * any problems you may encounter, the programs and documents any     *
00044  * files created by the programs are provided **AS IS** without any   *
00045  * warranty as to correctness, merchantability or fitness for any     *
00046  * particular or general use.                                         *
00047  *                                                                    *
00048  * THE RESPONSIBILITY FOR ANY ADVERSE CONSEQUENCES FROM THE USE OF    *
00049  * PROGRAMS OR DOCUMENTS OR ANY FILE OR FILES CREATED BY USE OF THE   *
00050  * PROGRAMS OR DOCUMENTS LIES SOLELY WITH THE USERS OF THE PROGRAMS   *
00051  * OR DOCUMENTS OR FILE OR FILES AND NOT WITH AUTHORS OF THE          *
00052  * PROGRAMS OR DOCUMENTS.                                             *
00053  **********************************************************************/
00054  
00055 /**********************************************************************
00056  *                          The IUCr Policy                           *
00057  *                                 on                                 *
00058  *     the Use of the Crystallographic Information File (CIF)         *
00059  *                                                                    *
00060  * The Crystallographic Information File (Hall, Allen & Brown,        *
00061  * 1991) is, as of January 1992, the recommended method for           *
00062  * submitting publications to Acta Crystallographica Section C. The   *
00063  * International Union of Crystallography holds the Copyright on      *
00064  * the CIF, and has applied for Patents on the STAR File syntax       *
00065  * which is the basis for the CIF format.                             *
00066  *                                                                    *
00067  * It is a principal objective of the IUCr to promote the use of      *
00068  * CIF for the exchange and storage of scientific data. The IUCr's    *
00069  * sponsorship of the CIF development was motivated by its            *
00070  * responsibility to its scientific journals, which set the           *
00071  * standards in crystallographic publishing. The IUCr intends that    *
00072  * CIFs will be used increasingly for electronic submission of        *
00073  * manuscripts to these journals in future. The IUCr recognises       *
00074  * that, if the CIF and the STAR File are to be adopted as a means    *
00075  * for universal data exchange, the syntax of these files must be     *
00076  * strictly and uniformly adhered to. Even small deviations from      *
00077  * the syntax would ultimately cause the demise of the universal      *
00078  * file concept. Through its Copyrights and Patents the IUCr has      *
00079  * taken the steps needed to ensure strict conformance with this      *
00080  * syntax.                                                            *
00081  *                                                                    *
00082  * The IUCr policy on the use of the CIF and STAR File processes is   *
00083  * as follows:                                                        *
00084  * _________________________________________________________________  *
00085  *                                                                    *
00086  *  * 1 CIFs and STAR Files may be generated, stored or transmitted,  *
00087  *    without permission or charge, provided their purpose is not     *
00088  *    specifically for profit or commercial gain, and provided that   *
00089  *    the published syntax is strictly adhered to.                    *
00090  *  * 2 Computer software may be developed for use with CIFs or STAR  *
00091  *    files, without permission or charge, provided it is distributed *
00092  *    in the public domain. This condition also applies to software   *
00093  *    for which a charge is made, provided that its primary function  *
00094  *    is for use with files that satisfy condition 1 and that it is   *
00095  *    distributed as a minor component of a larger package of         *
00096  *    software.                                                       *
00097  *  * 3 Permission will be granted for the use of CIFs and STAR Files *
00098  *    for specific commercial purposes (such as databases or network  *
00099  *    exchange processes), and for the distribution of commercial     *
00100  *    CIF/STAR software, on written application to the IUCr Executive *
00101  *    Secretary, 2 Abbey Square, Chester CH1 2HU, England. The        *
00102  *    nature, terms and duration of the licences granted will be      *
00103  *    determined by the IUCr Executive and Finance Committees.        *
00104  *                                                                    *
00105  * _________________________________________________________________  *
00106  *                                                                    *
00107  * In summary, the IUCr wishes to promote the use of the STAR File    *
00108  * concepts as a standard universal data file. It will insist on      *
00109  * strict compliance with the published syntax for all                *
00110  * applications. To assist with this compliance, the IUCr provides    *
00111  * public domain software for checking the logical integrity of a     *
00112  * CIF, and for validating the data name definitions contained        *
00113  * within a CIF. Detailed information on this software, and the       *
00114  * associated dictionaries, may be obtained from the IUCr Office at   *
00115  * 5 Abbey Square, Chester CH1 2HU, England.                          *
00116  **********************************************************************/
00117 
00118 #ifdef __cplusplus
00119 
00120 extern "C" {
00121 
00122 #endif
00123 
00124 #include <stdio.h>
00125 #include <stdlib.h>
00126 #include <string.h>
00127 #include <ctype.h>
00128 
00129 #include "cbf.h"
00130 #include "cbf_alloc.h"
00131 #include "cbf_tree.h"
00132 #include "cbf_context.h"
00133 #include "cbf_binary.h"
00134 
00135 
00136   /* Make a new node */
00137 
00138 int cbf_make_node (cbf_node **node, CBF_NODETYPE type, 
00139                    cbf_context *context, const char *name)
00140 {
00141   int errorcode;
00142   
00143   if (!node)
00144 
00145     return CBF_ARGUMENT;
00146 
00147 
00148     /* Create the new node */
00149 
00150   cbf_failnez (cbf_alloc ((void **) node, NULL, sizeof (cbf_node), 1))
00151 
00152     
00153     /* Initialise the node */
00154 
00155   (*node)->type = type;
00156 
00157   (*node)->name = NULL;
00158 
00159   (*node)->link = NULL;
00160 
00161   (*node)->parent = NULL;
00162       
00163   (*node)->children = 0;
00164 
00165   (*node)->child_size = 0;
00166 
00167   (*node)->child = NULL;
00168 
00169 
00170     /* Add the context? */
00171 
00172   if (type == CBF_LINK)
00173 
00174     (*node)->context = NULL;
00175 
00176   else
00177   {
00178       /* Does the context exist? */
00179 
00180     if (context)
00181 
00182       (*node)->context = context;
00183 
00184     else
00185     
00186       (*node)->context = NULL;
00187 
00188 
00189       /* Add a context connection */
00190 
00191     cbf_onfailnez (cbf_add_contextconnection (&(*node)->context), 
00192                cbf_free ((void **) node, NULL))
00193 
00194 
00195       /* Name the node */
00196 
00197     errorcode = cbf_name_node (*node, name);
00198 
00199     if (errorcode)
00200     {
00201       errorcode |= cbf_free_context (&(*node)->context);
00202       
00203       return errorcode | cbf_free_node (*node);
00204     }
00205   }
00206 
00207 
00208     /* Success */
00209 
00210   return 0;
00211 }
00212 
00213 
00214   /* Make a new node allowing for duplicates */
00215 
00216 int cbf_make_new_node (cbf_node **node, CBF_NODETYPE type, 
00217                        cbf_context *context, const char *name)
00218 {
00219   int errorcode;
00220   
00221   if (!node)
00222 
00223     return CBF_ARGUMENT;
00224 
00225 
00226     /* Create the new node */
00227 
00228   cbf_failnez (cbf_alloc ((void **) node, NULL, sizeof (cbf_node), 1))
00229 
00230     
00231     /* Initialise the node */
00232 
00233   (*node)->type = type;
00234 
00235   (*node)->name = NULL;
00236 
00237   (*node)->link = NULL;
00238 
00239   (*node)->parent = NULL;
00240       
00241   (*node)->children = 0;
00242 
00243   (*node)->child_size = 0;
00244 
00245   (*node)->child = NULL;
00246 
00247 
00248     /* Add the context? */
00249 
00250   if (type == CBF_LINK)
00251 
00252     (*node)->context = NULL;
00253 
00254   else
00255   {
00256       /* Does the context exist? */
00257 
00258     if (context)
00259 
00260       (*node)->context = context;
00261 
00262     else
00263     
00264       (*node)->context = NULL;
00265 
00266 
00267       /* Add a context connection */
00268 
00269     cbf_onfailnez (cbf_add_contextconnection (&(*node)->context), 
00270                    cbf_free ((void **) node, NULL))
00271 
00272 
00273       /* Name the node */
00274 
00275     errorcode = cbf_name_new_node (*node, name);
00276 
00277     if (errorcode)
00278     {
00279       errorcode |= cbf_free_context (&(*node)->context);
00280       
00281       return errorcode | cbf_free_node (*node);
00282     }
00283   }
00284 
00285 
00286     /* Success */
00287 
00288   return 0;
00289 }
00290 
00291 
00292   /* Free a node */
00293 
00294 int cbf_free_node (cbf_node *node)
00295 {
00296   unsigned int count;
00297 
00298   
00299     /* Check the arguments */
00300     
00301   if (!node)
00302 
00303     return CBF_ARGUMENT;
00304 
00305 
00306     /* Disconnect the node from its parent? */
00307 
00308   if (node->parent)
00309 
00310     for (count = 0; count < node->parent->children; count++)
00311 
00312       if (node->parent->child [count] == node)
00313       {
00314         node->parent->children--;
00315 
00316         if (node->parent->children == 0)
00317 
00318           cbf_failnez (cbf_free ((void **) &node->parent->child,
00319                                        &node->parent->child_size))
00320 
00321         else
00322 
00323           if (node->parent->children > count)
00324           
00325             memmove (node->parent->child + count, 
00326                      node->parent->child + count + 1,
00327                     (node->parent->children - count) * sizeof (cbf_node *));
00328 
00329         break;
00330       }
00331 
00332 
00333     /* Free the children */
00334 
00335   cbf_failnez (cbf_set_children (node, 0))
00336 
00337 
00338     /* Free the name */
00339 
00340   cbf_free_string (NULL, node->name);
00341 
00342 
00343     /* Free the context connection */
00344 
00345   cbf_failnez (cbf_delete_contextconnection (&node->context))
00346 
00347 
00348     /* Free the node */
00349 
00350   return cbf_free ((void **) &node, NULL);
00351 }
00352 
00353 
00354   /* Set the number of children */
00355 
00356 int cbf_set_children (cbf_node *node, unsigned int children)
00357 {
00358   unsigned int count, new_size, kblock;
00359 
00360   int errorcode;
00361 
00362 
00363     /* Check the arguments */
00364 
00365   if (!node)
00366 
00367     return CBF_ARGUMENT;
00368 
00369 
00370     /* Is the current size correct? */
00371 
00372   if (children == node->children)
00373 
00374     return 0;
00375     
00376     /* Compute a target new size */
00377 
00378   kblock = 16;
00379 
00380   if (children > 128*2) kblock = 128;
00381 
00382   if (children > 512*2) kblock = 512;
00383 
00384   new_size = (((int)((children -1)/kblock)))*kblock+kblock;
00385 
00386   if (new_size < children) new_size = children;
00387 
00388     /* Decrease the number of children? */
00389 
00390   if (children < node->children)
00391   {
00392     errorcode = 0;
00393     
00394     for (count = children; count < node->children; count++)
00395 
00396         /* Free the child */
00397 
00398       if (node->type == CBF_COLUMN)
00399     
00400         errorcode |= cbf_set_columnrow (node, count, NULL, 1);
00401 
00402       else
00403 
00404         if (node->type != CBF_LINK)
00405 
00406           if (node->child [count])
00407           {
00408             node->child [count]->parent = NULL;
00409         
00410             errorcode |= cbf_free_node (node->child [count]);
00411 
00412             node->child [count] = NULL;
00413           }
00414 
00415     if (children == 0)
00416 
00417       errorcode = cbf_free ((void **) &node->child, &node->child_size);
00418 
00419     node->children = children;
00420 
00421     if (new_size < node->child_size )
00422       cbf_failnez (cbf_realloc ((void * *) &node->child, &node->child_size,
00423                                            sizeof (cbf_node  *), new_size))
00424 
00425     return errorcode;
00426   }
00427 
00428 
00429     /* Increase the number of children */
00430 
00431   if (new_size > node->child_size)
00432     cbf_failnez (cbf_realloc ((void **) &node->child, &node->child_size,
00433                                         sizeof (cbf_node *), new_size))
00434 
00435   node->children = children;
00436 
00437 
00438     /* Success */
00439 
00440   return 0;
00441 }
00442   
00443 
00444   /* Trace a link */
00445 
00446 cbf_node *cbf_get_link (const cbf_node *node)
00447 {
00448   while (node)
00449 
00450     if (node->type == CBF_LINK)
00451 
00452       node = node->link;
00453 
00454     else
00455 
00456       return (cbf_node *) node;
00457 
00458 
00459     /* Fail */
00460 
00461   return NULL;
00462 }
00463 
00464 
00465   /* Find a child node */
00466 
00467 int cbf_find_child (cbf_node **child, const cbf_node *node, const char *name)
00468 {
00469   unsigned int count;
00470 
00471   const char *namec, *nodenamec;
00472 
00473 
00474     /* Follow any links */
00475 
00476   node = cbf_get_link (node);
00477   
00478 
00479     /* Check the arguments */
00480 
00481   if (!node)
00482 
00483     return CBF_ARGUMENT;
00484 
00485 
00486     /* Is it a normal node? */
00487 
00488   if (node->type == CBF_COLUMN)
00489 
00490     return CBF_ARGUMENT;
00491 
00492 
00493     /* Search the children */
00494 
00495   for (count = 0; count < node->children; count++)
00496 
00497     if (name)
00498     {
00499       if (node->child [count]->name)
00500       {
00501         for (namec = name, nodenamec = node->child [count]->name;
00502             *namec && toupper (*nodenamec) == toupper (*namec);
00503              namec++, nodenamec++);
00504 
00505         if (!*namec && !*nodenamec)
00506         {
00507           if (child)
00508           
00509             *child = node->child [count];
00510 
00511           return 0;
00512         }
00513       }
00514     }
00515     else
00516 
00517       if (name == node->child [count]->name)
00518       {
00519         if (child)
00520         
00521           *child = node->child [count];
00522 
00523         return 0;
00524       }
00525 
00526 
00527     /* Fail */
00528 
00529   return CBF_NOTFOUND;
00530 }
00531 
00532 
00533   /* Find a child node, accepting the last match  */
00534 
00535 int cbf_find_last_child (cbf_node **child, const cbf_node *node, 
00536                          const char *name)
00537 {
00538   int count;
00539 
00540   const char *namec, *nodenamec;
00541 
00542 
00543     /* Follow any links */
00544 
00545   node = cbf_get_link (node);
00546   
00547 
00548     /* Check the arguments */
00549 
00550   if (!node)
00551 
00552     return CBF_ARGUMENT;
00553 
00554 
00555     /* Is it a normal node? */
00556 
00557   if (node->type == CBF_COLUMN)
00558 
00559     return CBF_ARGUMENT;
00560 
00561 
00562     /* Search the children */
00563 
00564   for (count = ((int) node->children) - 1; count >= 0; count--)
00565 
00566     if (name)
00567     {
00568       if (node->child [count]->name)
00569       {
00570         for (namec = name, nodenamec = node->child [count]->name;
00571             *namec && toupper (*nodenamec) == toupper (*namec);
00572              namec++, nodenamec++);
00573 
00574         if (!*namec && !*nodenamec)
00575         {
00576           if (child)
00577           
00578             *child = node->child [count];
00579 
00580           return 0;
00581         }
00582       }
00583     }
00584     else
00585 
00586       if (name == node->child [count]->name)
00587       {
00588         if (child)
00589         
00590           *child = node->child [count];
00591 
00592         return 0;
00593       }
00594 
00595 
00596     /* Fail */
00597 
00598   return CBF_NOTFOUND;
00599 }
00600 
00601 
00602   /* Find a parent node */
00603 
00604 int cbf_find_parent (cbf_node **parent, const cbf_node *node, 
00605                      CBF_NODETYPE type)
00606 {
00607     /* Follow any links */
00608 
00609   node = cbf_get_link (node);
00610 
00611 
00612     /* Check the arguments */
00613 
00614   if (!node)
00615 
00616     return CBF_ARGUMENT;
00617 
00618 
00619     /* Find the parent */
00620     
00621   while (node)
00622   {
00623     if (node->type == type)
00624     {
00625       if (parent)
00626       
00627         *parent = (cbf_node *) node;
00628       
00629       return 0;
00630     }
00631 
00632     node = node->parent;
00633   }
00634 
00635 
00636     /* Fail */
00637 
00638   return CBF_NOTFOUND;
00639 }
00640 
00641 
00642   /* Count the number of children */
00643 
00644 int cbf_count_children (unsigned int *children, const cbf_node *node)
00645 {
00646     /* Follow any links */
00647 
00648   node = cbf_get_link (node);
00649 
00650 
00651     /* Check the arguments */
00652     
00653   if (!children || !node)
00654 
00655     return CBF_ARGUMENT;
00656 
00657 
00658     /* Success */
00659 
00660   *children = node->children;
00661   
00662   return 0;
00663 }
00664 
00665 
00666   /* Get the index of a child */
00667 
00668 int cbf_child_index (unsigned int *index, const cbf_node *node)
00669 {
00670   cbf_node *parent;
00671 
00672   unsigned int child;
00673 
00674   
00675     /* Follow any links */
00676 
00677   node = cbf_get_link (node);
00678 
00679 
00680     /* Check the arguments */
00681 
00682   if (!node)
00683 
00684     return CBF_ARGUMENT;
00685 
00686 
00687     /* Get the parent */
00688 
00689   parent = node->parent;
00690 
00691   if (!parent)
00692 
00693     return CBF_NOTFOUND;
00694 
00695 
00696     /* Find the child */
00697 
00698   for (child = 0; child < parent->children; child++)
00699 
00700     if (parent->child [child] == node)
00701     {
00702       if (index)
00703 
00704         *index = child;
00705 
00706       return 0;
00707     }
00708 
00709 
00710     /* Fail */
00711 
00712   return CBF_NOTFOUND;
00713 }
00714 
00715 
00716   /* Get the specified child */
00717 
00718 int cbf_get_child (cbf_node **child, const cbf_node *node, unsigned int index)
00719 {
00720     /* Follow any links */
00721 
00722   node = cbf_get_link (node);
00723   
00724 
00725     /* Check the arguments */
00726 
00727   if (!node)
00728 
00729     return CBF_ARGUMENT;
00730 
00731 
00732     /* Is it a normal node? */
00733 
00734   if (node->type == CBF_COLUMN)
00735 
00736     return CBF_ARGUMENT;
00737 
00738 
00739     /* Does the child exists? */
00740 
00741   if (index < node->children)
00742   {
00743     if (child)
00744           
00745       *child = node->child [index];
00746 
00747     return 0;
00748   }
00749 
00750 
00751     /* Fail */
00752 
00753   return CBF_NOTFOUND;
00754 }
00755 
00756 
00757   /* Get the name of a node */
00758 
00759 int cbf_get_name (const char **name, cbf_node *node)
00760 {
00761     /* Follow any links */
00762 
00763   node = cbf_get_link (node);
00764 
00765 
00766     /* Check the arguments */
00767       
00768   if (!node)
00769 
00770     return CBF_ARGUMENT;
00771 
00772 
00773     /* Set the name */
00774 
00775   if (name)
00776 
00777     *name = node->name;
00778 
00779 
00780     /* Success */
00781 
00782   return 0;
00783 }
00784 
00785 
00786   /* All of the following functions assume that all of the strings have
00787      been created using cbf_copy_string and that no pointers to the
00788      strings are retained by the calling functions */
00789 
00790   /* Name a node */
00791 
00792 int cbf_name_node (cbf_node *node, const char *name)
00793 {
00794     /* Follow any links */
00795 
00796   node = cbf_get_link (node);
00797 
00798 
00799     /* Check the arguments */
00800       
00801   if (!node)
00802 
00803     return CBF_ARGUMENT;
00804     
00805 
00806     /* Is there a sibling with this name? */
00807 
00808   if (node->parent)
00809 
00810     if (cbf_find_child (NULL, node->parent, name) == 0)
00811 
00812       return CBF_IDENTICAL;
00813       
00814 
00815     /* Replace the old name */
00816 
00817   cbf_free_string (NULL, node->name);
00818 
00819   node->name = name;
00820 
00821 
00822     /* Success */      
00823 
00824   return 0;
00825 }
00826 
00827 
00828   /* Name a node allowing for duplicates  */
00829 
00830 int cbf_name_new_node (cbf_node *node, const char *name)
00831 {
00832     /* Follow any links */
00833 
00834   node = cbf_get_link (node);
00835 
00836 
00837     /* Check the arguments */
00838       
00839   if (!node)
00840 
00841     return CBF_ARGUMENT;
00842     
00843 
00844     /* Replace the old name */
00845 
00846   cbf_free_string (NULL, node->name);
00847 
00848   node->name = (char *) name;
00849 
00850 
00851     /* Success */      
00852 
00853   return 0;
00854 }
00855 
00856 
00857   /* Add a child to a node */
00858 
00859 int cbf_add_child (cbf_node *node, cbf_node *child)
00860 {
00861     /* Follow any links */
00862 
00863   node = cbf_get_link (node);
00864 
00865 
00866     /* Check the first argument */
00867     
00868   if (!node)
00869 
00870     return CBF_ARGUMENT;
00871 
00872 
00873     /* Follow any links */
00874 
00875   child = cbf_get_link (child);
00876 
00877 
00878     /* Check the second argument */
00879     
00880   if (!child)
00881 
00882     return CBF_ARGUMENT;
00883     
00884 
00885     /* Is there already a child with this name? */
00886     
00887   if (cbf_find_child (NULL, node, child->name) == 0)
00888 
00889     return CBF_IDENTICAL;
00890 
00891 
00892     /* Add the child */
00893 
00894   cbf_failnez (cbf_set_children (node, node->children + 1))
00895 
00896   child->parent = node;
00897 
00898   node->child [node->children - 1] = child;
00899 
00900 
00901     /* Success */
00902 
00903   return 0;
00904 }
00905 
00906 
00907   /* Add a child to a node with duplicates allowed */
00908 
00909 int cbf_add_new_child (cbf_node *node, cbf_node *child)
00910 {
00911     /* Follow any links */
00912 
00913   node = cbf_get_link (node);
00914 
00915 
00916     /* Check the first argument */
00917     
00918   if (!node)
00919 
00920     return CBF_ARGUMENT;
00921 
00922 
00923     /* Follow any links */
00924 
00925   child = cbf_get_link (child);
00926 
00927 
00928     /* Check the second argument */
00929     
00930   if (!child)
00931 
00932     return CBF_ARGUMENT;
00933 
00934 
00935     /* Add the child */
00936 
00937   cbf_failnez (cbf_set_children (node, node->children + 1))
00938 
00939   child->parent = node;
00940 
00941   node->child [node->children - 1] = child;
00942 
00943 
00944     /* Success */
00945 
00946   return 0;
00947 }
00948 
00949 
00950   /* Make a new child node */
00951 
00952 int cbf_make_child (cbf_node **child, cbf_node *node, 
00953                     CBF_NODETYPE type, const char *name)
00954 {
00955   cbf_node *newchild;
00956 
00957   int errorcode;
00958 
00959   
00960     /* Check the type */
00961 
00962   if (type == CBF_LINK)
00963 
00964     return CBF_ARGUMENT;
00965     
00966 
00967     /* Follow any links */
00968 
00969   node = cbf_get_link (node);
00970 
00971 
00972     /* Does the child already exist? */
00973 
00974   errorcode = cbf_find_last_child (child, node, name);
00975 
00976   if (errorcode == 0)
00977   {
00978     cbf_free_string (NULL, name);
00979     
00980     return 0;
00981   }
00982 
00983   if (errorcode != CBF_NOTFOUND)
00984 
00985     return errorcode;
00986 
00987 
00988     /* Make a new node */
00989 
00990   cbf_failnez (cbf_make_node (&newchild, type, node->context, name))
00991 
00992   errorcode = cbf_add_child (node, newchild);
00993 
00994   if (errorcode)
00995   {
00996     newchild->name = NULL;
00997 
00998     cbf_free_node (newchild);
00999     
01000     return errorcode;
01001   }
01002 
01003 
01004     /* Success */
01005 
01006   if (child)
01007 
01008     *child = newchild;
01009 
01010   return 0;
01011 }
01012 
01013 
01014   /* Make a new child node, with duplicates allowed */
01015 
01016 int cbf_make_new_child (cbf_node **child, cbf_node *node,
01017                         CBF_NODETYPE type, const char *name)
01018 {
01019   cbf_node *newchild;
01020 
01021   int errorcode;
01022 
01023   
01024     /* Check the type */
01025 
01026   if (type == CBF_LINK)
01027 
01028     return CBF_ARGUMENT;
01029     
01030 
01031     /* Follow any links */
01032 
01033   node = cbf_get_link (node);
01034 
01035 
01036     /* Make a new node */
01037 
01038   cbf_failnez (cbf_make_new_node (&newchild, type, node->context, name))
01039 
01040   errorcode = cbf_add_new_child (node, newchild);
01041 
01042   if (errorcode)
01043   {
01044     newchild->name = NULL;
01045 
01046     cbf_free_node (newchild);
01047     
01048     return errorcode;
01049   }
01050 
01051 
01052     /* Success */
01053 
01054   if (child)
01055 
01056     *child = newchild;
01057 
01058   return 0;
01059 }
01060 
01061 
01062   /* Change a link */
01063 
01064 int cbf_set_link (cbf_node *link, cbf_node *node)
01065 {
01066     /* Check the arguments */
01067     
01068   if (!link)
01069 
01070     return CBF_ARGUMENT;
01071 
01072 
01073     /* Check the type */
01074 
01075   if (link->type != CBF_LINK)
01076 
01077     return CBF_ARGUMENT;
01078 
01079 
01080     /* Change the link */
01081 
01082   link->link = node;
01083 
01084 
01085     /* Success */
01086 
01087   return 0;
01088 }
01089 
01090 
01091   /* Add a child link */
01092 
01093 int cbf_add_link (cbf_node *link, cbf_node *child)
01094 {
01095     /* Check the arguments */
01096     
01097   if (!link)
01098 
01099     return CBF_ARGUMENT;
01100 
01101 
01102     /* Check the type */
01103 
01104   if (link->type != CBF_LINK)
01105 
01106     return CBF_ARGUMENT;
01107 
01108 
01109     /* Add the child */
01110 
01111   cbf_failnez (cbf_set_children (link, link->children + 1))
01112 
01113   link->child [link->children - 1] = child;
01114   
01115 
01116     /* Success */
01117 
01118   return 0;
01119 }
01120                                                   
01121 
01122   /* Set a link successively to each child link */
01123 
01124 int cbf_shift_link (cbf_node *link)
01125 {
01126     /* Check the arguments */
01127     
01128   if (!link)
01129 
01130     return CBF_ARGUMENT;
01131 
01132 
01133     /* Check the type */
01134 
01135   if (link->type != CBF_LINK)
01136 
01137     return CBF_ARGUMENT;
01138 
01139 
01140     /* Do the children exist? */
01141 
01142   if (link->children == 0)
01143 
01144     return CBF_ARGUMENT;
01145 
01146 
01147     /* Change the link */
01148 
01149   link->link = link->child [0];
01150 
01151 
01152     /* Shift the children */
01153 
01154   memmove (link->child, link->child + 1, 
01155           (link->children - 1) * sizeof (cbf_node *));
01156 
01157   link->child [link->children - 1] = link->link;
01158 
01159 
01160     /* Success */
01161 
01162   return 0;
01163 }
01164 
01165 
01166   /* Set the value of a row */
01167 
01168 int cbf_set_columnrow (cbf_node *column, unsigned int row,
01169                                          const char *value, int free)
01170 {
01171     /* Follow any links */
01172 
01173   column = cbf_get_link (column);
01174 
01175 
01176     /* Check the arguments */
01177     
01178   if (!column)
01179 
01180     return CBF_ARGUMENT;
01181 
01182 
01183     /* Check the node type */
01184 
01185   if (column->type != CBF_COLUMN)
01186 
01187     return CBF_ARGUMENT;
01188 
01189 
01190     /* Increase the column size? */
01191 
01192   if (row + 1 > column->children)
01193 
01194     cbf_failnez (cbf_set_children (column, row + 1))
01195 
01196 
01197     /* Remove the old value */
01198 
01199   if (free)
01200 
01201     cbf_failnez (cbf_free_value (column->context, column, row))
01202 
01203 
01204     /* Set the new value */
01205 
01206   column->child [row] = (cbf_node *) value;
01207 
01208 
01209     /* Success */
01210 
01211   return 0;
01212 }
01213 
01214 
01215   /* Get the value of a row */
01216 
01217 int cbf_get_columnrow (const char **value, const cbf_node *column, 
01218                                            unsigned int row)
01219 {
01220     /* Follow any links */
01221 
01222   column = cbf_get_link (column);
01223 
01224 
01225     /* Check the arguments */
01226     
01227   if (!column)
01228 
01229     return CBF_ARGUMENT;
01230 
01231 
01232     /* Check the node type */
01233 
01234   if (column->type != CBF_COLUMN)
01235 
01236     return CBF_ARGUMENT;
01237 
01238 
01239     /* Is the value in the column? */
01240 
01241   if (row + 1 > column->children)
01242 
01243     return CBF_NOTFOUND;
01244 
01245 
01246     /* Success */
01247 
01248   if (value)
01249 
01250     *value = (const char *) column->child [row];
01251 
01252   return 0;
01253 }
01254 
01255 
01256   /* Inset a value into a column */
01257 
01258 int cbf_insert_columnrow (cbf_node *column, unsigned int row, 
01259                           const char *value)
01260 {
01261     /* Follow any links */
01262 
01263   column = cbf_get_link (column);
01264 
01265 
01266     /* Check the arguments */
01267 
01268   if (!column)
01269 
01270     return CBF_ARGUMENT;
01271 
01272   if (row > column->children)
01273 
01274     return CBF_NOTFOUND;
01275 
01276 
01277     /* Increase the column size */
01278 
01279   cbf_failnez (cbf_set_children (column, column->children + 1))
01280 
01281 
01282     /* Move any values further down the column */
01283 
01284   if (row < column->children - 1)
01285 
01286     memmove (column->child + row + 1, column->child + row,
01287                sizeof (cbf_node *) * (column->children - row - 1));
01288   
01289 
01290     /* Set the value */
01291 
01292   column->child [row] = (cbf_node *) value;
01293 
01294 
01295     /* Success */
01296 
01297   return 0;
01298 }
01299 
01300 
01301   /* Delete a row from a column */
01302 
01303 int cbf_delete_columnrow (cbf_node *column, unsigned int row)
01304 {
01305     /* Follow any links */
01306 
01307   column = cbf_get_link (column);
01308 
01309 
01310     /* Check the arguments */
01311 
01312   if (!column)
01313 
01314     return CBF_ARGUMENT;
01315 
01316   if (row >= column->children)
01317 
01318     return CBF_NOTFOUND;
01319 
01320 
01321     /* Free the value */
01322 
01323   cbf_failnez (cbf_set_columnrow (column, row, NULL, 1))
01324 
01325 
01326     /* Move any values further down the column */
01327 
01328   if (row < column->children - 1)
01329 
01330     memmove (column->child + row, column->child + row + 1,
01331              sizeof (cbf_node *) * (column->children - row - 1));
01332 
01333   column->child [column->children - 1] = NULL;
01334 
01335 
01336     /* Decrease the column size */
01337 
01338   return cbf_set_children (column, column->children - 1);
01339 }
01340 
01341 
01342   /* Add a value to a column */
01343 
01344 int cbf_add_columnrow (cbf_node *column, const char *value)
01345 {
01346     /* Follow any links */
01347 
01348   column = cbf_get_link (column);
01349 
01350 
01351     /* Check the arguments */
01352 
01353   if (!column)
01354 
01355     return CBF_ARGUMENT;
01356 
01357 
01358     /* Add the value */
01359 
01360   return cbf_set_columnrow (column, column->children, value, 1);
01361 }
01362 
01363 
01364 #ifdef __cplusplus
01365 
01366 }
01367 
01368 #endif