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 | |
---|
24 | static 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 | |
---|
73 | GBT_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 | |
---|
136 | void 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 | |
---|
160 | GB_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 | |
---|
173 | static 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 |
---|
222 | static 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 | |
---|
290 | static 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 | |
---|
335 | static 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 | |
---|
422 | GB_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 | } |
---|
425 | GB_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 | |
---|
429 | GB_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 | |
---|
437 | GBT_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 | |
---|
539 | static 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 | |
---|
578 | GBT_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 | |
---|
631 | GBT_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 | |
---|
635 | GBT_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 | ********************************************************************************************/ |
---|
650 | long 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 | |
---|
657 | struct 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 | |
---|
666 | static 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 | |
---|
693 | GB_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, <d); |
---|
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 | */ |
---|
729 | GB_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 | */ |
---|
741 | void 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 | |
---|
751 | GBDATA *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 | |
---|
757 | long 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 | |
---|
766 | char *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 | |
---|
785 | char *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 | |
---|
796 | const 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 | |
---|
839 | GB_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 | |
---|
849 | char **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 | |
---|
885 | char **GBT_get_tree_names(GBDATA *Main){ |
---|
886 | int dummy; |
---|
887 | return GBT_get_tree_names_and_count(Main, &dummy); |
---|
888 | } |
---|
889 | |
---|
890 | char *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 | |
---|
909 | int 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 | |
---|
916 | GB_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 | |
---|
926 | GB_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 | |
---|
940 | char *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 | |
---|