00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <climits>
00020 #include "ncl/nxstaxablock.h"
00021
00022 #include "ncl/nxsreader.h"
00023
00024 using namespace std;
00025
00028 unsigned NxsTaxaBlock::GetMaxIndex() const
00029 {
00030 unsigned nct = dimNTax;
00031 if (nct == 0)
00032 return UINT_MAX;
00033 return nct - 1;
00034 }
00035
00036 std::vector<std::string> NxsTaxaBlockAPI::GetAllLabels() const
00037 {
00038 const unsigned n = GetNTaxTotal();
00039 std::vector<std::string> v(n);
00040 for (unsigned i = 0; i < n; ++i)
00041 {
00042 NxsString nextLabel = GetTaxonLabel(i);
00043 v[i] = std::string(nextLabel.c_str());
00044 }
00045 return v;
00046 }
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057 unsigned NxsTaxaBlock::TaxLabelToNumber(const std::string &label) const
00058 {
00059 std::string r(label.c_str());
00060 NxsString::to_upper(r);
00061 return CapitalizedTaxLabelToNumber(r);
00062 }
00063
00064
00065
00066
00067
00068
00069 unsigned NxsTaxaBlock::GetIndicesForLabel(const std::string &label,
00070 NxsUnsignedSet *inds) const
00071 {
00072 NxsString emsg;
00073 const unsigned numb = TaxLabelToNumber(label);
00074 if (numb != 0)
00075 {
00076 if (inds)
00077 inds->insert(numb - 1);
00078 return 1;
00079 }
00080 return GetIndicesFromSetOrAsNumber(label, inds, taxSets, GetMaxIndex(), "taxon");
00081 }
00082
00083 bool NxsTaxaBlock::AddNewIndexSet(const std::string &label, const NxsUnsignedSet & inds)
00084 {
00085 NxsString nlab(label.c_str());
00086 const bool replaced = taxSets.count(nlab) > 0;
00087 taxSets[nlab] = inds;
00088 return replaced;
00089 }
00090
00091
00092 bool NxsTaxaBlock::AddNewPartition(const std::string &label, const NxsPartition & inds)
00093 {
00094 NxsString ls(label.c_str());
00095 bool replaced = taxPartitions.count(ls) > 0;
00096 taxPartitions[ls] = inds;
00097 return replaced;
00098 }
00099
00100
00101
00102 NxsTaxaBlock::NxsTaxaBlock()
00103 {
00104 dimNTax = 0;
00105 id = "TAXA";
00106 }
00107
00108 NxsTaxaBlock::~NxsTaxaBlock()
00109 {}
00110
00117 void NxsTaxaBlock::Read(
00118 NxsToken &token)
00119 {
00120 Reset();
00121 isEmpty = false;
00122 isUserSupplied = true;
00123
00124 DemandEndSemicolon(token, "BEGIN TAXA");
00125
00126 for (;;)
00127 {
00128 token.GetNextToken();
00129 NxsBlock::NxsCommandResult res = HandleBasicBlockCommands(token);
00130 if (res == NxsBlock::NxsCommandResult(STOP_PARSING_BLOCK))
00131 return;
00132 if (res != NxsBlock::NxsCommandResult(HANDLED_COMMAND))
00133 {
00134 if (token.Equals("DIMENSIONS"))
00135 {
00136 token.GetNextToken();
00137 if (!token.Equals("NTAX"))
00138 {
00139 errormsg = "Expecting NTAX keyword, but found ";
00140 errormsg += token.GetToken();
00141 errormsg += " instead";
00142 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
00143 }
00144 DemandEquals(token, "after NTAX");
00145 dimNTax = DemandPositiveInt(token, "NTAX");
00146 taxLabels.reserve(dimNTax);
00147 DemandEndSemicolon(token, "DIMENSIONS");
00148 }
00149 else if (token.Equals("TAXLABELS"))
00150 HandleTaxLabels(token);
00151 else
00152 SkipCommand(token);
00153 }
00154 }
00155 }
00156
00161 void NxsTaxaBlock::HandleTaxLabels(NxsToken &token)
00162 {
00163 if (dimNTax == 0)
00164 {
00165 errormsg = "NTAX must be specified before TAXLABELS command";
00166 throw NxsException(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
00167 }
00168 taxLabels.clear();
00169 labelToIndex.clear();
00170 for (unsigned i = 0; i < dimNTax; i++)
00171 {
00172 token.GetNextToken();
00173 try
00174 {
00175 NxsString t = token.GetToken();
00176 AddTaxonLabel(t);
00177 }
00178 catch (const NxsException & x)
00179 {
00180 throw NxsException(x.msg, token);
00181 }
00182 }
00183 DemandEndSemicolon(token, "TAXLABELS");
00184 }
00185
00186
00187
00188
00189 void NxsTaxaBlock::Report(
00190 std::ostream &out) NCL_COULD_BE_CONST
00191 {
00192 out << endl;
00193 out << id << " block contains ";
00194 if (dimNTax == 0)
00195 {
00196 out << "no taxa" << endl;
00197 return;
00198 }
00199 if (dimNTax == 1)
00200 out << "1 taxon" << endl;
00201 else
00202 out << dimNTax << " taxa" << endl;
00203 for (unsigned k = 0; k < dimNTax; k++)
00204 out << " " << (k+1) << " " << GetTaxonLabel(k) << endl;
00205 }
00206
00207
00208
00209 void NxsTaxaBlock::WriteAsNexus(std::ostream &out) const
00210 {
00211 out << "BEGIN TAXA;\n";
00212 WriteBasicBlockCommands(out);
00213 out << " DIMENSIONS NTax = " << dimNTax << ";\n";
00214 this->WriteTaxLabelsCommand(out);
00215 WriteSkippedCommands(out);
00216 out << "END;\n";
00217 }
00218
00219
00220
00221 void NxsTaxaBlock::WriteTaxLabelsCommand(std::ostream &out) const
00222 {
00223 const unsigned nLabels = this->GetNumTaxonLabels();
00224 if (nLabels > 0)
00225 {
00226 out << " TAXLABELS";
00227 for (NxsStringVector::const_iterator kIt = taxLabels.begin(); kIt != taxLabels.end(); ++kIt)
00228 out << ' ' << NxsString::GetEscaped(*kIt);
00229 out << ";\n";
00230 }
00231 }
00232
00233
00234
00235 void NxsTaxaBlock::Reset()
00236 {
00237 NxsBlock::Reset();
00238 taxLabels.clear();
00239 labelToIndex.clear();
00240 dimNTax = 0;
00241 inactiveTaxa.clear();
00242 taxSets.clear();
00243 taxPartitions.clear();
00244 }
00245
00246
00247
00248
00249
00250 unsigned NxsTaxaBlock::AddTaxonLabel(
00251 const std::string & rs)
00252 {
00253 unsigned ind = (unsigned)taxLabels.size();
00254 NxsString s(rs.c_str());
00255 std::string x(rs.c_str());
00256 NxsString::to_upper(x);
00257 CheckCapitalizedTaxonLabel(x);
00258 taxLabels.push_back(s);
00259 labelToIndex[x] = ind;
00260 return ind;
00261 }
00262
00263
00264
00265
00266
00267
00268 void NxsTaxaBlock::CheckCapitalizedTaxonLabel(
00269 const std::string &s) const
00270 {
00271 unsigned ind = (unsigned)taxLabels.size();
00272 if (dimNTax <= ind)
00273 {
00274 NxsString e = "Number of stored labels exceeds the NTax specified.";
00275 throw NxsException(e);
00276 }
00277 if (CapitalizedTaxLabelToNumber(s) != 0)
00278 {
00279 NxsString e = "TaxLabels cannot be repeated. The label ";
00280 e << s << " has already been stored.";
00281 throw DuplicatedLabelNxsException(e);
00282 }
00283 if (s.length() == 1 && NxsString::IsNexusPunctuation(s[0]))
00284 {
00285 NxsString e = "Illegal TaxLabel found:\n";
00286 e << s << "\n TaxLabels cannot be punctuation.";
00287 throw NxsException(e);
00288 }
00289 }
00290
00291
00292 void NxsTaxaBlock::ChangeTaxonLabel(
00293 unsigned i,
00294 NxsString s)
00295 {
00296 if (i >= (unsigned)taxLabels.size())
00297 {
00298 NxsString e = "The label for taxon ";
00299 e << (i+1) << " cannot be changed, because the only " << (unsigned)taxLabels.size() << " taxlabel(s) have been assigned.";
00300 throw NxsNCLAPIException(e);
00301 }
00302 RemoveTaxonLabel(i);
00303 std::string x(s.c_str());
00304 NxsString::to_upper(x);
00305 CheckCapitalizedTaxonLabel(x);
00306 taxLabels[i] = NxsString(s.c_str());
00307 labelToIndex[x] = i;
00308 }
00309
00310 void NxsTaxaBlock::RemoveTaxonLabel(
00311 unsigned i)
00312 {
00313 std::string oldLabel(taxLabels[i].c_str());
00314 NxsString::to_upper(oldLabel);
00315 labelToIndex.erase(oldLabel);
00316 taxLabels[i] = NxsString();
00317 }
00318
00319
00320
00321
00322 unsigned NxsTaxaBlock::GetMaxTaxonLabelLength()
00323 {
00324 NxsStringVector::const_iterator tlIt = taxLabels.begin();
00325 unsigned maxlen = 0;
00326 for (; tlIt < taxLabels.end(); ++tlIt)
00327 {
00328 const unsigned thislen = (unsigned)tlIt->size();
00329 if (thislen > maxlen)
00330 maxlen = thislen;
00331 }
00332 return maxlen;
00333 }
00334
00335
00336
00337 NxsString NxsTaxaBlock::GetTaxonLabel(unsigned i) const
00338 {
00339 if (i >= dimNTax)
00340 {
00341 NxsString e = "The taxon index ";
00342 e << i << " is out of range. Only " << dimNTax << " taxa in block.";
00343 throw NxsNCLAPIException(e);
00344 }
00345 if (i < (unsigned)taxLabels.size())
00346 return taxLabels[i];
00347 NxsString s;
00348 s += (i + 1);
00349 return s;
00350 }
00351
00356 bool NxsTaxaBlock::NeedsQuotes(
00357 unsigned i)
00358 {
00359 const NxsString x(GetTaxonLabel(i).c_str());
00360 return x.QuotesNeeded();
00361 }
00362
00365 bool NxsTaxaBlock::IsAlreadyDefined(
00366 const std::string & s)
00367 {
00368 return (TaxLabelToNumber(s) != 0);
00369 }
00370
00375 unsigned NxsTaxaBlock::FindTaxon(
00376 const NxsString &s) const
00377 {
00378 unsigned k = TaxLabelToNumber(s);
00379 if (k == 0)
00380 throw NxsTaxaBlock::NxsX_NoSuchTaxon();
00381 return (k - 1);
00382 }
00383
00386 unsigned NxsTaxaBlock::GetNumTaxonLabels() const
00387 {
00388 return (unsigned)taxLabels.size();
00389 }
00390
00393 void NxsTaxaBlock::SetNtax(
00394 unsigned n)
00395 {
00396 dimNTax = n;
00397 if (taxLabels.size() > dimNTax)
00398 {
00399 for (unsigned i = dimNTax; i < taxLabels.size(); i++)
00400 RemoveTaxonLabel(i);
00401 taxLabels.resize(dimNTax);
00402 }
00403 else
00404 taxLabels.reserve(dimNTax);
00405 }
00406
00407 NxsTaxaBlock *NxsTaxaBlockFactory::GetBlockReaderForID(const std::string & idneeded, NxsReader *reader, NxsToken *)
00408 {
00409 if (reader == NULL || idneeded != "TAXA")
00410 return NULL;
00411 NxsTaxaBlock * nb = new NxsTaxaBlock();
00412 nb->SetImplementsLinkAPI(false);
00413 return nb;
00414 }
00415
00416 NxsTaxaBlockAPI * NxsTaxaBlockSurrogate::GetTaxaBlockPtr(int *status) const
00417 {
00418 if (status)
00419 *status = GetTaxaLinkStatus();
00420 return taxa;
00421 }
00422
00423
00424 void NxsTaxaBlockSurrogate::SetTaxaLinkStatus(NxsBlock::NxsBlockLinkStatus s)
00425 {
00426 if (taxaLinkStatus & NxsBlock::BLOCK_LINK_USED)
00427 {
00428 throw NxsNCLAPIException("Resetting a used taxaLinkStatus");
00429 }
00430 taxaLinkStatus = s;
00431 }
00432
00433
00434 void NxsTaxaBlockSurrogate::SetTaxaBlockPtr(NxsTaxaBlockAPI *c, NxsBlock::NxsBlockLinkStatus s)
00435 {
00436 SetTaxaLinkStatus(s);
00437 taxa = c;
00438 }
00439
00440
00441 void NxsTaxaBlockSurrogate::HandleLinkTaxaCommand(NxsToken & token)
00442 {
00443 token.GetNextToken();
00444 const std::map<std::string, std::string> kv = token.ProcessAsSimpleKeyValuePairs("LINK");
00445 std::map<std::string, std::string>::const_iterator pairIt = kv.begin();
00446 for (;pairIt != kv.end(); ++pairIt)
00447 {
00448 NxsTaxaBlockAPI *entryTaxa = taxa;
00449 int entryTaxaLinkStatus = taxaLinkStatus;
00450 NxsString key(pairIt->first.c_str());
00451 key.ToUpper();
00452 NxsString value(pairIt->second.c_str());
00453 if (key == "TAXA")
00454 {
00455 if (taxa && !taxa->GetID().EqualsCaseInsensitive(value))
00456 {
00457 if (GetTaxaLinkStatus() & NxsBlock::BLOCK_LINK_USED)
00458 {
00459 NxsString errormsg = "LINK to a Taxa block must occur before commands that use a taxa block";
00460 throw NxsException(errormsg, token);
00461 }
00462 SetTaxaBlockPtr(NULL, NxsBlock::BLOCK_LINK_UNINITIALIZED);
00463 }
00464 if (!taxa)
00465 {
00466 if (!nxsReader)
00467 {
00468 NxsString errormsg = "API Error: No nxsReader during parse in NxsTaxaBlockSurrogate::HandleLinkTaxaCommand";
00469 throw NxsNCLAPIException(errormsg, token);
00470 }
00471 NxsTaxaBlockAPI * cb = nxsReader->GetTaxaBlockByTitle(value.c_str(), NULL);
00472 if (cb == NULL)
00473 {
00474 NxsString errormsg = "Unknown TAXA block (";
00475 errormsg += value;
00476 errormsg +=") referred to in the LINK command";
00477 taxa = entryTaxa;
00478 taxaLinkStatus = entryTaxaLinkStatus;
00479 throw NxsException(errormsg, token);
00480 }
00481 SetTaxaBlockPtr(cb, NxsBlock::BLOCK_LINK_FROM_LINK_CMD);
00482 }
00483 }
00484 else
00485 {
00486 NxsString errormsg = "Skipping unknown LINK subcommand: ";
00487 errormsg += pairIt->first.c_str();
00488 nxsReader->NexusWarnToken(errormsg, NxsReader::SKIPPING_CONTENT_WARNING, token);
00489 errormsg.clear();
00490 }
00491 }
00492 }
00493 void NxsTaxaBlockSurrogate::WriteLinkTaxaCommand(std::ostream &out) const
00494 {
00495 if (taxa && !(taxa->GetTitle().empty()))
00496 out << " LINK TAXA = " << NxsString::GetEscaped(taxa->GetTitle()) << ";\n";
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506 void NxsTaxaBlockSurrogate::AssureTaxaBlock(bool allocBlock, NxsToken &token, const char *cmd)
00507 {
00508 if (!allocBlock)
00509 {
00510 if (taxa != NULL)
00511 return;
00512 if (!nxsReader)
00513 {
00514 NxsString errormsg = "API Error: No nxsReader during parse in NxsTaxaBlockSurrogate::AssureTaxaBlock";
00515 throw NxsNCLAPIException(errormsg, token);
00516 }
00517 unsigned nTb;
00518 NxsTaxaBlockAPI * cb = nxsReader->GetTaxaBlockByTitle(NULL, &nTb);
00519 if (cb == NULL)
00520 {
00521 NxsString errormsg = "TAXA Block has been not been read, but a ";
00522 if (cmd)
00523 errormsg += cmd;
00524 errormsg += " command (which requires a TAXA block) has been encountered. Either add a TAXA block or (for blocks other than the TREES block) you may use a \"DIMENSIONS NEWTAXA NTAX= ...\" command to introduces taxa.";
00525 throw NxsException(errormsg, token);
00526 }
00527 if (nTb > 1)
00528 {
00529 NxsString errormsg = "Multiple TAXA Blocks have been read (or implied using NEWTAXA in other blocks) and a ";
00530 if (cmd)
00531 errormsg += cmd;
00532 errormsg += " command (which requires a TAXA block) has been encountered";
00533 std::string bn = token.GetBlockName();
00534 if (!bn.empty())
00535 {
00536 errormsg += " in a ";
00537 errormsg += bn;
00538 errormsg += " block.";
00539 }
00540 errormsg += ".\nThis can be caused by reading multiple files. It is possible that\neach file is readable separately, but cannot be read unambiguously when read in sequence.\n";
00541 errormsg += "One way to correct this is to use the\n TITLE some-unique-name-here ;\ncommand in the TAXA block and an accompanying\n LINK TAXA=the-unique-title-goes here;\n";
00542 errormsg += "command to specify which TAXA block is needed.";
00543 cb->WarnDangerousContent(errormsg, token);
00544 }
00545 taxa = cb;
00546 return;
00547 }
00548 if (nxsReader != NULL)
00549 {
00550 NxsTaxaBlockFactory * tbf = nxsReader->GetTaxaBlockFactory();
00551 if (tbf)
00552 {
00553 std::string s("TAXA");
00554 taxa = tbf->GetBlockReaderForID(s, nxsReader, &token);
00555 ownsTaxaBlock = true;
00556 passedRefOfOwnedBlock = false;
00557 taxaLinkStatus = NxsBlock::BLOCK_LINK_TO_IMPLIED_BLOCK;
00558 }
00559 }
00560 if (taxa == NULL)
00561 {
00562 taxa = new NxsTaxaBlock();
00563 ownsTaxaBlock = true;
00564 passedRefOfOwnedBlock = false;
00565 taxaLinkStatus = NxsBlock::BLOCK_LINK_TO_IMPLIED_BLOCK;
00566 }
00567 }
00568
00569 bool NxsTaxaBlockSurrogate::SurrogateSwapEquivalentTaxaBlock(NxsTaxaBlockAPI * tb)
00570 {
00571 NxsTaxaBlockFactory * tbf = nxsReader->GetTaxaBlockFactory();
00572 if (this->taxa && this->ownsTaxaBlock && tbf)
00573 tbf->BlockError(taxa);
00574 this->SetTaxaBlockPtr(tb, NxsBlock::BLOCK_LINK_EQUIVALENT_TO_IMPLIED);
00575 return true;
00576 }
00577
00578 void NxsTaxaBlockSurrogate::ResetSurrogate()
00579 {
00580 if (ownsTaxaBlock)
00581 {
00582 if (!passedRefOfOwnedBlock)
00583 {
00584 if (taxa != NULL && nxsReader != NULL)
00585 {
00586 NxsTaxaBlockFactory * factory = nxsReader->GetTaxaBlockFactory();
00587 if (factory)
00588 {
00589 factory->BlockError(taxa);
00590 taxa = NULL;
00591 }
00592 }
00593 if (taxa)
00594 delete taxa;
00595 }
00596 taxa = NULL;
00597 ownsTaxaBlock = false;
00598 taxaLinkStatus = NxsBlock::BLOCK_LINK_UNINITIALIZED;
00599 }
00600 newtaxa = false;
00601 passedRefOfOwnedBlock = false;
00602 }
00603
00604 VecBlockPtr NxsTaxaBlockSurrogate::GetCreatedTaxaBlocks()
00605 {
00606 VecBlockPtr vbp;
00607 if (newtaxa && taxa)
00608 {
00609 vbp.push_back(taxa);
00610 passedRefOfOwnedBlock = true;
00611 }
00612 return vbp;
00613 }
00618 void NxsTaxaBlockSurrogate::HandleTaxLabels(
00619 NxsToken & token)
00620 {
00621 if (!newtaxa || taxa == NULL)
00622 {
00623 NxsString errormsg = "NEWTAXA must have been specified in DIMENSIONS command to use the TAXLABELS command in a ";
00624 errormsg << GetBlockName() << " block";
00625 throw NxsException(errormsg, token);
00626 }
00627 taxa->HandleTaxLabels(token);
00628 }
00629