ARB
TreeWrite.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : TreeWrite.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // =============================================================== //
10 
11 #include <TreeWrite.h>
12 #include <TreeNode.h>
13 #include <arb_strbuf.h>
14 #include <arb_file.h>
15 #include <xml.hxx>
16 
17 using namespace std;
18 
19 #define tree_assert(cond) arb_assert(cond)
20 
21 inline void replace_by_underscore(char *str, const char *toReplace) {
22  char *unwanted = strpbrk(str, toReplace);
23  while (unwanted) {
24  unwanted[0] = '_';
25  unwanted = strpbrk(unwanted+1, toReplace);
26  }
27 }
28 
29 inline bool isQuoteChar(char c) { return c == '"' || c == '\''; }
30 inline bool whole_label_quoted(const char *label, size_t length) { return isQuoteChar(label[0]) && label[0] == label[length-1]; }
31 
32 
33 const char *Node_ID_Labeler::speciesLabel(GBDATA *, GBDATA *, TreeNode *leafNode, const char *) const {
34  return leafNode->name;
35 }
36 const char *Node_ID_Labeler::groupLabel(GBDATA *, GBDATA *, TreeNode *innerNode, const char *) const {
37  return innerNode->name;
38 }
39 
40 inline char first_non_ascii_char(const char *label) {
41  for (int i = 0; label[i]; ++i) {
42  if (label[i]<0) { // non-ASCII chars are negative (because char is signed)
43  return label[i];
44  }
45  }
46  return 0;
47 }
48 
49 static GB_ERROR export_tree_label(const char *label, FILE *out, LabelQuoting qmode) {
50  // writes a label into the Newick file
51  // label is quoted if necessary
52  // label may be an internal_node_label, a leaf_label or a root_label
54 
55  tree_assert(label);
56 
57  bool accept_non_ascii = qmode&LABEL_ACCEPT_NON_ASCII;
58  char non_ASCII = accept_non_ascii ? 0 : first_non_ascii_char(label);
59 
60  if (non_ASCII) {
61  error = GBS_global_string("non-ASCII character ('%c'=%i) detected in label '%s'",
62  non_ASCII, int(safeCharIndex(non_ASCII)), label);
63  }
64  else {
65  const char *disallowed_chars = " \t\'\"()[]:;,"; // '(' is first problem_char
66  const char *problem_chars = disallowed_chars+4;
67  tree_assert(problem_chars[0] == '(');
68 
69  bool need_quotes = strpbrk(label, disallowed_chars);
70  char used_quote = 0;
71  bool force_quotes = (qmode & LABEL_FORCE_QUOTES);
72 
73  if (force_quotes || need_quotes) {
74  if (qmode&LABEL_SINGLE_QUOTES) used_quote = '\'';
75  else if (qmode&LABEL_DOUBLE_QUOTES) used_quote = '\"';
76  }
77 
78  char *fixed_label;
79  {
80  size_t label_length = strlen(label);
81  fixed_label = ARB_strduplen(label, label_length);
82 
83  if (whole_label_quoted(fixed_label, label_length)) {
84  // if whole label is quoted -> remove quotes
85  memmove(fixed_label, fixed_label+1, label_length-2);
86  fixed_label[label_length-2] = 0;
87  }
88  }
89 
90  if (used_quote) {
91  // replace all problematic characters if requested
92  bool force_replace = (qmode & LABEL_FORCE_REPLACE);
93  if (force_replace) replace_by_underscore(fixed_label, problem_chars); // @@@ warn during export if problem_chars occurred, but were not replaced?
94 
95  // replace used quote by an '_' if it appears inside label
96  char used_quote_as_string[] = { used_quote, 0 };
97  replace_by_underscore(fixed_label, used_quote_as_string);
98 
99  if (!force_quotes) {
100  need_quotes = strpbrk(fixed_label, disallowed_chars);
101  if (!need_quotes) used_quote = 0; // @@@ fails if both quote-types are used in one name
102  }
103  }
104  else {
105  // unquoted label - always replace all problematic characters by '_'
106  replace_by_underscore(fixed_label, disallowed_chars);
107  }
108 
109  if (used_quote) fputc(used_quote, out);
110  fputs(fixed_label, out);
111  if (used_quote) fputc(used_quote, out);
112 
113  free(fixed_label);
114  }
115 
116  return error;
117 }
118 
119 
120 
121 // documentation of the Newick Format is in ../../SOURCE_TOOLS/docs/newick_doc.html
122 
123 inline void indentTo(int indent, FILE *out) {
124  for (int i = 0; i < indent; i++) {
125  putc(' ', out);
126  putc(' ', out);
127  }
128 }
129 
130 inline void print_branchlength(GBT_LEN length, FILE *out) {
131  fputc(':', out);
132  fputs(GBT_len2string(length, false), out);
133 }
134 
135 static GB_ERROR export_tree_node_print(GBDATA *gb_main, FILE *out, TreeNode *tree, const char *tree_name,
136  bool pretty, int indent,
137  const TreeLabeler& labeler, bool save_branchlengths,
138  BootstrapSaveStyle bootstrap_style, bool save_groupnames, LabelQuoting qmode)
139 {
140  GB_ERROR error = NULp;
141 
142  if (pretty) indentTo(indent, out);
143 
144  if (tree->is_leaf()) {
145  const char *label = labeler.speciesLabel(gb_main, tree->gb_node, tree, tree_name);
146  error = export_tree_label(label, out, qmode);
147  }
148  else {
149  if (pretty) fputs("(\n", out);
150  else putc('(', out);
151 
152  error = export_tree_node_print(gb_main, out, tree->get_leftson(), tree_name, pretty, indent+1, labeler, save_branchlengths, bootstrap_style, save_groupnames, qmode);
153  if (!error) {
154  if (save_branchlengths) print_branchlength(tree->leftlen, out);
155  fputs(",\n", out);
156 
157  error = export_tree_node_print(gb_main, out, tree->get_rightson(), tree_name, pretty, indent+1, labeler, save_branchlengths, bootstrap_style, save_groupnames, qmode);
158  }
159  if (!error) {
160  if (save_branchlengths) print_branchlength(tree->rightlen, out);
161  fputc('\n', out);
162 
163  if (pretty) indentTo(indent, out);
164  fputc(')', out);
165 
166  char *remark = NULp;
167  GBT_RemarkType remType = REMARK_NONE;
168  if (bootstrap_style != SAVE_NO_BRANCH_REMARKS) {
169  if (!tree->is_root_node()) {
170  const bool want100 = bootstrap_style == SAVE_BOOTSTRAPS_INCL_100 || bootstrap_style == SAVE_ANY_BRANCH_REMARKS_INCL_100;
171  double value;
172  switch (remType = tree->parse_bootstrap(value, GB_warning)) {
173  case REMARK_OTHER:
174  if (bootstrap_style >= SAVE_CUSTOM_REMARKS) {
175  remark = strdup(tree->get_remark());
176  break;
177  }
178  remType = REMARK_NONE; // avoid ':' gets added later
179  FALLTHROUGH;
180 
181  case REMARK_NONE:
182  if (!want100) break;
183  value = 100.0; // 100%
184  FALLTHROUGH;
185 
186  case REMARK_BOOTSTRAP:
187  if (bootstrap_style != SAVE_CUSTOM_REMARKS) {
188  remark = GBS_global_string_copy("%i", int(value+0.5));
189  }
190  break;
191 
192  }
193  }
194  }
195 
196  const char *label = NULp;
197  {
198  bool useGroupLabel = save_groupnames && tree->has_group_info();
199  if (useGroupLabel) {
200  const char *group = labeler.groupLabel(gb_main, tree->gb_node, tree, tree_name);
201  if (tree->keelTarget()) {
202  error = GBS_global_string("contains a keeled group named '%s'\n"
203  "(to export a tree, you have to correct all keeled groups)", group);
204  }
205  else {
206  if (remark) {
207  size_t glen = strlen(group);
208  if (whole_label_quoted(group, glen)) {
209  char *group_unquoted = ARB_strndup(group+1, glen-2);
210  tree_assert(group_unquoted[0]);
211  label = GBS_global_string("%s:%s", remark, group_unquoted);
212  free(group_unquoted);
213  }
214  else {
215  tree_assert(group[0]);
216  label = GBS_global_string("%s:%s", remark, group);
217  }
218  }
219  else {
220  tree_assert(group[0]);
221  label = group;
222  }
223  }
224  }
225  else if (remark) {
226  if (remType == REMARK_OTHER) { // (note that remType may be faked)
227  label = GBS_global_string("%s:", remark);
228  }
229  else {
230  label = remark;
231  }
232  }
233  }
234 
235  if (label) {
236  tree_assert(!error);
237  error = export_tree_label(label, out, qmode);
238  }
239 
240  free(remark);
241  }
242  }
243 
244  return error;
245 }
246 
247 inline string buildNodeIdentifier(const string& parent_id, int& son_counter) {
248  ++son_counter;
249  if (parent_id.empty()) return GBS_global_string("n_%i", son_counter);
250  return GBS_global_string("%s.%i", parent_id.c_str(), son_counter);
251 }
252 
253 static const char *export_tree_node_print_xml(GBDATA *gb_main, TreeNode *tree, double my_length, const char *tree_name,
254  const TreeLabeler& labeler, bool skip_folded, const string& parent_id, int& parent_son_counter) {
255  const char *error = NULp;
256 
257  if (tree->is_leaf()) {
258  XML_Tag item_tag("ITEM");
259 
260  item_tag.add_attribute("name", buildNodeIdentifier(parent_id, parent_son_counter));
261  item_tag.add_attribute("itemname", labeler.speciesLabel(gb_main, tree->gb_node, tree, tree_name));
262  item_tag.add_attribute("length", GBS_global_string("%.5f", my_length));
263  }
264  else {
265  char *bootstrap = NULp;
266  {
267  double value;
268  switch (tree->parse_bootstrap(value, GB_warning)) {
269  case REMARK_BOOTSTRAP: bootstrap = GBS_global_string_copy("%i", int(value+0.5)); break;
270  case REMARK_OTHER: break; // @@@ other branch-remarks are currently not saved into xml format
271  case REMARK_NONE: break;
272  }
273  }
274 
275  bool folded = false;
276  char *groupname = NULp;
277  if (tree->name) {
278  const char *buf = labeler.speciesLabel(gb_main, tree->gb_node, tree, tree_name);
279  tree_assert(buf);
280  groupname = strdup(buf);
281 
282  GBDATA *gb_grouped = GB_entry(tree->gb_node, "grouped");
283  if (gb_grouped) {
284  folded = GB_read_byte(gb_grouped);
285  }
286  }
287 
288  if (my_length || bootstrap || groupname) {
289  bool hide_this_group = skip_folded && folded; // hide folded groups only if skip_folded is true
290 
291  XML_Tag branch_tag(hide_this_group ? "FOLDED_GROUP" : "BRANCH");
292  string my_id = buildNodeIdentifier(parent_id, parent_son_counter);
293 
294  branch_tag.add_attribute("name", my_id);
295 
296  if (my_length) {
297  branch_tag.add_attribute("length", GBS_global_string("%.5f", my_length));
298  }
299  if (bootstrap) {
300  branch_tag.add_attribute("bootstrap", bootstrap);
301  freenull(bootstrap);
302  }
303  if (groupname) {
304  branch_tag.add_attribute("groupname", groupname);
305  freenull(groupname);
306  if (folded) branch_tag.add_attribute("folded", "1");
307  }
308  else {
309  tree_assert(!folded);
310  }
311 
312  if (hide_this_group) {
313  branch_tag.add_attribute("items_in_group", GBT_count_leafs(tree));
314  }
315  else {
316  int my_son_counter = 0;
317  if (!error) error = export_tree_node_print_xml(gb_main, tree->get_leftson(), tree->leftlen, tree_name, labeler, skip_folded, my_id, my_son_counter);
318  if (!error) error = export_tree_node_print_xml(gb_main, tree->get_rightson(), tree->rightlen, tree_name, labeler, skip_folded, my_id, my_son_counter);
319  }
320  }
321  else {
322  if (!error) error = export_tree_node_print_xml(gb_main, tree->get_leftson(), tree->leftlen, tree_name, labeler, skip_folded, parent_id, parent_son_counter);
323  if (!error) error = export_tree_node_print_xml(gb_main, tree->get_rightson(), tree->rightlen, tree_name, labeler, skip_folded, parent_id, parent_son_counter);
324  }
325  }
326 
327  return error;
328 }
329 
330 GB_ERROR TREE_write_XML(GBDATA *gb_main, const char *db_name, const char *tree_name, const TreeLabeler& labeler, bool skip_folded, const char *path) {
331  GB_ERROR error = NULp;
332  FILE *output = fopen(path, "w");
333 
334  if (!output) error = GB_export_errorf("file '%s' could not be opened for writing", path);
335  else {
336  GB_transaction ta(gb_main);
337 
338  TreeNode *tree = GBT_read_tree(gb_main, tree_name, new SimpleRoot);
339  if (!tree) error = GB_await_error();
340  else {
341  error = GBT_link_tree(tree, gb_main, true);
342 
343  if (!error) {
344  GBDATA *tree_cont = GBT_find_tree(gb_main, tree_name);
345  GBDATA *tree_remark = GB_entry(tree_cont, "remark");
346 
347  XML_Document xml_doc("ARB_TREE", "arb_tree.dtd", output);
348 
349  xml_doc.add_attribute("database", db_name);
350  xml_doc.add_attribute("treename", tree_name);
351  xml_doc.add_attribute("export_date", ARB_date_string());
352 
353  if (tree_remark) {
354  char *remark = GB_read_string(tree_remark);
355  XML_Tag remark_tag("COMMENT");
356  XML_Text remark_text(remark);
357  free(remark);
358  }
359 
360  int my_son_counter = 0;
361  error = export_tree_node_print_xml(gb_main, tree, 0.0, tree_name, labeler, skip_folded, "", my_son_counter);
362  }
363  }
364  fclose(output);
365  }
366 
367  return error;
368 }
369 
370 static char *complete_newick_comment(const char *comment) {
371  // ensure that all '[' in 'comment' are closed by corresponding ']' by inserting additional brackets
372 
373  int openBrackets = 0;
374  GBS_strstruct out(strlen(comment)*1.1);
375 
376  for (int o = 0; comment[o]; ++o) {
377  switch (comment[o]) {
378  case '[':
379  openBrackets++;
380  break;
381  case ']':
382  if (openBrackets == 0) { // no brackets opened
383  out.put('['); // insert one to enforce balancing
384  }
385  else {
386  openBrackets--;
387  }
388  break;
389 
390  default:
391  break;
392  }
393  out.put(comment[o]);
394  }
395 
396  while (openBrackets>0) { // close all opened brackets
397  out.put(']');
398  openBrackets--;
399  }
400 
401  tree_assert(openBrackets == 0);
402 
403  return out.release();
404 }
405 
406 GB_ERROR TREE_write_Newick(GBDATA *gb_main, const char *tree_name, const TreeLabeler& labeler, bool save_branchlengths, BootstrapSaveStyle bootstrap_style, bool save_groupnames, bool pretty, LabelQuoting quoteMode, const char *path) {
407  // userland newick exporter
408  // see also: testcode newick exporter in ../../ARBDB/adtree.cxx@NEWICK_EXPORTER
409 
410  GB_ERROR error = NULp;
411  FILE *output = fopen(path, "w");
412 
413  if (!output) error = GBS_global_string("file '%s' could not be opened for writing", path);
414  else {
415  GB_transaction ta(gb_main);
416 
417  TreeNode *tree = GBT_read_tree(gb_main, tree_name, new SimpleRoot);
418  if (!tree) error = GB_await_error();
419  else {
420  error = GBT_link_tree(tree, gb_main, true);
421 
422  if (!error) { // write tree comment
423  char *remark = NULp;
424  GBDATA *tree_cont = GBT_find_tree(gb_main, tree_name);
425  GBDATA *tree_remark = GB_entry(tree_cont, "remark");
426 
427  if (tree_remark) {
428  remark = GB_read_string(tree_remark);
429  }
430  {
431  const char *saved_to = GBS_global_string("%s saved to %s", tree_name, path);
432  freeset(remark, GBS_log_action_to(remark, saved_to, true));
433  }
434 
435  if (remark) {
436  char *wellformed = complete_newick_comment(remark);
437 
438  tree_assert(wellformed);
439 
440  fputc('[', output); fputs(wellformed, output); fputs("]\n", output);
441  free(wellformed);
442  }
443  free(remark);
444  }
445 
446  if (!error) { // check save style is valid
447  if (quoteMode == LABEL_DISALLOW_QUOTES) {
448 #define QUOTING_REQUIRED_WHEN_SAVING "It is required to allow quoting of tree labels when saving "
449  if (save_groupnames && bootstrap_style != SAVE_NO_BRANCH_REMARKS) { // true for any remarks
450  error = QUOTING_REQUIRED_WHEN_SAVING "bootstraps/remarks AND groupnames.";
451  }
452  else if (bootstrap_style >= SAVE_CUSTOM_REMARKS) {
453  error = QUOTING_REQUIRED_WHEN_SAVING "non-bootstrap remarks.";
454  }
455 #undef QUOTING_REQUIRED_WHEN_SAVING
456  }
457  }
458 
459  if (!error) { // write tree structure
460  error = export_tree_node_print(gb_main, output, tree, tree_name, pretty, 0, labeler, save_branchlengths, bootstrap_style, save_groupnames, quoteMode);
461  }
462 
463  destroy(tree);
464  }
465 
466  fprintf(output, ";\n");
467  fclose(output);
468 
469  if (error) {
470  GB_unlink_or_warn(path, &error);
471  }
472  }
473 
474  return error;
475 }
476 
477 // --------------------------------------------------------------------------------
478 
479 static void export_tree_node_print_remove(char *str) {
480  int i = 0;
481  while (char c = str[i]) {
482  if (c == '\'' || c == '\"') str[i] = '.';
483  i++;
484  }
485 }
486 
487 static void export_tree_rek(TreeNode *tree, FILE *out, bool export_branchlens, bool dquot) {
488  if (tree->is_leaf()) {
490  fprintf(out,
491  dquot ? " \"%s\" " : " '%s' ",
492  tree->name);
493  }
494  else {
495  fputc('(', out);
496  export_tree_rek(tree->get_leftson(), out, export_branchlens, dquot); if (export_branchlens) fprintf(out, ":%.5f,", tree->leftlen);
497  export_tree_rek(tree->get_rightson(), out, export_branchlens, dquot); if (export_branchlens) fprintf(out, ":%.5f", tree->rightlen);
498  fputc(')', out);
499 
500  if (tree->name) {
502  fprintf(out,
503  dquot ? "\"%s\"" : "'%s'",
504  tree->name);
505  }
506  }
507 }
508 
509 // @@@ maybe replace TREE_export_tree by TREE_write_Newick (need some additional parameters: no comment, trifurcation)
510 
511 GB_ERROR TREE_export_tree(GBDATA *, FILE *out, TreeNode *tree, bool triple_root, bool export_branchlens, bool dquot) {
512  if (triple_root) {
513  TreeNode *one, *two, *three;
514  if (tree->is_leaf()) {
515  return GB_export_error("Tree is too small, minimum 3 nodes");
516  }
517  if (tree->leftson->is_leaf() && tree->rightson->is_leaf()) {
518  return GB_export_error("Tree is too small, minimum 3 nodes");
519  }
520  if (tree->leftson->is_leaf()) {
521  one = tree->get_leftson();
522  two = tree->get_rightson()->get_leftson();
523  three = tree->get_rightson()->get_rightson();
524  }
525  else {
526  one = tree->get_leftson()->get_leftson();
527  two = tree->get_leftson()->get_rightson();
528  three = tree->get_rightson();
529  }
530  fputc('(', out);
531  export_tree_rek(one, out, export_branchlens, dquot); if (export_branchlens) fprintf(out, ":%.5f", 1.0); fputc(',', out);
532  export_tree_rek(two, out, export_branchlens, dquot); if (export_branchlens) fprintf(out, ":%.5f", 1.0); fputc(',', out);
533  export_tree_rek(three, out, export_branchlens, dquot); if (export_branchlens) fprintf(out, ":%.5f", 1.0);
534  fputc(')', out);
535  }
536  else {
537  export_tree_rek(tree, out, export_branchlens, dquot);
538  }
539  return NULp;
540 }
541 
542 
const char * GB_ERROR
Definition: arb_core.h:25
GB_ERROR TREE_export_tree(GBDATA *, FILE *out, TreeNode *tree, bool triple_root, bool export_branchlens, bool dquot)
Definition: TreeWrite.cxx:511
size_t GBT_count_leafs(const TreeNode *tree)
Definition: adtree.cxx:894
void GB_warning(const char *message)
Definition: arb_msg.cxx:530
void indentTo(int indent, FILE *out)
Definition: TreeWrite.cxx:123
GB_ERROR TREE_write_XML(GBDATA *gb_main, const char *db_name, const char *tree_name, const TreeLabeler &labeler, bool skip_folded, const char *path)
Definition: TreeWrite.cxx:330
GB_ERROR GBT_link_tree(TreeNode *tree, GBDATA *gb_main, bool show_status)
Definition: adtree.cxx:1027
virtual const char * speciesLabel(GBDATA *gb_main, GBDATA *gb_species, TreeNode *species, const char *tree_name) const =0
CONSTEXPR_INLINE unsigned char safeCharIndex(char c)
Definition: dupstr.h:73
bool has_group_info() const
Definition: TreeNode.h:498
void GB_unlink_or_warn(const char *path, GB_ERROR *error)
Definition: arb_file.cxx:206
static GB_ERROR export_tree_node_print(GBDATA *gb_main, FILE *out, TreeNode *tree, const char *tree_name, bool pretty, int indent, const TreeLabeler &labeler, bool save_branchlengths, BootstrapSaveStyle bootstrap_style, bool save_groupnames, LabelQuoting qmode)
Definition: TreeWrite.cxx:135
static const char * export_tree_node_print_xml(GBDATA *gb_main, TreeNode *tree, double my_length, const char *tree_name, const TreeLabeler &labeler, bool skip_folded, const string &parent_id, int &parent_son_counter)
Definition: TreeWrite.cxx:253
const char * ARB_date_string()
Definition: arb_string.cxx:35
TreeNode * GBT_read_tree(GBDATA *gb_main, const char *tree_name, TreeRoot *troot)
Definition: adtree.cxx:889
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
STL namespace.
char * release()
Definition: arb_strbuf.h:129
GBT_LEN leftlen
Definition: TreeNode.h:224
TreeNode * rightson
Definition: TreeNode.h:223
GB_ERROR GB_export_error(const char *error)
Definition: arb_msg.cxx:257
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
char * ARB_strduplen(const char *p, unsigned len)
Definition: arb_string.h:33
string buildNodeIdentifier(const string &parent_id, int &son_counter)
Definition: TreeWrite.cxx:247
const char * speciesLabel(GBDATA *, GBDATA *, TreeNode *species, const char *) const OVERRIDE
Definition: TreeWrite.cxx:33
static void export_tree_node_print_remove(char *str)
Definition: TreeWrite.cxx:479
static int group[MAXN+1]
Definition: ClustalV.cxx:65
GBT_RemarkType parse_bootstrap(double &bootstrap, WarningConsumer report)
Definition: TreeNode.cxx:763
GB_ERROR TREE_write_Newick(GBDATA *gb_main, const char *tree_name, const TreeLabeler &labeler, bool save_branchlengths, BootstrapSaveStyle bootstrap_style, bool save_groupnames, bool pretty, LabelQuoting quoteMode, const char *path)
Definition: TreeWrite.cxx:406
static void error(const char *msg)
Definition: mkptypes.cxx:96
void replace_by_underscore(char *str, const char *toReplace)
Definition: TreeWrite.cxx:21
fputc('\n', stderr)
bool is_root_node() const
Definition: TreeNode.h:486
static char * complete_newick_comment(const char *comment)
Definition: TreeWrite.cxx:370
TreeNode * leftson
Definition: TreeNode.h:223
GBT_RemarkType
Definition: arbdbt.h:30
char * GBS_log_action_to(const char *comment, const char *action, bool stamp)
Definition: adstring.cxx:981
GBT_LEN rightlen
Definition: TreeNode.h:224
a xml text node
Definition: xml.hxx:122
fputs(TRACE_PREFIX, stderr)
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:262
bool is_leaf() const
Definition: TreeNode.h:263
char * ARB_strndup(const char *start, int len)
Definition: arb_string.h:83
const char * GBT_len2string(GBT_LEN length, bool lowPrecision)
Definition: adtree.cxx:1424
const char * groupLabel(GBDATA *, GBDATA *, TreeNode *species, const char *) const OVERRIDE
Definition: TreeWrite.cxx:36
Definition: output.h:122
bool whole_label_quoted(const char *label, size_t length)
Definition: TreeWrite.cxx:30
char * name
Definition: TreeNode.h:226
int GB_read_byte(GBDATA *gbd)
Definition: arbdb.cxx:734
static void export_tree_rek(TreeNode *tree, FILE *out, bool export_branchlens, bool dquot)
Definition: TreeWrite.cxx:487
char * GB_read_string(GBDATA *gbd)
Definition: arbdb.cxx:909
static GB_ERROR export_tree_label(const char *label, FILE *out, LabelQuoting qmode)
Definition: TreeWrite.cxx:49
float GBT_LEN
Definition: arbdb_base.h:34
#define NULp
Definition: cxxforward.h:116
#define QUOTING_REQUIRED_WHEN_SAVING
void print_branchlength(GBT_LEN length, FILE *out)
Definition: TreeWrite.cxx:130
LabelQuoting
Definition: TreeWrite.h:18
bool isQuoteChar(char c)
Definition: TreeWrite.cxx:29
#define FALLTHROUGH
Definition: cxxforward.h:136
TreeNode * keelTarget()
Definition: TreeNode.h:515
GBDATA * GBT_find_tree(GBDATA *gb_main, const char *tree_name)
Definition: adtree.cxx:1052
GB_transaction ta(gb_var)
void destroy(TreeNode *that)
Definition: TreeNode.h:667
GBDATA * gb_node
Definition: TreeNode.h:225
GBDATA * gb_main
Definition: adname.cxx:32
const char * get_remark() const
Definition: TreeNode.h:357
size_t length
char first_non_ascii_char(const char *label)
Definition: TreeWrite.cxx:40
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
Definition: output.h:28
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
const char * label
BootstrapSaveStyle
Definition: TreeWrite.h:29
void put(char c)
Definition: arb_strbuf.h:179
#define tree_assert(cond)
Definition: TreeWrite.cxx:19