ARB
LabelTranslator.cxx
Go to the documentation of this file.
1 // ========================================================= //
2 // //
3 // File : LabelTranslator.cxx //
4 // Purpose : Translate tree labels //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in Sep 21 //
7 // http://www.arb-home.de/ //
8 // //
9 // ========================================================= //
10 
11 #include "LabelTranslator.h"
12 #include <TreeNode.h>
13 #include <gb_aci.h>
14 #include <arb_unordered_set.h>
15 
16 using namespace std;
17 
18 typedef arb_unordered_set<string> StringSet;
19 
20 class TranslationReport : virtual Noncopyable {
21  StringSet translatedLabels;
22 
23 public:
24  GB_ERROR notify_translate_label(string label) { // @@@ !also pass input translation
25  // returns error if labels found in tree are not unique
26  StringSet::const_iterator found = translatedLabels.find(label);
27  if (found != translatedLabels.end()) {
28  return GBS_global_string("Encountered duplicated label '%s' in tree.", label.c_str());
29  }
30  translatedLabels.insert(label);
31  return NULp;
32  }
33 };
34 
35 
38  if (tree->is_leaf()) {
39  if (!tree->gb_node) { // only translate unlinked leafs (i.e. not-yet-linked nodes or real zombies)
40  error = report.notify_translate_label(tree->name); // @@@ !need to do duplication check for original label (from tree) and for aci-modified label.
41  if (!error) {
42  ErrorOrLabel translation = translate(tree->name);
43  if (translation.hasError()) {
44  error = translation.getError().deliver(); // @@@R instead use ARB_ERROR in translate_unlinked_labels_in_tree?
45  }
46  else {
47  string translated = translation.getValue();
48  if (translated != tree->name) {
49  freedup(tree->name, translated.c_str());
50  }
51  // @@@L count translated (into report?)
52  }
53  }
54  }
55  }
56  else {
57  error = translate_unlinked_labels_in_tree(tree->get_leftson(), report);
58  if (!error) error = translate_unlinked_labels_in_tree(tree->get_rightson(), report);
59  }
60  return error;
61 }
62 
63 inline bool generated_by_multiple_species(const char *species_list) {
64  return strchr(species_list, ',') != NULp;
65 }
66 
67 ErrorOrLabel ACI_LabelTranslator::translate(const char *label) const {
68  StringMap::const_iterator found = identifier2shortname.find(label);
69  if (found != identifier2shortname.end()) {
70  const char *species_id = found->second.c_str();
71  if (generated_by_multiple_species(species_id)) {
72  return ErrorOrLabel(GBS_global_string("label '%s' is ambiguous (generated for multiple species: %s)", label, species_id), "");
73  }
74  return ErrorOrLabel(NULp, species_id);
75  }
76 
77  // @@@ !need to make sure 'label' is not a species name (otherwise would accidentally link)
78  // @@@L add option to ACI_LabelTranslator: refuse unmatched translation -> bail out with error here.
79  return ErrorOrLabel(NULp, label); // no translation found -> return original
80 }
81 
83  GB_transaction ta(gb_main);
85 
86  if (ta.ok()) {
87  GBL_env env(gb_main, NULp); // @@@ pass treename?
88 
89  for (GBDATA *gb_species = GBT_first_species(gb_main);
90  gb_species && !error;
91  gb_species = GBT_next_species(gb_species))
92  {
93  GBL_call_env callEnv(gb_species, env);
94  char *identifier = GB_command_interpreter_in_env("", species_aci.c_str(), callEnv);
95  const char *shortname = GBT_get_name(gb_species);
96 
97  if (!identifier) {
98  error = GB_await_error();
99  }
100  else {
101  if (!identifier[0]) {
102  error = GBS_global_string("empty identifier generated (for species '%s')", shortname);
103  }
104  else {
105  StringMap::const_iterator found = identifier2shortname.find(identifier);
106  if (found != identifier2shortname.end()) {
107  const string& prev_shortnames = found->second;
108  identifier2shortname[identifier] = prev_shortnames+','+shortname;
109  }
110  else {
111  identifier2shortname[identifier] = shortname;
112  }
113  }
114  free(identifier);
115  }
116  }
117  }
118 
119  error = ta.close(error);
120 
121  return error;
122 }
123 
125  // @@@R make this a member of LabelTranslator.
126  // @@@R afterwards: make most of class interfaces private.
127 
128  GB_ERROR error = NULp;
129 
130  error = translator.generate_species_identifiers(gb_main); // @@@L ensure this is performed only once!
131 
132  if (!error) {
133  // translate all unlinked labels in tree:
134  TranslationReport report;
135  error = translator.translate_unlinked_labels_in_tree(tree, report);
136  }
137 
138  if (error) {
139  error = GBS_global_string("failed to translate tree labels: %s", error);
140  }
141 
142  return error;
143 }
144 
const char * GB_ERROR
Definition: arb_core.h:25
GB_ERROR notify_translate_label(string label)
ErrorOr< std::string > ErrorOrLabel
bool ok() const
Definition: arbdb.h:150
bool hasError() const
Definition: ErrorOrType.h:51
TYPE getValue() const
Definition: ErrorOrType.h:59
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
STL namespace.
set< string > StringSet
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
GB_ERROR deliver() const
Definition: arb_error.h:116
virtual GB_ERROR generate_species_identifiers(GBDATA *gb_main) const =0
static void error(const char *msg)
Definition: mkptypes.cxx:96
bool generated_by_multiple_species(const char *species_list)
GB_ERROR generate_species_identifiers(GBDATA *gb_main) const OVERRIDE
GB_ERROR TREE_translate_labels(GBDATA *gb_main, TreeNode *tree, const LabelTranslator &translator)
bool is_leaf() const
Definition: TreeNode.h:263
GB_ERROR close(GB_ERROR error)
Definition: arbdbpp.cxx:35
char * name
Definition: TreeNode.h:226
GBDATA * GBT_first_species(GBDATA *gb_main)
Definition: aditem.cxx:124
GBDATA * GBT_next_species(GBDATA *gb_species)
Definition: aditem.cxx:128
#define NULp
Definition: cxxforward.h:116
const char * GBT_get_name(GBDATA *gb_item)
Definition: aditem.cxx:468
NOT4PERL char * GB_command_interpreter_in_env(const char *str, const char *commands, const GBL_call_env &callEnv)
Definition: gb_aci.cxx:361
ARB_ERROR getError() const
Definition: ErrorOrType.h:54
GB_transaction ta(gb_var)
GBDATA * gb_node
Definition: TreeNode.h:225
GBDATA * gb_main
Definition: adname.cxx:32
arb_unordered_set< string > StringSet
GB_ERROR translate_unlinked_labels_in_tree(TreeNode *tree, TranslationReport &report) const
const char * label