[med-svn] [Git][med-team/cmaple][upstream] New upstream version 2.0.0+dfsg
Andreas Tille (@tille)
gitlab at salsa.debian.org
Fri Sep 11 16:23:27 BST 2026
Andreas Tille pushed to branch upstream at Debian Med / cmaple
Commits:
38d8ad37 by Andreas Tille at 2026-09-11T16:33:10+02:00
New upstream version 2.0.0+dfsg
- - - - -
14 changed files:
- + libraries/ncl/CMakeLists.txt
- + libraries/ncl/ncl.h
- + libraries/ncl/nxsblock.cpp
- + libraries/ncl/nxsblock.h
- + libraries/ncl/nxsdefs.h
- + libraries/ncl/nxsexception.cpp
- + libraries/ncl/nxsexception.h
- + libraries/ncl/nxsindent.h
- + libraries/ncl/nxsreader.cpp
- + libraries/ncl/nxsreader.h
- + libraries/ncl/nxsstring.cpp
- + libraries/ncl/nxsstring.h
- + libraries/ncl/nxstoken.cpp
- + libraries/ncl/nxstoken.h
Changes:
=====================================
libraries/ncl/CMakeLists.txt
=====================================
@@ -0,0 +1,21 @@
+add_library(ncl
+#nxsassumptionsblock.cpp
+nxsblock.h nxsblock.cpp
+#nxscharactersblock.cpp
+#nxsdatablock.cpp
+#nxsdiscretedatum.cpp
+#nxsdiscretematrix.cpp
+#nxsdistancedatum.cpp
+#nxsdistancesblock.cpp
+#nxsemptyblock.cpp
+nxsexception.h nxsexception.cpp
+nxsdefs.h
+nxsreader.h nxsreader.cpp
+#nxssetreader.cpp
+nxsindent.h
+nxsstring.h nxsstring.cpp
+#nxstaxablock.cpp
+nxstoken.h nxstoken.cpp
+#nxstreesblock.cpp
+ncl.h
+)
=====================================
libraries/ncl/ncl.h
=====================================
@@ -0,0 +1,108 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#ifndef NCL_NCL_H
+#define NCL_NCL_H
+
+#if defined(_MSC_VER) && !defined(CLANG_UNDER_VS)
+# pragma warning(disable:4786)
+# pragma warning(disable:4291)
+#endif
+
+#if !defined(__DECCXX)
+# include <cassert>
+# include <cctype>
+# include <cmath>
+# include <cstdarg>
+# include <cstdio>
+# include <cstdarg>
+# include <cstdlib>
+# include <ctime>
+# include <cfloat>
+#else
+# include <assert.h>
+# include <ctype.h>
+# include <stdarg.h>
+# include <math.h>
+# include <stdarg.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <time.h>
+# include <float.h>
+#endif
+
+#include <algorithm>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <list>
+#include <map>
+#include <set>
+#include <stdexcept>
+#include <string>
+#if defined(__GNUC__)
+# if __GNUC__ < 3
+# include <strstream>
+# else
+# include <sstream>
+# endif
+#endif
+#include <vector>
+using namespace std;
+
+#if defined(__MWERKS__)
+# if __ide_target("Simple-Win Release") || __ide_target("Phorest-Mac-Release")
+# define NDEBUG
+# else
+# undef NDEBUG
+# endif
+#endif
+
+#if defined( __BORLANDC__ )
+# include <dos.h>
+#endif
+
+#if defined(__MWERKS__)
+# define HAVE_PRAGMA_UNUSED
+ // mwerks (and may be other compilers) want return values even if the function throws an exception
+ //
+# define DEMANDS_UNREACHABLE_RETURN
+
+#endif
+
+#include "nxsdefs.h"
+#include "nxstoken.h"
+#include "nxsblock.h"
+#include "nxsexception.h"
+#include "nxsstring.h"
+#include "nxsreader.h"
+/*
+#include "nxssetreader.h"
+#include "nxstaxablock.h"
+#include "nxstreesblock.h"
+#include "nxsdistancedatum.h"
+#include "nxsdistancesblock.h"
+#include "nxsdiscretedatum.h"
+#include "nxsdiscretematrix.h"
+#include "nxscharactersblock.h"
+#include "nxsassumptionsblock.h"
+#include "nxsdatablock.h"
+#include "nxsemptyblock.h"*/
+
+#endif
=====================================
libraries/ncl/nxsblock.cpp
=====================================
@@ -0,0 +1,193 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#include "ncl.h"
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Initializes all pointer data members to NULL, and all bool data members to true except isUserSupplied, which is
+| initialized to false.
+*/
+NxsBlock::NxsBlock()
+ {
+ next = NULL;
+ nexus = NULL;
+ isEmpty = true;
+ isEnabled = true;
+ isUserSupplied = false;
+
+ id.clear();
+ errormsg.clear();
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Nothing to be done.
+*/
+NxsBlock::~NxsBlock()
+ {
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This base class version simply returns 0 but a derived class should override this function if it needs to construct
+| and run a NxsSetReader object to read a set involving characters. The NxsSetReader object may need to use this
+| function to look up a character label encountered in the set. A class that overrides this method should return the
+| character index in the range [1..nchar].
+*/
+unsigned NxsBlock::CharLabelToNumber(
+ NxsString s) /* the character label to be translated to the character's number */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(s)
+# endif
+ return 0;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Sets the value of isEnabled to false. A NxsBlock can be disabled (by calling this method) if blocks of that type
+| are to be skipped during execution of the NEXUS file. If a disabled block is encountered, the virtual
+| NxsReader::SkippingDisabledBlock function is called, giving your application the opportunity to inform the user
+| that a block was skipped.
+*/
+void NxsBlock::Disable()
+ {
+ isEnabled = false;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Sets the value of isEnabled to true. A NxsBlock can be disabled (by calling Disable) if blocks of that type are to
+| be skipped during execution of the NEXUS file. If a disabled block is encountered, the virtual
+| NxsReader::SkippingDisabledBlock function is called, giving your application the opportunity to inform the user
+| that a block was skipped.
+*/
+void NxsBlock::Enable()
+ {
+ isEnabled = true;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns value of isEnabled, which can be controlled through use of the Enable and Disable member functions. A
+| NxsBlock should be disabled if blocks of that type are to be skipped during execution of the NEXUS file. If a
+| disabled block is encountered, the virtual NxsReader::SkippingDisabledBlock function is called, giving your
+| application the opportunity to inform the user that a block was skipped.
+*/
+bool NxsBlock::IsEnabled()
+ {
+ return isEnabled;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns value of isUserSupplied, which is true if and only if this block's Read function is called to process a
+| block of this type appearing in a data file. This is useful because in some cases, a block object may be created
+| internally (e.g. a NxsTaxaBlock may be populated using taxon names provided in a DATA block), and such blocks do
+| not require permission from the user to delete data stored therein.
+*/
+bool NxsBlock::IsUserSupplied()
+ {
+ return isUserSupplied;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if Read function has not been called since the last Reset. This base class version simply returns the
+| value of the data member isEmpty. If you derive a new block class from NxsBlock, be sure to set isEmpty to true in
+| your Reset function and isEmpty to false in your Read function.
+*/
+bool NxsBlock::IsEmpty()
+ {
+ return isEmpty;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns the id NxsString.
+*/
+NxsString NxsBlock::GetID()
+ {
+ return id;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This virtual function must be overridden for each derived class to provide the ability to read everything following
+| the block name (which is read by the NxsReader object) to the end or endblock statement. Characters are read from
+| the input stream 'in'. Note that to get output comments displayed, you must derive a class from NxsToken, override
+| the member function OutputComment to display a supplied comment, and then pass a reference to an object of the
+| derived class to this function.
+*/
+void NxsBlock::Read(
+ NxsToken &token) /* the NxsToken to use for reading block */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(token)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This virtual function should be overridden for each derived class to completely reset the block object in
+| preparation for reading in another block of this type. This function is called by the NxsReader object just prior to
+| calling the block object's Read function.
+*/
+void NxsBlock::Reset()
+ {
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This virtual function provides a brief report of the contents of the block.
+*/
+void NxsBlock::Report(
+ ostream &out) /* the output stream to which the report is sent */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(out)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Sets the nexus data member of the NxsBlock object to 'nxsptr'.
+*/
+void NxsBlock::SetNexus(
+ NxsReader *nxsptr) /* pointer to a NxsReader object */
+ {
+ nexus = nxsptr;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This function is called when an unknown command named commandName is about to be skipped. This version of the
+| function does nothing (i.e., no warning is issued that a command was unrecognized). Override this virtual function
+| in a derived class to provide such warnings to the user.
+*/
+void NxsBlock::SkippingCommand(
+ NxsString commandName) /* the name of the command being skipped */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(commandName)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This base class version simply returns 0, but a derived class should override this function if it needs to construct
+| and run a NxsSetReader object to read a set involving taxa. The NxsSetReader object may need to use this function to
+| look up a taxon label encountered in the set. A class that overrides this method should return the taxon index in
+| the range [1..ntax].
+*/
+unsigned NxsBlock::TaxonLabelToNumber(
+ NxsString s) /* the taxon label to be translated to a taxon number */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(s)
+# endif
+ return 0;
+ }
+
=====================================
libraries/ncl/nxsblock.h
=====================================
@@ -0,0 +1,76 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+#ifndef NCL_NXSBLOCK_H
+#define NCL_NXSBLOCK_H
+
+#include "nxsstring.h" //for NxsString
+#include "nxstoken.h" //for NxsToken
+class NxsReader;
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This is the base class from which all block classes are derived. A NxsBlock-derived class encapsulates a Nexus block
+| (e.g. DATA block, TREES block, etc.). The abstract virtual function Read must be overridden for each derived class
+| to provide the ability to read everything following the block name (which is read by the NxsReader object) to the
+| end or endblock statement. Derived classes must provide their own data storage and access functions. The abstract
+| virtual function Report must be overridden to provide some feedback to user on contents of block. The abstract
+| virtual function Reset must be overridden to empty the block of all its contents, restoring it to its
+| just-constructed state.
+*/
+class NxsBlock
+ {
+ friend class NxsReader;
+
+ public:
+ NxsBlock();
+ virtual ~NxsBlock();
+
+ void SetNexus(NxsReader *nxsptr);
+
+ NxsString GetID();
+ bool IsEmpty();
+
+ void Enable();
+ void Disable();
+ bool IsEnabled();
+ bool IsUserSupplied();
+
+ virtual unsigned CharLabelToNumber(NxsString s);
+ virtual unsigned TaxonLabelToNumber(NxsString s);
+
+ virtual void SkippingCommand(NxsString commandName);
+
+ virtual void Report(std::ostream &out);
+ virtual void Reset();
+
+ NxsString errormsg; /* workspace for creating error messages */
+
+ protected:
+ bool isEmpty; /* true if this object is currently storing data */
+ bool isEnabled; /* true if this block is currently ebabled */
+ bool isUserSupplied; /* true if this object has been read from a file; false otherwise */
+ NxsReader *nexus; /* pointer to the Nexus file reader object */
+ NxsBlock *next; /* pointer to next block in list */
+ NxsString id; /* holds name of block (e.g., "DATA", "TREES", etc.) */
+
+ virtual void Read(NxsToken &token);
+ };
+
+#endif
+
+
=====================================
libraries/ncl/nxsdefs.h
=====================================
@@ -0,0 +1,85 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+#ifndef NCL_NXSDEFS_H
+#define NCL_NXSDEFS_H
+
+#define NCL_NAME_AND_VERSION "NCL version 2.0"
+#define NCL_COPYRIGHT "Copyright (c) 1999-2003 by Paul O. Lewis"
+#define NCL_HOMEPAGEURL "http://lewis.eeb.uconn.edu/ncl/"
+
+// Maximum number of states that can be stored; the only limitation is that this
+// number be less than the maximum size of an int (not likely to be a problem).
+// A good number for this is 76, which is 96 (the number of distinct symbols
+// able to be input from a standard keyboard) less 20 (the number of symbols
+// symbols disallowed by the NEXUS standard for use as state symbols)
+//
+#define NCL_MAX_STATES 76
+
+#if defined(__MWERKS__) || defined(__DECCXX) || defined(_MSC_VER)
+ typedef long file_pos;
+#else
+ typedef streampos file_pos;
+#endif
+
+#define SUPPORT_OLD_NCL_NAMES
+
+#include <vector> //for std::vector
+#include <set> //for std::set
+#include <map> //for std::map
+#ifdef CLANG_UNDER_VS
+#include <xstddef> //for std::less
+#endif
+
+#include "nxsstring.h"
+
+typedef std::vector<bool> NxsBoolVector;
+typedef std::vector<char> NxsCharVector;
+typedef std::vector<unsigned> NxsUnsignedVector;
+typedef std::vector<NxsStringVector> NxsAllelesVector;
+
+typedef std::set< unsigned, std::less<unsigned> > NxsUnsignedSet;
+
+typedef std::map< unsigned, NxsStringVector, std::less<unsigned> > NxsStringVectorMap;
+typedef std::map< NxsString, NxsString, std::less<NxsString> > NxsStringMap;
+typedef std::map< NxsString, NxsUnsignedSet, std::less<NxsString> > NxsUnsignedSetMap;
+
+// The following typedefs are simply for maintaining compatibility with existing code.
+// The names on the right are deprecated and should not be used.
+//
+typedef NxsBoolVector BoolVect;
+typedef NxsUnsignedSet IntSet;
+typedef NxsUnsignedSetMap IntSetMap;
+typedef NxsAllelesVector AllelesVect;
+typedef NxsStringVector LabelList;
+typedef NxsStringVector StrVec;
+typedef NxsStringVector vecStr;
+typedef NxsStringVectorMap LabelListBag;
+typedef NxsStringMap AssocList;
+
+//class NxsTreesBlock;
+//class NxsTaxaBlock;
+//class NxsAllelesBlock;
+//class NxsAssumptionsBlock;
+//class NxsCharactersBlock;
+//class NxsDistancesBlock;
+//class NxsAssumptionsBlock;
+//class NxsDiscreteDatum;
+//class NxsDiscreteMatrix;
+
+#endif
=====================================
libraries/ncl/nxsexception.cpp
=====================================
@@ -0,0 +1,49 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#include "ncl.h"
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Copies 's' to msg and sets line, col and pos to the current line, column and position in the file where parsing
+| stopped.
+*/
+NxsException::NxsException(
+ const NxsString &s, /* the message for the user */
+ file_pos fp, /* the current file position */
+ long fl, /* the current file line */
+ long fc) /* the current file column */
+ {
+ pos = fp;
+ line = fl;
+ col = fc;
+ msg = s;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Creates a NxsException object with the specified message, getting file position information from the NxsToken.
+*/
+NxsException::NxsException(
+ const NxsString &s, /* message that describes the error */
+ const NxsToken &t) /* NxsToken that was supplied the last token (the token that caused the error) */
+ {
+ msg = s;
+ pos = t.GetFilePosition();
+ line = t.GetFileLine();
+ col = t.GetFileColumn();
+ }
=====================================
libraries/ncl/nxsexception.h
=====================================
@@ -0,0 +1,45 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#ifndef NCL_NXSEXCEPTION_H
+#define NCL_NXSEXCEPTION_H
+
+#include "nxsstring.h" //for NxsString
+#include "nxsdefs.h" //for file_pos
+
+class NxsToken;
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Exception class that conveys a message specific to the problem encountered.
+*/
+class NxsException
+ {
+ public:
+ NxsString msg; /* NxsString to hold message */
+ file_pos pos; /* current file position */
+ long line; /* current line in file */
+ long col; /* column of current line */
+
+ explicit NxsException(const NxsString &s, file_pos fp = 0, long fl = 0L, long fc = 0L);
+ NxsException(const NxsString &s, const NxsToken &t);
+ };
+
+typedef NxsException XNexus;
+
+#endif
=====================================
libraries/ncl/nxsindent.h
=====================================
@@ -0,0 +1,58 @@
+// Copyright (C) 1999-2003 Paul O. Lewis and Mark T. Holder
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#ifndef NCL_NXSINDENT_H
+#define NCL_NXSINDENT_H
+
+#include <ostream> //for std::ostream
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Manipulator for use in indenting text `leftMarg' characters.
+*/
+class Indent
+ {
+ public:
+ Indent(unsigned i);
+
+ unsigned leftMarg; /* the amount by which to indent */
+ };
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Initializes `leftMarg' to `i'.
+*/
+inline Indent::Indent(
+ unsigned i) /* the amount (in characters) by which to indent */
+ {
+ leftMarg = i;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Output operator for the Indent manipulator.
+*/
+inline std::ostream &operator <<(
+ std::ostream &o, /* the ostream object */
+ const Indent &i) /* the Indent object to be sent to `o' */
+ {
+#if defined (HAVE_PRAGMA_UNUSED)
+# pragma unused(i)
+#endif
+ return o;
+ }
+
+#endif
=====================================
libraries/ncl/nxsreader.cpp
=====================================
@@ -0,0 +1,493 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+#include "ncl.h"
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Initializes both `blockList' and `currBlock' to NULL.
+*/
+NxsReader::NxsReader()
+ {
+ blockList = NULL;
+ currBlock = NULL;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Nothing to be done.
+*/
+NxsReader::~NxsReader()
+ {
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Adds `newBlock' to the end of the list of NxsBlock objects growing from `blockList'. If `blockList' points to NULL,
+| this function sets `blockList' to point to `newBlock'. Calls SetNexus method of `newBlock' to inform `newBlock' of
+| the NxsReader object that now owns it. This is useful when the `newBlock' object needs to communicate with the
+| outside world through the NxsReader object, such as when it issues progress reports as it is reading the contents
+| of its block.
+*/
+void NxsReader::Add(
+ NxsBlock *newBlock) /* a pointer to an existing block object */
+ {
+ assert(newBlock != NULL);
+
+ newBlock->SetNexus(this);
+
+ if (!blockList)
+ blockList = newBlock;
+ else
+ {
+ // Add new block to end of list
+ //
+ NxsBlock *curr;
+ for (curr = blockList; curr && curr->next;)
+ curr = curr->next;
+ assert(curr && !curr->next);
+ curr->next = newBlock;
+ }
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns position (first block has position 0) of block `b' in `blockList'. Returns UINT_MAX if `b' cannot be found
+| in `blockList'.
+*/
+unsigned NxsReader::PositionInBlockList(
+ NxsBlock *b) /* a pointer to an existing block object */
+ {
+ unsigned pos = 0;
+ NxsBlock *curr = blockList;
+
+ for (;;)
+ {
+ if (curr == NULL || curr == b)
+ break;
+ pos++;
+ curr = curr->next;
+ }
+
+ if (curr == NULL)
+ pos = UINT_MAX;
+
+ return pos;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Reassign should be called if a block (`oldb') is about to be deleted (perhaps to make way for new data). Create
+| the new block (`newb') before deleting `oldb', then call Reassign to replace `oldb' in `blockList' with `newb'.
+| Assumes `oldb' exists and is in `blockList'.
+*/
+void NxsReader::Reassign(
+ NxsBlock *oldb, /* a pointer to the block object soon to be deleted */
+ NxsBlock *newb) /* a pointer to oldb's replacement */
+ {
+ NxsBlock *prev = NULL;
+ NxsBlock *curr = blockList;
+ newb->SetNexus(this);
+
+ for (;;)
+ {
+ if (curr == NULL || curr == oldb)
+ break;
+ prev = curr;
+ curr = curr->next;
+ }
+
+ assert(curr != NULL);
+
+ newb->next = curr->next;
+ if (prev == NULL)
+ blockList = newb;
+ else
+ prev->next = newb;
+ curr->next = NULL;
+ curr->SetNexus(NULL);
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| If `blockList' data member still equals NULL, returns true; otherwise, returns false. `blockList' will not be equal
+| to NULL if the Add function has been called to add a block object to the list.
+*/
+bool NxsReader::BlockListEmpty()
+ {
+ return (blockList == NULL ? true : false);
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This function was created for purposes of debugging a new NxsBlock. This version does nothing; to create an active
+| DebugReportBlock function, override this version in the derived class and call the Report function of `nexusBlock'.
+| This function is called whenever the main NxsReader Execute function encounters the [&spillall] command comment
+| between blocks in the data file. The Execute function goes through all blocks and passes them, in turn, to this
+| DebugReportBlock function so that their contents are displayed. Placing the [&spillall] command comment between
+| different versions of a block allows multiple blocks of the same type to be tested using one long data file. Say
+| you are interested in testing whether the normal, transpose, and interleave format of a matrix can all be read
+| correctly. If you put three versions of the block in the data file one after the other, the second one will wipe out
+| the first, and the third one will wipe out the second, unless you have a way to report on each one before the next
+| one is read. This function provides that ability.
+*/
+void NxsReader::DebugReportBlock(
+ NxsBlock &nexusBlock) /* the block that should be reported */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(nexusBlock)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Detaches `oldBlock' from the list of NxsBlock objects growing from `blockList'. If `blockList' itself points to
+| `oldBlock', this function sets `blockList' to point to `oldBlock->next'. Note: the object pointed to by `oldBlock'
+| is not deleted, it is simply detached from the linked list. No harm is done in Detaching a block pointer that has
+| already been detached previously; if `oldBlock' is not found in the block list, Detach simply returns quietly. If
+| `oldBlock' is found, its SetNexus object is called to set the NxsReader pointer to NULL, indicating that it is no
+| longer owned by (i.e., attached to) a NxsReader object.
+*/
+void NxsReader::Detach(
+ NxsBlock *oldBlock) /* a pointer to an existing block object */
+ {
+ assert(oldBlock != NULL);
+
+ // Return quietly if there are not blocks attached
+ //
+ if (blockList == NULL)
+ return;
+
+ if (blockList == oldBlock)
+ {
+ blockList = oldBlock->next;
+ oldBlock->SetNexus(NULL);
+ }
+ else
+ {
+ // Bug fix MTH 6/17/2002: old version detached intervening blocks as well
+ //
+ NxsBlock *curr = blockList;
+ for (; curr->next != NULL && curr->next != oldBlock;)
+ curr = curr->next;
+
+ // Line below can be uncommented to find cases where Detach function is
+ // called for pointers that are not in the linked list. If line below is
+ // uncommented, the part of the descriptive comment that precedes this
+ // function about "...simply returns quietly" will be incorrect (at least
+ // in the Debugging version of the program where asserts are active).
+ //
+ //assert(curr->next == oldBlock);
+
+ if (curr->next == oldBlock)
+ {
+ curr->next = oldBlock->next;
+ oldBlock->SetNexus(NULL);
+ }
+ }
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Called by the NxsReader object when a block named `blockName' is entered. Allows derived class overriding this
+| function to notify user of progress in parsing the NEXUS file. Also gives program the opportunity to ask user if it
+| is ok to purge data currently contained in this block. If user is asked whether existing data should be deleted, and
+| the answer comes back no, then then the overrided function should return false, otherwise it should return true.
+| This (base class) version always returns true.
+*/
+bool NxsReader::EnteringBlock(
+ NxsString blockName) /* the name of the block just entered */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(blockName)
+# endif
+ return true;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Called by the NxsReader object when a block named `blockName' is being exited. Allows derived class overriding this
+| function to notify user of progress in parsing the NEXUS file.
+*/
+void NxsReader::ExitingBlock(
+ NxsString blockName) /* the name of the block being exited */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(blockName)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Reads the NxsReader data file from the input stream provided by `token'. This function is responsible for reading
+| through the name of a each block. Once it has read a block name, it searches `blockList' for a block object to
+| handle reading the remainder of the block's contents. The block object is responsible for reading the END or
+| ENDBLOCK command as well as the trailing semicolon. This function also handles reading comments that are outside
+| of blocks, as well as the initial "#NEXUS" keyword. The `notifyStartStop' argument is provided in case you do not
+| wish the ExecuteStart and ExecuteStop functions to be called. These functions are primarily used for creating and
+| destroying a dialog box to show progress, and nested Execute calls can thus cause problems (e.g., a dialog box is
+| destroyed when the inner Execute calls ExecuteStop and the outer Execute still expects the dialog box to be
+| available). Specifying `notifyStartStop' false for all the nested Execute calls thus allows the outermost Execute
+| call to control creation and destruction of the dialog box.
+*/
+void NxsReader::Execute(
+ NxsToken &token, /* the token object used to grab NxsReader tokens */
+ bool notifyStartStop) /* if true, ExecuteStarting and ExecuteStopping will be called */
+ {
+ char id_str[256];
+ currBlock = NULL;
+
+ bool disabledBlock = false;
+ NxsString errormsg;
+
+ try
+ {
+ token.GetNextToken();
+ }
+ catch (NxsException x)
+ {
+ NexusError(token.errormsg, 0, 0, 0);
+ return;
+ }
+
+ if (!token.Equals("#NEXUS"))
+ {
+ errormsg = "Expecting #NEXUS to be the first token in the file, but found ";
+ errormsg += token.GetToken();
+ errormsg += " instead";
+ NexusError(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
+ return;
+ }
+
+ if (notifyStartStop)
+ ExecuteStarting();
+
+ for (;;)
+ {
+ token.SetLabileFlagBit(NxsToken::saveCommandComments);
+ token.GetNextToken();
+
+ if (token.AtEOF())
+ break;
+
+ if (token.Equals("BEGIN"))
+ {
+ disabledBlock = false;
+ token.GetNextToken();
+
+ for (currBlock = blockList; currBlock != NULL; currBlock = currBlock->next)
+ {
+ if (token.Equals(currBlock->GetID()))
+ {
+ if (currBlock->IsEnabled())
+ {
+ strcpy(id_str, currBlock->GetID().c_str());
+ bool ok_to_read = EnteringBlock(id_str);
+ if (!ok_to_read)
+ currBlock = NULL;
+ else
+ {
+ currBlock->Reset();
+
+ // We need to back up currBlock, because the Read statement might trigger
+ // a recursive call to Execute (if the block contains instructions to execute
+ // another file, then the same NxsReader object may be used and any member fields (e.g. currBlock)
+ // could be trashed.
+ //
+ NxsBlock *tempBlock = currBlock;
+
+ try
+ {
+ currBlock->Read(token);
+ currBlock = tempBlock;
+ }
+
+ catch (NxsException x)
+ {
+ currBlock = tempBlock;
+ if (currBlock->errormsg.length() > 0)
+ NexusError(currBlock->errormsg, x.pos, x.line, x.col);
+ else
+ NexusError(x.msg, x.pos, x.line, x.col);
+ currBlock = NULL;
+ return;
+ } // catch (NxsException x)
+ ExitingBlock(id_str /*currBlock->GetID()*/);
+ } // else
+ } // if (currBlock->IsEnabled())
+
+ else
+ {
+ disabledBlock = true;
+ SkippingDisabledBlock(token.GetToken());
+ }
+ break;
+ } // if (token.Equals(currBlock->GetID()))
+ } // for (currBlock = blockList; currBlock != NULL; currBlock = currBlock->next)
+
+ if (currBlock == NULL)
+ {
+ token.BlanksToUnderscores();
+ NxsString currBlockName = token.GetToken();
+
+ if (!disabledBlock)
+ SkippingBlock(currBlockName);
+
+ for (;;)
+ {
+ token.SetLabileFlagBit(token.hyphenNotPunctuation);
+ token.GetNextToken();
+
+ if (token.Equals("END") || token.Equals("ENDBLOCK"))
+ {
+ token.GetNextToken();
+
+ if (!token.Equals(";"))
+ {
+ errormsg = "Expecting ';' after END or ENDBLOCK command, but found ";
+ errormsg += token.GetToken();
+ errormsg += " instead";
+ NexusError(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
+ return;
+ }
+ break;
+ }
+
+ if (token.AtEOF())
+ {
+ errormsg = "Encountered end of file before END or ENDBLOCK in block ";
+ errormsg += currBlockName;
+ NexusError(errormsg, token.GetFilePosition(), token.GetFileLine(), token.GetFileColumn());
+ return;
+ }
+ } // for (;;)
+ } // if (currBlock == NULL)
+ currBlock = NULL;
+ } // if (token.Equals("BEGIN"))
+
+ else if (token.Equals("&SHOWALL"))
+ {
+ for (NxsBlock* showBlock = blockList; showBlock != NULL; showBlock = showBlock->next)
+ {
+ DebugReportBlock(*showBlock);
+ }
+ }
+
+ else if (token.Equals("&LEAVE"))
+ {
+ break;
+ }
+
+ } // for (;;)
+
+ if (notifyStartStop)
+ ExecuteStopping();
+
+ currBlock = NULL;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns a string containing the copyright notice for the NxsReader Class Library, useful for reporting the use of
+| this library by programs that interact with the user.
+*/
+const char *NxsReader::NCLCopyrightNotice()
+ {
+ return NCL_COPYRIGHT;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns a string containing the URL for the NxsReader Class Library internet home page.
+*/
+const char *NxsReader::NCLHomePageURL()
+ {
+ return NCL_HOMEPAGEURL;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns a string containing the name and current version of the NxsReader Class Library, useful for reporting the
+| use of this library by programs that interact with the user.
+*/
+const char *NxsReader::NCLNameAndVersion()
+ {
+ return NCL_NAME_AND_VERSION;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Called just after Execute member function reads the opening "#NEXUS" token in a NEXUS data file. Override this
+| virtual base class function if your application needs to do anything at this point in the execution of a NEXUS data
+| file (e.g. good opportunity to pop up a dialog box showing progress). Be sure to call the Execute function with the
+| `notifyStartStop' argument set to true, otherwise ExecuteStarting will not be called.
+|
+*/
+void NxsReader::ExecuteStarting()
+ {
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Called when Execute member function encounters the end of the NEXUS data file, or the special comment [&LEAVE] is
+| found between NEXUS blocks. Override this virtual base class function if your application needs to do anything at
+| this point in the execution of a NEXUS data file (e.g. good opportunity to hide or destroy a dialog box showing
+| progress). Be sure to call the Execute function with the `notifyStartStop' argument set to true, otherwise
+| ExecuteStopping will not be called.
+*/
+void NxsReader::ExecuteStopping()
+ {
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Called when an error is encountered in a NEXUS file. Allows program to give user details of the error as well as
+| the precise location of the error.
+*/
+void NxsReader::NexusError(
+ NxsString msg, /* the error message to be displayed */
+ file_pos pos, /* the current file position */
+ long line, /* the current file line */
+ long col) /* the current column within the current file line */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(msg, pos, line, col)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This function may be used to report progess while reading through a file. For example, the NxsAllelesBlock class
+| uses this function to report the name of the population it is currently reading so the user doesn't think the
+| program has hung on large data sets.
+*/
+void NxsReader::OutputComment(
+ const NxsString &comment) /* a comment to be shown on the output */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(comment)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This function is called when an unknown block named `blockName' is about to be skipped. Override this pure virtual
+| function to provide an indication of progress as the NEXUS file is being read.
+*/
+void NxsReader::SkippingBlock(
+ NxsString blockName) /* the name of the block being skipped */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(blockName)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This function is called when a disabled block named `blockName' is encountered in a NEXUS data file being executed.
+| Override this pure virtual function to handle this event in an appropriate manner. For example, the program may
+| wish to inform the user that a data block was encountered in what is supposed to be a tree file.
+*/
+void NxsReader::SkippingDisabledBlock(
+ NxsString blockName) /* the name of the disabled block being skipped */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(blockName)
+# endif
+ }
+
=====================================
libraries/ncl/nxsreader.h
=====================================
@@ -0,0 +1,78 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#ifndef NCL_NXSREADER_H
+#define NCL_NXSREADER_H
+#include <climits>
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This is the class that orchestrates the reading of a NEXUS data file. An object of this class should be created,
+| and objects of any block classes that are expected to be needed should be added to `blockList' using the Add
+| member function. The Execute member function is then called, which reads the data file until encountering a block
+| name, at which point the correct block is looked up in `blockList' and that object's Read method called.
+*/
+class NxsReader
+ {
+ public:
+ enum NxsTolerateFlags /* Flags used with data member tolerate used to allow some flexibility with respect to the NEXUS format */
+ {
+ allowMissingInEquate = 0x0001, /* if set, equate symbols are allowed for missing data symbol */
+ allowPunctuationInNames = 0x0002 /* if set, some punctuation is allowed within tokens representing labels for taxa, characters, and sets */
+ };
+
+ NxsReader();
+ virtual ~NxsReader();
+
+ bool BlockListEmpty();
+ unsigned PositionInBlockList(NxsBlock *b);
+ void Add(NxsBlock *newBlock);
+ void Detach(NxsBlock *newBlock);
+ void Reassign(NxsBlock *oldb, NxsBlock *newb);
+ void Execute(NxsToken& token, bool notifyStartStop = true);
+
+ virtual void DebugReportBlock(NxsBlock &nexusBlock);
+
+ const char *NCLNameAndVersion();
+ const char *NCLCopyrightNotice();
+ const char *NCLHomePageURL();
+
+ virtual void ExecuteStarting();
+ virtual void ExecuteStopping();
+
+ virtual bool EnteringBlock(NxsString blockName);
+ virtual void ExitingBlock(NxsString blockName);
+
+ virtual void OutputComment(const NxsString &comment);
+
+ virtual void NexusError(NxsString msg, file_pos pos, long line, long col);
+
+ virtual void SkippingDisabledBlock(NxsString blockName);
+ virtual void SkippingBlock(NxsString blockName);
+
+ protected:
+
+ NxsBlock *blockList; /* pointer to first block in list of blocks */
+ NxsBlock *currBlock; /* pointer to current block in list of blocks */
+ };
+
+typedef NxsBlock NexusBlock;
+typedef NxsReader Nexus;
+
+#endif
+
=====================================
libraries/ncl/nxsstring.cpp
=====================================
@@ -0,0 +1,896 @@
+// Copyright (C) 1999-2003 Paul O. Lewis and Mark T. Holder
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#include "ncl.h"
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Capitalizes every character in the stored string.
+*/
+NxsString &NxsString::ToUpper()
+ {
+ for (NxsString::iterator sIt = begin(); sIt != end(); sIt++)
+ *sIt = (char) toupper(*sIt);
+ return *this;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Appends a string representation of the supplied double to the stored string and returns a reference to itself.
+*/
+NxsString &NxsString::operator+=(
+ const double d) /* the double value to append */
+ {
+ char tmp[81];
+
+ // Create a C-string representing the supplied double value.
+ // The # causes a decimal point to always be output.
+ //
+ snprintf(tmp, sizeof(tmp), "%#3.6f", d);
+ unsigned tmplen = (unsigned)strlen(tmp);
+
+ // If the C-string has a lot of trailing zeros, lop them off
+ //
+ for (;;)
+ {
+ if (tmplen < 3 || tmp[tmplen-1] != '0' || tmp[tmplen-2] == '.')
+ break;
+ tmp[tmplen-1] = '\0';
+ tmplen--;
+ }
+
+ append(tmp);
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Adds `n' copies of the character `c' to the end of the stored string and returns a reference to itself.
+*/
+NxsString &NxsString::AddTail(
+ char c, /* the character to use in the appended tail */
+ unsigned n) /* the number of times `c' is to be appended */
+ {
+ char s[2];
+ s[0] = c;
+ s[1] = '\0';
+
+ for (unsigned i = 0; i < n; i++)
+ append(s);
+
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Replaces the stored string with a copy of itself surrounded by single quotes (single quotes inside the string are
+| converted to the '' pair of characters that signify a single quote). Returns a reference to itself.
+*/
+NxsString &NxsString::AddQuotes()
+ {
+ NxsString withQuotes;
+ int len = length();
+ withQuotes.reserve(len + 4);
+ withQuotes += '\'';
+ for (NxsString::const_iterator sIt = begin(); sIt != end(); sIt++)
+ {
+ withQuotes += *sIt;
+ if (*sIt == '\'')
+ withQuotes += '\'';
+ }
+ withQuotes += '\'';
+ *this = withQuotes;
+
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Appends a printf-style formatted string onto the end of this NxsString and returns the number of characters added to the
+| string. For example, the following code would result in the string s being set to "ts-tv rate ratio = 4.56789":
+|>
+| double kappa = 4.56789;
+| NxsString s;
+| s.PrintF("ts-tv rate ratio = %.5f", kappa);
+|>
+*/
+int NxsString::PrintF(
+ const char *formatStr, /* the printf-style format string */
+ ...) /* other arguments referred to by the format string */
+ {
+ const int kInitialBufferSize = 256;
+ char buf[kInitialBufferSize];
+
+ // Create a pointer to the list of optional arguments
+ //
+ va_list argList;
+
+ // Set arg_ptr to the first optional argument in argList. The
+ // second argument (formatStr) is the last non-optional argument.
+ //
+ va_start(argList, formatStr);
+
+ // If vsnprintf returns -1, means kInitialBufferSize was not large enough.
+ // In this case, only kInitialBufferSize bytes are written.
+ //
+ int nAdded = vsnprintf(buf, kInitialBufferSize, formatStr, argList);
+
+ // Reset the argument list pointer
+ //
+ va_end(argList);
+
+ // Currently, if formatted string is too long to fit into the supplied buf,
+ // just adding a terminating '\0' and returning the truncated string
+ // Need to think of a better solution
+ //
+ if (nAdded < 0 || nAdded >= kInitialBufferSize)
+ buf[kInitialBufferSize - 1] = '\0';
+
+ *this << buf;
+
+#if 0
+ // This part not being used anymore because there seems to be some differences
+ // between compilers in what is returned from the vsnprintf function. VC returns
+ // -1 if string is too long, Metrowerks returns the number of bytes that it would
+ // have used had there been enough space!
+ //
+
+ if (nAdded >= kInitialBufferSize)
+ {
+ char *tempbuf = new char[nAdded + 2];
+
+ va_list argList;
+ va_start(argList, formatStr);
+
+ unsigned newNAdded = vsnprintf(tempbuf, nAdded + 1, formatStr, argList);
+
+ va_end(argList);
+
+ assert(nAdded == newNAdded);
+
+ *this << tempbuf;
+ delete [] tempbuf;
+ }
+ else
+ *this << buf;
+
+#endif
+
+ return nAdded;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns true if the string is a abbreviation (or complete copy) of the argument `s'.
+*/
+bool NxsString::IsStdAbbreviation(
+ const NxsString &s, /* the string for which the stored string is potentially an abbreviation */
+ bool respectCase) /* if true, comparison will be case-sensitive */
+ const
+ {
+ if (empty())
+ return false;
+
+ // s is the unabbreviated comparison string
+ //
+ const unsigned slen = static_cast<unsigned long>(s.size());
+
+ // t is the stored string
+ //
+ const unsigned tlen = static_cast<unsigned long>(size());
+
+ // t cannot be an abbreviation of s if it is longer than s
+ //
+ if (tlen > slen)
+ return false;
+
+ // Examine each character in t and return false (meaning "not an abbreviation")
+ // if at any point the corresponding character in s is different
+ //
+ for (unsigned k = 0; k < tlen; k++)
+ {
+ if (respectCase)
+ {
+ if ((*this)[k] != s[k])
+ return false;
+ }
+ else if (toupper((*this)[k]) != toupper(s[k]))
+ return false;
+ }
+
+ return true;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns true if the stored string is a case-insensitive abbreviation (or complete copy) of `s' and the stored string
+| has all of the characters that are in the initial capitalized portion of `s'. For example if `s' is "KAPpa" then
+| "kappa", "kapp", or "kap" (with any capitalization pattern) will return true and all other strings will return false.
+| Always returns false if the stored string has length of zero.
+*/
+bool NxsString::IsCapAbbreviation(
+ const NxsString &s) /* the string for which the stored string is potentially an abbreviation */
+ const
+ {
+ if (empty())
+ return false;
+
+ // s is the unabbreviated comparison string
+ //
+ const unsigned slen = static_cast<unsigned>(s.size());
+
+ // t is the stored string
+ //
+ const unsigned tlen = static_cast<unsigned>(size());
+
+ // If the stored string is longer than s then it cannot be an abbreviation of s
+ //
+ if (tlen > slen)
+ return false;
+
+ unsigned k = 0;
+ for (; k < slen; k++)
+ {
+ if (isupper(s[k]))
+ {
+ // If still in the uppercase portion of s and we've run out of characters
+ // in t, then t is not a valid abbrevation of s
+ //
+ if (k >= tlen)
+ return false;
+
+ // If kth character in t is not equal to kth character in s, then
+ // t is not an abbrevation of s
+ //
+ char tokenChar = (char)toupper((*this)[k]);
+ if (tokenChar != s[k])
+ return false;
+ }
+ else if (!isalpha(s[k]))
+ {
+ // Get here if we are no longer in the upper case portion of s and
+ // s[k] is not an alphabetic character. This section is necessary because
+ // we are dealing with a section of s that is not alphabetical and thus
+ // we cannot tell whether this should be part of the abbrevation or not
+ // (i.e. we cannot tell if it is capitalized or not). In this case, we
+ // pretend that we are still in the upper case portion of s and return
+ // false if we have run out of characters in t (meaning that the abbreviation
+ // was too short) or we find a mismatch.
+ //
+ if (k >= tlen)
+ return false;
+
+ if ((*this)[k] != s[k])
+ return false;
+ }
+ else
+ {
+ // Get here if we are no longer in the upper case portion of s and
+ // s[k] is an alphabetic character. Just break because we have determined
+ // that t is in fact a valid abbreviation of s.
+ //
+ break;
+ }
+ }
+
+ // Check the lower case portion of s and any corresponding characters in t for mismatches
+ // Even though the abbreviation is valid up to this point, it will become invalid if
+ // any mismatches are found beyond the upper case portion of s
+ //
+ for (; k < tlen; k++)
+ {
+ const char tokenChar = (char)toupper((*this)[k]);
+ const char otherChar = (char)toupper(s[k]);
+ if (tokenChar != otherChar)
+ return false;
+ }
+
+ return true;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Right-justifies `x' in a field `w' characters wide, using blank spaces to fill in unused portions on the left-hand
+| side of the field. Specify true for `clear_first' to first empty the string. Assumes `w' is large enough to
+| accommodate the string representation of `x'.
+*/
+NxsString &NxsString::RightJustifyLong(
+ long x, /* long value to right justify */
+ unsigned int w, /* width of field */
+ bool clear_first) /* if true, initialize string first to empty string */
+ {
+ bool x_negative = (x < 0L ? true : false);
+ unsigned long xabs = (x_negative ? (-x) : x);
+ unsigned num_spaces = w;
+
+ // If w = 10 and x = 123, we need 7 blank spaces before x
+ // log10(123) is 2.09, indicating that x is at least 10^2 = 100 but not
+ // 10^3 = 1000, thus x requires at least 3 characters to display
+ //
+ unsigned x_width = (x == 0 ? 1 :1 + (int)log10((double)xabs));
+ if (x_negative)
+ x_width++; // for the minus sign
+
+ assert(x_width <= num_spaces);
+ num_spaces -= x_width;
+
+ if (clear_first)
+ erase();
+
+ for (unsigned k = 0; k < num_spaces; k++)
+ *this += ' ';
+
+ if (x_negative)
+ *this += '-';
+
+ *this += xabs;
+ return *this;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Right-justifies `x' in a field `w' characters wide with precision `p', using blank spaces to fill in unused
+| portions on the left-hand side of the field. Specify true for `clear_first' to first empty the string. Assumes that
+| the specified width is enough to accommodate the string representation of `x'.
+*/
+NxsString &NxsString::RightJustifyDbl(
+ double x, /* double value to right justify */
+ unsigned w, /* width of field */
+ unsigned p, /* precision to use when displaying `x' */
+ bool clear_first) /* if true, initialize stored string first to the empty string */
+ {
+ if (clear_first)
+ erase();
+
+ char fmtstr[81];
+ snprintf(fmtstr, sizeof(fmtstr), "%%.%df", p);
+ NxsString tmp;
+ tmp.PrintF(fmtstr, x);
+
+ unsigned num_spaces = w - tmp.length();
+ assert(num_spaces >= 0);
+
+ for (unsigned k = 0; k < num_spaces; k++)
+ *this += ' ';
+
+ *this += tmp;
+ return *this;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Right-justifies `s' in a field `w' characters wide, using blank spaces to fill in unused portions on the left-hand
+| side of the field. Specify true for `clear_first' to first empty the string. Assumes that the specified width is
+| enough to accommodate `s'.
+*/
+NxsString &NxsString::RightJustifyString(
+ const NxsString &s, /* string to right justify */
+ unsigned w, /* width of field */
+ bool clear_first) /* if true, initialize string first to the empty string */
+ {
+ if (clear_first)
+ erase();
+
+ unsigned num_spaces = w - s.length();
+ assert(num_spaces >= 0);
+
+ for (unsigned k = 0; k < num_spaces; k++)
+ *this += ' ';
+
+ *this += s;
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns true if the string needs to be surrounded by single-quotes to make it a single nexus token.
+*/
+bool NxsString::QuotesNeeded() const
+ {
+ bool quotes_needed = false;
+
+ for (NxsString::const_iterator sIt = begin(); sIt != end(); sIt++)
+ {
+ char c = (*sIt);
+
+ if (!isgraph(c))
+ {
+ // The standard C function isgraph returns zero if c is either a space or is not a printable character.
+ //
+ quotes_needed = true;
+ }
+ else if (strchr("(){}\"-]/\\,;:=*`+<>", c) != NULL)
+ {
+ // Get here if c is any NEXUS punctuation mark except left square bracket ([) or apostrophe (').
+ // Left square bracket characters and apostrophes never get returned as punctuation by NxsToken,
+ // so we should never encounter them here.
+ //
+
+ if (length() > 1)
+ quotes_needed = true;
+ }
+ else if (c == '\'' || c == '[')
+ {
+ // Get here if c is either an apostrophe or left square bracket. Quotes are needed if one of these
+ // characters is all there is to this string
+ //
+ //@POL Mark, I'm confused.
+ //
+ quotes_needed = true;
+ }
+
+ if (quotes_needed)
+ break;
+ }
+
+ return quotes_needed;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Converts any blank spaces found in the stored string to the underscore character.
+*/
+NxsString &NxsString::BlanksToUnderscores()
+ {
+ unsigned len = length();
+ for (unsigned k = 0; k < len; k++)
+ {
+ char &ch = at(k);
+ if (ch == ' ')
+ ch = '_';
+ }
+ return *this;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Converts any underscore characters found in the stored string to blank spaces.
+*/
+NxsString &NxsString::UnderscoresToBlanks()
+ {
+ unsigned len = length();
+ for (unsigned k = 0; k < len; k++)
+ {
+ char &ch = at(k);
+ if (ch == '_')
+ ch = ' ';
+ }
+ return *this;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Shortens stored string to `n' - 3 characters, making the last three characters "...". If string is already less than
+| `n' characters in length, this function has no effect. This is useful when it is desirable to show some of the
+| contents of a string, even when the string will not fit in its entirety into the space available for displaying it.
+| Assumes that `n' is at least 4.
+*/
+NxsString &NxsString::ShortenTo(
+ unsigned n) /* maximum number of characters available for displaying the string */
+ {
+ assert(n > 3);
+ if (length() <= static_cast<unsigned>(n))
+ return *this;
+
+ NxsString s;
+ for (NxsString::iterator sIt = begin(); sIt != end(); sIt++)
+ {
+ s += (*sIt);
+ if (s.length() >= n - 3)
+ break;
+ }
+ s += "...";
+
+ *this = s;
+ return *this;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Converts every character in the stored string to its lower case equivalent.
+*/
+NxsString &NxsString::ToLower()
+ {
+ for (NxsString::iterator sIt = begin(); sIt != end(); sIt++)
+ {
+ char c = (char)tolower(*sIt);
+ *sIt = c;
+ }
+ return *this;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if the stored string can be interpreted as a double value, and returns false otherwise.
+*/
+bool NxsString::IsADouble() const
+ {
+ const char *str = c_str();
+ unsigned i = 0;
+ bool hadDecimalPt = false;
+ bool hadExp = false;
+ bool hadDigit = false;
+ bool hadDigitInExp = false;
+
+ // First char can be -
+ //
+ if (str[i]=='-')
+ i++;
+
+ while (str[i])
+ {
+ if (isdigit(str[i]))
+ {
+ // Digits are always OK
+ //
+ if (hadExp)
+ hadDigitInExp = true;
+ else
+ hadDigit = true;
+ }
+ else if (str[i] == '.')
+ {
+ // One decimal point is allowed and it must be before the exponent
+ //
+ if (hadExp || hadDecimalPt)
+ return false;
+ hadDecimalPt = true;
+ }
+ else if (str[i] == 'e' || str[i] == 'E')
+ {
+ // One e is allowed, but it must be after at least one digit
+ //
+ if (hadExp || !hadDigit)
+ return false;
+ hadExp = true;
+ }
+ else if (str[i] == '-')
+ {
+ // Another - is allowed if it is preceded by e
+ //
+ if (!hadExp || (str[i-1] != 'e' && str[i-1] != 'E') )
+ return false;
+ }
+ else
+ return false;
+ i++;
+ }
+
+ if (hadExp)
+ {
+ if (hadDigitInExp)
+ return true;
+ return false;
+ }
+
+ if (hadDigit)
+ return true;
+ return false;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if stored string can be interpreted as a long integer.
+*/
+bool NxsString::IsALong() const
+ {
+ const char *str = c_str();
+ unsigned i = 0;
+
+ // First char can be -
+ //
+ if (str[i]=='-')
+ i++;
+
+ if (!isdigit(str[i]))
+ return false;
+
+ while (str[i])
+ {
+ if (!isdigit(str[i]))
+ return false;
+ i++;
+ }
+
+ return true;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns true if the stored string is a non-case-sensitive copy of the argument `s'. Note: will return true if both the
+| stored string and `s' are empty strings.
+*/
+bool NxsString::EqualsCaseInsensitive(
+ const NxsString &s) /* the comparison string */
+ const
+ {
+ unsigned k;
+ unsigned slen = s.size();
+ unsigned tlen = size();
+ if (slen != tlen)
+ return false;
+
+ for (k = 0; k < tlen; k++)
+ {
+ if ((char)toupper((*this)[k]) != (char)toupper(s[k]))
+ return false;
+ }
+
+ return true;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Creates a string representation of the hexadecimal version of the long integer `p'. For example, if `p' equals 123,
+| and if 2 was specified for `nFours', the resulting string would be "7B". If 4 was specified for `nFours', then the
+| resulting string would be "007B".
+*/
+NxsString NxsString::ToHex(
+ long p, /* the value to display in hexadecimal */
+ unsigned nFours) /* the number of hexadecimal digits to display */
+ {
+ NxsString s;
+ char decod[] = "0123456789ABCDEF";
+ for (int i = nFours - 1; i >= 0 ; i--)
+ {
+ unsigned long k = (p >> (4*i));
+ unsigned long masked = (k & 0x000f);
+ s += decod[masked];
+ }
+ return s;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Checks to see if the stored string begins with upper case letters and, if so, returns all of the contiguous capitalized
+| prefix. If the stored string begins with lower case letters, an empty string is returned.
+*/
+NxsString NxsString::UpperCasePrefix() const
+ {
+ NxsString x;
+ unsigned i = 0;
+ while (i < size() && isupper((*this)[i]))
+ x += (*this)[i++];
+ return x;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Converts the stored string to an unsigned int using the standard C function strtol, throwing NxsX_NotANumber if the
+| conversion fails. Returns UINT_MAX if the number is too large to fit in an unsigned (or was a negative number).
+*/
+unsigned NxsString::ConvertToUnsigned() const
+ {
+ long l = ConvertToLong();
+ if (l < 0 || l >UINT_MAX)
+ return UINT_MAX;
+ return static_cast<unsigned> (l);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Converts the stored string to an int using the standard C function strtol, throwing NxsX_NotANumber if the conversion
+| fails. Returns INT_MAX if the number is too large to fit in an int or -INT_MAX if it is too small.
+*/
+int NxsString::ConvertToInt() const
+ {
+ long l = ConvertToLong();
+ if (l == LONG_MAX || l > INT_MAX)
+ return INT_MAX;
+ if (l == -LONG_MAX || l <-INT_MAX)
+ return -INT_MAX;
+ return static_cast<int> (l);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Converts the stored string to a long using the standard C function strtol, throwing NxsX_NotANumber if the conversion
+| fails.
+*/
+long NxsString::ConvertToLong() const
+ {
+ if (length() == 0 || !(isdigit(at(0)) || at(0) == '-'))
+ throw NxsX_NotANumber();
+ const char *b = c_str();
+ char *endP;
+ long l = strtol(b, &endP, 10);
+ if (l == 0 && endP == b)
+ throw NxsX_NotANumber();
+ return l;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Converts the stored string to a double using the standard C function strtod, throwing NxsX_NotANumber if the conversion
+| fails. Returns DBL_MAX or -DBL_MAX if the number is out of bounds.
+*/
+double NxsString::ConvertToDouble() const
+ {
+ if (length() == 0)
+ throw NxsX_NotANumber();
+
+ char ch = at(0);
+ if (isdigit(ch) || ch == '-' || ch == '.'|| toupper(ch) == 'E')
+ {
+ const char *b = c_str();
+ char *endP;
+ double d = strtod(b, &endP);
+ if (d == 0.0 && endP == b)
+ throw NxsX_NotANumber();
+ if (d == HUGE_VAL)
+ return DBL_MAX;
+ if (d == -HUGE_VAL)
+ return -DBL_MAX;
+ return d;
+ }
+ throw NxsX_NotANumber();
+#if defined (DEMANDS_UNREACHABLE_RETURN)
+ return DBL_MAX;
+#endif
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Transforms the vector of NxsString objects by making them all lower case and then capitalizing the first portion of
+| them so that the capitalized portion is enough to uniquely specify each. Returns true if the strings are long enough
+| to uniquely specify each. Horrendously bad algorithm, but shouldn't be called often.
+*/
+bool SetToShortestAbbreviation(
+ NxsStringVector &strVec, /* vector of NxsString objects */
+ bool allowTooShort) /* */
+ {
+ NxsStringVector upperCasePortion;
+ unsigned i;
+ for (i = 0; i < strVec.size(); i++)
+ {
+ // Change the next string to lower case
+ //
+ strVec[i].ToLower();
+
+ unsigned prefLen = 0;
+ NxsString pref;
+
+ if (prefLen >= strVec[i].size())
+ return false;
+ pref += (char) toupper(strVec[i][prefLen++]);
+ bool moreChars = true;
+
+ // Keep adding letters from the current string until pref is unique.
+ // Then add this pref to upperCasePortion (vector of previous prefs)
+ //
+ for (;moreChars;)
+ {
+ size_t prevInd = 0;
+ for (; prevInd < upperCasePortion.size(); prevInd++)
+ {
+ if (pref == upperCasePortion[prevInd])
+ {
+ // Conflict - both abbreviations need to grow
+ //
+ if (prefLen >= strVec[i].size())
+ {
+ if (allowTooShort)
+ {
+ if (prefLen < strVec[prevInd].size())
+ upperCasePortion[prevInd] += (char) toupper(strVec[prevInd][prefLen]);
+ moreChars = false;
+ break;
+ }
+ else
+ return false;
+ }
+ pref += (char) toupper(strVec[i][prefLen]);
+ if (prefLen >= strVec[prevInd].size())
+ {
+ if (allowTooShort)
+ {
+ prevInd = 0;
+ prefLen++;
+ break;
+ }
+ else
+ return false;
+ }
+ upperCasePortion[prevInd] += (char) toupper(strVec[prevInd][prefLen++]);
+ prevInd = 0;
+ break;
+ }
+ else
+ {
+ unsigned j;
+ for (j = 0; j < prefLen; j++)
+ {
+ if (pref[j] != upperCasePortion[prevInd][j])
+ break;
+ }
+ if (j == prefLen)
+ {
+ // pref agrees with the first part of another abbreviation, lengthen it.
+ //
+ if (prefLen >= strVec[i].size())
+ {
+ if (allowTooShort)
+ {
+ moreChars = false;
+ break;
+ }
+ else
+ return false;
+ }
+ pref += (char) toupper(strVec[i][prefLen++]);
+ break;
+ }
+ }
+ }
+ if (prevInd == upperCasePortion.size() || !moreChars)
+ {
+ // Made it all the way through with no problems, add this
+ // prefix as command i's upper case portion
+ //
+ upperCasePortion.push_back(pref);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < strVec.size(); i++)
+ {
+ for (size_t j = 0; j < upperCasePortion[i].size(); j++)
+ strVec[i][j] = upperCasePortion[i][j];
+ }
+
+ return true;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns a vector of NxsString objects that match the entire `testStr'.
+*/
+NxsStringVector GetVecOfPossibleAbbrevMatches(
+ const NxsString &testStr, /* string to match */
+ const NxsStringVector &possMatches) /* vector of possible matches */
+ {
+ NxsStringVector matches;
+ for (size_t i = 0; i < possMatches.size(); i++)
+ {
+ if (testStr.Abbreviates(possMatches[i]))
+ matches.push_back(possMatches[i]);
+ }
+ return matches;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Written to make it easy to initialize a vector of strings. Similar to the perl split function. Converts a string like
+| this -- "A|bro|ken strin|g" -- to a vector of strings with four elements: "A", "bro", "ken string", and "g".
+*/
+NxsStringVector BreakPipeSeparatedList(
+ const NxsString &strList) /* the string submitted for splitting */
+ {
+ NxsString::const_iterator p = strList.begin();
+ NxsString ss;
+ NxsStringVector retVec;
+ for (;;)
+ {
+ bool done = (p == strList.end());
+ if (done || (*p == '|'))
+ {
+ retVec.push_back(ss);
+ ss.clear();
+ if (done)
+ break;
+ p++;
+ }
+ ss += *p;
+ p++;
+ }
+ return retVec;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns true if the Equals comparison function is true for this or any element in the vector `s'.
+| (James B. 23-Jul-2020, moved this here, from nxsstring.h, because the references to NxsStringVector
+| were a problem when compiling in Visual Studio).
+*/
+bool NxsString::IsInVector(
+ const NxsStringVector& s, /* the vector of NxsString objects to be searched */
+ NxsString::CmpEnum mode) /* the argument passed to the Equals function, which is called for every element in the vector `s' */
+ const
+{
+ for (NxsStringVector::const_iterator sIt = s.begin(); sIt != s.end(); sIt++)
+ {
+ if (Equals(*sIt, mode))
+ return true;
+ }
+ return false;
+}
+
=====================================
libraries/ncl/nxsstring.h
=====================================
@@ -0,0 +1,601 @@
+// Copyright (C) 1999-2003 Paul O. Lewis and Mark T. Holder
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#ifndef NCL_NXSSTRING_H
+#define NCL_NXSSTRING_H
+
+#include <cassert>
+#include <cstring>
+#include <string>
+#include <vector> //for std::vector
+#include "nxsindent.h"
+#include <climits>
+
+class IndexSet;
+
+/*----------------------------------------------------------------------------------------------------------------------
+| A string class for use with the Nexus Class Library. NxsString inherits most of its functionality from the standard
+| template library class string, adding certain abilities needed for use in NCL, such as the ability to discern
+| whether a short string represents an abbreviation for the string currently stored. Another important addition is
+| the member function PrintF, which accepts a format string and an arbitrary number of arguments, allowing a string
+| to be built in a manner similar to the standard C function printf. Many operators are also provided for appending
+| numbers to the ends of strings, an ability which is very useful for producing default labels (e.g. taxon1, taxon2,
+| etc.).
+*/
+
+class NxsString
+ : public std::string
+ {
+ public:
+
+ class NxsX_NotANumber {}; /* exception thrown if attempt to convert string to a number fails */
+
+ enum CmpEnum /* enum that is used to specify string comparison modes */
+ {
+ respect_case,
+ no_respect_case,
+ abbrev
+ };
+
+ NxsString();
+ NxsString(const char *s);
+ NxsString(const NxsString &s);
+
+ // Accessors
+ //
+ bool Abbreviates(const NxsString &s, NxsString::CmpEnum mode = NxsString::no_respect_case) const;
+ unsigned ConvertToUnsigned() const;
+ int ConvertToInt() const;
+ long ConvertToLong() const;
+ double ConvertToDouble() const;
+ bool Equals(const NxsString &s, NxsString::CmpEnum mode = respect_case) const;
+ bool EqualsCaseInsensitive(const NxsString &s) const;
+ NxsString GetQuoted() const;
+ bool IsADouble() const;
+ bool IsALong() const;
+ bool IsCapAbbreviation(const NxsString &s) const;
+ bool IsInVector(const std::vector<NxsString> &s, NxsString::CmpEnum mode = respect_case) const;
+ bool IsStdAbbreviation(const NxsString &s, bool respectCase) const;
+ bool IsNexusPunctuation(const char c) const;
+ bool QuotesNeeded() const;
+ NxsString UpperCasePrefix() const;
+ friend std::ostream &operator<<(std::ostream &out, const NxsString &s);
+
+ // Modifiers
+ //
+ //NxsString &operator=(const NxsString &s);
+ NxsString &operator=(char);
+ NxsString &operator=(const char *s);
+ NxsString &operator+=(const char *s);
+ NxsString &operator+=(const NxsString &s);
+ NxsString &operator+=(const char c);
+ NxsString &operator+=(const int i);
+ NxsString &operator+=(unsigned i);
+ NxsString &operator+=(unsigned long i);
+ NxsString &operator+=(const long l);
+ NxsString &operator+=(const double d);
+ NxsString &operator+=(const IndexSet &d);
+ NxsString &operator<<(int i);
+ NxsString &operator<<(unsigned i);
+ NxsString &operator<<(long l);
+ NxsString &operator<<(unsigned long l);
+ NxsString &operator<<(double d);
+ NxsString &operator<<(const char *c);
+ NxsString &operator<<(char c);
+ NxsString &operator<<(const NxsString &s);
+ NxsString &operator<<(const IndexSet &s);
+ NxsString &operator<<(Indent) {return *this;} //@temp need a system for handling indentation
+ NxsString &operator<<(NxsString &(*funcPtr)(NxsString &));
+
+ // Functions that should be in base class string but aren't
+ void clear();
+
+ int PrintF(const char *formatStr, ...);
+
+ unsigned char *p_str(unsigned char *) const;
+
+ NxsString &AddQuotes();
+ NxsString &AddTail(char c, unsigned n);
+ NxsString &NumberThenWord(unsigned i, NxsString s);
+ NxsString &ShortenTo(unsigned n);
+ NxsString &AppendDouble(unsigned minFieldFormat, unsigned precFormat, double x);
+ NxsString &Capitalize();
+
+ NxsString &RightJustifyString(const NxsString &s, unsigned w, bool clear_first = false);
+ NxsString &RightJustifyLong(long x, unsigned w, bool clear_first = false);
+ NxsString &RightJustifyDbl(double x, unsigned w, unsigned p, bool clear_first = false);
+
+ NxsString &ToLower();
+ NxsString &ToUpper();
+
+ NxsString &BlanksToUnderscores();
+ NxsString &UnderscoresToBlanks();
+
+ // Debugging
+ //
+ static NxsString ToHex(long p, unsigned nFours);
+ };
+
+typedef std::vector<NxsString> NxsStringVector;
+
+#if defined (NXS_SUPPORT_OLD_NAMES)
+ typedef NxsString nxsstring;
+#endif
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Function object (Unary Predicate functor) that stores one string. The ()(const NxsString &) operator then returns the
+| result of a case-insensitive compare. Useful for STL find algorithms. Could be made faster than sequential case
+| insenstive comparisons, because the string stored in the object is just capitalized once.
+*/
+class NStrCaseInsensitiveEquals
+ {
+ public :
+
+ NStrCaseInsensitiveEquals(const NxsString &s);
+ bool operator()(const NxsString &s);
+
+ protected :
+
+ NxsString compStr;
+ };
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Function object (Unary Predicate functor) that stores one string. The ()(const NxsString &) operator then returns the
+| result of a case-sensitive compare. Useful for STL find algorithms.
+*/
+class NStrCaseSensitiveEquals
+ {
+ public :
+
+ NStrCaseSensitiveEquals(const NxsString &s);
+ bool operator()(const NxsString &s) const;
+
+ protected :
+
+ NxsString compStr;
+ };
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Binary function class that performs case-Insensitive string compares.
+*/
+/*struct NxsStringEqual
+ : public std::binary_function<NxsString, NxsString, bool>
+ {
+ bool operator()(const NxsString &x, const NxsString &y) const;
+ };*/
+
+// ############################# start NStrCaseInsensitiveEquals functions ##########################
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Creates a function object for case-insensitive comparisons of `s' to a container of strings.
+*/
+inline NStrCaseInsensitiveEquals::NStrCaseInsensitiveEquals(
+ const NxsString &s) /* the string to be compared */
+ {
+ compStr = s;
+ compStr.Capitalize();
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns the result of a case-sensitive compare of `s' and the string stored when the NStrCaseInsensitiveEquals object
+| was created. Could be made more efficient (currently capitalizes the entire argument even though the first character may
+| be wrong).
+*/
+inline bool NStrCaseInsensitiveEquals::operator()(
+ const NxsString &s) /* the string to be compared */
+ {
+ if (s.length() == compStr.length())
+ {
+ NxsString capS(s);
+ capS.Capitalize();
+ return capS == compStr;
+ }
+ return false;
+ }
+
+// ############################# start NStrCaseSensitiveEquals functions ##########################
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Creates a function object for case-sensitive comparisons of `s' to a container of strings.
+*/
+inline NStrCaseSensitiveEquals::NStrCaseSensitiveEquals(
+ const NxsString &s) /* the string that all other strings will be compared to when the (const NxsString &) operator is called */
+ {
+ compStr = s;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns the result of a case-sensitive compare of `s' and the string stored when the NStrCaseSensitiveEquals was
+| created.
+*/
+inline bool NStrCaseSensitiveEquals::operator()(
+ const NxsString &s) /* the string to be compared */
+ const
+ {
+ return (compStr == s);
+ }
+
+// ############################# start NxsStringEqual functions ##########################
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if the strings `x' and `y' are identical (NOT case sensitive)
+*/
+/*inline bool NxsStringEqual::operator()(
+ const NxsString &x,
+ const NxsString &y)
+ const
+ {
+ return x.EqualsCaseInsensitive(y);
+ }*/
+
+// ############################# start NxsString functions ##########################
+
+/*----------------------------------------------------------------------------------------------------------------------
+| The default constructor.
+*/
+inline NxsString::NxsString()
+ : std::string()
+ {
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns a single-quoted version of the NxsString. The calling object is not altered. Written for ease of use. Simply
+| copies the stored string, then returns the copy after calling its AddQuotes function.
+*/
+inline NxsString NxsString::GetQuoted()
+ const
+ {
+ NxsString s(*this);
+ s.AddQuotes();
+ return s;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Most containers in the standard template library can be completely erased using the clear function, but none is
+| provided for the class string and hence is provided here.
+*/
+inline void NxsString::clear()
+ {
+ erase();
+ }
+
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| A copy constructor taking a C-string argument.
+*/
+inline NxsString::NxsString(
+ const char *s) /* the C-string that forms the basis for the new NxsString object */
+ {
+ assign(s);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| A copy constructor taking a NxsString reference argument.
+*/
+inline NxsString::NxsString(
+ const NxsString &s) /* reference to a NxsString to be used to create this copy */
+ {
+ assign(s);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Sets the stored string equal to the supplied C-string `s'.
+*/
+inline NxsString &NxsString::operator=(
+ const char *s) /* the string for comparison */
+ {
+ assign(s);
+ return *this;
+ }
+
+//inline NxsString& NxsString::operator=(
+// const NxsString &s)
+// {
+// assign(s);
+// return *this;
+// }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Appends the supplied C-string `s' to the stored string.
+*/
+inline NxsString &NxsString::operator+=(
+ const char *s) /* the C-string to be appended */
+ {
+ append(std::string(s));
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Appends the characters in the supplied NxsString reference `s' to the stored string.
+*/
+inline NxsString &NxsString::operator+=(
+ const NxsString &s) /* the string to append */
+ {
+ append(s);
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Appends the character `c' to the stored string.
+*/
+inline NxsString &NxsString::operator+=(
+ const char c) /* the character to append */
+ {
+ char s[2];
+ s[0] = c;
+ s[1] = '\0';
+ append(std::string(s));
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Sets the stored string to the supplied character 'c'.
+*/
+inline NxsString &NxsString::operator=(
+ char c) /* the character to which the stored string should be set */
+ {
+ clear();
+ return (*this += c);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Uses the standard C sprintf function to append the character representation of the supplied integer i' to the stored
+| string (format code %d). For example, if the stored string is "taxon" and `i' is 9, the result is "taxon9".
+*/
+inline NxsString &NxsString::operator+=(
+ const int i) /* the int to append */
+ {
+ char tmp[81];
+ snprintf(tmp, sizeof(tmp), "%d", i);
+ append(tmp);
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Capitalizes all lower case letters in the stored string by calling ToUpper.
+*/
+inline NxsString &NxsString::Capitalize()
+ {
+ ToUpper();
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns true if the stored string is an abbreviation (or complete copy) of the supplied string `s'.
+*/
+inline bool NxsString::Abbreviates(
+ const NxsString &s, /* the full comparison string */
+ NxsString::CmpEnum mode) /* if equal to abbrev, a non-case-sensitive comparison will be made, otherwise comparison will respect case */
+ const
+ {
+ if (mode == NxsString::abbrev)
+ return IsCapAbbreviation(s);
+ else
+ return IsStdAbbreviation(s, mode == respect_case);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Uses standard C function sprintf to append the unsigned integer `i' to the stored string (format code %u).
+*/
+inline NxsString& NxsString::operator+=(
+ unsigned i) /* the integer to be appended */
+ {
+ char tmp[81];
+ snprintf(tmp, sizeof(tmp), "%u", i);
+ append(tmp);
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Uses standard C function sprintf to append the long integer `l' to the stored string (format code %ld).
+*/
+inline NxsString& NxsString::operator+=(
+ const long l) /* the long integer to be appended */
+ {
+ char tmp[81];
+ snprintf(tmp, sizeof(tmp), "%ld", l);
+ append(tmp);
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Uses standard C function sprintf to append the unsigned long integer `l' to the stored string (format code %lu).
+*/
+inline NxsString& NxsString::operator+=(
+ const unsigned long l) /* the unsigned long integer to be appended */
+ {
+ char tmp[81];
+ snprintf(tmp, sizeof(tmp), "%lu", l);
+ append(tmp);
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Uses the mode argument to call (and return the result of) the correct string comparison function.
+*/
+inline bool NxsString::Equals(
+ const NxsString &s, /* the string to which *this is compared */
+ NxsString::CmpEnum mode) /* should be one of these three: respect_case, no_respect_case or abbrev */
+ const
+ {
+ switch (mode) {
+ case NxsString::respect_case :
+ return (strcmp(this->c_str(), s.c_str()) == 0);
+ case NxsString::no_respect_case :
+ return this->EqualsCaseInsensitive(s);
+ case NxsString::abbrev :
+ return this->IsCapAbbreviation(s);
+ default :
+ assert(0);// incorrect setting for mode
+ }
+ return false;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Allows functions that take and return references to NxsString strings to be placed in a series of << operators.
+| See the NxsString endl function.
+*/
+inline NxsString &NxsString::operator<<(
+ NxsString &(*funcPtr)(NxsString &)) /* pointer to a function returning a reference to a NxsString */
+ {
+ return funcPtr(*this);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns true if `c' is any Nexus punctuation character:
+|>
+| ()[]{}/\,;:=*'"`-+<>
+|>
+*/
+inline bool NxsString::IsNexusPunctuation(
+ const char c) /* the character in question */
+ const
+ {
+ return (strchr("()[]{}/\\,;:=*\'\"`-+<>", c) != 0);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Creates a new string (and returns a reference to the new string) composed of the integer `i' followed by a space and
+| then the string `s'. If `i' is not 1, then an 's' character is appended to make `s' plural. For example, if `i' were 0,
+| 1, or 2, and `s' is "character", then the returned string would be "0 characters", "1 character" or "2 characters",
+| respectively. Obviously this only works if adding an 's' to the supplied string makes it plural.
+*/
+inline NxsString &NxsString::NumberThenWord(
+ unsigned i, /* the number */
+ const NxsString s) /* the string needing to be pluralized */
+ {
+ (*this).erase();
+ *this << i << ' ' << s;
+ if (i != 1)
+ *this << 's';
+ return *this;
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ int i) /* the integer to append */
+ {
+ return (*this += i);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ unsigned i) /* the unsigned integer to append */
+ {
+ return (*this += (int) i);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ long l) /* the long integer to append */
+ {
+ return (*this += l);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ unsigned long l) /* the unsigned long integer to append */
+ {
+ return (*this += l);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ double d) /* the double floating point value to append */
+ {
+ return (*this += d);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ const char *c) /* the C-string to append */
+ {
+ return (*this += c);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ char c) /* the char to append */
+ {
+ return (*this += c);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Another way to call the += operator (written to make it possible to use a NxsString like an ostream)
+*/
+inline NxsString &NxsString::operator<<(
+ const NxsString &s) /* the NxsString to append */
+ {
+ return (*this += s);
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Returns string as a Pascal string (array of unsigned characters with the length in the first byte).
+*/
+inline unsigned char *NxsString::p_str(
+ unsigned char *buffer) /* buffer to receive current string in Pascal form (i.e. length in first byte) */
+ const
+ {
+ memmove(buffer + 1, c_str(), length());
+ buffer[0] = length();
+ return buffer;
+ }
+
+// ############################# start of standalone functions ##########################
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Appends a newline character to the string `s' and the returns a reference to `s'. Used with << operator to allow
+| strings to be written to like ostreams.
+*/
+inline NxsString &endl(
+ NxsString &s) /* the string to which the newline character is to be appended */
+ {
+ return (s += '\n');
+ }
+
+/*--------------------------------------------------------------------------------------------------------------------------
+| Writes the string `s' to the ostream `out'.
+*/
+inline std::ostream &operator<<(
+ std::ostream &out, /* the stream to which the string `s' is to be written */
+ const NxsString &s) /* the string to write */
+ {
+ out << s.c_str();
+ return out;
+ }
+
+NxsStringVector BreakPipeSeparatedList(const NxsString &strList);
+NxsStringVector GetVecOfPossibleAbbrevMatches(const NxsString &testStr,const NxsStringVector &possMatches);
+bool SetToShortestAbbreviation(NxsStringVector &strVec, bool allowTooShort = false);
+
+#endif
=====================================
libraries/ncl/nxstoken.cpp
=====================================
@@ -0,0 +1,622 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+#include "ncl.h"
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Sets atEOF and atEOL to false, comment and token to the empty string, filecol and fileline to 1, filepos to 0,
+| labileFlags to 0 and saved and special to the null character. Initializes the istream reference data
+| member in to the supplied istream `i'.
+*/
+NxsToken::NxsToken(
+ istream &i) /* the istream object to which the token is to be associated */
+ : in(i)
+ {
+ atEOF = false;
+ atEOL = false;
+ comment.clear();
+ filecol = 1L;
+ fileline = 1L;
+ filepos = 0L;
+ labileFlags = 0;
+ saved = '\0';
+ special = '\0';
+
+ whitespace[0] = ' ';
+ whitespace[1] = '\t';
+ whitespace[2] = '\n';
+ whitespace[3] = '\0';
+
+ punctuation[0] = '(';
+ punctuation[1] = ')';
+ punctuation[2] = '[';
+ punctuation[3] = ']';
+ punctuation[4] = '{';
+ punctuation[5] = '}';
+ punctuation[6] = '/';
+ punctuation[7] = '\\';
+ punctuation[8] = ',';
+ punctuation[9] = ';';
+ punctuation[10] = ':';
+ punctuation[11] = '=';
+ punctuation[12] = '*';
+ punctuation[13] = '\'';
+ punctuation[14] = '"';
+ punctuation[15] = '`';
+ punctuation[16] = '+';
+ punctuation[17] = '-';
+ punctuation[18] = '<';
+ punctuation[19] = '>';
+ punctuation[20] = '\0';
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Nothing needs to be done; all objects take care of deleting themselves.
+*/
+NxsToken::~NxsToken()
+ {
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Reads rest of comment (starting '[' already input) and acts accordingly. If comment is an output comment, and if
+| an output stream has been attached, writes the output comment to the output stream. Otherwise, output comments are
+| simply ignored like regular comments. If the labileFlag bit saveCommandComments is in effect, the comment (without
+| the square brackets) will be stored in token.
+*/
+void NxsToken::GetComment()
+ {
+ // Set comment level to 1 initially. Every ']' encountered reduces
+ // level by one, so that we know we can stop when level becomes 0.
+ //
+ int level = 1;
+
+ // Get first character
+ //
+ char ch = GetNextChar();
+ if (atEOF)
+ {
+ errormsg = "Unexpected end of file inside comment";
+ throw NxsException( errormsg, GetFilePosition(), GetFileLine(), GetFileColumn());
+ }
+
+ // See if first character is the output comment symbol ('!')
+ // or command comment symbol (&)
+ //
+ int printing = 0;
+ int command = 0;
+ if (ch == '!')
+ printing = 1;
+ else if (ch == '&' && labileFlags & saveCommandComments)
+ {
+ command = 1;
+ AppendToToken(ch);
+ }
+ else if (ch == ']')
+ return;
+
+ // Now read the rest of the comment
+ //
+ for(;;)
+ {
+ ch = GetNextChar();
+ if (atEOF)
+ break;
+
+ if (ch == ']')
+ level--;
+ else if (ch == '[')
+ level++;
+
+ if (level == 0)
+ break;
+
+ if (printing)
+ AppendToComment(ch);
+ else if (command)
+ AppendToToken(ch);
+ }
+
+ if (printing)
+ {
+ // Allow output comment to be printed or displayed in most appropriate
+ // manner for target operating system
+ //
+ OutputComment(comment);
+
+ // Now that we are done with it, free the memory used to store the comment
+ //
+ //comment;
+ }
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Reads rest of a token surrounded with curly brackets (the starting '{' has already been input) up to and including
+| the matching '}' character. All nested curly-bracketed phrases will be included.
+*/
+void NxsToken::GetCurlyBracketedToken()
+ {
+ // Set level to 1 initially. Every '}' encountered reduces
+ // level by one, so that we know we can stop when level becomes 0.
+ //
+ int level = 1;
+
+ char ch;
+ for(;;)
+ {
+ ch = GetNextChar();
+ if (atEOF)
+ break;
+
+ if (ch == '}')
+ level--;
+ else if (ch == '{')
+ level++;
+
+ AppendToToken(ch);
+
+ if (level == 0)
+ break;
+ }
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Gets remainder of a double-quoted NEXUS word (the first double quote character was read in already by GetNextToken).
+| This function reads characters until the next double quote is encountered. Tandem double quotes within a
+| double-quoted NEXUS word are not allowed and will be treated as the end of the first word and the beginning of the
+| next double-quoted NEXUS word. Tandem single quotes inside a double-quoted NEXUS word are saved as two separate
+| single quote characters; to embed a single quote inside a double-quoted NEXUS word, simply use the single quote by
+| itself (not paired with another tandem single quote).
+*/
+void NxsToken::GetDoubleQuotedToken()
+ {
+ char ch;
+
+ for(;;)
+ {
+ ch = GetNextChar();
+ if (atEOF)
+ break;
+
+ if (ch == '\"')
+ break;
+ else
+ AppendToToken(ch);
+ }
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Gets remainder of a quoted NEXUS word (the first single quote character was read in already by GetNextToken). This
+| function reads characters until the next single quote is encountered. An exception occurs if two single quotes occur
+| one after the other, in which case the function continues to gather characters until an isolated single quote is
+| found. The tandem quotes are stored as a single quote character in the token NxsString.
+*/
+void NxsToken::GetQuoted()
+ {
+ char ch;
+
+ for(;;)
+ {
+ ch = GetNextChar();
+ if (atEOF)
+ break;
+
+ if (ch == '\'' && saved == '\'')
+ {
+ // Paired single quotes, save as one single quote
+ //
+ AppendToToken(ch);
+ saved = '\0';
+ }
+ else if (ch == '\'' && saved == '\0')
+ {
+ // Save the single quote to see if it is followed by another
+ //
+ saved = '\'';
+ }
+ else if (saved == '\'')
+ {
+ // Previously read character was single quote but this is something else, save current character so that it will
+ // be the first character in the next token read
+ //
+ saved = ch;
+ break;
+ }
+ else
+ AppendToToken(ch);
+ }
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Reads rest of parenthetical token (starting '(' already input) up to and including the matching ')' character. All
+| nested parenthetical phrases will be included.
+*/
+void NxsToken::GetParentheticalToken()
+ {
+ // Set level to 1 initially. Every ')' encountered reduces
+ // level by one, so that we know we can stop when level becomes 0.
+ //
+ int level = 1;
+
+ char ch;
+ for(;;)
+ {
+ ch = GetNextChar();
+ if (atEOF)
+ break;
+
+ if (ch == ')')
+ level--;
+ else if (ch == '(')
+ level++;
+
+ AppendToToken(ch);
+
+ if (level == 0)
+ break;
+ }
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if token begins with the capitalized portion of `s' and, if token is longer than `s', the remaining
+| characters match those in the lower-case portion of `s'. The comparison is case insensitive. This function should be
+| used instead of the Begins function if you wish to allow for abbreviations of commands and also want to ensure that
+| user does not type in a word that does not correspond to any command.
+*/
+bool NxsToken::Abbreviation(
+ NxsString s) /* the comparison string */
+ {
+ int k;
+ int slen = s.size();
+ int tlen = token.size();
+ char tokenChar, otherChar;
+
+ // The variable mlen refers to the "mandatory" portion
+ // that is the upper-case portion of s
+ //
+ int mlen;
+ for (mlen = 0; mlen < slen; mlen++)
+ {
+ if (!isupper(s[mlen]))
+ break;
+ }
+
+ // User must have typed at least mlen characters in
+ // for there to even be a chance at a match
+ //
+ if (tlen < mlen)
+ return false;
+
+ // If user typed in more characters than are contained in s,
+ // then there must be a mismatch
+ //
+ if (tlen > slen)
+ return false;
+
+ // Check the mandatory portion for mismatches
+ //
+ for (k = 0; k < mlen; k++)
+ {
+ tokenChar = (char)toupper( token[k]);
+ otherChar = s[k];
+ if (tokenChar != otherChar)
+ return false;
+ }
+
+ // Check the auxiliary portion for mismatches (if necessary)
+ //
+ for (k = mlen; k < tlen; k++)
+ {
+ tokenChar = (char)toupper( token[k]);
+ otherChar = (char)toupper( s[k]);
+ if (tokenChar != otherChar)
+ return false;
+ }
+
+ return true;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if token NxsString begins with the NxsString `s'. This function should be used instead of the Equals
+| function if you wish to allow for abbreviations of commands.
+*/
+bool NxsToken::Begins(
+ NxsString s, /* the comparison string */
+ bool respect_case) /* determines whether comparison is case sensitive */
+ {
+ unsigned k;
+ char tokenChar, otherChar;
+
+ unsigned slen = s.size();
+ if (slen > token.size())
+ return false;
+
+ for (k = 0; k < slen; k++)
+ {
+ if (respect_case)
+ {
+ tokenChar = token[k];
+ otherChar = s[k];
+ }
+ else
+ {
+ tokenChar = (char)toupper( token[k]);
+ otherChar = (char)toupper( s[k]);
+ }
+
+ if (tokenChar != otherChar)
+ return false;
+ }
+
+ return true;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if token NxsString exactly equals `s'. If abbreviations are to be allowed, either Begins or
+| Abbreviation should be used instead of Equals.
+*/
+bool NxsToken::Equals(
+ NxsString s, /* the string for comparison to the string currently stored in this token */
+ bool respect_case) /* if true, comparison will be case-sensitive */
+ {
+ unsigned k;
+ char tokenChar, otherChar;
+
+ unsigned slen = s.size();
+ if (slen != token.size())
+ return false;
+
+ for (k = 0; k < token.size(); k++)
+ {
+ if (respect_case)
+ {
+ tokenChar = token[k];
+ otherChar = s[k];
+ }
+ else
+ {
+ tokenChar = (char)toupper( token[k]);
+ otherChar = (char)toupper( s[k]);
+ }
+ if (tokenChar != otherChar)
+ return false;
+ }
+
+ return true;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Reads characters from in until a complete token has been read and stored in token. GetNextToken performs a number
+| of useful operations in the process of retrieving tokens:
+|~
+| o any underscore characters encountered are stored as blank spaces (unless the labile flag bit preserveUnderscores
+| is set)
+| o if the first character of the next token is an isolated single quote, then the entire quoted NxsString is saved
+| as the next token
+| o paired single quotes are automatically converted to single quotes before being stored
+| o comments are handled automatically (normal comments are treated as whitespace and output comments are passed to
+| the function OutputComment which does nothing in the NxsToken class but can be overridden in a derived class to
+| handle these in an appropriate fashion)
+| o leading whitespace (including comments) is automatically skipped
+| o if the end of the file is reached on reading this token, the atEOF flag is set and may be queried using the AtEOF
+| member function
+| o punctuation characters are always returned as individual tokens (see the Maddison, Swofford, and Maddison paper
+| for the definition of punctuation characters) unless the flag ignorePunctuation is set in labileFlags,
+| in which case the normal punctuation symbols are treated just like any other darkspace character.
+|~
+| The behavior of GetNextToken may be altered by using labile flags. For example, the labile flag saveCommandComments
+| can be set using the member function SetLabileFlagBit. This will cause comments of the form [&X] to be saved as
+| tokens (without the square brackets), but only for the aquisition of the next token. Labile flags are cleared after
+| each application.
+*/
+void NxsToken::GetNextToken()
+ {
+ ResetToken();
+
+ char ch = ' ';
+ if (saved == '\0' || IsWhitespace(saved))
+ {
+ // Skip leading whitespace
+ //
+ while( IsWhitespace(ch) && !atEOF)
+ ch = GetNextChar();
+ saved = ch;
+ }
+
+ for(;;)
+ {
+ // Break now if singleCharacterToken mode on and token length > 0.
+ //
+ if (labileFlags & singleCharacterToken && token.size() > 0)
+ break;
+
+ // Get next character either from saved or from input stream.
+ //
+ if (saved != '\0')
+ {
+ ch = saved;
+ saved = '\0';
+ }
+ else
+ ch = GetNextChar();
+
+ // Break now if we've hit EOF.
+ //
+ if (atEOF)
+ break;
+
+ if (ch == '\n' && labileFlags & newlineIsToken)
+ {
+ if (token.size() > 0)
+ {
+ // Newline came after token, save newline until next time when it will be
+ // reported as a separate token.
+ //
+ atEOL = 0;
+ saved = ch;
+ }
+ else
+ {
+ atEOL = 1;
+ AppendToToken(ch);
+ }
+ break;
+ }
+
+ else if (IsWhitespace(ch))
+ {
+ // Break only if we've begun adding to token (remember, if we hit a comment before a token,
+ // there might be further white space between the comment and the next token).
+ //
+ if (token.size() > 0)
+ break;
+ }
+
+ else if (ch == '_')
+ {
+ // If underscores are discovered in unquoted tokens, they should be
+ // automatically converted to spaces.
+ //
+ if (!(labileFlags & preserveUnderscores))
+ ch = ' ';
+ AppendToToken(ch);
+ }
+
+ else if (ch == '[')
+ {
+ // Get rest of comment and deal with it, but notice that we only break if the comment ends a token,
+ // not if it starts one (comment counts as whitespace). In the case of command comments
+ // (if saveCommandComment) GetComment will add to the token NxsString, causing us to break because
+ // token.size() will be greater than 0.
+ //
+ GetComment();
+ if (token.size() > 0)
+ break;
+ }
+
+ else if (ch == '(' && labileFlags & parentheticalToken)
+ {
+ AppendToToken(ch);
+
+ // Get rest of parenthetical token.
+ //
+ GetParentheticalToken();
+ break;
+ }
+
+ else if (ch == '{' && labileFlags & curlyBracketedToken)
+ {
+ AppendToToken(ch);
+
+ // Get rest of curly-bracketed token.
+ //
+ GetCurlyBracketedToken();
+ break;
+ }
+
+ else if (ch == '\"' && labileFlags & doubleQuotedToken)
+ {
+ // Get rest of double-quoted token.
+ //
+ GetDoubleQuotedToken();
+ break;
+ }
+
+ else if (ch == '\'')
+ {
+ if (token.size() > 0)
+ {
+ // We've encountered a single quote after a token has
+ // already begun to be read; should be another tandem
+ // single quote character immediately following.
+ //
+ ch = GetNextChar();
+ if (ch == '\'')
+ AppendToToken(ch);
+ else
+ {
+ errormsg = "Expecting second single quote character";
+ throw NxsException( errormsg, GetFilePosition(), GetFileLine(), GetFileColumn());
+ }
+ }
+ else
+ {
+ // Get rest of quoted NEXUS word and break, since
+ // we will have eaten one token after calling GetQuoted.
+ //
+ GetQuoted();
+ }
+ break;
+ }
+
+ else if (IsPunctuation(ch))
+ {
+ if (token.size() > 0)
+ {
+ // If we've already begun reading the token, encountering
+ // a punctuation character means we should stop, saving
+ // the punctuation character for the next token.
+ //
+ saved = ch;
+ break;
+ }
+ else
+ {
+ // If we haven't already begun reading the token, encountering
+ // a punctuation character means we should stop and return
+ // the punctuation character as this token (i.e., the token
+ // is just the single punctuation character.
+ //
+ AppendToToken(ch);
+ break;
+ }
+ }
+
+ else
+ {
+ AppendToToken(ch);
+ }
+
+ }
+
+ labileFlags = 0;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Strips whitespace from currently-stored token. Removes leading, trailing, and embedded whitespace characters.
+*/
+void NxsToken::StripWhitespace()
+ {
+ NxsString s;
+ for (unsigned j = 0; j < token.size(); j++)
+ {
+ if (IsWhitespace( token[j]))
+ continue;
+ s += token[j];
+ }
+ token = s;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Converts all alphabetical characters in token to upper case.
+*/
+void NxsToken::ToUpper()
+ {
+ for (unsigned i = 0; i < token.size(); i++)
+ token[i] = (char)toupper(token[i]);
+ }
+
=====================================
libraries/ncl/nxstoken.h
=====================================
@@ -0,0 +1,539 @@
+// Copyright (C) 1999-2003 Paul O. Lewis
+//
+// This file is part of NCL (Nexus Class Library) version 2.0.
+//
+// NCL is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// NCL is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with NCL; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+
+#ifndef NCL_NXSTOKEN_H
+#define NCL_NXSTOKEN_H
+
+#include <iostream> //for std::ostream
+#include "nxsstring.h" //for NxsString and NxsStringVector
+#include "nxsexception.h" //for NxsException
+#include "nxsdefs.h" //for file_pos
+/*----------------------------------------------------------------------------------------------------------------------
+| NxsToken objects are used by NxsReader to extract words (tokens) from a NEXUS data file. NxsToken objects know to
+| correctly skip NEXUS comments and understand NEXUS punctuation, making reading a NEXUS file as simple as repeatedly
+| calling the GetNextToken() function and then interpreting the token returned. If the token object is not attached
+| to an input stream, calls to GetNextToken() will have no effect. If the token object is not attached to an output
+| stream, output comments will be discarded (i.e., not output anywhere) and calls to Write or Writeln will be
+| ineffective. If input and output streams have been attached to the token object, however, tokens are read one at a
+| time from the input stream, and comments are correctly read and either written to the output stream (if an output
+| comment) or ignored (if not an output comment). Sequences of characters surrounded by single quotes are read in as
+| single tokens. A pair of adjacent single quotes are stored as a single quote, and underscore characters are stored
+| as blanks.
+*/
+class NxsToken
+ {
+ public:
+
+ enum NxsTokenFlags /* For use with the variable labileFlags */
+ {
+ saveCommandComments = 0x0001, /* if set, command comments of the form [&X] are not ignored but are instead saved as regular tokens (without the square brackets, however) */
+ parentheticalToken = 0x0002, /* if set, and if next character encountered is a left parenthesis, token will include everything up to the matching right parenthesis */
+ curlyBracketedToken = 0x0004, /* if set, and if next character encountered is a left curly bracket, token will include everything up to the matching right curly bracket */
+ doubleQuotedToken = 0x0008, /* if set, grabs entire phrase surrounded by double quotes */
+ singleCharacterToken = 0x0010, /* if set, next non-whitespace character returned as token */
+ newlineIsToken = 0x0020, /* if set, newline character treated as a token and atEOL set if newline encountered */
+ tildeIsPunctuation = 0x0040, /* if set, tilde character treated as punctuation and returned as a separate token */
+ useSpecialPunctuation = 0x0080, /* if set, character specified by the data member special is treated as punctuation and returned as a separate token */
+ hyphenNotPunctuation = 0x0100, /* if set, the hyphen character is not treated as punctutation (it is normally returned as a separate token) */
+ preserveUnderscores = 0x0200, /* if set, underscore characters inside tokens are not converted to blank spaces (normally, all underscores are automatically converted to blanks) */
+ ignorePunctuation = 0x0400 /* if set, the normal punctuation symbols are treated the same as any other darkspace characters */
+ };
+
+ NxsString errormsg;
+
+ NxsToken(std::istream &i);
+ virtual ~NxsToken();
+
+ bool AtEOF();
+ bool AtEOL();
+ bool Abbreviation(NxsString s);
+ bool Begins(NxsString s, bool respect_case = false);
+ void BlanksToUnderscores();
+ bool Equals(NxsString s, bool respect_case = false);
+ long GetFileColumn() const;
+ file_pos GetFilePosition() const;
+ long GetFileLine() const;
+ void GetNextToken();
+ NxsString GetToken(bool respect_case = true);
+ const char *GetTokenAsCStr(bool respect_case = true);
+ const NxsString &GetTokenReference();
+ int GetTokenLength() const;
+ bool IsPlusMinusToken();
+ bool IsPunctuationToken();
+ bool IsWhitespaceToken();
+ void ReplaceToken(const NxsString s);
+ void ResetToken();
+ void SetSpecialPunctuationCharacter(char c);
+ void SetLabileFlagBit(int bit);
+ bool StoppedOn(char ch);
+ void StripWhitespace();
+ void ToUpper();
+ void Write(std::ostream &out);
+ void Writeln(std::ostream &out);
+
+ virtual void OutputComment(const NxsString &msg);
+ void GetNextContiguousToken(char stop_char); // Added by BQM
+ protected:
+
+ void AppendToComment(char ch);
+ void AppendToToken(char ch);
+ char GetNextChar();
+ void GetComment();
+ void GetCurlyBracketedToken();
+ void GetDoubleQuotedToken();
+ void GetQuoted();
+ void GetParentheticalToken();
+ bool IsPunctuation(char ch);
+ bool IsWhitespace(char ch);
+
+ private:
+
+ std::istream ∈ /* reference to input stream from which tokens will be read */
+ file_pos filepos; /* current file position (for Metrowerks compiler, type is streampos rather than long) */
+ long fileline; /* current file line */
+ long filecol; /* current column in current line (refers to column immediately following token just read) */
+ NxsString token; /* the character buffer used to store the current token */
+ NxsString comment; /* temporary buffer used to store output comments while they are being built */
+ char saved; /* either '\0' or is last character read from input stream */
+ bool atEOF; /* true if end of file has been encountered */
+ bool atEOL; /* true if newline encountered while newlineIsToken labile flag set */
+ char special; /* ad hoc punctuation character; default value is '\0' */
+ int labileFlags; /* storage for flags in the NxsTokenFlags enum */
+ char punctuation[21]; /* stores the 20 NEXUS punctuation characters */
+ char whitespace[4]; /* stores the 3 whitespace characters: blank space, tab and newline */
+ };
+
+typedef NxsToken NexusToken;
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns the token for functions that only need read only access - faster than GetToken.
+*/
+inline const NxsString &NxsToken::GetTokenReference()
+ {
+ return token;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| This function is called whenever an output comment (i.e., a comment beginning with an exclamation point) is found
+| in the data file. This version of OutputComment does nothing; override this virtual function to display the output
+| comment in the most appropriate way for the platform you are supporting.
+*/
+inline void NxsToken::OutputComment(
+ const NxsString &msg) /* the contents of the printable comment discovered in the NEXUS data file */
+ {
+# if defined(HAVE_PRAGMA_UNUSED)
+# pragma unused(msg)
+# endif
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Adds `ch' to end of comment NxsString.
+*/
+inline void NxsToken::AppendToComment(
+ char ch) /* character to be appended to comment */
+ {
+ comment += ch;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Adds `ch' to end of current token.
+*/
+inline void NxsToken::AppendToToken(
+ char ch) /* character to be appended to token */
+ {
+ // First three lines proved necessary to keep Borland's implementation of STL from crashing
+ // under some circumstances (may no longer be necessary)
+ //
+ char s[2];
+ s[0] = ch;
+ s[1] = '\0';
+
+ token += s;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Reads next character from in and does all of the following before returning it to the calling function:
+|~
+| o if character read is either a carriage return or line feed, the variable line is incremented by one and the
+| variable col is reset to zero
+| o if character read is a carriage return, and a peek at the next character to be read reveals that it is a line
+| feed, then the next (line feed) character is read
+| o if either a carriage return or line feed is read, the character returned to the calling function is '\n' if
+| character read is neither a carriage return nor a line feed, col is incremented by one and the character is
+| returned as is to the calling function
+| o in all cases, the variable filepos is updated using a call to the tellg function of istream.
+|~
+*/
+inline char NxsToken::GetNextChar()
+ {
+ int ch = in.get();
+ int failed = in.bad();
+ if (failed)
+ {
+ errormsg = "Unknown error reading data file (check to make sure file exists)";
+ throw NxsException(errormsg, *this);
+ }
+
+ if (ch == 13 || ch == 10)
+ {
+ fileline++;
+ filecol = 1L;
+
+ if (ch == 13 && (int)in.peek() == 10)
+ ch = in.get();
+
+ atEOL = 1;
+ }
+ else if (ch == EOF)
+ atEOF = 1;
+ else
+ {
+ filecol++;
+ atEOL = 0;
+ }
+
+# if defined(__DECCXX)
+ filepos = 0L;
+# else
+ // BQM this cause crash compiling with clang under Windows!
+// filepos = in.tellg();
+ filepos += 1;
+# endif
+
+ if (atEOF)
+ return '\0';
+ else if (atEOL)
+ return '\n';
+ else
+ return (char)ch;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if character supplied is considered a punctuation character. The following twenty characters are
+| considered punctuation characters:
+|>
+| ()[]{}/\,;:=*'"`+-<>
+|>
+| Exceptions:
+|~
+| o The tilde character ('~') is also considered punctuation if the tildeIsPunctuation labile flag is set
+| o The special punctuation character (specified using the SetSpecialPunctuationCharacter) is also considered
+| punctuation if the useSpecialPunctuation labile flag is set
+| o The hyphen (i.e., minus sign) character ('-') is not considered punctuation if the hyphenNotPunctuation
+| labile flag is set
+|~
+| Use the SetLabileFlagBit method to set one or more NxsLabileFlags flags in `labileFlags'
+*/
+inline bool NxsToken::IsPunctuation(
+ char ch) /* the character in question */
+ {
+ // PAUP 4.0b10
+ // o allows ]`<> inside taxon names
+ // o allows `<> inside taxset names
+ //
+ bool is_punctuation = false;
+ if (strchr(punctuation, ch))
+ is_punctuation = true;
+ if (labileFlags & tildeIsPunctuation && ch == '~')
+ is_punctuation = true;
+ if (labileFlags & useSpecialPunctuation && ch == special)
+ is_punctuation = true;
+ if (labileFlags & hyphenNotPunctuation && ch == '-')
+ is_punctuation = false;
+
+ return is_punctuation;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if character supplied is considered a whitespace character. Note: treats '\n' as darkspace if labile
+| flag newlineIsToken is in effect.
+*/
+inline bool NxsToken::IsWhitespace(
+ char ch) /* the character in question */
+ {
+ bool ws = false;
+
+ // If ch is found in the whitespace array, it's whitespace
+ //
+ if (strchr(whitespace, ch))
+ ws = true;
+
+ // Unless of course ch is the newline character and we're currently
+ // treating newlines as darkspace!
+ //
+ if (labileFlags & newlineIsToken && ch == '\n')
+ ws = false;
+
+ return ws;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if and only if last call to GetNextToken encountered the end-of-file character (or for some reason the
+| input stream is now out of commission).
+*/
+inline bool NxsToken::AtEOF()
+ {
+ return atEOF;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if and only if last call to GetNextToken encountered the newline character while the newlineIsToken
+| labile flag was in effect.
+*/
+inline bool NxsToken::AtEOL()
+ {
+ return atEOL;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Converts all blanks in token to underscore characters. Normally, underscores found in the tokens read from a NEXUS
+| file are converted to blanks automatically as they are read; this function reverts the blanks back to underscores.
+*/
+inline void NxsToken::BlanksToUnderscores()
+ {
+ token.BlanksToUnderscores();
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns value stored in `filecol', which keeps track of the current column in the data file (i.e., number of
+| characters since the last new line was encountered).
+*/
+inline long NxsToken::GetFileColumn() const
+ {
+ return filecol;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns value stored in filepos, which keeps track of the current position in the data file (i.e., number of
+| characters since the beginning of the file). Note: for Metrowerks compiler, you must use the offset() method of
+| the streampos class to use the value returned.
+*/
+inline file_pos NxsToken::GetFilePosition() const
+ {
+ return filepos;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns value stored in `fileline', which keeps track of the current line in the data file (i.e., number of new
+| lines encountered thus far).
+*/
+inline long NxsToken::GetFileLine() const
+ {
+ return fileline;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns the data member `token'. Specifying false for`respect_case' parameter causes all characters in `token'
+| to be converted to upper case before `token' is returned. Specifying true results in GetToken returning exactly
+| what it read from the file.
+*/
+inline NxsString NxsToken::GetToken(
+ bool respect_case) /* determines whether token is converted to upper case before being returned */
+ {
+ if (!respect_case)
+ ToUpper();
+
+ return token;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns the data member `token' as a C-style string. Specifying false for`respect_case' parameter causes all
+| characters in `token' to be converted to upper case before the `token' C-string is returned. Specifying true
+| results in GetTokenAsCStr returning exactly what it read from the file.
+*/
+inline const char *NxsToken::GetTokenAsCStr(
+ bool respect_case) /* determines whether token is converted to upper case before being returned */
+ {
+ if (!respect_case)
+ ToUpper();
+
+ return token.c_str();
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns token.size().
+*/
+inline int NxsToken::GetTokenLength() const
+ {
+ return token.size();
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if current token is a single character and this character is either '+' or '-'.
+*/
+inline bool NxsToken::IsPlusMinusToken()
+ {
+ if (token.size() == 1 && ( token[0] == '+' || token[0] == '-') )
+ return true;
+ else
+ return false;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if current token is a single character and this character is a punctuation character (as defined in
+| IsPunctuation function).
+*/
+inline bool NxsToken::IsPunctuationToken()
+ {
+ if (token.size() == 1 && IsPunctuation( token[0]))
+ return true;
+ else
+ return false;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Returns true if current token is a single character and this character is a whitespace character (as defined in
+| IsWhitespace function).
+*/
+inline bool NxsToken::IsWhitespaceToken()
+ {
+ if (token.size() == 1 && IsWhitespace( token[0]))
+ return true;
+ else
+ return false;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Replaces current token NxsString with s.
+*/
+inline void NxsToken::ReplaceToken(
+ const NxsString s) /* NxsString to replace current token NxsString */
+ {
+ token = s;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Sets token to the empty NxsString ("").
+*/
+inline void NxsToken::ResetToken()
+ {
+ token.clear();
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Sets the special punctuation character to `c'. If the labile bit useSpecialPunctuation is set, this character will
+| be added to the standard list of punctuation symbols, and will be returned as a separate token like the other
+| punctuation characters.
+*/
+inline void NxsToken::SetSpecialPunctuationCharacter(
+ char c) /* the character to which `special' is set */
+ {
+ special = c;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Sets the bit specified in the variable `labileFlags'. The available bits are specified in the NxsTokenFlags enum.
+| All bits in `labileFlags' are cleared after each token is read.
+*/
+inline void NxsToken::SetLabileFlagBit(
+ int bit) /* the bit (see NxsTokenFlags enum) to set in `labileFlags' */
+ {
+ labileFlags |= bit;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Checks character stored in the variable saved to see if it matches supplied character `ch'. Good for checking such
+| things as whether token stopped reading characters because it encountered a newline (and labileFlags bit
+| newlineIsToken was set):
+|>
+| StoppedOn('\n');
+|>
+| or whether token stopped reading characters because of a punctuation character such as a comma:
+|>
+| StoppedOn(',');
+|>
+*/
+inline bool NxsToken::StoppedOn(
+ char ch) /* the character to compare with saved character */
+ {
+ if (saved == ch)
+ return true;
+ else
+ return false;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Simply outputs the current NxsString stored in `token' to the output stream `out'. Does not send a newline to the
+| output stream afterwards.
+*/
+inline void NxsToken::Write(
+ std::ostream &out) /* the output stream to which to write token NxsString */
+ {
+ out << token;
+ }
+
+/*----------------------------------------------------------------------------------------------------------------------
+| Simply outputs the current NxsString stored in `token' to the output stream `out'. Sends a newline to the output
+| stream afterwards.
+*/
+inline void NxsToken::Writeln(
+ std::ostream &out) /* the output stream to which to write `token' */
+ {
+ out << token << std::endl;
+ }
+
+/**
+ * Added by BQM: return the contiguous string (including white space) as token
+ * until hitting stop_char
+ * @param stop_char a character to stop reading in
+ */
+inline void NxsToken::GetNextContiguousToken(char stop_char) {
+ ResetToken();
+
+ char ch = ' ';
+ if (saved == '\0' || IsWhitespace(saved))
+ {
+ // Skip leading whitespace
+ //
+ while( IsWhitespace(ch) && !atEOF)
+ ch = GetNextChar();
+ saved = ch;
+ }
+ for (;;) {
+
+ // Get next character either from saved or from input stream.
+ //
+ if (saved != '\0')
+ {
+ ch = saved;
+ saved = '\0';
+ }
+ else
+ ch = GetNextChar();
+
+ // Break now if we've hit EOF.
+ //
+ if (atEOF)
+ break;
+ if (ch == stop_char) {
+ saved = ch;
+ break;
+ }
+ AppendToToken(ch);
+ }
+ // Skip ending whitespace
+ if (token.empty()) return;
+ NxsString::iterator last = token.end();
+ while (last != token.begin() && IsWhitespace(*(last-1))) {
+ last--;
+ }
+ if (last != token.end()) token.erase(last, token.end());
+}
+
+#endif
View it on GitLab: https://salsa.debian.org/med-team/cmaple/-/commit/38d8ad377e55111d7b6d7f46dd6677b0a523f5b4
--
View it on GitLab: https://salsa.debian.org/med-team/cmaple/-/commit/38d8ad377e55111d7b6d7f46dd6677b0a523f5b4
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20260911/b6362e5c/attachment-0001.htm>
More information about the debian-med-commit
mailing list