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