source: tags/arb_5.5/ARBDB/adtree.c

Last change on this file was 6143, checked in by westram, 15 years ago
  • backport [6141] (parts changing code, but only strings and comments)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.6 KB
Line 
1/* ============================================================ */
2/*                                                              */
3/*   File      : adtree.c                                       */
4/*   Purpose   : tree functions                                 */
5/*                                                              */
6/*   Institute of Microbiology (Technical University Munich)    */
7/*   www.arb-home.de                                            */
8/*                                                              */
9/* ============================================================ */
10
11#include <stdlib.h>
12#include <string.h>
13
14#include <adlocal.h>
15#include <arbdbt.h>
16
17#define GBT_PUT_DATA 1
18#define GBT_GET_SIZE 0
19
20/* ---------------------- */
21/*      remove leafs      */
22
23
24static GBT_TREE *fixDeletedSon(GBT_TREE *tree) {
25    // fix tree after one son has been deleted
26    // (Note: this function only works correct for trees with minimum element size!)
27    GBT_TREE *delNode = tree;
28
29    if (delNode->leftson) {
30        ad_assert(!delNode->rightson);
31        tree             = delNode->leftson;
32        delNode->leftson = 0;
33    }
34    else {
35        ad_assert(!delNode->leftson);
36        ad_assert(delNode->rightson);
37       
38        tree              = delNode->rightson;
39        delNode->rightson = 0;
40    }
41
42    // now tree is the new tree
43    tree->father = delNode->father;
44
45    if (delNode->remark_branch && !tree->remark_branch) { // rescue remarks if possible
46        tree->remark_branch    = delNode->remark_branch;
47        delNode->remark_branch = 0;
48    }
49    if (delNode->gb_node && !tree->gb_node) { // rescue group if possible
50        tree->gb_node    = delNode->gb_node;
51        delNode->gb_node = 0;
52    }
53
54    delNode->is_leaf = GB_TRUE; // don't try recursive delete
55
56    if (delNode->father) { // not root
57        GBT_delete_tree(delNode);
58    }
59    else { // root node
60        if (delNode->tree_is_one_piece_of_memory) {
61            // don't change root -> copy instead
62            memcpy(delNode, tree, sizeof(GBT_TREE));
63            tree = delNode;
64        }
65        else {
66            GBT_delete_tree(delNode);
67        }
68    }
69    return tree;
70}
71
72
73GBT_TREE *GBT_remove_leafs(GBT_TREE *tree, GBT_TREE_REMOVE_TYPE mode, GB_HASH *species_hash, int *removed, int *groups_removed) {
74    // Given 'tree' can either
75    // - be linked (in this case 'species_hash' shall be NULL)
76    // - be unlinked (in this case 'species_hash' has to be provided)
77    //
78    // If 'removed' and/or 'groups_removed' is given, it's used to count the removed leafs/groups.
79
80    if (tree->is_leaf) {
81        if (tree->name) {
82            GB_BOOL  deleteSelf = GB_FALSE;
83            GBDATA  *gb_node;
84
85            if (species_hash) {
86                gb_node = (GBDATA*)GBS_read_hash(species_hash, tree->name);
87                ad_assert(tree->gb_node == 0); // don't call linked tree with 'species_hash'!
88            }
89            else gb_node = tree->gb_node;
90
91            if (gb_node) {
92                if (mode & (GBT_REMOVE_MARKED|GBT_REMOVE_NOT_MARKED)) {
93                    long flag = GB_read_flag(gb_node);
94                    deleteSelf = (flag && (mode&GBT_REMOVE_MARKED)) || (!flag && (mode&GBT_REMOVE_NOT_MARKED));
95                }
96            }
97            else { // zombie
98                if (mode & GBT_REMOVE_DELETED) deleteSelf = GB_TRUE;
99            }
100
101            if (deleteSelf) {
102                GBT_delete_tree(tree);
103                if (removed) (*removed)++;
104                tree = 0;
105            }
106        }
107    }
108    else {
109        tree->leftson  = GBT_remove_leafs(tree->leftson, mode, species_hash, removed, groups_removed);
110        tree->rightson = GBT_remove_leafs(tree->rightson, mode, species_hash, removed, groups_removed);
111
112        if (tree->leftson) {
113            if (!tree->rightson) { // right son deleted
114                tree = fixDeletedSon(tree);
115            }
116            // otherwise no son deleted
117        }
118        else if (tree->rightson) { // left son deleted
119            tree = fixDeletedSon(tree);
120        }
121        else {                  // everything deleted -> delete self
122            if (tree->name && groups_removed) (*groups_removed)++;
123            tree->is_leaf = GB_TRUE;
124            GBT_delete_tree(tree);
125            tree          = 0;
126        }
127    }
128
129    return tree;
130}
131
132/* ------------------- */
133/*      free tree      */
134
135
136void GBT_delete_tree(GBT_TREE *tree)
137     /* frees a tree only in memory (not in the database)
138        to delete the tree in Database
139        just call GB_delete((GBDATA *)gb_tree);
140     */
141{
142    free(tree->name);
143    free(tree->remark_branch);
144
145    if (!tree->is_leaf) {
146        GBT_delete_tree(tree->leftson);
147        GBT_delete_tree(tree->rightson);
148    }
149    if (!tree->tree_is_one_piece_of_memory || !tree->father) {
150        free(tree);
151    }
152}
153
154
155/********************************************************************************************
156                    some tree write functions
157********************************************************************************************/
158
159
160GB_ERROR GBT_write_group_name(GBDATA *gb_group_name, const char *new_group_name) {
161    GB_ERROR error = 0;
162    size_t   len   = strlen(new_group_name);
163
164    if (len >= GB_GROUP_NAME_MAX) {
165        error = GBS_global_string("Group name '%s' too long (max %i characters)", new_group_name, GB_GROUP_NAME_MAX);
166    }
167    else {
168        error = GB_write_string(gb_group_name, new_group_name);
169    }
170    return error;
171}
172
173static GB_ERROR gbt_write_tree_nodes(GBDATA *gb_tree, GBT_TREE *node, long *startid) {
174    // increments '*startid' for each inner node (not for leafs)
175
176    GB_ERROR error = NULL;
177
178    if (!node->is_leaf) {
179        GB_BOOL node_is_used = GB_FALSE;
180
181        if (node->name && node->name[0]) {
182            if (!node->gb_node) {
183                node->gb_node = GB_create_container(gb_tree, "node");
184                if (!node->gb_node) error = GB_await_error();
185            }
186            if (!error) {
187                GBDATA *gb_name     = GB_search(node->gb_node,"group_name",GB_STRING);
188                if (!gb_name) error = GB_await_error();
189                else    error       = GBT_write_group_name(gb_name, node->name);
190
191                node_is_used = GB_TRUE; // wrote groupname -> node is used
192            }
193        }
194
195        if (node->gb_node && !error) {
196            if (!node_is_used) {
197                GBDATA *gb_nonid = GB_child(node->gb_node);
198                while (gb_nonid && strcmp("id", GB_read_key_pntr(gb_nonid)) == 0) {
199                    gb_nonid = GB_nextChild(gb_nonid);
200                }
201                if (gb_nonid) node_is_used = GB_TRUE; // found child that is not "id" -> node is used
202            }
203
204            if (node_is_used) { // set id for used nodes
205                error             = GBT_write_int(node->gb_node, "id", *startid);
206                if (!error) error = GB_write_usr_private(node->gb_node,0);
207            }
208            else {          // delete unused nodes
209                error = GB_delete(node->gb_node);
210                if (!error) node->gb_node = 0;
211            }
212        }
213
214        (*startid)++;
215        if (!error) error = gbt_write_tree_nodes(gb_tree, node->leftson, startid);
216        if (!error) error = gbt_write_tree_nodes(gb_tree, node->rightson, startid);
217    }
218    return error;
219}
220
221#if 0
222static long gbt_write_tree_nodes_old(GBDATA *gb_tree, GBT_TREE *node, long startid) {
223    long me;
224    GB_ERROR error;
225    const char *key;
226    GBDATA *gb_id,*gb_name,*gb_any;
227    if (node->is_leaf) return 0;
228    me = startid;
229    if (node->name && (strlen(node->name)) ) {
230        if (!node->gb_node) {
231            node->gb_node = GB_create_container(gb_tree,"node");
232        }
233        gb_name = GB_search(node->gb_node,"group_name",GB_STRING);
234        error = GBT_write_group_name(gb_name, node->name);
235        if (error) return -1;
236    }
237    if (node->gb_node) {         /* delete not used nodes else write id */
238        gb_any = GB_child(node->gb_node);
239        if (gb_any) {
240            key = GB_read_key_pntr(gb_any);
241            if (strcmp(key,"id") == 0) {
242                gb_any = GB_nextChild(gb_any);
243            }
244        }
245
246        if (gb_any){
247            gb_id = GB_search(node->gb_node,"id",GB_INT);
248#if defined(DEBUG) && defined(DEVEL_RALF)
249            {
250                int old = GB_read_int(gb_id);
251                if (old != me) {
252                    printf("id changed in gbt_write_tree_nodes(): old=%i new=%li (tree-node=%p; gb_node=%p)\n",
253                           old, me, node, node->gb_node);
254                }
255            }
256#endif /* DEBUG */
257            error = GB_write_int(gb_id,me);
258            GB_write_usr_private(node->gb_node,0);
259            if (error) return -1;
260        }
261        else {
262#if defined(DEBUG) && defined(DEVEL_RALF)
263            {
264                GBDATA *gb_id2 = GB_entry(node->gb_node, "id");
265                int     id     = 0;
266                if (gb_id2) id = GB_read_int(gb_id2);
267
268                printf("deleting node w/o info: tree-node=%p; gb_node=%p prev.id=%i\n",
269                       node, node->gb_node, id);
270            }
271#endif /* DEBUG */
272            GB_delete(node->gb_node);
273            node->gb_node = 0;
274        }
275    }
276    startid++;
277    if (!node->leftson->is_leaf) {
278        startid = gbt_write_tree_nodes(gb_tree,node->leftson,startid);
279        if (startid<0) return startid;
280    }
281
282    if (!node->rightson->is_leaf) {
283        startid = gbt_write_tree_nodes(gb_tree,node->rightson,startid);
284        if (startid<0) return startid;
285    }
286    return startid;
287}
288#endif
289
290static char *gbt_write_tree_rek_new(GBT_TREE *node, char *dest, long mode) {
291    char buffer[40];        /* just real numbers */
292    char    *c1;
293
294    if ( (c1 = node->remark_branch) ) {
295        int c;
296        if (mode == GBT_PUT_DATA) {
297            *(dest++) = 'R';
298            while ( (c= *(c1++))  ) {
299                if (c == 1) continue;
300                *(dest++) = c;
301            }
302            *(dest++) = 1;
303        }else{
304            dest += strlen(c1) + 2;
305        }
306    }
307
308    if (node->is_leaf){
309        if (mode == GBT_PUT_DATA) {
310            *(dest++) = 'L';
311            if (node->name) strcpy(dest,node->name);
312            while ( (c1= (char *)strchr(dest,1)) ) *c1 = 2;
313            dest += strlen(dest);
314            *(dest++) = 1;
315            return dest;
316        }else{
317            if (node->name) return dest+1+strlen(node->name)+1; /* N name term */
318            return dest+1+1;
319        }
320    }else{
321        sprintf(buffer,"%g,%g;",node->leftlen,node->rightlen);
322        if (mode == GBT_PUT_DATA) {
323            *(dest++) = 'N';
324            strcpy(dest,buffer);
325            dest += strlen(buffer);
326        }else{
327            dest += strlen(buffer)+1;
328        }
329        dest = gbt_write_tree_rek_new(node->leftson,  dest, mode);
330        dest = gbt_write_tree_rek_new(node->rightson, dest, mode);
331        return dest;
332    }
333}
334
335static GB_ERROR gbt_write_tree(GBDATA *gb_main, GBDATA *gb_tree, const char *tree_name, GBT_TREE *tree, int plain_only) {
336    /* writes a tree to the database.
337
338    If tree is loaded by function GBT_read_tree(..) then 'tree_name' should be zero !!!!!!
339    else 'gb_tree' should be set to zero.
340
341    to copy a tree call GB_copy((GBDATA *)dest,(GBDATA *)source);
342    or set recursively all tree->gb_node variables to zero (that unlinks the tree),
343
344    if 'plain_only' == 1 only the plain tree string is written
345
346    */
347    GB_ERROR error = 0;
348
349    gb_assert(!plain_only || (tree_name == 0)); // if plain_only == 1 -> set tree_name to 0
350
351    if (tree) {
352        if (tree_name) {
353            if (gb_tree) error = GBS_global_string("can't change name of existing tree (to '%s')", tree_name);
354            else {
355                error = GBT_check_tree_name(tree_name);
356                if (!error) {
357                    GBDATA *gb_tree_data = GB_search(gb_main, "tree_data", GB_CREATE_CONTAINER);
358                    gb_tree              = GB_search(gb_tree_data, tree_name, GB_CREATE_CONTAINER);
359
360                    if (!gb_tree) error = GB_await_error();
361                }
362            }
363        }
364        else {
365            if (!gb_tree) error = "No tree name given";
366        }
367
368        ad_assert(gb_tree || error);
369
370        if (!error) {
371            if (!plain_only) {
372                // mark all old style tree data for deletion
373                GBDATA *gb_node;
374                for (gb_node = GB_entry(gb_tree,"node"); gb_node; gb_node = GB_nextEntry(gb_node)) {
375                    GB_write_usr_private(gb_node,1);
376                }
377            }
378
379            // build tree-string and save to DB
380            {
381                char *t_size = gbt_write_tree_rek_new(tree, 0, GBT_GET_SIZE); // calc size of tree-string
382                char *ctree  = (char *)GB_calloc(sizeof(char),(size_t)(t_size+1)); // allocate buffer for tree-string
383
384                t_size = gbt_write_tree_rek_new(tree, ctree, GBT_PUT_DATA); // write into buffer
385                *(t_size) = 0;
386
387                error = GB_set_compression(gb_main,0); // no more compressions
388                if (!error) {
389                    error        = GBT_write_string(gb_tree, "tree", ctree);
390                    GB_ERROR err = GB_set_compression(gb_main,-1); // again allow all types of compression
391                    if (!error) error = err;
392                }
393                free(ctree);
394            }
395        }
396
397        if (!plain_only && !error) {
398            // save nodes to DB
399            long size         = 0;
400            error             = gbt_write_tree_nodes(gb_tree, tree, &size); // reports number of nodes in 'size'
401            if (!error) error = GBT_write_int(gb_tree, "nnodes", size);
402
403            if (!error) {
404                GBDATA *gb_node;
405                GBDATA *gb_node_next;
406
407                for (gb_node = GB_entry(gb_tree,"node"); // delete all ghost nodes
408                     gb_node && !error;
409                     gb_node = gb_node_next)
410                {
411                    GBDATA *gbd = GB_entry(gb_node,"id");
412                    gb_node_next = GB_nextEntry(gb_node);
413                    if (!gbd || GB_read_usr_private(gb_node)) error = GB_delete(gb_node);
414                }
415            }
416        }
417    }
418
419    return error;
420}
421
422GB_ERROR GBT_write_tree(GBDATA *gb_main, GBDATA *gb_tree, const char *tree_name, GBT_TREE *tree) {
423    return gbt_write_tree(gb_main, gb_tree, tree_name, tree, 0);
424}
425GB_ERROR GBT_write_plain_tree(GBDATA *gb_main, GBDATA *gb_tree, char *tree_name, GBT_TREE *tree) {
426    return gbt_write_tree(gb_main, gb_tree, tree_name, tree, 1);
427}
428
429GB_ERROR GBT_write_tree_rem(GBDATA *gb_main,const char *tree_name, const char *remark) {
430    return GBT_write_string(GBT_get_tree(gb_main, tree_name), "remark", remark);
431}
432
433/********************************************************************************************
434                    some tree read functions
435********************************************************************************************/
436
437GBT_TREE *gbt_read_tree_rek(char **data, long *startid, GBDATA **gb_tree_nodes, long structure_size, int size_of_tree, GB_ERROR *error)
438{
439    GBT_TREE    *node;
440    GBDATA      *gb_group_name;
441    char         c;
442    char        *p1;
443    static char *membase;
444
445    gb_assert(error);
446    if (*error) return NULL;
447
448    if (structure_size>0){
449        node = (GBT_TREE *)GB_calloc(1,(size_t)structure_size);
450    }
451    else {
452        if (!startid[0]){
453            membase =(char *)GB_calloc(size_of_tree+1,(size_t)(-2*structure_size)); /* because of inner nodes */
454        }
455        node = (GBT_TREE *)membase;
456        node->tree_is_one_piece_of_memory = 1;
457        membase -= structure_size;
458    }
459
460    c = *((*data)++);
461
462    if (c=='R') {
463        p1 = strchr(*data,1);
464        *(p1++) = 0;
465        node->remark_branch = strdup(*data);
466        c = *(p1++);
467        *data = p1;
468    }
469
470
471    if (c=='N') {
472        p1 = (char *)strchr(*data,',');
473        *(p1++) = 0;
474        node->leftlen = GB_atof(*data);
475        *data = p1;
476        p1 = (char *)strchr(*data,';');
477        *(p1++) = 0;
478        node->rightlen = GB_atof(*data);
479        *data = p1;
480        if ((*startid < size_of_tree) && (node->gb_node = gb_tree_nodes[*startid])){
481            gb_group_name = GB_entry(node->gb_node,"group_name");
482            if (gb_group_name) {
483                node->name = GB_read_string(gb_group_name);
484            }
485        }
486        (*startid)++;
487        node->leftson = gbt_read_tree_rek(data,startid,gb_tree_nodes,structure_size,size_of_tree, error);
488        if (!node->leftson) {
489            if (!node->tree_is_one_piece_of_memory) free((char *)node);
490            return NULL;
491        }
492        node->rightson = gbt_read_tree_rek(data,startid,gb_tree_nodes,structure_size,size_of_tree, error);
493        if (!node->rightson) {
494            if (!node->tree_is_one_piece_of_memory) free((char *)node);
495            return NULL;
496        }
497        node->leftson->father = node;
498        node->rightson->father = node;
499    }
500    else if (c=='L') {
501        node->is_leaf = GB_TRUE;
502        p1            = (char *)strchr(*data,1);
503
504        gb_assert(p1);
505        gb_assert(p1[0] == 1);
506
507        *p1        = 0;
508        node->name = strdup(*data);
509        *data      = p1+1;
510    }
511    else {
512        if (!c) {
513            *error = "Unexpected end of tree definition.";
514        }
515        else {
516            *error = GBS_global_string("Can't interpret tree definition (expected 'N' or 'L' - not '%c')", c);
517        }
518        /* GB_internal_error("Error reading tree 362436"); */
519        return NULL;
520    }
521    return node;
522}
523
524
525/** Loads a tree from the database into any user defined structure.
526    make sure that the first eight members members of your
527    structure looks exactly like GBT_TREE, You should send the size
528    of your structure ( minimum sizeof GBT_TREE) to this
529    function.
530
531    If size < 0 then the tree is allocated as just one big piece of memory,
532    which can be freed by free((char *)root_of_tree) + deleting names or
533    by GBT_delete_tree.
534
535    tree_name is the name of the tree in the db
536    return NULL if any error occur
537*/
538
539static GBT_TREE *read_tree_and_size_internal(GBDATA *gb_tree, GBDATA *gb_ctree, int structure_size, int size, GB_ERROR *error) {
540    GBDATA   **gb_tree_nodes;
541    GBT_TREE  *node = 0;
542
543    gb_tree_nodes = (GBDATA **)GB_calloc(sizeof(GBDATA *),(size_t)size);
544    if (gb_tree) {
545        GBDATA *gb_node;
546
547        for (gb_node = GB_entry(gb_tree,"node"); gb_node && !*error; gb_node = GB_nextEntry(gb_node)) {
548            long    i;
549            GBDATA *gbd = GB_entry(gb_node,"id");
550            if (!gbd) continue;
551
552            /*{ GB_export_error("ERROR while reading tree '%s' 4634",tree_name);return NULL;}*/
553            i = GB_read_int(gbd);
554            if ( i<0 || i>= size ) {
555                *error = "An inner node of the tree is corrupt";
556            }
557            else {
558                gb_tree_nodes[i] = gb_node;
559            }
560        }
561    }
562    if (!*error) {
563        char *cptr[1];
564        long  startid[1];
565        char *fbuf;
566
567        startid[0] = 0;
568        fbuf       = cptr[0] = GB_read_string(gb_ctree);
569        node       = gbt_read_tree_rek(cptr, startid, gb_tree_nodes, structure_size,(int)size, error);
570        free (fbuf);
571    }
572
573    free((char *)gb_tree_nodes);
574
575    return node;
576}
577
578GBT_TREE *GBT_read_tree_and_size(GBDATA *gb_main,const char *tree_name, long structure_size, int *tree_size) {
579    /* Read a tree from DB.
580     * In case of failure, return NULL (and export error)
581     */
582    GB_ERROR error = 0;
583
584    if (!tree_name) {
585        error = "no treename given";
586    }
587    else {
588        error = GBT_check_tree_name(tree_name);
589        if (!error) {
590            GBDATA *gb_tree = GBT_get_tree(gb_main, tree_name);
591
592            if (!gb_tree) {
593                error = GBS_global_string("Could not find tree '%s'", tree_name);
594            }
595            else {
596                GBDATA *gb_nnodes = GB_entry(gb_tree, "nnodes");
597                if (!gb_nnodes) {
598                    error = GBS_global_string("Tree '%s' is empty", tree_name);
599                }
600                else {
601                    long size = GB_read_int(gb_nnodes);
602                    if (!size) {
603                        error = GBS_global_string("Tree '%s' has zero size", tree_name);
604                    }
605                    else {
606                        GBDATA *gb_ctree = GB_search(gb_tree, "tree", GB_FIND);
607                        if (!gb_ctree) {
608                            error = "Sorry - old tree format no longer supported";
609                        }
610                        else { /* "new" style tree */
611                            GBT_TREE *tree = read_tree_and_size_internal(gb_tree, gb_ctree, structure_size, size, &error);
612                            if (!error) {
613                                gb_assert(tree);
614                                if (tree_size) *tree_size = size; /* return size of tree */
615                                return tree;
616                            }
617
618                            gb_assert(!tree);
619                        }
620                    }
621                }
622            }
623        }
624    }
625
626    gb_assert(error);
627    GB_export_errorf("Couldn't read tree '%s' (Reason: %s)", tree_name, error);
628    return NULL;
629}
630
631GBT_TREE *GBT_read_tree(GBDATA *gb_main,const char *tree_name, long structure_size) {
632    return GBT_read_tree_and_size(gb_main, tree_name, structure_size, 0);
633}
634
635GBT_TREE *GBT_read_plain_tree(GBDATA *gb_main, GBDATA *gb_ctree, long structure_size, GB_ERROR *error) {
636    GBT_TREE *t;
637
638    gb_assert(error && !*error); /* expect cleared error*/
639
640    GB_push_transaction(gb_main);
641    t = read_tree_and_size_internal(0, gb_ctree, structure_size, 0, error);
642    GB_pop_transaction(gb_main);
643
644    return t;
645}
646
647/********************************************************************************************
648                    link the tree tips to the database
649********************************************************************************************/
650long GBT_count_nodes(GBT_TREE *tree){
651    if ( tree->is_leaf ) {
652        return 1;
653    }
654    return GBT_count_nodes(tree->leftson) + GBT_count_nodes(tree->rightson);
655}
656
657struct link_tree_data {
658    GB_HASH *species_hash;
659    GB_HASH *seen_species;      /* used to count duplicates */
660    int      nodes; /* if != 0 -> update status */;
661    int      counter;
662    int      zombies;           /* counts zombies */
663    int      duplicates;        /* counts duplicates */
664};
665
666static GB_ERROR gbt_link_tree_to_hash_rek(GBT_TREE *tree, struct link_tree_data *ltd) {
667    GB_ERROR error = 0;
668    if (tree->is_leaf) {
669        if (ltd->nodes) { /* update status? */
670            GB_status(ltd->counter/(double)ltd->nodes);
671            ltd->counter++;
672        }
673
674        tree->gb_node = 0;
675        if (tree->name) {
676            GBDATA *gbd = (GBDATA*)GBS_read_hash(ltd->species_hash, tree->name);
677            if (gbd) tree->gb_node = gbd;
678            else ltd->zombies++;
679
680            if (ltd->seen_species) {
681                if (GBS_read_hash(ltd->seen_species, tree->name)) ltd->duplicates++;
682                else GBS_write_hash(ltd->seen_species, tree->name, 1);
683            }
684        }
685    }
686    else {
687        error = gbt_link_tree_to_hash_rek(tree->leftson, ltd);
688        if (!error) error = gbt_link_tree_to_hash_rek(tree->rightson, ltd);
689    }
690    return error;
691}
692
693GB_ERROR GBT_link_tree_using_species_hash(GBT_TREE *tree, GB_BOOL show_status, GB_HASH *species_hash, int *zombies, int *duplicates) {
694    GB_ERROR              error;
695    struct link_tree_data ltd;
696    long                  leafs = 0;
697
698    if (duplicates || show_status) {
699        leafs = GBT_count_nodes(tree);
700    }
701   
702    ltd.species_hash = species_hash;
703    ltd.seen_species = leafs ? GBS_create_hash(2*leafs, GB_IGNORE_CASE) : 0;
704    ltd.zombies      = 0;
705    ltd.duplicates   = 0;
706    ltd.counter      = 0;
707
708    if (show_status) {
709        GB_status2("Relinking tree to database");
710        ltd.nodes = leafs;
711    }
712    else {
713        ltd.nodes = 0;
714    }
715
716    error = gbt_link_tree_to_hash_rek(tree, &ltd);
717    if (ltd.seen_species) GBS_free_hash(ltd.seen_species);
718
719    if (zombies) *zombies = ltd.zombies;
720    if (duplicates) *duplicates = ltd.duplicates;
721
722    return error;
723}
724
725/** Link a given tree to the database. That means that for all tips the member
726    gb_node is set to the database container holding the species data.
727    returns the number of zombies and duplicates in 'zombies' and 'duplicates'
728*/
729GB_ERROR GBT_link_tree(GBT_TREE *tree,GBDATA *gb_main,GB_BOOL show_status, int *zombies, int *duplicates)
730{
731    GB_HASH  *species_hash = GBT_create_species_hash(gb_main);
732    GB_ERROR  error        = GBT_link_tree_using_species_hash(tree, show_status, species_hash, zombies, duplicates);
733
734    GBS_free_hash(species_hash);
735
736    return error;
737}
738
739/** Unlink a given tree from the database.
740 */
741void GBT_unlink_tree(GBT_TREE *tree)
742{
743    tree->gb_node = 0;
744    if (!tree->is_leaf) {
745        GBT_unlink_tree(tree->leftson);
746        GBT_unlink_tree(tree->rightson);
747    }
748}
749
750
751GBDATA *GBT_get_tree(GBDATA *gb_main, const char *tree_name) {
752    /* returns the datapntr to the database structure, which is the container for the tree */
753    GBDATA *gb_treedata = GB_search(gb_main,"tree_data",GB_CREATE_CONTAINER);
754    return GB_entry(gb_treedata, tree_name);
755}
756
757long GBT_size_of_tree(GBDATA *gb_main, const char *tree_name) {
758    GBDATA *gb_tree = GBT_get_tree(gb_main,tree_name);
759    GBDATA *gb_nnodes;
760    if (!gb_tree) return -1;
761    gb_nnodes = GB_entry(gb_tree,"nnodes");
762    if (!gb_nnodes) return -1;
763    return GB_read_int(gb_nnodes);
764}
765
766char *GBT_find_largest_tree(GBDATA *gb_main){
767    char   *largest     = 0;
768    long    maxnodes    = 0;
769    GBDATA *gb_treedata = GB_search(gb_main,"tree_data",GB_CREATE_CONTAINER);
770    GBDATA *gb_tree;
771
772    for (gb_tree = GB_child(gb_treedata);
773         gb_tree;
774         gb_tree = GB_nextChild(gb_tree))
775    {
776        long *nnodes = GBT_read_int(gb_tree, "nnodes");
777        if (nnodes && *nnodes>maxnodes) {
778            freeset(largest, GB_read_key(gb_tree));
779            maxnodes = *nnodes;
780        }
781    }
782    return largest;
783}
784
785char *GBT_find_latest_tree(GBDATA *gb_main){
786    char **names = GBT_get_tree_names(gb_main);
787    char *name = 0;
788    char **pname;
789    if (!names) return NULL;
790    for (pname = names;*pname;pname++) name = *pname;
791    if (name) name = strdup(name);
792    GBT_free_names(names);
793    return name;
794}
795
796const char *GBT_tree_info_string(GBDATA *gb_main, const char *tree_name, int maxTreeNameLen) {
797    /* maxTreeNameLen shall be the max len of the longest tree name (or -1 -> do not format) */
798
799    const char *result  = 0;
800    GBDATA     *gb_tree = GBT_get_tree(gb_main,tree_name);
801   
802    if (!gb_tree) {
803        GB_export_errorf("tree '%s' not found",tree_name);
804    }
805    else {
806        GBDATA *gb_nnodes = GB_entry(gb_tree,"nnodes");
807        if (!gb_nnodes) {
808            GB_export_errorf("nnodes not found in tree '%s'",tree_name);
809        }
810        else {
811            const char *sizeInfo = GBS_global_string("(%li:%i)", GB_read_int(gb_nnodes)+1, GB_read_security_write(gb_tree));
812            GBDATA     *gb_rem   = GB_entry(gb_tree,"remark");
813            int         len;
814
815            if (maxTreeNameLen == -1) {
816                result = GBS_global_string("%s %11s", tree_name, sizeInfo);
817                len    = strlen(tree_name);
818            }
819            else {
820                result = GBS_global_string("%-*s %11s", maxTreeNameLen, tree_name, sizeInfo);
821                len    = maxTreeNameLen;
822            }
823            if (gb_rem) {
824                const char *remark    = GB_read_char_pntr(gb_rem);
825                const int   remarkLen = 800;
826                char       *res2      = GB_give_other_buffer(remark, len+1+11+2+remarkLen+1);
827
828                strcpy(res2, result);
829                strcat(res2, "  ");
830                strncat(res2, remark, remarkLen);
831
832                result = res2;
833            }
834        }
835    }
836    return result;
837}
838
839GB_ERROR GBT_check_tree_name(const char *tree_name)
840{
841    GB_ERROR error;
842    if ( (error = GB_check_key(tree_name)) ) return error;
843    if (strncmp(tree_name,"tree_",5)){
844        return GB_export_errorf("your treename '%s' does not begin with 'tree_'",tree_name);
845    }
846    return 0;
847}
848
849char **GBT_get_tree_names_and_count(GBDATA *Main, int *countPtr){
850    /* returns an null terminated array of string pointers */
851
852    int      count       = 0;
853    GBDATA  *gb_treedata = GB_entry(Main,"tree_data");
854    char   **erg         = 0;
855
856    if (gb_treedata) {
857        GBDATA *gb_tree;
858        count = 0;
859
860        for (gb_tree = GB_child(gb_treedata);
861             gb_tree;
862             gb_tree = GB_nextChild(gb_tree))
863        {
864            count ++;
865        }
866
867        if (count) {
868            erg   = (char **)GB_calloc(sizeof(char *),(size_t)count+1);
869            count = 0;
870
871            for (gb_tree = GB_child(gb_treedata);
872                 gb_tree;
873                 gb_tree = GB_nextChild(gb_tree) )
874            {
875                erg[count] = GB_read_key(gb_tree);
876                count ++;
877            }
878        }
879    }
880
881    *countPtr = count;
882    return erg;
883}
884
885char **GBT_get_tree_names(GBDATA *Main){
886    int dummy;
887    return GBT_get_tree_names_and_count(Main, &dummy);
888}
889
890char *GBT_get_next_tree_name(GBDATA *gb_main, const char *tree_name) {
891    /* returns a heap-copy of the name of the next tree behind 'tree_name'.
892     * If 'tree_name' is NULL or points to the last tree, returns the first tree.
893     * If no tree exists, returns NULL.
894     */
895    GBDATA *gb_tree = 0;
896
897    if (tree_name) {
898        gb_tree = GBT_get_tree(gb_main, tree_name);
899        gb_tree = GB_nextChild(gb_tree);
900    }
901    if (!gb_tree) {
902        GBDATA *gb_treedata = GB_search(gb_main,"tree_data",GB_CREATE_CONTAINER);
903        gb_tree = GB_child(gb_treedata);
904    }
905
906    return gb_tree ? GB_read_key(gb_tree) : NULL;
907}
908
909int gbt_sum_leafs(GBT_TREE *tree){
910    if (tree->is_leaf){
911        return 1;
912    }
913    return gbt_sum_leafs(tree->leftson) + gbt_sum_leafs(tree->rightson);
914}
915
916GB_CSTR *gbt_fill_species_names(GB_CSTR *des,GBT_TREE *tree) {
917    if (tree->is_leaf){
918        des[0] = tree->name;
919        return des+1;
920    }
921    des = gbt_fill_species_names(des,tree->leftson);
922    des = gbt_fill_species_names(des,tree->rightson);
923    return des;
924}
925
926GB_CSTR *GBT_get_species_names_of_tree(GBT_TREE *tree){
927    /* creates an array of all species names in a tree,
928     * The names are not allocated (so they may change as side effect of renaming species) */
929
930    int size = gbt_sum_leafs(tree);
931    GB_CSTR *result = (GB_CSTR *)GB_calloc(sizeof(char *),size +1);
932#if defined(DEBUG)
933    GB_CSTR *check =
934#endif // DEBUG
935        gbt_fill_species_names(result,tree);
936    ad_assert(check - size == result);
937    return result;
938}
939
940char *GBT_existing_tree(GBDATA *gb_main, const char *tree_name) {
941    /* search for an existing or an alternate tree */
942    GBDATA *gb_tree     = 0;
943    GBDATA *gb_treedata = GB_entry(gb_main,"tree_data");
944
945    if (gb_treedata) {
946        gb_tree = GB_entry(gb_treedata, tree_name);
947        if (!gb_tree) gb_tree = GB_child(gb_treedata); // take any tree
948    }
949
950    return gb_tree ? GB_read_key(gb_tree) : NULL;
951}
952
Note: See TracBrowser for help on using the repository browser.