1 // Copyright (C) 1999-2003 Paul O. Lewis
2 //
3 // This file is part of NCL (Nexus Class Library) version 2.0.
4 //
5 // NCL is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2 of the License, or
8 // (at your option) any later version.
9 //
10 // NCL is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with NCL; if not, write to the Free Software Foundation, Inc.,
17 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 //
19
20 #include "ncl.h"
21
22 /*----------------------------------------------------------------------------------------------------------------------
23 | Initializes id to "TAXA" and ntax to 0.
24 */
NxsTaxaBlock()25 NxsTaxaBlock::NxsTaxaBlock()
26 : NxsBlock()
27 {
28 ntax = 0;
29 id = "TAXA";
30 }
31
32 /*----------------------------------------------------------------------------------------------------------------------
33 | Erases taxonLabels vector.
34 */
~NxsTaxaBlock()35 NxsTaxaBlock::~NxsTaxaBlock()
36 {
37 taxonLabels.erase(taxonLabels.begin(), taxonLabels.end());
38 }
39
40 /*----------------------------------------------------------------------------------------------------------------------
41 | This function provides the ability to read everything following the block name (which is read by the NxsReader
42 | object) to the end or endblock statement. Characters are read from the input stream in. Overrides the abstract
43 | virtual function in the base class.
44 */
Read(NxsToken & token)45 void NxsTaxaBlock::Read(
46 NxsToken &token) /* the token used to read from in */
47 {
48 ntax = 0;
49 int nominal_ntax = 0;
50 isEmpty = false;
51 isUserSupplied = true;
52
53 // This should be the semicolon after the block name
54 //
55 token.GetNextToken();
56
57 if (!token.Equals(";"))
58 {
59 errormsg = "Expecting ';' after TAXA block name, but found ";
60 errormsg += token.GetToken();
61 errormsg += " instead";
62 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
63 }
64
65 for (;;)
66 {
67 token.GetNextToken();
68
69 if (token.Equals("DIMENSIONS"))
70 {
71 // This should be the NTAX keyword
72 //
73 token.GetNextToken();
74
75 if (!token.Equals("NTAX"))
76 {
77 errormsg = "Expecting NTAX keyword, but found ";
78 errormsg += token.GetToken();
79 errormsg += " instead";
80 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
81 }
82
83 // This should be the equals sign
84 //
85 token.GetNextToken();
86
87 if (!token.Equals("="))
88 {
89 errormsg = "Expecting '=', but found ";
90 errormsg += token.GetToken();
91 errormsg += " instead";
92 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
93 }
94
95 // This should be the number of taxa
96 //
97 token.GetNextToken();
98
99 nominal_ntax = atoi(token.GetToken().c_str());
100 if (nominal_ntax <= 0)
101 {
102 errormsg = "NTAX should be greater than zero (";
103 errormsg += token.GetToken();
104 errormsg += " was specified)";
105 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
106 }
107
108 // This should be the terminating semicolon
109 //
110 token.GetNextToken();
111
112 if (!token.Equals(";"))
113 {
114 errormsg = "Expecting ';' to terminate DIMENSIONS command, but found ";
115 errormsg += token.GetToken();
116 errormsg += " instead";
117 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
118 }
119 } // if (token.Equals("DIMENSIONS"))
120
121 else if (token.Equals("TAXLABELS"))
122 {
123 if (nominal_ntax <= 0)
124 {
125 errormsg = "NTAX must be specified before TAXLABELS command";
126 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
127 }
128
129 for (unsigned i = 0; (int)i < nominal_ntax; i++)
130 {
131 token.SetLabileFlagBit(NxsToken::hyphenNotPunctuation + NxsToken::preserveUnderscores);
132 token.GetNextToken();
133 //@pol should check to make sure this is not punctuation
134 AddTaxonLabel(token.GetToken());
135 }
136
137 // This should be terminating semicolon
138 //
139 token.GetNextToken();
140
141 if (!token.Equals(";"))
142 {
143 errormsg = "Expecting ';' to terminate TAXLABELS command, but found ";
144 errormsg += token.GetToken();
145 errormsg += " instead";
146 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
147 }
148 } // if (token.Equals("TAXLABELS"))
149
150 else if (token.Equals("END") || token.Equals("ENDBLOCK"))
151 {
152 // Get the semicolon following END
153 //
154 token.GetNextToken();
155
156 if (!token.Equals(";"))
157 {
158 errormsg = "Expecting ';' to terminate the ENDBLOCK command, but found ";
159 errormsg += token.GetToken();
160 errormsg += " instead";
161 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
162 }
163 break;
164 } // if (token.Equals("END") || token.Equals("ENDBLOCK"))
165
166 else
167 {
168 SkippingCommand(token.GetToken());
169 do
170 {
171 token.GetNextToken();
172 }
173 while (!token.AtEOF() && !token.Equals(";"));
174
175 if (token.AtEOF())
176 {
177 errormsg = "Unexpected end of file encountered";
178 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
179 }
180 } // token not END, ENDBLOCK, TAXLABELS, or DIMENSIONS
181 } // GetNextToken loop
182 }
183
184 /*----------------------------------------------------------------------------------------------------------------------
185 | This function outputs a brief report of the contents of this taxa block. Overrides the abstract virtual function in
186 | the base class.
187 */
Report(ostream & out)188 void NxsTaxaBlock::Report(
189 ostream &out) /* the output stream to which to write the report */
190 {
191 out << endl;
192 out << id << " block contains ";
193
194 if (ntax == 0)
195 {
196 out << "no taxa" << endl;
197 }
198 else if (ntax == 1)
199 out << "one taxon" << endl;
200 else
201 out << ntax << " taxa" << endl;
202
203 if (ntax == 0)
204 return;
205
206 for (unsigned k = 0; k < ntax; k++)
207 {
208 out << '\t' << (k+1) << '\t' << taxonLabels[k] << endl;
209 }
210 }
211
212 /*----------------------------------------------------------------------------------------------------------------------
213 | Flushes taxonLabels and sets ntax to 0 in preparation for reading a new TAXA block.
214 */
Reset()215 void NxsTaxaBlock::Reset()
216 {
217 errormsg.clear();
218 isEmpty = true;
219 isEnabled = true;
220 isUserSupplied = false;
221
222 ntax = 0;
223 taxonLabels.clear();
224 needsQuotes.clear();
225 }
226
227 /*----------------------------------------------------------------------------------------------------------------------
228 | Adds taxon label 's' to end of list of taxon labels and increments ntax by 1. Returns index of taxon label just
229 | added.
230 */
AddTaxonLabel(NxsString s)231 unsigned NxsTaxaBlock::AddTaxonLabel(
232 NxsString s) /* the taxon label to add */
233 {
234 isEmpty = false;
235 if (s.QuotesNeeded())
236 needsQuotes.push_back(true);
237 else
238 needsQuotes.push_back(false);
239
240 taxonLabels.push_back(s);
241 ntax++;
242 return (ntax-1);
243 }
244
245 /*----------------------------------------------------------------------------------------------------------------------
246 | Changes the label for taxon 'i' to 's'.
247 */
ChangeTaxonLabel(unsigned i,NxsString s)248 void NxsTaxaBlock::ChangeTaxonLabel(
249 unsigned i, /* the taxon label number to change */
250 NxsString s) /* the string used to replace label i */
251 {
252 assert(i < (unsigned)taxonLabels.size());
253
254 if (s.QuotesNeeded())
255 needsQuotes[i] = true;
256 else
257 needsQuotes[i] = false;
258
259 taxonLabels[i] = s;
260 }
261
262 /*----------------------------------------------------------------------------------------------------------------------
263 | Returns the length of the longest taxon label stored. Useful for formatting purposes in outputting the data matrix
264 | (i.e., you want the left edge of the matrix to line up).
265 */
GetMaxTaxonLabelLength()266 unsigned NxsTaxaBlock::GetMaxTaxonLabelLength()
267 {
268 assert(ntax == (unsigned)taxonLabels.size());
269
270 unsigned maxlen = 0;
271 for (unsigned i = 0; i < ntax; i++)
272 {
273 unsigned thislen = taxonLabels[i].size();
274 if (thislen > maxlen)
275 maxlen = thislen;
276 }
277 return maxlen;
278 }
279
280 /*----------------------------------------------------------------------------------------------------------------------
281 | Returns the label for taxon 'i'.
282 */
GetTaxonLabel(unsigned i)283 NxsString NxsTaxaBlock::GetTaxonLabel(
284 unsigned i) /* the taxon label number to return */
285 {
286 assert(i >= 0);
287 assert(i < (unsigned)taxonLabels.size());
288
289 return taxonLabels[i];
290 }
291
292 /*----------------------------------------------------------------------------------------------------------------------
293 | Returns true if taxonLabels[i] contains embedded spaces and thus should be surrounded by single quotes if output is
294 | NEXUS format.
295 */
NeedsQuotes(unsigned i)296 bool NxsTaxaBlock::NeedsQuotes(
297 unsigned i) /* the taxon label number in question */
298 {
299 assert(i >= 0);
300 assert(i < (unsigned)taxonLabels.size());
301
302 return needsQuotes[i];
303 }
304
305 /*----------------------------------------------------------------------------------------------------------------------
306 | Returns true if taxon label equal to 's' can be found in the taxonLabels list, and returns false otherwise.
307 */
IsAlreadyDefined(NxsString s)308 bool NxsTaxaBlock::IsAlreadyDefined(
309 NxsString s) /* the s to attempt to find in the taxonLabels list */
310 {
311 NxsStringVector::const_iterator iter = find(taxonLabels.begin(), taxonLabels.end(), s);
312 bool taxonLabelFound = (iter != taxonLabels.end());
313 return taxonLabelFound;
314 }
315
316 /*----------------------------------------------------------------------------------------------------------------------
317 | Returns index of taxon named 's' in taxonLabels list. If taxon named 's' cannot be found, or if there are no
318 | labels currently stored in the taxonLabels list, throws NxsX_NoSuchTaxon exception.
319 */
FindTaxon(NxsString s)320 unsigned NxsTaxaBlock::FindTaxon(
321 NxsString s) /* the string to attempt to find in the taxonLabels list */
322 {
323 unsigned k = 0;
324 NxsStringVector::const_iterator i;
325 for (i = taxonLabels.begin(); i != taxonLabels.end(); ++i)
326 {
327 if (*i == s)
328 break;
329 k++;
330 }
331
332 if (i == taxonLabels.end())
333 throw NxsTaxaBlock::NxsX_NoSuchTaxon();
334
335 return k;
336 }
337
338 /*----------------------------------------------------------------------------------------------------------------------
339 | Returns number of taxon labels currently stored.
340 */
GetNumTaxonLabels()341 unsigned NxsTaxaBlock::GetNumTaxonLabels()
342 {
343 return (unsigned)taxonLabels.size();
344 }
345
346 /*----------------------------------------------------------------------------------------------------------------------
347 | Sets ntax to n.
348 */
SetNtax(unsigned n)349 void NxsTaxaBlock::SetNtax(
350 unsigned n) /* the number of taxa */
351 {
352 ntax = n;
353 }
354