ARB
adtree.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : adtree.cxx //
4 // Purpose : tree functions //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include <arb_progress.h>
12 #include "gb_local.h"
13 #include <arb_strarray.h>
14 #include <set>
15 #include <limits.h>
16 #include <arb_global_defs.h>
17 #include <arb_strbuf.h>
18 #include <arb_diff.h>
19 #include <arb_defs.h>
20 #include <arb_match.h>
21 #include <arb_msg_nospam.h>
22 #include "TreeNode.h"
23 
24 #define GBT_PUT_DATA 1
25 #define GBT_GET_SIZE 0
26 
28  return GBT_find_or_create(gb_main, "tree_data", 7);
29 }
30 
31 // ----------------------
32 // remove leafs
33 
34 TreeNode *GBT_remove_leafs(TreeNode *tree, GBT_TreeRemoveType mode, const GB_HASH *species_hash, int *removed, int *groups_removed) { // @@@ add tests for GBT_remove_leafs()
49  if (tree->is_leaf()) {
50  if (tree->name) {
51  bool deleteSelf = false;
52  GBDATA *gb_node;
53 
54  if (species_hash) {
55  gb_node = (GBDATA*)GBS_read_hash(species_hash, tree->name);
56  gb_assert(!tree->gb_node); // don't call linked tree with 'species_hash'!
57  }
58  else gb_node = tree->gb_node;
59 
60  if (gb_node) {
62  long flag = GB_read_flag(gb_node);
63  deleteSelf = (flag && (mode&GBT_REMOVE_MARKED)) || (!flag && (mode&GBT_REMOVE_UNMARKED));
64  }
65  }
66  else { // zombie
67  if (mode & GBT_REMOVE_ZOMBIES) deleteSelf = true;
68  }
69 
70  if (deleteSelf) {
71  gb_assert(!tree->is_root_node());
72 
73  TreeRoot *troot = tree->get_tree_root();
74  tree->forget_origin();
75  destroy(tree, troot);
76 
77  tree = NULp;
78  if (removed) (*removed)++;
79  }
80  }
81  }
82  else {
83  tree->leftson = GBT_remove_leafs(tree->get_leftson(), mode, species_hash, removed, groups_removed);
84  tree->rightson = GBT_remove_leafs(tree->get_rightson(), mode, species_hash, removed, groups_removed);
85 
86  if (tree->leftson) {
87  if (!tree->rightson) { // right son deleted
88  tree = tree->fixDeletedSon();
89  }
90  // otherwise no son deleted
91  }
92  else if (tree->rightson) { // left son deleted
93  tree = tree->fixDeletedSon();
94  }
95  else { // everything deleted -> delete self
96  if (tree->name && groups_removed) (*groups_removed)++;
97 
98  TreeRoot *troot = tree->get_tree_root();
99  if (!tree->is_root_node()) tree->forget_origin();
100  tree->forget_relatives();
101  destroy(tree, troot);
102 
103  tree = NULp;
104  }
105  }
106 
107  return tree;
108 }
109 
110 // ---------------------
111 // trees order
112 
113 inline int get_tree_idx(GBDATA *gb_tree) {
114  GBDATA *gb_order = GB_entry(gb_tree, "order");
115  int idx = 0;
116  if (gb_order) {
117  idx = GB_read_int(gb_order);
118  gb_assert(idx>0); // invalid index
119  }
120  return idx;
121 }
122 
123 inline int get_max_tree_idx(GBDATA *gb_treedata) {
124  int max_idx = 0;
125  for (GBDATA *gb_tree = GB_child(gb_treedata); gb_tree; gb_tree = GB_nextChild(gb_tree)) {
126  int idx = get_tree_idx(gb_tree);
127  if (idx>max_idx) max_idx = idx;
128  }
129  return max_idx;
130 }
131 
132 inline GBDATA *get_tree_with_idx(GBDATA *gb_treedata, int at_idx) {
133  GBDATA *gb_found = NULp;
134  for (GBDATA *gb_tree = GB_child(gb_treedata); gb_tree && !gb_found; gb_tree = GB_nextChild(gb_tree)) {
135  int idx = get_tree_idx(gb_tree);
136  if (idx == at_idx) {
137  gb_found = gb_tree;
138  }
139  }
140  return gb_found;
141 }
142 
143 inline GBDATA *get_tree_infrontof_idx(GBDATA *gb_treedata, int infrontof_idx) {
144  GBDATA *gb_infrontof = NULp;
145  if (infrontof_idx) {
146  int best_idx = 0;
147  for (GBDATA *gb_tree = GB_child(gb_treedata); gb_tree; gb_tree = GB_nextChild(gb_tree)) {
148  int idx = get_tree_idx(gb_tree);
149  gb_assert(idx);
150  if (idx>best_idx && idx<infrontof_idx) {
151  best_idx = idx;
152  gb_infrontof = gb_tree;
153  }
154  }
155  }
156  return gb_infrontof;
157 }
158 
159 inline GBDATA *get_tree_behind_idx(GBDATA *gb_treedata, int behind_idx) {
160  GBDATA *gb_behind = NULp;
161  if (behind_idx) {
162  int best_idx = INT_MAX;
163  for (GBDATA *gb_tree = GB_child(gb_treedata); gb_tree; gb_tree = GB_nextChild(gb_tree)) {
164  int idx = get_tree_idx(gb_tree);
165  gb_assert(idx);
166  if (idx>behind_idx && idx<best_idx) {
167  best_idx = idx;
168  gb_behind = gb_tree;
169  }
170  }
171  }
172  return gb_behind;
173 }
174 
175 inline GB_ERROR set_tree_idx(GBDATA *gb_tree, int idx) {
176  GB_ERROR error = NULp;
177  GBDATA *gb_order = GB_entry(gb_tree, "order");
178  if (!gb_order) {
179  gb_order = GB_create(gb_tree, "order", GB_INT);
180  if (!gb_order) error = GB_await_error();
181  }
182  if (!error) error = GB_write_int(gb_order, idx);
183  return error;
184 }
185 
186 static GB_ERROR reserve_tree_idx(GBDATA *gb_treedata, int idx) {
187  GB_ERROR error = NULp;
188  GBDATA *gb_tree = get_tree_with_idx(gb_treedata, idx);
189  if (gb_tree) {
190  error = reserve_tree_idx(gb_treedata, idx+1);
191  if (!error) error = set_tree_idx(gb_tree, idx+1);
192  }
193  return error;
194 }
195 
196 static void ensure_trees_have_order(GBDATA *gb_treedata) {
197  GBDATA *gb_main = GB_get_father(gb_treedata);
198 
199  gb_assert(GB_get_root(gb_main) == gb_main);
200  gb_assert(GBT_get_tree_data(gb_main) == gb_treedata);
201 
202  GB_ERROR error = NULp;
203  GBDATA *gb_tree_order_flag = GB_search(gb_main, "/tmp/trees_have_order", GB_INT);
204 
205  if (!gb_tree_order_flag) error = GB_await_error();
206  else {
207  if (GB_read_int(gb_tree_order_flag) == 0) { // not checked yet
208  int max_idx = get_max_tree_idx(gb_treedata);
209  for (GBDATA *gb_tree = GB_child(gb_treedata); gb_tree && !error; gb_tree = GB_nextChild(gb_tree)) {
210  if (!get_tree_idx(gb_tree)) {
211  error = set_tree_idx(gb_tree, ++max_idx);
212  }
213  }
214  if (!error) error = GB_write_int(gb_tree_order_flag, 1);
215  }
216  }
217  if (error) GBK_terminatef("failed to order trees (Reason: %s)", error);
218 }
219 
220 static void tree_set_default_order(GBDATA *gb_tree) {
221  // if 'gb_tree' has no order yet, move it to the bottom (as done previously)
222  if (!get_tree_idx(gb_tree)) {
223  set_tree_idx(gb_tree, get_max_tree_idx(GB_get_father(gb_tree))+1);
224  }
225 }
226 
227 // -----------------------------
228 // tree write functions
229 
230 GB_ERROR GBT_check_valid_group_name(const char *new_group_name) {
231  gb_assert(new_group_name);
232 
233  if (!new_group_name[0]) { // empty groupname
234  return "Invalid empty groupname";
235  }
236 
237  double bootstrap;
238  const char *label = new_group_name;
239  char *remark;
240  bool is_bootstrap = parse_treelabel(label, bootstrap, remark);
241  GB_ERROR error = NULp;
242 
243  if (is_bootstrap || remark) {
244  // inner-node labels that get interpreted as bootstrap or custom remark,
245  // are not allowed to be used as groupname:
246  gb_assert(contradicted(is_bootstrap, remark));
247 
248  GBS_strstruct buf(200);
249  buf.cat("Invalid group name "); buf.cat_sQuoted(new_group_name);
250  buf.cat(" (would be misinterpreted as ");
251 
252  if (label) { buf.cat("group named "); buf.cat_sQuoted(label); }
253  else { buf.cat("plain inner node"); }
254 
255  buf.cat(" with ");
256 
257  if (is_bootstrap) { // after reimporting 'new_group_name' it would be misinterpreted as bootstrap value.
258  gb_assert(!remark);
259 
260  while (bootstrap<100.0) bootstrap *= 100.0;
261  while (bootstrap>100.0) bootstrap /= 100.0;
262 
263  buf.cat("a support value of ");
264  buf.nprintf(20, "%.0f%%", bootstrap);
265  }
266  else {
267  gb_assert(remark);
268  buf.cat("remark ");
269  buf.cat_sQuoted(remark);
270  freenull(remark);
271  }
272 
273  buf.cat(" if re-imported from newick file)");
274  error = GBS_static_string(buf.get_data());
275  }
276  return error;
277 }
278 
279 GB_ERROR GBT_write_group_name(GBDATA *gb_group_name, const char *new_group_name, bool pedantic) {
280  // Note: Calling this function in 'pedantic' mode may raise many warnings, if called for many groups.
281  // Callers should consider instantiating a MessageSpamFilter!
282 
283  GB_ERROR error = NULp;
284 
285  gb_assert(strcmp(GB_read_key_pntr(gb_group_name), "group_name") == 0);
286 
287  if (!error) {
288  // deny several uses of '!' (at start and in the middle after '=' or ' ')
289  for (const char *em = strchr(new_group_name, KEELED_INDICATOR); em && !error; em = strchr(em+1, KEELED_INDICATOR)) {
290  if (em == new_group_name || em[-1] == ' ' || em[-1] == '=') {
291  error = GBS_global_string("Invalid placement of '%c' in group name '%s'\n(reserved for keeled groups)", KEELED_INDICATOR, new_group_name);
292  }
293  }
294  }
295 
296  if (!error) {
297  size_t len = strlen(new_group_name);
298  if (len >= GB_GROUP_NAME_MAX) {
299  error = GBS_global_string("Group name '%s' too long (max %i characters)", new_group_name, GB_GROUP_NAME_MAX);
300  }
301  else if (len<1) {
302  error = "Invalid empty group name";
303  }
304  }
305 
306  if (!error) error = GBT_check_valid_group_name(new_group_name);
307 
308  // warn about unwanted groupnames:
309  if (!error && pedantic) {
310  // group names which may be misinterpreted as bootstrap-values (see also #767):
311  const char *num = "0123456789.";
312  size_t numAtStart = strspn(new_group_name, num);
313 
314  if (numAtStart && !new_group_name[numAtStart]) {
315  GB_warningf("Warning: group name '%s' may be misinterpreted as bootstrap value\n"
316  "(consider prefixing a non-numeric character)",
317  new_group_name);
318  }
319 
320  // warn about possible conflicts (of characters in group name) with taxonomy:
321  {
322  static const char *TAXCHARS = "/;";
323  const char *seenTaxChar = strpbrk(new_group_name, TAXCHARS);
324  if (seenTaxChar) { // only warn about first char found
325  GB_warningf("Warning: group name '%s' contains a '%c' (this will interfere with taxonomy!)",
326  new_group_name, seenTaxChar[0]);
327  }
328  }
329 
330  if (strchr(new_group_name, '_')) {
331  GB_warningf("Warning: group name '%s' contains a '_' (reserved for overlapping groups)",
332  new_group_name);
333  }
334 
335  {
336  const char *tilde = strrchr(new_group_name, '~');
337  if (tilde && tilde[1]) { // tilde followed by sth
338  do ++tilde; while (isdigit(tilde[0]));
339  if (tilde[0] == 0) { // seen only digits behind tilde
340  GB_warningf("Warning: group name '%s' contains a '~' followed by digits only (reserved for splitted groups)",
341  new_group_name);
342  }
343  }
344  }
345  }
346 
347 
348 
349  if (!error) {
350  error = GB_write_string(gb_group_name, new_group_name);
351  }
352  return error;
353 }
354 GB_ERROR GBT_write_name_to_groupData(GBDATA *gb_group, bool createNameEntry, const char *new_group_name, bool pedantic) {
355  GBDATA *gb_group_name = GB_search(gb_group, "group_name", createNameEntry ? GB_STRING : GB_FIND);
356  return gb_group_name
357  ? GBT_write_group_name(gb_group_name, new_group_name, pedantic)
358  : GB_await_error();
359 }
360 
361 static GB_ERROR gbt_write_tree_nodes(GBDATA *gb_tree, TreeNode *node, long *startid) {
362  // increments '*startid' for each inner node (not for leafs)
363 
364  GB_ERROR error = NULp;
365 
366  if (!node->is_leaf()) {
367  bool node_is_used = false;
368 
369  if (node->name && node->name[0]) {
370  if (!node->gb_node) {
371  node->gb_node = GB_create_container(gb_tree, "node");
372  if (!node->gb_node) error = GB_await_error();
373  }
374  if (!error) {
375  GBDATA *gb_name = GB_search(node->gb_node, "group_name", GB_STRING);
376  if (!gb_name) error = GB_await_error();
377  else error = GBT_write_group_name(gb_name, node->name, false);
378 
379  node_is_used = true; // wrote groupname -> node is used
380  }
381  if (!error) {
382  int keeledState = node->keeledStateInfo();
383  GBDATA *gb_keeled = GB_search(node->gb_node, "keeled", keeledState ? GB_INT : GB_FIND); // only force creation if keeledState != 0
384  if (!gb_keeled) error = keeledState || GB_have_error() ? GB_await_error() : NULp;
385  else error = GB_write_int(gb_keeled, keeledState);
386  }
387  }
388 
389  if (node->gb_node && !error) {
390  if (!node_is_used) {
391  GBDATA *gb_nonid = GB_child(node->gb_node);
392  while (gb_nonid && strcmp("id", GB_read_key_pntr(gb_nonid)) == 0) {
393  gb_nonid = GB_nextChild(gb_nonid);
394  }
395  if (gb_nonid) node_is_used = true; // found child that is not "id" -> node is used
396  }
397 
398  if (node_is_used) { // set id for used nodes
399  error = GBT_write_int(node->gb_node, "id", *startid);
400  if (!error) GB_clear_user_flag(node->gb_node, GB_USERFLAG_GHOSTNODE); // mark node as "used"
401  }
402  else { // delete unused nodes
403  error = GB_delete(node->gb_node);
404  if (!error) node->gb_node = NULp;
405  }
406  }
407 
408  (*startid)++;
409  if (!error) error = gbt_write_tree_nodes(gb_tree, node->get_leftson(), startid);
410  if (!error) error = gbt_write_tree_nodes(gb_tree, node->get_rightson(), startid);
411  }
412  return error;
413 }
414 
415 static char *gbt_write_tree_rek_new(const TreeNode *node, char *dest, long mode) {
416  if (node->is_leaf()) {
417  gb_assert(node->has_no_remark());
418  if (mode == GBT_PUT_DATA) {
419  *(dest++) = 'L';
420  if (node->name) strcpy(dest, node->name);
421 
422  char *c1;
423  while ((c1 = (char *)strchr(dest, 1))) {
424  *c1 = 2;
425  }
426  dest += strlen(dest);
427  *(dest++) = 1;
428 
429  return dest;
430  }
431  else {
432  if (node->name) return dest+1+strlen(node->name)+1; // N name term
433  return dest+1+1;
434  }
435  }
436  else {
437  { // write remark
438  const char *c1 = node->get_remark();
439  if (c1) {
440  if (mode == GBT_PUT_DATA) {
441  int c;
442  *(dest++) = 'R';
443  while ((c = *(c1++))) {
444  if (c == 1) continue;
445  *(dest++) = c;
446  }
447  *(dest++) = 1;
448  }
449  else {
450  dest += strlen(c1) + 2;
451  }
452  }
453  }
454  char buffer[40];
455  sprintf(buffer, "%g,%g;", node->leftlen, node->rightlen);
456  if (mode == GBT_PUT_DATA) {
457  *(dest++) = 'N';
458  strcpy(dest, buffer);
459  dest += strlen(buffer);
460  }
461  else {
462  dest += strlen(buffer)+1;
463  }
464  dest = gbt_write_tree_rek_new(node->get_leftson(), dest, mode);
465  dest = gbt_write_tree_rek_new(node->get_rightson(), dest, mode);
466  return dest;
467  }
468 }
469 
470 static GB_ERROR gbt_write_tree(GBDATA *gb_main, GBDATA *gb_tree, const char *tree_name, TreeNode *tree) {
480  GB_ERROR error = NULp;
481 
482  if (tree) {
483  if (tree_name) {
484  if (gb_tree) error = GBS_global_string("can't change name of existing tree (to '%s')", tree_name);
485  else {
486  error = GBT_check_tree_name(tree_name);
487  if (!error) {
488  GBDATA *gb_tree_data = GBT_get_tree_data(gb_main);
489  gb_tree = GB_search(gb_tree_data, tree_name, GB_CREATE_CONTAINER);
490 
491  if (!gb_tree) error = GB_await_error();
492  }
493  }
494  }
495  else {
496  if (!gb_tree) error = "No tree name given";
497  }
498 
499  gb_assert(gb_tree || error);
500 
501  if (!error) {
502  // mark all old style tree data for deletion
503  GBDATA *gb_node;
504  for (gb_node = GB_entry(gb_tree, "node"); gb_node; gb_node = GB_nextEntry(gb_node)) {
505  GB_raise_user_flag(gb_node, GB_USERFLAG_GHOSTNODE); // mark as "possibly unused"
506  }
507 
508  // build tree-string and save to DB
509  {
510  char *t_size = gbt_write_tree_rek_new(tree, NULp, GBT_GET_SIZE); // calc size of tree-string
511  char *ctree = ARB_calloc<char>(size_t(t_size+1)); // allocate buffer for tree-string
512 
513  t_size = gbt_write_tree_rek_new(tree, ctree, GBT_PUT_DATA); // write into buffer
514  *(t_size) = 0;
515 
516  bool was_allowed = GB_allow_compression(gb_main, false);
517  error = GBT_write_string(gb_tree, "tree", ctree);
518  GB_allow_compression(gb_main, was_allowed);
519  free(ctree);
520  }
521  }
522 
523  if (!error) {
524  // save nodes to DB
525  long size = 0;
526  error = gbt_write_tree_nodes(gb_tree, tree, &size); // reports number of nodes in 'size'
527  if (!error) error = GBT_write_int(gb_tree, "nnodes", size);
528 
529  if (!error) {
530  if (!GB_entry(gb_tree, "keep_ghostnodes")) { // see ../PARSIMONY/PARS_main.cxx@keep_ghostnodes
531  GBDATA *gb_node;
532  GBDATA *gb_node_next;
533 
534  for (gb_node = GB_entry(gb_tree, "node"); // delete all ghost nodes
535  gb_node && !error;
536  gb_node = gb_node_next)
537  {
538  GBDATA *gbd = GB_entry(gb_node, "id");
539  gb_node_next = GB_nextEntry(gb_node);
540  if (!gbd || GB_user_flag(gb_node, GB_USERFLAG_GHOSTNODE)) error = GB_delete(gb_node);
541  }
542  }
543  }
544  }
545 
546  if (!error) tree_set_default_order(gb_tree);
547  }
548 
549  return error;
550 }
551 
552 GB_ERROR GBT_write_tree(GBDATA *gb_main, const char *tree_name, TreeNode *tree) {
553  return gbt_write_tree(gb_main, NULp, tree_name, tree);
554 }
556  return gbt_write_tree(GB_get_root(gb_tree), gb_tree, NULp, tree);
557 }
558 
559 static GB_ERROR write_tree_remark(GBDATA *gb_tree, const char *remark) {
560  return GBT_write_string(gb_tree, "remark", remark);
561 }
562 GB_ERROR GBT_write_tree_remark(GBDATA *gb_main, const char *tree_name, const char *remark) {
563  return write_tree_remark(GBT_find_tree(gb_main, tree_name), remark);
564 }
565 
566 GB_ERROR GBT_log_to_tree_remark(GBDATA *gb_tree, const char *log_entry, bool stamp) {
573  GB_ERROR error = NULp;
574  const char *old_remark = GBT_read_char_pntr(gb_tree, "remark");
575  if (!old_remark && GB_have_error()) {
576  error = GB_await_error();
577  }
578  else {
579  char *new_remark = GBS_log_action_to(old_remark, log_entry, stamp);
580  error = write_tree_remark(gb_tree, new_remark);
581  free(new_remark);
582  }
583  return error;
584 }
585 GB_ERROR GBT_log_to_named_trees_remark(GBDATA *gb_main, const char *tree_name, const char *log_entry, bool stamp) {
593  GBDATA *gb_tree = GBT_find_tree(gb_main, tree_name);
594  return gb_tree
595  ? GBT_log_to_tree_remark(gb_tree, log_entry, stamp)
596  : GBS_global_string("No such tree (%s)", tree_name);
597 }
598 
599 GB_ERROR GBT_write_tree_with_remark(GBDATA *gb_main, const char *tree_name, TreeNode *tree, const char *remark) {
600  GB_ERROR error = GBT_write_tree(gb_main, tree_name, tree);
601  if (!error && remark) error = GBT_write_tree_remark(gb_main, tree_name, remark);
602  return error;
603 }
604 
605 // ----------------------------
606 // tree read functions
607 
609 void autocorrected_warning(const char *warning) {
610  GB_warning(warning);
611  gb_assert(autocorrected_tree);
612  if (autocorrected_tree) {
613  autocorrected_tree->set_auto_modified(true);
614  }
615 }
616 
617 static TreeNode *gbt_read_tree_rek(char **data, long *startid, GBDATA **gb_tree_nodes, TreeRoot *troot, int size_of_tree, GB_ERROR& error) {
618  TreeNode *node = NULp;
619  if (!error) {
620  node = troot->makeNode();
621 
622  char c = *((*data)++);
623  char *p1;
624 
625  if (c=='R') {
626  p1 = strchr(*data, 1);
627  *(p1++) = 0;
628 
629  node->set_remark(*data);
630  if (node->is_inner_node_with_remark()) {
631  double bootval;
632  if (node->parse_bootstrap(bootval, autocorrected_warning) == REMARK_BOOTSTRAP) {
633  if (bootval == 100.0) node->remove_remark(); // auto-remove 100% comments
634  else troot->set_bootstrap_seen(true); // activate auto-100% only if bootstrap value != 100% was seen
635  }
636  }
637 
638  c = *(p1++);
639  *data = p1;
640  }
641 
642 
643  if (c=='N') {
644  p1 = (char *)strchr(*data, ',');
645  *(p1++) = 0;
646  node->leftlen = GB_atof(*data);
647  *data = p1;
648  p1 = (char *)strchr(*data, ';');
649  *(p1++) = 0;
650  node->rightlen = GB_atof(*data);
651  *data = p1;
652  if ((*startid < size_of_tree) && (node->gb_node = gb_tree_nodes[*startid])) {
653  GBDATA *gb_group_name = GB_entry(node->gb_node, "group_name");
654  if (gb_group_name) {
655  node->name = GB_read_string(gb_group_name);
656  if (!node->name || !node->name[0]) {
657  char *auto_rename = ARB_strdup("<missing groupname>");
658  GBDATA *gb_main = GB_get_root(gb_group_name);
659 
660  const char *warn;
661  if (!node->name) {
662  warn = GBS_global_string("Unreadable 'group_name' detected (Reason: %s)", GB_await_error());
663  }
664  else {
665  warn = "Empty groupname detected";
666  }
667  warn = GBS_global_string("%s\nGroup has been named '%s'", warn, auto_rename);
668  GBT_message(gb_main, warn);
669 
670  GB_ERROR rename_error = GBT_write_group_name(gb_group_name, auto_rename, false);
671  if (rename_error) {
672  GBT_message(gb_main,
673  GBS_global_string("Failed to name group (Reason: %s)\n"
674  "Please check tree for corrupted groups, e.g. by using group search",
675  rename_error));
676  }
677  node->name = auto_rename;
678  }
679 
680  // init node according to saved "keeled" state:
681  GBDATA *gb_keeled = GB_entry(node->gb_node, "keeled");
682  if (gb_keeled) { // missing = default = not keeled
683  int keeledState = GB_read_int(gb_keeled);
684  node->setKeeledState(keeledState);
685  }
686  }
687  }
688  (*startid)++;
689  node->leftson = gbt_read_tree_rek(data, startid, gb_tree_nodes, troot, size_of_tree, error);
690  if (!node->leftson) freenull(node);
691  else {
692  node->rightson = gbt_read_tree_rek(data, startid, gb_tree_nodes, troot, size_of_tree, error);
693  if (!node->rightson) {
694  freenull(node->leftson);
695  freenull(node);
696  }
697  else {
698  node->leftson->father = node;
699  node->rightson->father = node;
700  }
701  }
702  }
703  else if (c=='L') {
704  node->markAsLeaf();
705  p1 = (char *)strchr(*data, 1);
706 
707  gb_assert(p1);
708  gb_assert(p1[0] == 1);
709 
710  *p1 = 0;
711  node->name = ARB_strdup(*data);
712  *data = p1+1;
713  }
714  else {
715  if (!c) {
716  error = "Unexpected end of tree definition.";
717  }
718  else {
719  error = GBS_global_string("Can't interpret tree definition (expected 'N' or 'L' - not '%c')", c);
720  }
721  freenull(node);
722  }
723  }
724  gb_assert(contradicted(node, error));
725  return node;
726 }
727 
728 
729 static TreeNode *read_tree_and_size_internal(GBDATA *gb_tree, GBDATA *gb_ctree, TreeRoot *troot, int node_count, GB_ERROR& error) {
730  GBDATA **gb_tree_nodes;
731  TreeNode *node = NULp; // root node
732 
733  ARB_calloc(gb_tree_nodes, node_count);
734  if (gb_tree) {
735  GBDATA *gb_node;
736 
737  for (gb_node = GB_entry(gb_tree, "node"); gb_node && !error; gb_node = GB_nextEntry(gb_node)) {
738  long i;
739  GBDATA *gbd = GB_entry(gb_node, "id");
740  if (!gbd) continue;
741 
742  i = GB_read_int(gbd);
743  if (i<0 || i >= node_count) {
744  error = "An inner node of the tree is corrupt";
745  }
746  else {
747  gb_tree_nodes[i] = gb_node;
748  }
749  }
750  }
751  if (!error) {
752  char * const treeString = GB_read_string(gb_ctree);
753  if (!treeString) {
754  error = GB_await_error();
755  }
756  else {
757  char *ts = treeString;
758  long id = 0;
759 
760  troot->set_bootstrap_seen(false); // will be update by gbt_read_tree_rek
761  troot->set_auto_modified(false); // may get set by gbt_read_tree_rek and code in 2nd half of this method.
762 
763  LocallyModify<TreeRoot*> trace_auto_modification(autocorrected_tree, troot);
764  node = gbt_read_tree_rek(&ts, &id, gb_tree_nodes, troot, node_count, error);
765  }
766  free(treeString);
767  }
768 
769  free(gb_tree_nodes);
770 
771  if (node) {
772  gb_assert(!node->father); // expect 'node' is the root-node
773 
774  {
775  const char *remark = node->get_remark();
776  if (remark) {
777  GBDATA *gb_main = GB_get_root(gb_tree);
778  GBT_message(gb_main, GBS_global_string("Warning: invalid remark '%s' at root of '%s' removed", remark, GB_read_key_pntr(gb_tree)));
779  node->remove_remark();
780  troot->set_auto_modified(true);
781  }
782  }
783 
784  if (node->has_group_info()) {
785  if (node->is_normal_group()) {
786  // workaround for #753:
787  GBDATA *gb_group = node->gb_node;
788  GBDATA *gb_main = GB_get_root(gb_group);
789  GBDATA *gb_group_name = GB_entry(gb_group, "group_name");
790 
791  gb_assert(gb_group_name);
792  if (gb_group_name) {
793  char *groupAtRoot_name = GB_read_string(gb_group_name);
794 
795  GBT_message(gb_main, GBS_global_string("Warning: invalid group '%s' at root of '%s' removed", groupAtRoot_name, GB_read_key_pntr(gb_tree)));
796  error = GB_delete(gb_group_name);
797  if (error) {
798  GBT_message(gb_main, GBS_global_string("Failed to delete 'group_name' of root-node (Reason: %s)", error));
799  error = NULp; // dont fail loading the tree
800  }
801  free(groupAtRoot_name);
802  }
803  freenull(node->name); // erase name from tree-structure
804  troot->set_auto_modified(true);
805  gb_assert(!node->is_normal_group());
806  }
807  else {
808  gb_assert(!node->keelTarget()); // root shall not host keeled group
809  // Assumed to be impossible; otherwise could be resolved by moving unkeeled group to other son(-of-root)
810  }
811  }
812  }
813  else {
814  gb_assert(error);
815  }
816 
817 
818  gb_assert(contradicted(node, error));
819  gb_assert(implicated(node, !node->is_normal_group()));
820  return node;
821 }
822 
823 TreeNode *GBT_read_tree_and_size(GBDATA *gb_main, const char *tree_name, TreeRoot *troot, int *tree_size) {
836  GB_ERROR error = NULp;
837 
838  if (!tree_name) {
839  error = "no treename given";
840  }
841  else {
842  error = GBT_check_tree_name(tree_name);
843  if (!error) {
844  GBDATA *gb_tree = GBT_find_tree(gb_main, tree_name);
845 
846  if (!gb_tree) {
847  error = "tree not found";
848  }
849  else {
850  GBDATA *gb_nnodes = GB_entry(gb_tree, "nnodes");
851  if (!gb_nnodes) {
852  error = "tree is empty";
853  }
854  else {
855  long size = GB_read_int(gb_nnodes);
856  if (!size) {
857  error = "has no nodes";
858  }
859  else {
860  GBDATA *gb_ctree = GB_search(gb_tree, "tree", GB_FIND);
861  if (!gb_ctree) {
862  error = "old unsupported tree format";
863  }
864  else { // "new" style tree
865  TreeNode *tree = read_tree_and_size_internal(gb_tree, gb_ctree, troot, size, error);
866  if (!error) {
867  gb_assert(tree);
868  if (tree_size) *tree_size = size; // return size of tree (=leafs-1)
870 
871  gb_assert(!tree->is_normal_group()); // root shall not be a group (see #753)
872  return tree;
873  }
874 
875  gb_assert(!tree);
876  }
877  }
878  }
879  }
880  }
881  }
882 
883  gb_assert(error);
884  GB_export_errorf("Failed to read tree '%s' (Reason: %s)", tree_name, error);
885  troot->delete_by_node();
886  return NULp;
887 }
888 
889 TreeNode *GBT_read_tree(GBDATA *gb_main, const char *tree_name, TreeRoot *troot) {
891  return GBT_read_tree_and_size(gb_main, tree_name, troot, NULp);
892 }
893 
894 size_t GBT_count_leafs(const TreeNode *tree) {
895  if (tree->is_leaf()) {
896  return 1;
897  }
898  return GBT_count_leafs(tree->get_leftson()) + GBT_count_leafs(tree->get_rightson());
899 }
900 
901 static GB_ERROR gbt_invalid_because(const TreeNode *tree, const char *reason) {
902  return GBS_global_string("((TreeNode*)0x%p) %s", tree, reason);
903 }
904 
905 inline bool has_son(const TreeNode *father, const TreeNode *son) {
906  return !father->is_leaf() && (father->leftson == son || father->rightson == son);
907 }
908 
909 static GB_ERROR gbt_is_invalid(bool is_root, const TreeNode *tree) {
910  if (tree->father) {
911  if (!has_son(tree->get_father(), tree)) return gbt_invalid_because(tree, "is not son of its father");
912  }
913  else {
914  if (!is_root) return gbt_invalid_because(tree, "has no father (but isn't root)");
915  }
916 
917  GB_ERROR error = NULp;
918  if (tree->is_leaf()) {
919  if (tree->leftson) return gbt_invalid_because(tree, "is leaf, but has leftson");
920  if (tree->rightson) return gbt_invalid_because(tree, "is leaf, but has rightson");
921  }
922  else {
923  if (!tree->leftson) return gbt_invalid_because(tree, "is inner node, but has no leftson");
924  if (!tree->rightson) return gbt_invalid_because(tree, "is inner node, but has no rightson");
925 
926  error = gbt_is_invalid(false, tree->get_leftson());
927  if (!error) error = gbt_is_invalid(false, tree->get_rightson());
928  }
929  return error;
930 }
931 
933  if (tree->father) return gbt_invalid_because(tree, "is expected to be the root-node, but has father");
934  if (tree->is_leaf()) return gbt_invalid_because(tree, "is expected to be the root-node, but is a leaf (tree too small)");
935  return gbt_is_invalid(true, tree);
936 }
937 
938 // -------------------------------------------
939 // link the tree tips to the database
940 
943  GB_HASH *seen_species; // used to count duplicates
945  int zombies; // counts zombies
946  int duplicates; // counts duplicates
947 };
948 
950  GB_ERROR error = NULp;
951  if (tree->is_leaf()) {
952  tree->gb_node = NULp;
953  if (tree->name) {
954  GBDATA *gbd = (GBDATA*)GBS_read_hash(ltd->species_hash, tree->name);
955  if (gbd) tree->gb_node = gbd;
956  else ltd->zombies++;
957 
958  if (ltd->seen_species) {
959  if (GBS_read_hash(ltd->seen_species, tree->name)) ltd->duplicates++;
960  else GBS_write_hash(ltd->seen_species, tree->name, 1);
961  }
962  }
963 
964  if (ltd->progress) ++(*ltd->progress);
965  }
966  else {
967  error = gbt_link_tree_to_hash_rek(tree->get_leftson(), ltd);
968  if (!error) error = gbt_link_tree_to_hash_rek(tree->get_rightson(), ltd);
969  }
970  return error;
971 }
972 
973 static GB_ERROR GBT_link_tree_using_species_hash(TreeNode *tree, bool show_status, GB_HASH *species_hash, int *zombies, int *duplicates) {
974  GB_ERROR error;
975  link_tree_data ltd;
976  long leafs = 0;
977 
978  if (duplicates || show_status) {
979  leafs = GBT_count_leafs(tree);
980  }
981 
982  ltd.species_hash = species_hash;
983  ltd.seen_species = leafs ? GBS_create_hash(leafs, GB_IGNORE_CASE) : NULp;
984  ltd.zombies = 0;
985  ltd.duplicates = 0;
986 
987  if (show_status) {
988  ltd.progress = new arb_progress("Relinking tree to database", leafs);
989  }
990  else {
991  ltd.progress = NULp;
992  }
993 
994  error = gbt_link_tree_to_hash_rek(tree, &ltd);
996 
997  if (zombies) *zombies = ltd.zombies;
998  if (duplicates) *duplicates = ltd.duplicates;
999 
1000  delete ltd.progress;
1001 
1002  return error;
1003 }
1004 
1005 GB_ERROR GBT_link_tree_and_count(TreeNode *tree, GBDATA *gb_main, bool show_status, int *zombies, int *duplicates) {
1020  GB_HASH *species_hash = GBT_create_species_hash(gb_main);
1021  GB_ERROR error = GBT_link_tree_using_species_hash(tree, show_status, species_hash, zombies, duplicates);
1022 
1023  GBS_free_hash(species_hash);
1024 
1025  return error;
1026 }
1032  return GBT_link_tree_and_count(tree, gb_main, show_status, NULp, NULp);
1033 }
1034 
1039  gb_node = NULp;
1040  if (!is_leaf()) {
1041  get_leftson()->unlink_from_DB();
1042  get_rightson()->unlink_from_DB();
1043  }
1044 }
1046  tree->unlink_from_DB();
1047 }
1048 
1049 // ----------------------
1050 // search trees
1051 
1052 GBDATA *GBT_find_tree(GBDATA *gb_main, const char *tree_name) {
1057  return GB_entry(GBT_get_tree_data(gb_main), tree_name);
1058 }
1059 
1060 inline bool is_tree(GBDATA *gb_tree) {
1061  if (!gb_tree) return false;
1062  GBDATA *gb_tree_data = GB_get_father(gb_tree);
1063  return gb_tree_data && GB_has_key(gb_tree_data, "tree_data");
1064 }
1065 
1067  return GB_child(GBT_get_tree_data(gb_main));
1068 }
1069 
1070 inline GBDATA *get_next_tree(GBDATA *gb_tree) {
1071  if (!gb_tree) return NULp;
1072  gb_assert(is_tree(gb_tree));
1073  return GB_nextChild(gb_tree);
1074 }
1075 
1077  long maxnodes = 0;
1078  GBDATA *gb_largest = NULp;
1079 
1080  for (GBDATA *gb_tree = get_first_tree(gb_main); gb_tree; gb_tree = get_next_tree(gb_tree)) {
1081  long *nnodes = GBT_read_int(gb_tree, "nnodes");
1082  if (nnodes && *nnodes>maxnodes) {
1083  gb_largest = gb_tree;
1084  maxnodes = *nnodes;
1085  }
1086  }
1087  return gb_largest;
1088 }
1089 
1091  GBDATA *gb_treedata = GB_get_father(gb_tree);
1092  ensure_trees_have_order(gb_treedata);
1093  return get_tree_infrontof_idx(gb_treedata, get_tree_idx(gb_tree));
1094 }
1096  GBDATA *gb_treedata = GB_get_father(gb_tree);
1097  ensure_trees_have_order(gb_treedata);
1098  return get_tree_behind_idx(gb_treedata, get_tree_idx(gb_tree));
1099 }
1100 
1102  GBDATA *gb_treedata = GBT_get_tree_data(gb_main);
1103  ensure_trees_have_order(gb_treedata);
1104 
1105  GBDATA *gb_top = get_tree_with_idx(gb_treedata, 1);
1106  if (!gb_top) gb_top = get_tree_behind_idx(gb_treedata, 1);
1107  return gb_top;
1108 }
1110  GBDATA *gb_treedata = GBT_get_tree_data(gb_main);
1111  ensure_trees_have_order(gb_treedata);
1112  return get_tree_infrontof_idx(gb_treedata, INT_MAX);
1113 }
1114 
1115 const char *GBT_existing_tree(GBDATA *gb_main, const char *tree_name) {
1116  // search for a specify existing tree (and fallback to any existing)
1117  GBDATA *gb_tree = GBT_find_tree(gb_main, tree_name);
1118  if (!gb_tree) gb_tree = get_first_tree(gb_main);
1119  return GBT_get_tree_name(gb_tree);
1120 }
1121 
1123  GBDATA *gb_other = NULp;
1124  if (gb_tree) {
1125  gb_other = GBT_tree_behind(gb_tree);
1126  if (!gb_other) {
1127  gb_other = GBT_find_top_tree(GB_get_root(gb_tree));
1128  if (gb_other == gb_tree) gb_other = NULp;
1129  }
1130  }
1131  gb_assert(gb_other != gb_tree);
1132  return gb_other;
1133 }
1134 
1135 // --------------------
1136 // tree names
1137 
1138 const char *GBT_get_tree_name(GBDATA *gb_tree) {
1139  if (!gb_tree) return NULp;
1140  gb_assert(is_tree(gb_tree));
1141  return GB_read_key_pntr(gb_tree);
1142 }
1143 
1144 GB_ERROR GBT_check_tree_name(const char *tree_name) {
1145  GB_ERROR error = GB_check_key(tree_name);
1146  if (!error) {
1147  if (strncmp(tree_name, "tree_", 5) != 0) {
1148  error = "has to start with 'tree_'";
1149  }
1150  }
1151  if (error) {
1152  if (strcmp(tree_name, NO_TREE_SELECTED) == 0) {
1153  error = "no tree selected"; // overwrites existing error
1154  }
1155  else {
1156  error = GBS_global_string("not a valid treename '%s' (Reason: %s)", tree_name, error);
1157  }
1158  }
1159  return error;
1160 }
1161 
1163  return GBT_get_tree_name(find_largest_tree(gb_main));
1164 }
1165 
1167  return GBT_get_tree_name(GBT_find_bottom_tree(gb_main));
1168 }
1169 
1170 // -------------------
1171 // tree info
1172 
1173 const char *GBT_tree_info_string(GBDATA *gb_main, const char *tree_name, int maxTreeNameLen) {
1174  // maxTreeNameLen shall be the max len of the longest tree name (or -1 -> do not format)
1175 
1176  const char *result = NULp;
1177  GBDATA *gb_tree = GBT_find_tree(gb_main, tree_name);
1178 
1179  if (!gb_tree) {
1180  GB_export_errorf("tree '%s' not found", tree_name);
1181  }
1182  else {
1183  GBDATA *gb_nnodes = GB_entry(gb_tree, "nnodes");
1184  if (!gb_nnodes) {
1185  GB_export_errorf("nnodes not found in tree '%s'", tree_name);
1186  }
1187  else {
1188  const long nodes = GB_read_int(gb_nnodes)+1;
1189  const char *sizeInfo = GBS_global_string("(%li:%i)", nodes, GB_read_security_write(gb_tree));
1190  GBDATA *gb_rem = GB_entry(gb_tree, "remark");
1191  int len;
1192 
1193  if (maxTreeNameLen == -1) {
1194  result = GBS_global_string("%s %11s", tree_name, sizeInfo);
1195  len = strlen(tree_name);
1196  }
1197  else {
1198  result = GBS_global_string("%-*s %11s", maxTreeNameLen, tree_name, sizeInfo);
1199  len = maxTreeNameLen;
1200  }
1201  if (gb_rem) {
1202  const char *remark = GB_read_char_pntr(gb_rem);
1203  const int remarkLen = 800;
1204  char *res2 = GB_give_other_buffer(remark, len+1+11+2+remarkLen+1);
1205 
1206  strcpy(res2, result);
1207  strcat(res2, " ");
1208  strncat(res2, remark, remarkLen);
1209 
1210  result = res2;
1211  }
1212 
1213  if (nodes<2) {
1214  GB_warningf("Warning: tree '%s' has less than 2 nodes (is invalid + can be deleted).", tree_name);
1215  }
1216  }
1217  }
1218  return result;
1219 }
1220 
1221 long GBT_size_of_tree(GBDATA *gb_main, const char *tree_name) {
1222  // return the number of inner nodes in binary tree (or -1 if unknown)
1223  // Note:
1224  // leafs = size + 1
1225  // inner nodes in unrooted tree = size - 1
1226 
1227  long nnodes = -1;
1228  GBDATA *gb_tree = GBT_find_tree(gb_main, tree_name);
1229  if (gb_tree) {
1230  GBDATA *gb_nnodes = GB_entry(gb_tree, "nnodes");
1231  if (gb_nnodes) {
1232  nnodes = GB_read_int(gb_nnodes);
1233  }
1234  }
1235  return nnodes;
1236 }
1237 
1238 
1240  int idx;
1241  const char *name;
1242 
1243  bool operator<(const indexed_name& other) const { return idx < other.idx; }
1244 };
1245 
1247  // stores tree names in 'names'
1248 
1249  GBDATA *gb_treedata = GBT_get_tree_data(gb_main);
1250  ensure_trees_have_order(gb_treedata);
1251 
1252  long tree_count = GB_number_of_subentries(gb_treedata);
1253 
1254  names.reserve(tree_count);
1255  typedef std::set<indexed_name> ordered_trees;
1256  ordered_trees trees;
1257 
1258  {
1259  int t = 0;
1260  int count = 0;
1261  for (GBDATA *gb_tree = GB_child(gb_treedata); gb_tree; gb_tree = GB_nextChild(gb_tree), ++t) {
1262  indexed_name iname;
1263  iname.name = GB_read_key_pntr(gb_tree);
1264  iname.idx = sorted ? get_tree_idx(gb_tree) : ++count;
1265 
1266  trees.insert(iname);
1267  }
1268  }
1269 
1270  if (tree_count != (long)trees.size()) { // there are duplicated "order" entries
1271  gb_assert(sorted); // should not happen in unsorted mode
1272 
1273  typedef std::set<int> ints;
1274 
1275  ints used_indices;
1276  GBDATA *gb_first_tree = GB_child(gb_treedata);
1277  GBDATA *gb_tree = gb_first_tree;
1278 
1279  while (gb_tree) {
1280  int idx = get_tree_idx(gb_tree);
1281  if (used_indices.find(idx) != used_indices.end()) { // duplicate order
1282  GB_ERROR error = reserve_tree_idx(gb_treedata, idx+1);
1283  if (!error) error = set_tree_idx(gb_tree, idx+1);
1284  if (error) GBK_terminatef("failed to fix tree-order (Reason: %s)", error);
1285 
1286  // now restart
1287  used_indices.clear();
1288  gb_tree = gb_first_tree;
1289  }
1290  else {
1291  used_indices.insert(idx);
1292  gb_tree = GB_nextChild(gb_tree);
1293  }
1294  }
1295  GBT_get_tree_names(names, gb_main, sorted);
1296  return;
1297  }
1298 
1299  for (ordered_trees::const_iterator t = trees.begin(); t != trees.end(); ++t) {
1300  names.put(t->name);
1301  }
1302 }
1303 
1304 NOT4PERL GB_ERROR GBT_move_tree(GBDATA *gb_moved_tree, GBT_ORDER_MODE mode, GBDATA *gb_target_tree) {
1305  // moves 'gb_moved_tree' next to 'gb_target_tree' (only changes tree-order)
1306  gb_assert(gb_moved_tree && gb_target_tree);
1307 
1308  GBDATA *gb_treedata = GB_get_father(gb_moved_tree);
1309  ensure_trees_have_order(gb_treedata);
1310 
1311  int target_idx = get_tree_idx(gb_target_tree);
1312  gb_assert(target_idx);
1313 
1314  if (mode == GBT_BEHIND) target_idx++;
1315 
1316  GB_ERROR error = reserve_tree_idx(gb_treedata, target_idx);
1317  if (!error) error = set_tree_idx(gb_moved_tree, target_idx);
1318 
1319  return error;
1320 }
1321 
1322 static GBDATA *get_source_and_check_target_tree(GBDATA *gb_main, const char *source_tree, const char *dest_tree, GB_ERROR& error) {
1323  GBDATA *gb_source_tree = NULp;
1324 
1325  error = GBT_check_tree_name(source_tree);
1326  if (!error) error = GBT_check_tree_name(dest_tree);
1327 
1328  if (error && strcmp(source_tree, NO_TREE_SELECTED) == 0) {
1329  error = "No tree selected";
1330  }
1331 
1332  if (!error && strcmp(source_tree, dest_tree) == 0) error = "source- and dest-tree are the same";
1333 
1334  if (!error) {
1335  gb_source_tree = GBT_find_tree(gb_main, source_tree);
1336  if (!gb_source_tree) error = GBS_global_string("tree '%s' not found", source_tree);
1337  else {
1338  GBDATA *gb_dest_tree = GBT_find_tree(gb_main, dest_tree);
1339  if (gb_dest_tree) {
1340  error = GBS_global_string("tree '%s' already exists", dest_tree);
1341  gb_source_tree = NULp;
1342  }
1343  }
1344  }
1345 
1346  gb_assert(contradicted(error, gb_source_tree));
1347  return gb_source_tree;
1348 }
1349 
1350 static GBDATA *copy_tree_container(GBDATA *gb_source_tree, const char *newName, GB_ERROR& error) {
1351  GBDATA *gb_treedata = GB_get_father(gb_source_tree);
1352  GBDATA *gb_dest_tree = GB_create_container(gb_treedata, newName);
1353 
1354  if (!gb_dest_tree) error = GB_await_error();
1355  else error = GB_copy_dropProtectMarksAndTempstate(gb_dest_tree, gb_source_tree);
1356 
1357  gb_assert(contradicted(error, gb_dest_tree));
1358  return gb_dest_tree;
1359 }
1360 
1361 GB_ERROR GBT_copy_tree(GBDATA *gb_main, const char *source_name, const char *dest_name) {
1362  GB_ERROR error;
1363  GBDATA *gb_source_tree = get_source_and_check_target_tree(gb_main, source_name, dest_name, error);
1364 
1365  if (gb_source_tree) {
1366  GBDATA *gb_dest_tree = copy_tree_container(gb_source_tree, dest_name, error);
1367  if (gb_dest_tree) {
1368  int source_idx = get_tree_idx(gb_source_tree);
1369  int dest_idx = source_idx+1;
1370 
1371  error = reserve_tree_idx(GB_get_father(gb_dest_tree), dest_idx);
1372  if (!error) error = set_tree_idx(gb_dest_tree, dest_idx);
1373  }
1374  }
1375 
1376  return error;
1377 }
1378 
1379 GB_ERROR GBT_rename_tree(GBDATA *gb_main, const char *source_name, const char *dest_name) {
1380  GB_ERROR error;
1381  GBDATA *gb_source_tree = get_source_and_check_target_tree(gb_main, source_name, dest_name, error);
1382 
1383  if (gb_source_tree) {
1384  error = GB_test_delete_possible(gb_source_tree);
1385  if (!error) {
1386  GBDATA *gb_dest_tree = copy_tree_container(gb_source_tree, dest_name, error);
1387  if (gb_dest_tree) error = GB_delete(gb_source_tree);
1388  }
1389  }
1390 
1391  if (error) {
1392  error = GBS_global_string("While renaming tree '%s' to '%s':\n%s",
1393  source_name, dest_name, error);
1394  }
1395 
1396  return error;
1397 }
1398 
1400  if (tree->is_leaf()) {
1401  current[0] = tree->name;
1402  return current+1;
1403  }
1404  current = fill_species_name_array(current, tree->get_leftson());
1405  current = fill_species_name_array(current, tree->get_rightson());
1406  return current;
1407 }
1408 
1410  /* creates an array of all species names in a tree,
1411  * The names are not allocated (so they may change as side effect of renaming species) */
1412 
1413  size_t size = GBT_count_leafs(tree);
1414  GB_CSTR *result = ARB_calloc<GB_CSTR>(size + 1);
1415 
1416  IF_ASSERTION_USED(GB_CSTR *check =) fill_species_name_array(result, tree);
1417  gb_assert(check - size == result);
1418 
1419  if (count) *count = size;
1420 
1421  return result;
1422 }
1423 
1424 const char *GBT_len2string(GBT_LEN length, bool lowPrecision) {
1425  // Create branchlength string saved into newick format.
1426  // If lowPrecision==true -> save with 3 digits behind '.' (otherwise uses 5 digits)
1427  // Data is valid until next call.
1428  static GBS_strstruct buf(20);
1429 
1430  buf.erase();
1431  buf.nprintf(10, lowPrecision ? "%.3f" : "%.5f", length);
1432 
1433  while (buf.peek_tail() == '0') buf.cut_tail(1);
1434  if (buf.peek_tail() == '.') buf.cut_tail(1);
1435 
1436  const char *data = buf.get_data();
1437  bool drop = strncmp(data, "0.", 2)==0 || strcmp(data, "-0")==0; // drop leading zero before '.' or '-' before sole zero
1438  return drop ? data+1 : data;
1439 }
1440 
1442  gb_assert(tree);
1443  if ((format&nWRAP) && indent>0) { out.put('\n'); out.nput(' ', indent); }
1444  if (tree->is_leaf()) {
1445  out.cat(tree->name);
1446  }
1447  else {
1448  out.put('(');
1449  tree2newick(tree->get_leftson(), out, format, indent+1);
1450  out.put(',');
1451  tree2newick(tree->get_rightson(), out, format, indent+1);
1452  if ((format&nWRAP) && indent>0) { out.put('\n'); out.nput(' ', indent); }
1453  out.put(')');
1454 
1455  if (format & (nGROUP|nREMARK)) {
1456  const char *remark = format&nREMARK ? tree->get_remark() : NULp;
1457  const char *group = NULp;
1458  const char *kgroup = NULp;
1459 
1460  if (format&nGROUP) {
1461  if (tree->is_normal_group()) group = tree->name;
1462  if (tree->is_keeled_group()) kgroup = tree->get_father()->name;
1463  }
1464 
1465  if (remark || group || kgroup) {
1466  out.put('\'');
1467  if (remark) {
1468  gb_assert(remark[0]); // expect non-empty
1469  out.cat(remark);
1470  if (group || !remark_will_parse_as_bootstrap(remark)) {
1471  out.put(':');
1472  }
1473  }
1474  if (group) {
1475  gb_assert(group[0]); // expect non-empty
1476  out.cat(group);
1477  }
1478  if (kgroup) {
1479  gb_assert(kgroup[0]); // expect non-empty
1480  if (group) out.cat(" = ");
1481  out.put(KEELED_INDICATOR);
1482  out.cat(kgroup);
1483  }
1484  out.put('\'');
1485  }
1486  }
1487  }
1488 
1489  if (format&nLENGTH && !tree->is_root_node()) {
1490  out.put(':');
1491  out.cat(GBT_len2string(tree->get_branchlength(), true));
1492  }
1493 }
1494 
1495 char *GBT_tree_2_newick(const TreeNode *tree, NewickFormat format, bool compact) {
1496  // testcode-only newick exporter
1497  // see also ../SL/TREE_WRITE/TreeWrite.cxx@NEWICK_EXPORTER
1499 
1500  GBS_strstruct out(1000);
1501  if (tree) {
1502 #if defined(UNIT_TESTS)
1503  LocallyModify<bool> hack_group_detection(tree->get_tree_root()->detect_groups_without_gbnode, true);
1504 #endif
1505  tree2newick(tree, out, format, 0);
1506  }
1507  out.put(';');
1508 
1509  char *result = out.release();
1510  if (compact && (format&nWRAP)) {
1511  GB_ERROR error = NULp;
1512 
1513  char *compact1 = GBS_regreplace(result, "/[\n ]*[)]/)/", &error);
1514  if (compact1) {
1515  char *compact2 = GBS_regreplace(compact1, "/[(][\n ]*/(/", &error);
1516  if (compact2) freeset(result, compact2);
1517  free(compact1);
1518  }
1519  if (error) {
1520  fprintf(stderr, "Error in GBT_tree_2_newick: %s\n", error);
1521  gb_assert(!error); // should be impossible; falls back to 'result' if happens
1522  }
1523  }
1524  return result;
1525 }
1526 
1527 
1528 // --------------------------------------------------------------------------------
1529 
1530 #ifdef UNIT_TESTS
1531 #include <test_unit.h>
1532 
1533 static const char *getTreeOrder(GBDATA *gb_main) {
1535  GBT_get_tree_names(names, gb_main, true);
1536 
1537  char *joined = GBT_join_strings(names, '|');
1538  char *size_and_names = GBS_global_string_copy("%zu:%s", names.size(), joined);
1539  free(joined);
1540 
1541  RETURN_LOCAL_ALLOC(size_and_names);
1542 }
1543 
1544 void TEST_tree_names() {
1545  TEST_EXPECT_ERROR_CONTAINS(GBT_check_tree_name(""), "not a valid treename");
1546  TEST_EXPECT_ERROR_CONTAINS(GBT_check_tree_name("not_a_treename"), "not a valid treename");
1547  TEST_EXPECT_ERROR_CONTAINS(GBT_check_tree_name("tree_bad.dot"), "not a valid treename");
1548 
1549  TEST_EXPECT_NO_ERROR(GBT_check_tree_name("tree_")); // ugly but ok
1551 }
1552 
1553 void TEST_tree_contraints() {
1554  // test minima
1555  const int MIN_LEAFS = 2;
1556 
1557  TEST_EXPECT_EQUAL(leafs_2_nodes (MIN_LEAFS, ROOTED), 3);
1558  TEST_EXPECT_EQUAL(leafs_2_nodes (MIN_LEAFS, UNROOTED), 2);
1559  TEST_EXPECT_EQUAL(leafs_2_edges (MIN_LEAFS, ROOTED), 2);
1560  TEST_EXPECT_EQUAL(leafs_2_edges (MIN_LEAFS, UNROOTED), 1);
1563 
1564  TEST_EXPECT_EQUAL(MIN_LEAFS, nodes_2_leafs(3, ROOTED)); // test minimum (3 nodes rooted)
1565  TEST_EXPECT_EQUAL(MIN_LEAFS, nodes_2_leafs(2, UNROOTED)); // test minimum (2 nodes unrooted)
1566 
1567  TEST_EXPECT_EQUAL(MIN_LEAFS, edges_2_leafs(2, ROOTED)); // test minimum (2 edges rooted)
1568  TEST_EXPECT_EQUAL(MIN_LEAFS, edges_2_leafs(1, UNROOTED)); // test minimum (1 edge unrooted)
1569 
1570  // test inverse functions:
1571  for (int i = 3; i<=7; ++i) {
1572  // test "leaf->XXX" and back conversions (any number of leafs is possible)
1575 
1578 
1579  bool odd = i%2;
1580  if (odd) {
1581  TEST_EXPECT_EQUAL(i, leafs_2_nodes(nodes_2_leafs(i, ROOTED), ROOTED)); // rooted trees only contain odd numbers of nodes
1582  TEST_EXPECT_EQUAL(i, leafs_2_edges(edges_2_leafs(i, UNROOTED), UNROOTED)); // unrooted trees only contain odd numbers of edges
1583  }
1584  else { // even
1585  TEST_EXPECT_EQUAL(i, leafs_2_nodes(nodes_2_leafs(i, UNROOTED), UNROOTED)); // unrooted trees only contain even numbers of nodes
1586  TEST_EXPECT_EQUAL(i, leafs_2_edges(edges_2_leafs(i, ROOTED), ROOTED)); // rooted trees only contain even numbers of edges
1587  }
1588 
1591 
1594 
1595  // test adding a leaf adds two nodes:
1596  int added = i+1;
1599  }
1600 }
1601 
1602 void TEST_copy_rename_delete_tree_order() {
1603  GB_shell shell;
1604  GBDATA *gb_main = GB_open("TEST_trees.arb", "r");
1605 
1606  {
1607  GB_transaction ta(gb_main);
1608 
1609  {
1611 
1612  TEST_EXPECT_EQUAL(GBT_name_of_largest_tree(gb_main), "tree_removal");
1613 
1614  TEST_EXPECT_EQUAL(GBT_get_tree_name(GBT_find_top_tree(gb_main)), "tree_test");
1615  TEST_EXPECT_EQUAL(GBT_name_of_bottom_tree(gb_main), "tree_removal");
1616 
1617  long inner_nodes = GBT_size_of_tree(gb_main, "tree_nj_bs");
1618  TEST_EXPECT_EQUAL(inner_nodes, 5);
1619  TEST_EXPECT_EQUAL(GBT_tree_info_string(gb_main, "tree_nj_bs", -1), "tree_nj_bs (6:0) PRG=dnadist CORR=none FILTER=none PKG=ARB");
1620  TEST_EXPECT_EQUAL(GBT_tree_info_string(gb_main, "tree_nj_bs", 20), "tree_nj_bs (6:0) PRG=dnadist CORR=none FILTER=none PKG=ARB");
1621 
1622  {
1623  TreeNode *tree = GBT_read_tree(gb_main, "tree_nj_bs", new SimpleRoot);
1624 
1625  TEST_REJECT_NULL(tree);
1626 
1627  size_t leaf_count = GBT_count_leafs(tree);
1628 
1629  size_t species_count;
1630  GB_CSTR *species = GBT_get_names_of_species_in_tree(tree, &species_count);
1631 
1632  StrArray species2;
1633  for (int i = 0; species[i]; ++i) species2.put(ARB_strdup(species[i]));
1634 
1635  TEST_EXPECT_EQUAL(species_count, leaf_count);
1636  TEST_EXPECT_EQUAL(long(species_count), inner_nodes+1);
1637  TEST_EXPECT_STRARRAY_CONTAINS(species2, '*', "CloButyr*CloButy2*CorGluta*CorAquat*CurCitre*CytAquat");
1638 
1639  free(species);
1640 
1641  TEST_EXPECT_NEWICK(nSIMPLE, tree, "(CloButyr,(CloButy2,((CorGluta,(CorAquat,CurCitre)),CytAquat)));");
1643 
1644  destroy(tree);
1645  }
1646 
1647  TEST_EXPECT_EQUAL(GBT_existing_tree(gb_main, "tree_nj_bs"), "tree_nj_bs");
1648  TEST_EXPECT_EQUAL(GBT_existing_tree(gb_main, "tree_nosuch"), "tree_test");
1649  }
1650 
1651  // changing tree order
1652  {
1653  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "8:tree_test|tree_tree2|tree_groups|tree_keeled|tree_keeled_2|tree_nj|tree_nj_bs|tree_removal");
1654 
1655  GBDATA *gb_test = GBT_find_tree(gb_main, "tree_test");
1656  GBDATA *gb_tree2 = GBT_find_tree(gb_main, "tree_tree2");
1657  GBDATA *gb_groups = GBT_find_tree(gb_main, "tree_groups");
1658  GBDATA *gb_keeled = GBT_find_tree(gb_main, "tree_keeled");
1659  GBDATA *gb_keeled2 = GBT_find_tree(gb_main, "tree_keeled_2");
1660  GBDATA *gb_nj = GBT_find_tree(gb_main, "tree_nj");
1661  GBDATA *gb_nj_bs = GBT_find_tree(gb_main, "tree_nj_bs");
1662  GBDATA *gb_removal = GBT_find_tree(gb_main, "tree_removal");
1663 
1664  TEST_EXPECT_NO_ERROR(GBT_move_tree(gb_test, GBT_BEHIND, gb_removal)); // move to bottom
1665  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "8:tree_tree2|tree_groups|tree_keeled|tree_keeled_2|tree_nj|tree_nj_bs|tree_removal|tree_test");
1666 
1667  TEST_EXPECT_EQUAL(GBT_tree_behind(gb_tree2), gb_groups);
1668  TEST_EXPECT_EQUAL(GBT_tree_behind(gb_keeled), gb_keeled2);
1669  TEST_EXPECT_EQUAL(GBT_tree_behind(gb_nj), gb_nj_bs);
1670  TEST_EXPECT_EQUAL(GBT_tree_behind(gb_nj_bs), gb_removal);
1671  TEST_EXPECT_EQUAL(GBT_tree_behind(gb_removal), gb_test);
1673 
1675  TEST_EXPECT_EQUAL(GBT_tree_infrontof(gb_groups), gb_tree2);
1676  TEST_EXPECT_EQUAL(GBT_tree_infrontof(gb_nj), gb_keeled2);
1677  TEST_EXPECT_EQUAL(GBT_tree_infrontof(gb_nj_bs), gb_nj);
1678  TEST_EXPECT_EQUAL(GBT_tree_infrontof(gb_removal), gb_nj_bs);
1679  TEST_EXPECT_EQUAL(GBT_tree_infrontof(gb_test), gb_removal);
1680 
1681  TEST_EXPECT_NO_ERROR(GBT_move_tree(gb_test, GBT_INFRONTOF, gb_tree2)); // move back to top
1682  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "8:tree_test|tree_tree2|tree_groups|tree_keeled|tree_keeled_2|tree_nj|tree_nj_bs|tree_removal");
1683 
1684  TEST_EXPECT_NO_ERROR(GBT_move_tree(gb_test, GBT_BEHIND, gb_tree2)); // move from top
1685  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "8:tree_tree2|tree_test|tree_groups|tree_keeled|tree_keeled_2|tree_nj|tree_nj_bs|tree_removal");
1686 
1687  TEST_EXPECT_NO_ERROR(GBT_move_tree(gb_removal, GBT_INFRONTOF, gb_nj)); // move from end
1688  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "8:tree_tree2|tree_test|tree_groups|tree_keeled|tree_keeled_2|tree_removal|tree_nj|tree_nj_bs");
1689 
1690  TEST_EXPECT_NO_ERROR(GBT_move_tree(gb_nj_bs, GBT_INFRONTOF, gb_nj_bs)); // noop
1691  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "8:tree_tree2|tree_test|tree_groups|tree_keeled|tree_keeled_2|tree_removal|tree_nj|tree_nj_bs");
1692 
1693  TEST_EXPECT_EQUAL(GBT_get_tree_name(GBT_find_top_tree(gb_main)), "tree_tree2");
1694 
1695  TEST_EXPECT_EQUAL(GBT_get_tree_name(GBT_find_next_tree(gb_removal)), "tree_nj");
1696  TEST_EXPECT_EQUAL(GBT_get_tree_name(GBT_find_next_tree(gb_nj_bs)), "tree_tree2"); // last -> first
1697  }
1698 
1699  // check tree order is maintained by copy, rename and delete
1700 
1701  {
1702  // copy
1703  TEST_EXPECT_ERROR_CONTAINS(GBT_copy_tree(gb_main, "tree_nosuch", "tree_whatever"), "tree 'tree_nosuch' not found");
1704  TEST_EXPECT_ERROR_CONTAINS(GBT_copy_tree(gb_main, "tree_test", "tree_test"), "source- and dest-tree are the same");
1705  TEST_EXPECT_ERROR_CONTAINS(GBT_copy_tree(gb_main, "tree_tree2", "tree_test"), "tree 'tree_test' already exists");
1706 
1707  TEST_EXPECT_NO_ERROR(GBT_copy_tree(gb_main, "tree_test", "tree_test_copy"));
1708  TEST_REJECT_NULL(GBT_find_tree(gb_main, "tree_test_copy"));
1709  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "9:tree_tree2|tree_test|tree_test_copy|tree_groups|tree_keeled|tree_keeled_2|tree_removal|tree_nj|tree_nj_bs");
1710 
1711  // rename
1712  TEST_EXPECT_NO_ERROR(GBT_rename_tree(gb_main, "tree_nj", "tree_renamed_nj"));
1713  TEST_REJECT_NULL(GBT_find_tree(gb_main, "tree_renamed_nj"));
1714  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "9:tree_tree2|tree_test|tree_test_copy|tree_groups|tree_keeled|tree_keeled_2|tree_removal|tree_renamed_nj|tree_nj_bs");
1715 
1716  TEST_EXPECT_NO_ERROR(GBT_rename_tree(gb_main, "tree_tree2", "tree_renamed_tree2"));
1717  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "9:tree_renamed_tree2|tree_test|tree_test_copy|tree_groups|tree_keeled|tree_keeled_2|tree_removal|tree_renamed_nj|tree_nj_bs");
1718 
1719  TEST_EXPECT_NO_ERROR(GBT_rename_tree(gb_main, "tree_test_copy", "tree_renamed_test_copy"));
1720  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "9:tree_renamed_tree2|tree_test|tree_renamed_test_copy|tree_groups|tree_keeled|tree_keeled_2|tree_removal|tree_renamed_nj|tree_nj_bs");
1721 
1722  // delete
1723 
1724  GBDATA *gb_nj_bs = GBT_find_tree(gb_main, "tree_nj_bs");
1725  GBDATA *gb_renamed_nj = GBT_find_tree(gb_main, "tree_renamed_nj");
1726  GBDATA *gb_renamed_test_copy = GBT_find_tree(gb_main, "tree_renamed_test_copy");
1727  GBDATA *gb_renamed_tree2 = GBT_find_tree(gb_main, "tree_renamed_tree2");
1728  GBDATA *gb_test = GBT_find_tree(gb_main, "tree_test");
1729  GBDATA *gb_removal = GBT_find_tree(gb_main, "tree_removal");
1730  GBDATA *gb_groups = GBT_find_tree(gb_main, "tree_groups");
1731  GBDATA *gb_keeled = GBT_find_tree(gb_main, "tree_keeled");
1732  GBDATA *gb_keeled2 = GBT_find_tree(gb_main, "tree_keeled_2");
1733 
1734  TEST_EXPECT_NO_ERROR(GB_delete(gb_renamed_tree2));
1735  TEST_EXPECT_NO_ERROR(GB_delete(gb_renamed_test_copy));
1736  TEST_EXPECT_NO_ERROR(GB_delete(gb_renamed_nj));
1737  TEST_EXPECT_NO_ERROR(GB_delete(gb_removal));
1738  TEST_EXPECT_NO_ERROR(GB_delete(gb_groups));
1739  TEST_EXPECT_NO_ERROR(GB_delete(gb_keeled));
1740  TEST_EXPECT_NO_ERROR(GB_delete(gb_keeled2));
1741 
1742  // .. two trees left
1743 
1744  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "2:tree_test|tree_nj_bs");
1745 
1746  TEST_EXPECT_EQUAL(find_largest_tree(gb_main), gb_test);
1747  TEST_EXPECT_EQUAL(GBT_find_top_tree(gb_main), gb_test);
1748  TEST_EXPECT_EQUAL(GBT_find_bottom_tree(gb_main), gb_nj_bs);
1749 
1750  TEST_EXPECT_EQUAL(GBT_find_next_tree(gb_test), gb_nj_bs);
1751  TEST_EXPECT_EQUAL(GBT_find_next_tree(gb_test), gb_nj_bs);
1752  TEST_EXPECT_EQUAL(GBT_find_next_tree(gb_nj_bs), gb_test);
1753 
1755  TEST_EXPECT_EQUAL(GBT_tree_behind (gb_test), gb_nj_bs);
1756 
1757  TEST_EXPECT_EQUAL(GBT_tree_infrontof(gb_nj_bs), gb_test);
1758  TEST_EXPECT_NULL (GBT_tree_behind (gb_nj_bs));
1759 
1760  TEST_EXPECT_NO_ERROR(GBT_move_tree(gb_test, GBT_BEHIND, gb_nj_bs)); // move to bottom
1761  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "2:tree_nj_bs|tree_test");
1762  TEST_EXPECT_NO_ERROR(GBT_move_tree(gb_test, GBT_INFRONTOF, gb_nj_bs)); // move to top
1763  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "2:tree_test|tree_nj_bs");
1764 
1765  TEST_EXPECT_NO_ERROR(GB_delete(gb_nj_bs));
1766 
1767  // .. one tree left
1768 
1769  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "1:tree_test");
1770 
1771  TEST_EXPECT_EQUAL(find_largest_tree(gb_main), gb_test);
1772  TEST_EXPECT_EQUAL(GBT_find_top_tree(gb_main), gb_test);
1773  TEST_EXPECT_EQUAL(GBT_find_bottom_tree(gb_main), gb_test);
1774 
1775  TEST_EXPECT_NULL(GBT_find_next_tree(gb_test)); // no other tree left
1778 
1779  TEST_EXPECT_NO_ERROR(GB_delete(gb_test));
1780 
1781  // .. no tree left
1782 
1783  TEST_EXPECT_EQUAL(getTreeOrder(gb_main), "0:");
1784 
1785  TEST_EXPECT_NULL(GBT_find_tree(gb_main, "tree_test"));
1786  TEST_EXPECT_NULL(GBT_existing_tree(gb_main, "tree_whatever"));
1788  }
1789  }
1790 
1791  GB_close(gb_main);
1792 }
1793 TEST_PUBLISH(TEST_copy_rename_delete_tree_order);
1794 
1795 
1796 void TEST_group_keeling() {
1797  GB_shell shell;
1798  GBDATA *gb_main = GB_open("TEST_trees.arb", "r");
1799 
1800  {
1801  GB_transaction ta(gb_main);
1802 
1803  const char *topo_tree2 = "(((CloTyro3,((CloButyr,CloButy2),CloBifer)),CloInnoc),(((CytAquat,(((CurCitre,CorAquat),CelBiazo),CorGluta)),(CloCarni,CloPaste)),((CloTyrob,CloTyro2),CloTyro4)'g2')'outer');";
1804  const char *topo_groups = "(((CloTyro3,((CloButyr,CloButy2),CloBifer)),CloInnoc)'upper',(((CytAquat,(((CurCitre,CorAquat),CelBiazo),CorGluta)),(CloCarni,CloPaste))'low1',((CloTyrob,CloTyro2)'twoleafs',CloTyro4)'low2')'lower');";
1805  const char *topo_keeled = "(CloTyrob,(((((CytAquat,(((CurCitre,CorAquat),CelBiazo),CorGluta)),(CloCarni,CloPaste))'low1',((CloTyro3,((CloButyr,CloButy2),CloBifer)),CloInnoc)'upper = !lower')'!low2',CloTyro4)'!twoleafs',CloTyro2));";
1806  // Note: shows fixed semantics (#735)
1807  // e.g.
1808  // - compare members of group 'twoleafs' in
1809  // * topo_groups (2 members) and
1810  // * topo_keeled (all but former 2 members in inverse group)
1811  // - compares locations of groups 'upper' and 'lower'
1812  // * topo_groups: located at sons of root
1813  // * topo_keeled: located at same node!
1814 
1815  {
1816  TreeNode *tree = GBT_read_tree(gb_main, "tree_tree2", new SimpleRoot);
1817  TEST_EXPECT_NEWICK(nGROUP, tree, topo_tree2);
1818  destroy(tree);
1819  }
1820  {
1821  TreeNode *tree = GBT_read_tree(gb_main, "tree_groups", new SimpleRoot);
1822  TEST_EXPECT_NEWICK(nGROUP, tree, topo_groups);
1823 
1824  TreeNode *CloTyrob = tree->findLeafNamed("CloTyrob");
1825  TEST_REJECT_NULL(CloTyrob);
1826  CloTyrob->set_root();
1827 
1828  tree = tree->get_root_node();
1829  TEST_EXPECT(tree->is_root_node());
1830 
1831  TEST_EXPECT_NEWICK(nGROUP, tree, topo_keeled);
1832 
1833  destroy(tree);
1834  }
1835  {
1836  TreeNode *tree = GBT_read_tree(gb_main, "tree_keeled", new SimpleRoot);
1837  TEST_EXPECT_NEWICK(nGROUP, tree, topo_keeled);
1838  destroy(tree);
1839  }
1840  {
1841  // Note: there is a HIDDEN_KEELED_GROUP at CytAquat (not shown here in topo, but displayed in dendro-tree-display)!
1842  // Group is found by group-search; see ../SL/GROUP_SEARCH/group_search.cxx@HIDDEN_KEELED_GROUP
1843  const char *topo_keeled2 = "(CloTyro4,((((CytAquat,(((CurCitre,CorAquat),CelBiazo),CorGluta)),(CloCarni,CloPaste))'low1',((CloTyro3,((CloButyr,CloButy2),CloBifer)),CloInnoc)'upper = !lower')'!low2',(CloTyrob,CloTyro2)'twoleafs'));";
1844  TreeNode *tree = GBT_read_tree(gb_main, "tree_keeled_2", new SimpleRoot);
1845  TEST_EXPECT_NEWICK(nGROUP, tree, topo_keeled2);
1846  destroy(tree);
1847  }
1848  }
1849 
1850  GB_close(gb_main);
1851 }
1852 
1853 void TEST_tree_remove_leafs() {
1854  GB_shell shell;
1855  GBDATA *gb_main = GB_open("TEST_trees.arb", "r");
1856 
1857  {
1858  GBT_TreeRemoveType tested_modes[] = {
1863  };
1864 
1865  const char *org_topo = "((CloInnoc:.371,(CloTyrob:.009,(CloTyro2:.017,(CloTyro3:1.046,CloTyro4:.061):.026):.017):.274):.029,(CloBifer:.388,((CloCarni:.12,CurCitre:.058):1,((CloPaste:.179,(Zombie1:.12,(CloButy2:.009,CloButyr:0):.564):.01):.131,(CytAquat:.711,(CelBiazo:.059,(CorGluta:.522,(CorAquat:.084,Zombie2:.058):.103):.054):.207):.162):.124):.124):.029);";
1866  const char *rem_marked_topo = "((CloInnoc:.371,(CloTyrob:.009,(CloTyro2:.017,(CloTyro3:1.046,CloTyro4:.061):.026):.017):.274):.029,(CloBifer:.388,(CloCarni:1,((CloPaste:.179,Zombie1:.01):.131,(CelBiazo:.059,Zombie2:.054):.162):.124):.124):.029);";
1867  const char *rem_unmarked_topo = "(CurCitre:1,((Zombie1:.12,(CloButy2:.009,CloButyr:0):.564):.131,(CytAquat:.711,(CorGluta:.522,(CorAquat:.084,Zombie2:.058):.103):.207):.162):.124);";
1868  const char *rem_zombies_topo = "((CloInnoc:.371,(CloTyrob:.009,(CloTyro2:.017,(CloTyro3:1.046,CloTyro4:.061):.026):.017):.274):.029,(CloBifer:.388,((CloCarni:.12,CurCitre:.058):1,((CloPaste:.179,(CloButy2:.009,CloButyr:0):.01):.131,(CytAquat:.711,(CelBiazo:.059,(CorGluta:.522,CorAquat:.103):.054):.207):.162):.124):.124):.029);";
1869  const char *kept_marked_topo = "(CurCitre:1,((CloButy2:.009,CloButyr:0):.131,(CytAquat:.711,(CorGluta:.522,CorAquat:.103):.207):.162):.124);";
1870 
1871  const char *kept_zombies_topo = "(Zombie1:.131,Zombie2:.162);";
1872  const char *kept_zombies_broken_topo = "Zombie2;";
1873 
1874  const char *empty_topo = ";";
1875 
1876  GB_transaction ta(gb_main);
1877  for (unsigned mode = 0; mode<ARRAY_ELEMS(tested_modes); ++mode) {
1878  GBT_TreeRemoveType what = tested_modes[mode];
1879 
1880  for (int linked = 0; linked<=1; ++linked) {
1881  TEST_ANNOTATE(GBS_global_string("mode=%u linked=%i", mode, linked));
1882 
1883  TreeNode *tree = GBT_read_tree(gb_main, "tree_removal", new SimpleRoot);
1884  gb_assert(tree);
1885  bool once = mode == 0 && linked == 0;
1886 
1887  if (linked) {
1888  int zombies = 0;
1889  int duplicates = 0;
1890 
1891  TEST_EXPECT_NO_ERROR(GBT_link_tree_and_count(tree, gb_main, false, &zombies, &duplicates));
1892 
1893  TEST_EXPECT_EQUAL(zombies, 2);
1894  TEST_EXPECT_EQUAL(duplicates, 0);
1895  }
1896 
1897  if (once) TEST_EXPECT_NEWICK(nLENGTH, tree, org_topo);
1898 
1899  int removedCount = 0;
1900  int groupsRemovedCount = 0;
1901 
1902  tree = GBT_remove_leafs(tree, what, NULp, &removedCount, &groupsRemovedCount);
1903 
1904  if (linked) {
1905  GBT_TreeRemoveType what_next = what;
1906 
1907  switch (what) {
1908  case GBT_REMOVE_MARKED:
1909  TEST_EXPECT_EQUAL(removedCount, 6);
1910  TEST_EXPECT_EQUAL(groupsRemovedCount, 0);
1911  TEST_EXPECT_NEWICK(nLENGTH, tree, rem_marked_topo);
1912  what_next = GBT_REMOVE_UNMARKED;
1913  break;
1914  case GBT_REMOVE_UNMARKED:
1915  TEST_EXPECT_EQUAL(removedCount, 9);
1916  TEST_EXPECT_EQUAL(groupsRemovedCount, 1);
1917  TEST_EXPECT_NEWICK(nLENGTH, tree, rem_unmarked_topo);
1918  what_next = GBT_REMOVE_MARKED;
1919  break;
1920  case GBT_REMOVE_ZOMBIES:
1921  TEST_EXPECT_EQUAL(removedCount, 2);
1922  TEST_EXPECT_EQUAL(groupsRemovedCount, 0);
1923  TEST_EXPECT_NEWICK(nLENGTH, tree, rem_zombies_topo);
1924  break;
1925  case GBT_KEEP_MARKED:
1926  TEST_EXPECT_EQUAL(removedCount, 11);
1927  TEST_EXPECT_EQUAL(groupsRemovedCount, 1);
1928  TEST_EXPECT_NEWICK(nLENGTH, tree, kept_marked_topo);
1929  {
1930  // just a test for nWRAP NewickFormat (may be removed later)
1931  const char *kept_marked_topo_wrapped =
1932  "(\n"
1933  " CurCitre:1,\n"
1934  " (\n"
1935  " (\n"
1936  " CloButy2:.009,\n"
1937  " CloButyr:0\n"
1938  " ):.131,\n"
1939  " (\n"
1940  " CytAquat:.711,\n"
1941  " (\n"
1942  " CorGluta:.522,\n"
1943  " CorAquat:.103\n"
1944  " ):.207\n"
1945  " ):.162\n"
1946  " ):.124);";
1947  TEST_EXPECT_NEWICK(NewickFormat(nLENGTH|nWRAP), tree, kept_marked_topo_wrapped);
1948 
1949  const char *expected_compacted =
1950  "(CurCitre:1,\n"
1951  " ((CloButy2:.009,\n"
1952  " CloButyr:0):.131,\n"
1953  " (CytAquat:.711,\n"
1954  " (CorGluta:.522,\n"
1955  " CorAquat:.103):.207):.162):.124);";
1956  char *compacted = GBT_tree_2_newick(tree, NewickFormat(nLENGTH|nWRAP), true);
1957  TEST_EXPECT_EQUAL(compacted, expected_compacted);
1958  free(compacted);
1959  }
1960  what_next = GBT_REMOVE_MARKED;
1961  break;
1962  }
1963 
1964  if (what_next != what) {
1965  gb_assert(tree);
1966  tree = GBT_remove_leafs(tree, what_next, NULp, &removedCount, &groupsRemovedCount);
1967 
1968  switch (what) {
1969  case GBT_REMOVE_MARKED: // + GBT_REMOVE_UNMARKED
1970  TEST_EXPECT_EQUAL(removedCount, 16);
1971  TEST_EXPECT_EQUAL(groupsRemovedCount, 1);
1972  TEST_EXPECT_NEWICK__BROKEN(nLENGTH, tree, kept_zombies_topo);
1973  TEST_EXPECT_NEWICK(nLENGTH, tree, kept_zombies_broken_topo); // @@@ invalid topology (single leaf)
1974  break;
1975  case GBT_REMOVE_UNMARKED: // + GBT_REMOVE_MARKED
1976  TEST_EXPECT_EQUAL(removedCount, 15);
1977  TEST_EXPECT_EQUAL(groupsRemovedCount, 1);
1978  TEST_EXPECT_NEWICK(nLENGTH, tree, kept_zombies_topo);
1979  break;
1980  case GBT_KEEP_MARKED: // + GBT_REMOVE_MARKED
1981  TEST_EXPECT_EQUAL(removedCount, 17);
1982  TEST_EXPECT_EQUAL__BROKEN(groupsRemovedCount, 2, 1); // @@@ expect that all groups have been removed!
1983  TEST_EXPECT_EQUAL(groupsRemovedCount, 1);
1984  TEST_EXPECT_NEWICK(nLENGTH, tree, empty_topo);
1985  break;
1986  default:
1987  TEST_REJECT(true);
1988  break;
1989  }
1990  }
1991  }
1992  else {
1993  switch (what) {
1994  case GBT_REMOVE_MARKED:
1995  case GBT_REMOVE_UNMARKED:
1996  TEST_EXPECT_EQUAL(removedCount, 0);
1997  TEST_EXPECT_EQUAL(groupsRemovedCount, 0);
1998  TEST_EXPECT_NEWICK(nLENGTH, tree, org_topo);
1999  break;
2000  case GBT_REMOVE_ZOMBIES:
2001  case GBT_KEEP_MARKED:
2002  TEST_EXPECT_EQUAL(removedCount, 17);
2003  TEST_EXPECT_EQUAL(groupsRemovedCount, 2);
2004  TEST_EXPECT_NEWICK(nLENGTH, tree, empty_topo);
2005  break;
2006  }
2007  }
2008 
2009  if (tree) {
2010  gb_assert(tree->is_root_node());
2011  destroy(tree);
2012  }
2013  }
2014  }
2015  }
2016 
2017  GB_close(gb_main);
2018 }
2019 TEST_PUBLISH(TEST_tree_remove_leafs);
2020 
2021 
2022 #endif // UNIT_TESTS
GB_ERROR GB_check_key(const char *key) __ATTR__USERESULT
Definition: adstring.cxx:85
GB_ERROR GB_copy_dropProtectMarksAndTempstate(GBDATA *dest, GBDATA *source)
Definition: arbdb.cxx:2152
Definition: arbdbt.h:49
const char * GB_ERROR
Definition: arb_core.h:25
void unlink_from_DB()
Definition: adtree.cxx:1035
string result
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
void cut_tail(size_t byte_count)
Definition: arb_strbuf.h:145
GBT_TreeRemoveType
Definition: arbdbt.h:32
void GB_warning(const char *message)
Definition: arb_msg.cxx:530
void put(const char *elem)
Definition: arb_strarray.h:188
size_t size() const
Definition: arb_strarray.h:85
AliDataPtr format(AliDataPtr data, const size_t wanted_len, GB_ERROR &error)
Definition: insdel.cxx:615
TreeNode * GBT_remove_leafs(TreeNode *tree, GBT_TreeRemoveType mode, const GB_HASH *species_hash, int *removed, int *groups_removed)
Definition: adtree.cxx:34
long GB_read_int(GBDATA *gbd)
Definition: arbdb.cxx:729
GBDATA * GB_child(GBDATA *father)
Definition: adquery.cxx:322
#define implicated(hypothesis, conclusion)
Definition: arb_assert.h:289
TreeNode * findLeafNamed(const char *wantedName)
Definition: TreeNode.cxx:276
long GBS_write_hash(GB_HASH *hs, const char *key, long val)
Definition: adhash.cxx:454
GBDATA * GBT_get_tree_data(GBDATA *gb_main)
Definition: adtree.cxx:27
bool operator<(const indexed_name &other) const
Definition: adtree.cxx:1243
static GB_CSTR * fill_species_name_array(GB_CSTR *current, const TreeNode *tree)
Definition: adtree.cxx:1399
const TreeNode * get_root_node() const
Definition: TreeNode.h:475
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1387
bool has_group_info() const
Definition: TreeNode.h:498
GBDATA * GBT_find_next_tree(GBDATA *gb_tree)
Definition: adtree.cxx:1122
static GB_ERROR reserve_tree_idx(GBDATA *gb_treedata, int idx)
Definition: adtree.cxx:186
char * GBT_tree_2_newick(const TreeNode *tree, NewickFormat format, bool compact)
Definition: adtree.cxx:1495
virtual void set_root()
Definition: TreeNode.cxx:208
const char * GBT_len2string(GBT_LEN length, bool lowPrecision)
Definition: adtree.cxx:1424
GB_ERROR GBT_rename_tree(GBDATA *gb_main, const char *source_name, const char *dest_name)
Definition: adtree.cxx:1379
GBDATA * get_next_tree(GBDATA *gb_tree)
Definition: adtree.cxx:1070
GBDATA * GB_nextEntry(GBDATA *entry)
Definition: adquery.cxx:339
#define TEST_EXPECT_STRARRAY_CONTAINS(strings, separator, expected)
Definition: test_unit.h:1338
void forget_origin()
Definition: TreeNode.h:466
static GBDATA * get_source_and_check_target_tree(GBDATA *gb_main, const char *source_tree, const char *dest_tree, GB_ERROR &error)
Definition: adtree.cxx:1322
#define NO_TREE_SELECTED
int get_max_tree_idx(GBDATA *gb_treedata)
Definition: adtree.cxx:123
TreeNode * GBT_read_tree(GBDATA *gb_main, const char *tree_name, TreeRoot *troot)
Definition: adtree.cxx:889
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
void setKeeledState(int keeledState)
Definition: TreeNode.h:532
CONSTEXPR_INLINE int nodes_2_innerNodes(int nodes, TreeModel model)
Definition: arbdbt.h:75
TreeRoot * get_tree_root() const
Definition: TreeNode.h:473
GB_ERROR GBT_copy_tree(GBDATA *gb_main, const char *source_name, const char *dest_name)
Definition: adtree.cxx:1361
static GB_ERROR gbt_is_invalid(bool is_root, const TreeNode *tree)
Definition: adtree.cxx:909
#define TEST_EXPECT_NEWICK__BROKEN(format, tree, expected_newick)
Definition: test_unit.h:1482
GB_ERROR GBT_log_to_named_trees_remark(GBDATA *gb_main, const char *tree_name, const char *log_entry, bool stamp)
Definition: adtree.cxx:585
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
void warning(int warning_num, const char *warning_message)
Definition: util.cxx:61
GBDATA * GBT_find_tree(GBDATA *gb_main, const char *tree_name)
Definition: adtree.cxx:1052
bool GB_have_error()
Definition: arb_msg.cxx:338
void erase()
Definition: arb_strbuf.h:141
CONSTEXPR_INLINE int leafs_2_innerNodes(int leafs, TreeModel model)
Definition: arbdbt.h:71
void GBK_terminatef(const char *templat,...)
Definition: arb_msg.cxx:523
char * release()
Definition: arb_strbuf.h:129
const char * GBT_tree_info_string(GBDATA *gb_main, const char *tree_name, int maxTreeNameLen)
Definition: adtree.cxx:1173
bool remark_will_parse_as_bootstrap(const char *label)
Definition: TreeNode.h:209
void nput(char c, size_t count)
Definition: arb_strbuf.h:185
void GBS_free_hash(GB_HASH *hs)
Definition: adhash.cxx:538
GB_HASH * GBT_create_species_hash(GBDATA *gb_main)
Definition: adhashtools.cxx:36
char * GBS_regreplace(const char *str, const char *regReplExpr, GB_ERROR *error)
Definition: arb_match.cxx:175
void cat(const char *from)
Definition: arb_strbuf.h:204
bool GB_allow_compression(GBDATA *gb_main, bool allow_compression)
Definition: arbdb.cxx:1896
static TreeRoot * autocorrected_tree
Definition: adtree.cxx:608
const char * GBT_existing_tree(GBDATA *gb_main, const char *tree_name)
Definition: adtree.cxx:1115
static char * gbt_write_tree_rek_new(const TreeNode *node, char *dest, long mode)
Definition: adtree.cxx:415
static TreeNode * gbt_read_tree_rek(char **data, long *startid, GBDATA **gb_tree_nodes, TreeRoot *troot, int size_of_tree, GB_ERROR &error)
Definition: adtree.cxx:617
const char * GBT_name_of_largest_tree(GBDATA *gb_main)
Definition: adtree.cxx:1162
#define ARRAY_ELEMS(array)
Definition: arb_defs.h:19
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
GBDATA * GB_get_father(GBDATA *gbd)
Definition: arbdb.cxx:1722
static TreeNode * read_tree_and_size_internal(GBDATA *gb_tree, GBDATA *gb_ctree, TreeRoot *troot, int node_count, GB_ERROR &error)
Definition: adtree.cxx:729
GBT_LEN leftlen
Definition: TreeNode.h:224
TreeNode * rightson
Definition: TreeNode.h:223
#define NOT4PERL
Definition: arbdb_base.h:23
GB_ERROR GB_delete(GBDATA *&source)
Definition: arbdb.cxx:1916
static GB_ERROR gbt_link_tree_to_hash_rek(TreeNode *tree, link_tree_data *ltd)
Definition: adtree.cxx:949
GB_BUFFER GB_give_other_buffer(GB_CBUFFER buffer, long size)
Definition: arbdb.cxx:363
static GB_ERROR gbt_write_tree(GBDATA *gb_main, GBDATA *gb_tree, const char *tree_name, TreeNode *tree)
Definition: adtree.cxx:470
TreeNode * GBT_read_tree_and_size(GBDATA *gb_main, const char *tree_name, TreeRoot *troot, int *tree_size)
Definition: adtree.cxx:823
GBDATA * GBT_find_bottom_tree(GBDATA *gb_main)
Definition: adtree.cxx:1109
POS_TREE1 * father
Definition: probe_tree.h:39
static FullNameMap names
void GB_raise_user_flag(GBDATA *gbd, unsigned char user_bit)
Definition: arbdb.cxx:2755
#define TEST_PUBLISH(testfunction)
Definition: test_unit.h:1517
bool GB_user_flag(GBDATA *gbd, unsigned char user_bit)
Definition: arbdb.cxx:2750
static GBDATA * find_largest_tree(GBDATA *gb_main)
Definition: adtree.cxx:1076
CONSTEXPR_INLINE int leafs_2_nodes(int leafs, TreeModel model)
Definition: arbdbt.h:54
static void ensure_trees_have_order(GBDATA *gb_treedata)
Definition: adtree.cxx:196
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
NOT4PERL long * GBT_read_int(GBDATA *gb_container, const char *fieldpath)
Definition: adtools.cxx:327
GBDATA * GBT_find_top_tree(GBDATA *gb_main)
Definition: adtree.cxx:1101
GB_ERROR GBT_overwrite_tree(GBDATA *gb_tree, TreeNode *tree)
Definition: adtree.cxx:555
GBDATA * GB_create_container(GBDATA *father, const char *key)
Definition: arbdb.cxx:1829
#define TEST_EXPECT(cond)
Definition: test_unit.h:1328
GBT_ORDER_MODE
Definition: arbdbt.h:44
void GB_warningf(const char *templat,...)
Definition: arb_msg.cxx:536
#define TEST_EXPECT_NEWICK(format, tree, expected_newick)
Definition: test_unit.h:1481
GB_CSTR GB_read_key_pntr(GBDATA *gbd)
Definition: arbdb.cxx:1656
#define GBT_GET_SIZE
Definition: adtree.cxx:25
virtual TreeNode * makeNode() const =0
GBDATA * GB_create(GBDATA *father, const char *key, GB_TYPES type)
Definition: arbdb.cxx:1781
GB_ERROR GBT_write_tree_with_remark(GBDATA *gb_main, const char *tree_name, TreeNode *tree, const char *remark)
Definition: adtree.cxx:599
GB_ERROR GBT_is_invalid(const TreeNode *tree)
Definition: adtree.cxx:932
static void tree_set_default_order(GBDATA *gb_tree)
Definition: adtree.cxx:220
long GB_number_of_subentries(GBDATA *gbd)
Definition: arbdb.cxx:2892
int keeledStateInfo() const
Definition: TreeNode.h:529
int GB_read_security_write(GBDATA *gbd)
Definition: arbdb.cxx:1572
CONSTEXPR_INLINE int leafs_2_edges(int leafs, TreeModel model)
Definition: arbdbt.h:62
#define TEST_EXPECT_EQUAL__BROKEN(expr, want, got)
Definition: test_unit.h:1295
static int group[MAXN+1]
Definition: ClustalV.cxx:65
GBT_RemarkType parse_bootstrap(double &bootstrap, WarningConsumer report)
Definition: TreeNode.cxx:763
#define GBT_PUT_DATA
Definition: adtree.cxx:24
GB_ERROR GBT_write_tree(GBDATA *gb_main, const char *tree_name, TreeNode *tree)
Definition: adtree.cxx:552
#define TEST_REJECT(cond)
Definition: test_unit.h:1330
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1325
GB_ERROR set_tree_idx(GBDATA *gb_tree, int idx)
Definition: adtree.cxx:175
TreeNode * father
Definition: TreeNode.h:223
static void error(const char *msg)
Definition: mkptypes.cxx:96
GBDATA * GB_get_root(GBDATA *gbd)
Definition: arbdb.cxx:1740
bool is_root_node() const
Definition: TreeNode.h:486
GB_CSTR * GBT_get_names_of_species_in_tree(const TreeNode *tree, size_t *count)
Definition: adtree.cxx:1409
bool is_keeled_group() const
Definition: TreeNode.h:542
bool parse_treelabel(const char *&label, double &bootstrap, char *&remark)
Definition: TreeNode.h:149
#define RETURN_LOCAL_ALLOC(mallocation)
Definition: smartptr.h:310
void GBT_get_tree_names(ConstStrArray &names, GBDATA *gb_main, bool sorted)
Definition: adtree.cxx:1246
GB_write_int const char GB_write_autoconv_string WRITE_SKELETON(write_pointer, GBDATA *,"%p", GB_write_pointer) char *AW_awa if)(!gb_var) return strdup("")
Definition: AW_awar.cxx:163
NOT4PERL GB_ERROR GBT_move_tree(GBDATA *gb_moved_tree, GBT_ORDER_MODE mode, GBDATA *gb_target_tree)
Definition: adtree.cxx:1304
size_t GBT_count_leafs(const TreeNode *tree)
Definition: adtree.cxx:894
static SearchTree * tree[SEARCH_PATTERNS]
Definition: ED4_search.cxx:629
GBDATA * get_tree_with_idx(GBDATA *gb_treedata, int at_idx)
Definition: adtree.cxx:132
int GB_read_flag(GBDATA *gbd)
Definition: arbdb.cxx:2796
bool is_tree(GBDATA *gb_tree)
Definition: adtree.cxx:1060
static GB_ERROR write_tree_remark(GBDATA *gb_tree, const char *remark)
Definition: adtree.cxx:559
GB_ERROR GBT_log_to_tree_remark(GBDATA *gb_tree, const char *log_entry, bool stamp)
Definition: adtree.cxx:566
NewickFormat
Definition: arbdb_base.h:68
TreeNode * leftson
Definition: TreeNode.h:223
char * GBS_log_action_to(const char *comment, const char *action, bool stamp)
Definition: adstring.cxx:981
#define RUNNING_TEST()
Definition: arb_assert.h:278
bool GB_has_key(GBDATA *gbd, const char *key)
Definition: arbdb.cxx:1707
void autocorrected_warning(const char *warning)
Definition: adtree.cxx:609
Definition: arbdb.h:86
GBT_LEN rightlen
Definition: TreeNode.h:224
GB_ERROR GB_write_int(GBDATA *gbd, long i)
Definition: arbdb.cxx:1250
static GB_ERROR gbt_write_tree_nodes(GBDATA *gb_tree, TreeNode *node, long *startid)
Definition: adtree.cxx:361
char peek_tail() const
Definition: arb_strbuf.h:150
GB_ERROR GBT_check_valid_group_name(const char *new_group_name)
Definition: adtree.cxx:230
long int flag
Definition: f2c.h:39
void remove_remark()
Definition: TreeNode.h:376
const char * GBT_get_tree_name(GBDATA *gb_tree)
Definition: adtree.cxx:1138
bool has_no_remark() const
Definition: TreeNode.h:381
static GB_ERROR GBT_link_tree_using_species_hash(TreeNode *tree, bool show_status, GB_HASH *species_hash, int *zombies, int *duplicates)
Definition: adtree.cxx:973
CONSTEXPR_INLINE int edges_2_leafs(int edges, TreeModel model)
Definition: arbdbt.h:66
char * GBT_join_strings(const CharPtrArray &strings, char separator)
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:262
long GBT_size_of_tree(GBDATA *gb_main, const char *tree_name)
Definition: adtree.cxx:1221
bool is_leaf() const
Definition: TreeNode.h:263
TYPE * ARB_calloc(size_t nelem)
Definition: arb_mem.h:81
#define IF_ASSERTION_USED(x)
Definition: arb_assert.h:308
TreeNode * fixDeletedSon()
Definition: TreeNode.cxx:855
#define TEST_EXPECT_NULL(n)
Definition: test_unit.h:1322
#define gb_assert(cond)
Definition: arbdbt.h:11
#define GB_GROUP_NAME_MAX
Definition: arbdbt.h:16
static GBDATA * copy_tree_container(GBDATA *gb_source_tree, const char *newName, GB_ERROR &error)
Definition: adtree.cxx:1350
GBDATA * get_tree_infrontof_idx(GBDATA *gb_treedata, int infrontof_idx)
Definition: adtree.cxx:143
bool is_inner_node_with_remark() const
Definition: TreeNode.h:366
GB_ERROR GBT_write_string(GBDATA *gb_container, const char *fieldpath, const char *content)
Definition: adtools.cxx:451
Definition: output.h:122
const char * name
Definition: adtree.cxx:1241
char * name
Definition: TreeNode.h:226
void nprintf(size_t maxlen, const char *templat,...) __ATTR__FORMAT_MEMBER(2)
Definition: arb_strbuf.cxx:29
void announce_tree_constructed()
Definition: TreeNode.h:455
GBDATA * GBT_tree_behind(GBDATA *gb_tree)
Definition: adtree.cxx:1095
char * GB_read_string(GBDATA *gbd)
Definition: arbdb.cxx:909
GBDATA * get_first_tree(GBDATA *gb_main)
Definition: adtree.cxx:1066
GBDATA * GBT_find_or_create(GBDATA *father, const char *key, long delete_level)
Definition: adtools.cxx:42
CONSTEXPR_INLINE int nodes_2_leafs(int nodes, TreeModel model)
Definition: arbdbt.h:58
void GBT_message(GBDATA *gb_main, const char *msg)
Definition: adtools.cxx:238
const char * GBS_static_string(const char *str)
Definition: arb_msg.cxx:212
bool has_son(const TreeNode *father, const TreeNode *son)
Definition: adtree.cxx:905
GB_ERROR GBT_check_tree_name(const char *tree_name)
Definition: adtree.cxx:1144
GB_ERROR GBT_write_group_name(GBDATA *gb_group_name, const char *new_group_name, bool pedantic)
Definition: adtree.cxx:279
void set_remark(const char *newRemark)
Definition: TreeNode.h:372
float GB_atof(const char *str)
Definition: arbdb.cxx:190
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1118
void GB_clear_user_flag(GBDATA *gbd, unsigned char user_bit)
Definition: arbdb.cxx:2760
float GBT_LEN
Definition: arbdb_base.h:34
void GBT_unlink_tree(TreeNode *tree)
Definition: adtree.cxx:1045
#define KEELED_INDICATOR
Definition: TreeNode.h:220
#define NULp
Definition: cxxforward.h:116
#define TEST_EXPECT_ERROR_CONTAINS(call, part)
Definition: test_unit.h:1114
GB_ERROR GB_test_delete_possible(GBDATA *gb_obj)
Definition: arbdb.cxx:1904
void reserve(size_t forElems)
Definition: arb_strarray.h:82
void markAsLeaf()
Definition: TreeNode.h:264
const char * get_data() const
Definition: arb_strbuf.h:120
GB_ERROR GBT_write_tree_remark(GBDATA *gb_main, const char *tree_name, const char *remark)
Definition: adtree.cxx:562
GBDATA * get_tree_behind_idx(GBDATA *gb_treedata, int behind_idx)
Definition: adtree.cxx:159
GBDATA * GB_nextChild(GBDATA *child)
Definition: adquery.cxx:326
TreeNode * keelTarget()
Definition: TreeNode.h:515
GBT_LEN get_branchlength() const
Definition: TreeNode.h:311
GB_transaction ta(gb_var)
GB_ERROR GBT_write_int(GBDATA *gb_container, const char *fieldpath, long content)
Definition: adtools.cxx:471
int get_tree_idx(GBDATA *gb_tree)
Definition: adtree.cxx:113
void destroy(TreeNode *that)
Definition: TreeNode.h:667
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:904
GBDATA * gb_node
Definition: TreeNode.h:225
GBDATA * gb_main
Definition: adname.cxx:32
static void tree2newick(const TreeNode *tree, GBS_strstruct &out, NewickFormat format, int indent)
Definition: adtree.cxx:1441
GB_ERROR GBT_write_name_to_groupData(GBDATA *gb_group, bool createNameEntry, const char *new_group_name, bool pedantic)
Definition: adtree.cxx:354
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
const char * get_remark() const
Definition: TreeNode.h:357
size_t length
void set_bootstrap_seen(bool seen)
Definition: TreeNode.h:116
void delete_by_node()
Definition: TreeNode.h:106
void forget_relatives()
Definition: TreeNode.h:467
const char * GBT_read_char_pntr(GBDATA *gb_container, const char *fieldpath)
Definition: adtools.cxx:307
GBDATA * GBT_tree_infrontof(GBDATA *gb_tree)
Definition: adtree.cxx:1090
const char * GB_CSTR
Definition: arbdb_base.h:25
GB_ERROR GBT_link_tree(TreeNode *tree, GBDATA *gb_main, bool show_status)
Definition: adtree.cxx:1027
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1294
bool is_normal_group() const
Definition: TreeNode.h:537
void cat_sQuoted(const char *from)
Definition: arb_strbuf.h:256
long GBS_read_hash(const GB_HASH *hs, const char *key)
Definition: adhash.cxx:392
void set_auto_modified(bool modified)
Definition: TreeNode.h:123
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
const char * GBT_name_of_bottom_tree(GBDATA *gb_main)
Definition: adtree.cxx:1166
GB_ERROR GBT_link_tree_and_count(TreeNode *tree, GBDATA *gb_main, bool show_status, int *zombies, int *duplicates)
Definition: adtree.cxx:1005
#define GB_USERFLAG_GHOSTNODE
Definition: arbdb.h:57
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:655
const char * label
GB_HASH * GBS_create_hash(long estimated_elements, GB_CASE case_sens)
Definition: adhash.cxx:253
void put(char c)
Definition: arb_strbuf.h:179
Definition: arbdb.h:66
static GB_ERROR gbt_invalid_because(const TreeNode *tree, const char *reason)
Definition: adtree.cxx:901