]> Dogcows Code - chaz/yoink/commitdiff
cleanup stlplus files
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Mon, 14 Jun 2010 22:13:37 +0000 (16:13 -0600)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Mon, 14 Jun 2010 22:13:37 +0000 (16:13 -0600)
245 files changed:
src/stlplus/README.txt [deleted file]
src/stlplus/containers/containers.hpp
src/stlplus/containers/containers_fixes.hpp
src/stlplus/containers/copy_functors.hpp
src/stlplus/containers/digraph.hpp
src/stlplus/containers/digraph.tpp
src/stlplus/containers/exceptions.hpp
src/stlplus/containers/foursome.hpp
src/stlplus/containers/foursome.tpp
src/stlplus/containers/hash.hpp
src/stlplus/containers/hash.tpp
src/stlplus/containers/matrix.hpp
src/stlplus/containers/matrix.tpp
src/stlplus/containers/ntree.hpp
src/stlplus/containers/ntree.tpp
src/stlplus/containers/safe_iterator.hpp
src/stlplus/containers/safe_iterator.tpp
src/stlplus/containers/simple_ptr.hpp
src/stlplus/containers/simple_ptr.tpp
src/stlplus/containers/smart_ptr.hpp
src/stlplus/containers/smart_ptr.tpp
src/stlplus/containers/triple.hpp
src/stlplus/containers/triple.tpp
src/stlplus/messages/stlplus_messages.txt [deleted file]
src/stlplus/persistence/persistence.hpp [deleted file]
src/stlplus/persistence/persistence_fixes.hpp [deleted file]
src/stlplus/persistence/persistent.hpp [deleted file]
src/stlplus/persistence/persistent_basic.hpp [deleted file]
src/stlplus/persistence/persistent_bitset.hpp [deleted file]
src/stlplus/persistence/persistent_bitset.tpp [deleted file]
src/stlplus/persistence/persistent_bool.cpp [deleted file]
src/stlplus/persistence/persistent_bool.hpp [deleted file]
src/stlplus/persistence/persistent_callback.hpp [deleted file]
src/stlplus/persistence/persistent_callback.tpp [deleted file]
src/stlplus/persistence/persistent_complex.hpp [deleted file]
src/stlplus/persistence/persistent_complex.tpp [deleted file]
src/stlplus/persistence/persistent_contexts.cpp [deleted file]
src/stlplus/persistence/persistent_contexts.hpp [deleted file]
src/stlplus/persistence/persistent_cstring.cpp [deleted file]
src/stlplus/persistence/persistent_cstring.hpp [deleted file]
src/stlplus/persistence/persistent_deque.hpp [deleted file]
src/stlplus/persistence/persistent_deque.tpp [deleted file]
src/stlplus/persistence/persistent_digraph.hpp [deleted file]
src/stlplus/persistence/persistent_digraph.tpp [deleted file]
src/stlplus/persistence/persistent_enum.hpp [deleted file]
src/stlplus/persistence/persistent_enum.tpp [deleted file]
src/stlplus/persistence/persistent_exceptions.cpp [deleted file]
src/stlplus/persistence/persistent_exceptions.hpp [deleted file]
src/stlplus/persistence/persistent_float.cpp [deleted file]
src/stlplus/persistence/persistent_float.hpp [deleted file]
src/stlplus/persistence/persistent_foursome.hpp [deleted file]
src/stlplus/persistence/persistent_foursome.tpp [deleted file]
src/stlplus/persistence/persistent_hash.hpp [deleted file]
src/stlplus/persistence/persistent_hash.tpp [deleted file]
src/stlplus/persistence/persistent_inf.cpp [deleted file]
src/stlplus/persistence/persistent_inf.hpp [deleted file]
src/stlplus/persistence/persistent_int.cpp [deleted file]
src/stlplus/persistence/persistent_int.hpp [deleted file]
src/stlplus/persistence/persistent_interface.hpp [deleted file]
src/stlplus/persistence/persistent_interface.tpp [deleted file]
src/stlplus/persistence/persistent_list.hpp [deleted file]
src/stlplus/persistence/persistent_list.tpp [deleted file]
src/stlplus/persistence/persistent_map.hpp [deleted file]
src/stlplus/persistence/persistent_map.tpp [deleted file]
src/stlplus/persistence/persistent_matrix.hpp [deleted file]
src/stlplus/persistence/persistent_matrix.tpp [deleted file]
src/stlplus/persistence/persistent_multimap.hpp [deleted file]
src/stlplus/persistence/persistent_multimap.tpp [deleted file]
src/stlplus/persistence/persistent_multiset.hpp [deleted file]
src/stlplus/persistence/persistent_multiset.tpp [deleted file]
src/stlplus/persistence/persistent_ntree.hpp [deleted file]
src/stlplus/persistence/persistent_ntree.tpp [deleted file]
src/stlplus/persistence/persistent_pair.hpp [deleted file]
src/stlplus/persistence/persistent_pair.tpp [deleted file]
src/stlplus/persistence/persistent_pointer.hpp [deleted file]
src/stlplus/persistence/persistent_pointer.tpp [deleted file]
src/stlplus/persistence/persistent_pointers.hpp [deleted file]
src/stlplus/persistence/persistent_set.hpp [deleted file]
src/stlplus/persistence/persistent_set.tpp [deleted file]
src/stlplus/persistence/persistent_shortcuts.hpp [deleted file]
src/stlplus/persistence/persistent_shortcuts.tpp [deleted file]
src/stlplus/persistence/persistent_simple_ptr.hpp [deleted file]
src/stlplus/persistence/persistent_simple_ptr.tpp [deleted file]
src/stlplus/persistence/persistent_smart_ptr.hpp [deleted file]
src/stlplus/persistence/persistent_smart_ptr.tpp [deleted file]
src/stlplus/persistence/persistent_stl.hpp [deleted file]
src/stlplus/persistence/persistent_stlplus.hpp [deleted file]
src/stlplus/persistence/persistent_string.cpp [deleted file]
src/stlplus/persistence/persistent_string.hpp [deleted file]
src/stlplus/persistence/persistent_string.tpp [deleted file]
src/stlplus/persistence/persistent_triple.hpp [deleted file]
src/stlplus/persistence/persistent_triple.tpp [deleted file]
src/stlplus/persistence/persistent_vector.cpp [deleted file]
src/stlplus/persistence/persistent_vector.hpp [deleted file]
src/stlplus/persistence/persistent_vector.tpp [deleted file]
src/stlplus/persistence/persistent_xref.hpp [deleted file]
src/stlplus/persistence/persistent_xref.tpp [deleted file]
src/stlplus/portability/build.cpp
src/stlplus/portability/build.hpp
src/stlplus/portability/debug.cpp
src/stlplus/portability/debug.hpp
src/stlplus/portability/dprintf.cpp
src/stlplus/portability/dprintf.hpp
src/stlplus/portability/dynaload.cpp
src/stlplus/portability/dynaload.hpp
src/stlplus/portability/file_system.cpp
src/stlplus/portability/file_system.hpp
src/stlplus/portability/inf.cpp
src/stlplus/portability/inf.hpp
src/stlplus/portability/ip_sockets.cpp
src/stlplus/portability/ip_sockets.hpp
src/stlplus/portability/portability.hpp
src/stlplus/portability/portability_exceptions.hpp
src/stlplus/portability/portability_fixes.cpp
src/stlplus/portability/portability_fixes.hpp
src/stlplus/portability/subprocesses.cpp
src/stlplus/portability/subprocesses.hpp
src/stlplus/portability/tcp.hpp
src/stlplus/portability/tcp_sockets.cpp
src/stlplus/portability/tcp_sockets.hpp
src/stlplus/portability/time.cpp
src/stlplus/portability/time.hpp
src/stlplus/portability/udp_sockets.cpp
src/stlplus/portability/udp_sockets.hpp
src/stlplus/portability/version.cpp
src/stlplus/portability/version.hpp
src/stlplus/portability/wildcard.cpp
src/stlplus/portability/wildcard.hpp
src/stlplus/strings/format_types.hpp
src/stlplus/strings/print_address.cpp
src/stlplus/strings/print_address.hpp
src/stlplus/strings/print_basic.hpp
src/stlplus/strings/print_bitset.hpp
src/stlplus/strings/print_bitset.tpp
src/stlplus/strings/print_bool.cpp
src/stlplus/strings/print_bool.hpp
src/stlplus/strings/print_cstring.cpp
src/stlplus/strings/print_cstring.hpp
src/stlplus/strings/print_digraph.hpp
src/stlplus/strings/print_digraph.tpp
src/stlplus/strings/print_float.cpp
src/stlplus/strings/print_float.hpp
src/stlplus/strings/print_foursome.hpp
src/stlplus/strings/print_foursome.tpp
src/stlplus/strings/print_hash.hpp
src/stlplus/strings/print_hash.tpp
src/stlplus/strings/print_inf.cpp
src/stlplus/strings/print_inf.hpp
src/stlplus/strings/print_int.cpp
src/stlplus/strings/print_int.hpp
src/stlplus/strings/print_list.hpp
src/stlplus/strings/print_list.tpp
src/stlplus/strings/print_map.hpp
src/stlplus/strings/print_map.tpp
src/stlplus/strings/print_matrix.hpp
src/stlplus/strings/print_matrix.tpp
src/stlplus/strings/print_ntree.hpp
src/stlplus/strings/print_ntree.tpp
src/stlplus/strings/print_pair.hpp
src/stlplus/strings/print_pair.tpp
src/stlplus/strings/print_pointer.hpp
src/stlplus/strings/print_pointer.tpp
src/stlplus/strings/print_sequence.hpp
src/stlplus/strings/print_sequence.tpp
src/stlplus/strings/print_set.hpp
src/stlplus/strings/print_set.tpp
src/stlplus/strings/print_simple_ptr.hpp
src/stlplus/strings/print_simple_ptr.tpp
src/stlplus/strings/print_smart_ptr.hpp
src/stlplus/strings/print_smart_ptr.tpp
src/stlplus/strings/print_stl.hpp
src/stlplus/strings/print_stlplus.hpp
src/stlplus/strings/print_string.cpp
src/stlplus/strings/print_string.hpp
src/stlplus/strings/print_triple.hpp
src/stlplus/strings/print_triple.tpp
src/stlplus/strings/print_vector.cpp
src/stlplus/strings/print_vector.hpp
src/stlplus/strings/print_vector.tpp
src/stlplus/strings/string_address.cpp
src/stlplus/strings/string_address.hpp
src/stlplus/strings/string_basic.hpp
src/stlplus/strings/string_bitset.hpp
src/stlplus/strings/string_bitset.tpp
src/stlplus/strings/string_bool.cpp
src/stlplus/strings/string_bool.hpp
src/stlplus/strings/string_cstring.cpp
src/stlplus/strings/string_cstring.hpp
src/stlplus/strings/string_digraph.hpp
src/stlplus/strings/string_digraph.tpp
src/stlplus/strings/string_float.cpp
src/stlplus/strings/string_float.hpp
src/stlplus/strings/string_foursome.hpp
src/stlplus/strings/string_foursome.tpp
src/stlplus/strings/string_hash.hpp
src/stlplus/strings/string_hash.tpp
src/stlplus/strings/string_inf.cpp
src/stlplus/strings/string_inf.hpp
src/stlplus/strings/string_int.cpp
src/stlplus/strings/string_int.hpp
src/stlplus/strings/string_list.hpp
src/stlplus/strings/string_list.tpp
src/stlplus/strings/string_map.hpp
src/stlplus/strings/string_map.tpp
src/stlplus/strings/string_matrix.hpp
src/stlplus/strings/string_matrix.tpp
src/stlplus/strings/string_ntree.hpp
src/stlplus/strings/string_ntree.tpp
src/stlplus/strings/string_pair.hpp
src/stlplus/strings/string_pair.tpp
src/stlplus/strings/string_pointer.hpp
src/stlplus/strings/string_pointer.tpp
src/stlplus/strings/string_sequence.hpp
src/stlplus/strings/string_sequence.tpp
src/stlplus/strings/string_set.hpp
src/stlplus/strings/string_set.tpp
src/stlplus/strings/string_simple_ptr.hpp
src/stlplus/strings/string_simple_ptr.tpp
src/stlplus/strings/string_smart_ptr.hpp
src/stlplus/strings/string_smart_ptr.tpp
src/stlplus/strings/string_stl.hpp
src/stlplus/strings/string_stlplus.hpp
src/stlplus/strings/string_string.cpp
src/stlplus/strings/string_string.hpp
src/stlplus/strings/string_triple.hpp
src/stlplus/strings/string_triple.tpp
src/stlplus/strings/string_utilities.cpp
src/stlplus/strings/string_utilities.hpp
src/stlplus/strings/string_vector.cpp
src/stlplus/strings/string_vector.hpp
src/stlplus/strings/string_vector.tpp
src/stlplus/strings/strings.hpp
src/stlplus/strings/strings_fixes.hpp
src/stlplus/subsystems/cli_parser.cpp [deleted file]
src/stlplus/subsystems/cli_parser.hpp [deleted file]
src/stlplus/subsystems/ini_manager.cpp [deleted file]
src/stlplus/subsystems/ini_manager.hpp [deleted file]
src/stlplus/subsystems/library_manager.cpp [deleted file]
src/stlplus/subsystems/library_manager.hpp [deleted file]
src/stlplus/subsystems/message_handler.cpp [deleted file]
src/stlplus/subsystems/message_handler.hpp [deleted file]
src/stlplus/subsystems/subsystems.hpp [deleted file]
src/stlplus/subsystems/subsystems_fixes.hpp [deleted file]
src/stlplus/subsystems/timer.cpp [deleted file]
src/stlplus/subsystems/timer.hpp [deleted file]

diff --git a/src/stlplus/README.txt b/src/stlplus/README.txt
deleted file mode 100644 (file)
index dad518e..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-This directory is for implementing STLplus as a library collection. The\r
-libraries are to be found in the directories:\r
-\r
-          containers\r
-          persistence\r
-          portability\r
-          strings\r
-          subsystems\r
-\r
-The documentation is in the 'docs' directory and starts with index.html.\r
-\r
-To build the STLplus3 library collection, use the project files supplied at\r
-this level - 'Makefile' for gcc, 'stlplus3.sln' for Visual Studio 9 (2008),\r
-'stlplus3.dsw' for Visual Studio 6 (and 7 or 8).\r
-\r
-The 'source' directory is provided with script files that allow the library\r
-collection to be merged into one large library - termed the monolithic build.\r
-See source/README.txt for instructions.\r
-\r
index 58637581643849b2d657bd0abde6b4e034a06b02..e99d31382f5586b185d2fc755486d1544177c800 100644 (file)
@@ -1,23 +1,23 @@
-#ifndef STLPLUS_CONTAINERS\r
-#define STLPLUS_CONTAINERS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Allows all the STLplus containers to be included in one go\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "digraph.hpp"\r
-#include "foursome.hpp"\r
-#include "hash.hpp"\r
-#include "matrix.hpp"\r
-#include "ntree.hpp"\r
-#include "smart_ptr.hpp"\r
-#include "triple.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_CONTAINERS
+#define STLPLUS_CONTAINERS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Allows all the STLplus containers to be included in one go
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "digraph.hpp"
+#include "foursome.hpp"
+#include "hash.hpp"
+#include "matrix.hpp"
+#include "ntree.hpp"
+#include "smart_ptr.hpp"
+#include "triple.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
index ad29f99e2ed5908afe8b73a1d2ca74a3c23f3fa3..f244323d279427e2094be08fb88702451276f641 100644 (file)
-#ifndef STLPLUS_CONTAINERS_FIXES\r
-#define STLPLUS_CONTAINERS_FIXES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Contains work arounds for OS or Compiler specific problems with container\r
-//   templates\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Unnecessary compiler warnings\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef _MSC_VER\r
-// Microsoft Visual Studio\r
-// shut up the following irritating warnings\r
-//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)\r
-//   4305 - VC6, identifier type was converted to a smaller type\r
-//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)\r
-//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it\r
-//   4290 - VC6, C++ exception specification ignored\r
-//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)\r
-//   4355 - VC6, 'this' : used in base member initializer list\r
-//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program\r
-//   4996 - VC8, 'xxxx' was declared deprecated\r
-#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4355 4675 4996)\r
-#endif\r
-\r
-#ifdef __BORLANDC__\r
-// Borland\r
-// Shut up the following irritating warnings\r
-//   8026 - Functions with exception specifications are not expanded inline\r
-//   8027 - Functions with xxx are not expanded inline\r
-#pragma warn -8026\r
-#pragma warn -8027\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Problems with the typename keyword\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// There are problems with using the 'typename' keyword. Technically, if you\r
-// use a type member of a template class (i.e. a type declared within the\r
-// template class by a local typedef), you need to tell the compiler that it\r
-// is a type name. This is because the compiler cannot work out whether a\r
-// member is a type, a method or a data field at compile time. However,\r
-// support for the typename keyword has traditionally been incomplete in both\r
-// gcc and Visual Studio. I have used macros to try to resolve this issue. The\r
-// macros add the keyword for compiler versions that require it and omit it\r
-// for compiler versions that do not support it\r
-\r
-// There are five places where typename keywords cause problems:\r
-//\r
-//   1) in a typedef where a template class's member type is being mapped onto\r
-//      a type definition within another template class or function \r
-//      e.g. template<typename T> fn () {\r
-//             typedef typename someclass<T>::member_type local_type;\r
-//                     ^^^^^^^^\r
-//   2) in a function parameter declaration, with similar rules to the above\r
-//      e.g. template<typename T> fn (typename someclass<T>::member_type)\r
-//                                    ^^^^^^^^\r
-//   3) in instantiating a template, the parameter to the template, with similar rules to the above\r
-//      e.g. template_class<typename someclass<T>::member_type>\r
-//                          ^^^^^^^^\r
-//   4) Return expressions\r
-//      e.g. return typename ntree<T>::const_iterator(this,m_root);\r
-//                  ^^^^^^^^\r
-//   5) Creating temporary objects when passing arguments to a function or constructor\r
-//      e.g. return typename ntree<T>::const_prefix_iterator(typename ntree<T>::const_iterator(this,m_root));\r
-//                                                           ^^^^^^^^\r
-// Note that the typename keyword is only required when the type being referred to is a member of a template class\r
-//\r
-// So far it *seems* as if all compilers either require all of them or none of\r
-// them, so this set of situations can be handled by a single macro\r
-\r
-// default values, overridden for individual problem cases below\r
-#define TYPENAME typename\r
-\r
-// GCC \r
-//   - pre-version 3 didn't handle typename in any of these cases\r
-//   - version 3 onwards, typename is required for all three cases as per default\r
-#ifdef __GNUC__\r
-#if __GNUC__ < 3\r
-#undef TYPENAME\r
-#define TYPENAME\r
-#endif\r
-#endif\r
-\r
-// Visual Studio\r
-//   - version 6 (compiler v.12) cannot handle typename in any of these cases\r
-//   - version 7 (.NET) (compiler v.13) requires a typename in a parameter specification but supports all\r
-//   - version 8 (2005) (compiler v.14) requires parameters and templates, supports all\r
-#ifdef _MSC_VER\r
-#if _MSC_VER <= 1200\r
-#undef TYPENAME\r
-#define TYPENAME\r
-#endif\r
-#endif\r
-\r
-// Borland \r
-//   - doesn't handle typename in 5.5, does in 5.82, not sure about other cases\r
-#ifdef __BORLANDC__\r
-#if __BORLANDC__ <= 0x550\r
-#undef TYPENAME\r
-#define TYPENAME\r
-#endif\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Member templates\r
-// e.g. a template function in a template class\r
-\r
-// Not all compilers support them - this fix can be used to disable member\r
-// templates for compilers that don't. Unfortunately that means that some\r
-// functionality will be missing for those compilers.\r
-\r
-#define STLPLUS_MEMBER_TEMPLATES\r
-\r
-// Visual Studio v6 (compiler version 12) does not support them\r
-#ifdef _MSC_VER\r
-#if _MSC_VER <= 1200\r
-#undef STLPLUS_MEMBER_TEMPLATES\r
-#endif\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_CONTAINERS_FIXES
+#define STLPLUS_CONTAINERS_FIXES
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Contains work arounds for OS or Compiler specific problems with container
+//   templates
+
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Unnecessary compiler warnings
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+// Microsoft Visual Studio
+// shut up the following irritating warnings
+//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)
+//   4305 - VC6, identifier type was converted to a smaller type
+//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)
+//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it
+//   4290 - VC6, C++ exception specification ignored
+//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)
+//   4355 - VC6, 'this' : used in base member initializer list
+//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program
+//   4996 - VC8, 'xxxx' was declared deprecated
+#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4355 4675 4996)
+#endif
+
+#ifdef __BORLANDC__
+// Borland
+// Shut up the following irritating warnings
+//   8026 - Functions with exception specifications are not expanded inline
+//   8027 - Functions with xxx are not expanded inline
+#pragma warn -8026
+#pragma warn -8027
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Problems with the typename keyword
+////////////////////////////////////////////////////////////////////////////////
+
+// There are problems with using the 'typename' keyword. Technically, if you
+// use a type member of a template class (i.e. a type declared within the
+// template class by a local typedef), you need to tell the compiler that it
+// is a type name. This is because the compiler cannot work out whether a
+// member is a type, a method or a data field at compile time. However,
+// support for the typename keyword has traditionally been incomplete in both
+// gcc and Visual Studio. I have used macros to try to resolve this issue. The
+// macros add the keyword for compiler versions that require it and omit it
+// for compiler versions that do not support it
+
+// There are five places where typename keywords cause problems:
+//
+//   1) in a typedef where a template class's member type is being mapped onto
+//      a type definition within another template class or function 
+//      e.g. template<typename T> fn () {
+//             typedef typename someclass<T>::member_type local_type;
+//                     ^^^^^^^^
+//   2) in a function parameter declaration, with similar rules to the above
+//      e.g. template<typename T> fn (typename someclass<T>::member_type)
+//                                    ^^^^^^^^
+//   3) in instantiating a template, the parameter to the template, with similar rules to the above
+//      e.g. template_class<typename someclass<T>::member_type>
+//                          ^^^^^^^^
+//   4) Return expressions
+//      e.g. return typename ntree<T>::const_iterator(this,m_root);
+//                  ^^^^^^^^
+//   5) Creating temporary objects when passing arguments to a function or constructor
+//      e.g. return typename ntree<T>::const_prefix_iterator(typename ntree<T>::const_iterator(this,m_root));
+//                                                           ^^^^^^^^
+// Note that the typename keyword is only required when the type being referred to is a member of a template class
+//
+// So far it *seems* as if all compilers either require all of them or none of
+// them, so this set of situations can be handled by a single macro
+
+// default values, overridden for individual problem cases below
+#define TYPENAME typename
+
+// GCC 
+//   - pre-version 3 didn't handle typename in any of these cases
+//   - version 3 onwards, typename is required for all three cases as per default
+#ifdef __GNUC__
+#if __GNUC__ < 3
+#undef TYPENAME
+#define TYPENAME
+#endif
+#endif
+
+// Visual Studio
+//   - version 6 (compiler v.12) cannot handle typename in any of these cases
+//   - version 7 (.NET) (compiler v.13) requires a typename in a parameter specification but supports all
+//   - version 8 (2005) (compiler v.14) requires parameters and templates, supports all
+#ifdef _MSC_VER
+#if _MSC_VER <= 1200
+#undef TYPENAME
+#define TYPENAME
+#endif
+#endif
+
+// Borland 
+//   - doesn't handle typename in 5.5, does in 5.82, not sure about other cases
+#ifdef __BORLANDC__
+#if __BORLANDC__ <= 0x550
+#undef TYPENAME
+#define TYPENAME
+#endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Member templates
+// e.g. a template function in a template class
+
+// Not all compilers support them - this fix can be used to disable member
+// templates for compilers that don't. Unfortunately that means that some
+// functionality will be missing for those compilers.
+
+#define STLPLUS_MEMBER_TEMPLATES
+
+// Visual Studio v6 (compiler version 12) does not support them
+#ifdef _MSC_VER
+#if _MSC_VER <= 1200
+#undef STLPLUS_MEMBER_TEMPLATES
+#endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
index c82ee9f0c0f920ab05a280b2f53a3d34925e2566..68f2b21b226a0d382c324552d853859bfe697f2b 100644 (file)
@@ -1,66 +1,66 @@
-#ifndef STLPLUS_COPY_FUNCTORS\r
-#define STLPLUS_COPY_FUNCTORS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   The function constructor classes below are used by the smart_ptr and the\r
-//   simple_ptr classes. They provide three (well ok, two) copying mechanisms.\r
-//   These classes have been separated from the smart_ptr header by DJDM, as\r
-//   the simple_ptr classes now also use them.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include "exceptions.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // copy functors implementing the three possible copy semantics\r
-\r
-  // constructor_copy uses the copy constructor of the object - used for simple types\r
-\r
-  template <typename T>\r
-  class constructor_copy\r
-  {\r
-  public:\r
-    T* operator() (const T& from) throw()\r
-      {\r
-        return new T(from);\r
-      }\r
-  };\r
-\r
-  // clone_copy uses the clone method of the object - used for polymorphic types\r
-\r
-  template <typename T>\r
-  class clone_copy\r
-  {\r
-  public:\r
-    T* operator() (const T& from) throw()\r
-      {\r
-        return from.clone();\r
-      }\r
-  };\r
-\r
-  // no_copy throws an exception - used for types that cannot be copied\r
-\r
-  template <typename T>\r
-  class no_copy\r
-  {\r
-  public:\r
-    T* operator() (const T& from) throw(illegal_copy)\r
-      {\r
-        throw illegal_copy("no_copy functor called");\r
-        return 0;\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_COPY_FUNCTORS
+#define STLPLUS_COPY_FUNCTORS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   The function constructor classes below are used by the smart_ptr and the
+//   simple_ptr classes. They provide three (well ok, two) copying mechanisms.
+//   These classes have been separated from the smart_ptr header by DJDM, as
+//   the simple_ptr classes now also use them.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include "exceptions.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // copy functors implementing the three possible copy semantics
+
+  // constructor_copy uses the copy constructor of the object - used for simple types
+
+  template <typename T>
+  class constructor_copy
+  {
+  public:
+    T* operator() (const T& from) throw()
+      {
+        return new T(from);
+      }
+  };
+
+  // clone_copy uses the clone method of the object - used for polymorphic types
+
+  template <typename T>
+  class clone_copy
+  {
+  public:
+    T* operator() (const T& from) throw()
+      {
+        return from.clone();
+      }
+  };
+
+  // no_copy throws an exception - used for types that cannot be copied
+
+  template <typename T>
+  class no_copy
+  {
+  public:
+    T* operator() (const T& from) throw(illegal_copy)
+      {
+        throw illegal_copy("no_copy functor called");
+        return 0;
+      }
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 8281998d24640512b3b1ddfe94fadcd4b3f9fd1e..7b603c11d0f7c5b87bc8e65fb4552d75b29c9e59 100644 (file)
-#ifndef STLPLUS_DIGRAPH\r
-#define STLPLUS_DIGRAPH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   STL-style Directed graph template component\r
-//   Digraph stands for directed-graph, i.e. all arcs have a direction\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include "safe_iterator.hpp"\r
-#include "exceptions.hpp"\r
-#include <vector>\r
-#include <map>\r
-#include <set>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Internals\r
-\r
-  template<typename NT, typename AT> class digraph_node;\r
-  template<typename NT, typename AT> class digraph_arc;\r
-  template<typename NT, typename AT> class digraph;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // The Digraph iterator classes\r
-  // a digraph_iterator points to a node whilst a digraph_arc_iterator points to an arc\r
-  // Note that these are redefined as:\r
-  //   digraph<NT,AT>::iterator           - points to a non-const node\r
-  //   digraph<NT,AT>::const_iterator     - points to a const node\r
-  //   digraph<NT,AT>::arc_iterator       - points to a non-const arc\r
-  //   digraph<NT,AT>::const_arc_iterator - points to a const arc\r
-  // and this is the form in which they should be used\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  class digraph_iterator : public safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >\r
-  {\r
-  public:\r
-    friend class digraph<NT,AT>;\r
-\r
-    // local type definitions\r
-    // an iterator points to an object whilst a const_iterator points to a const object\r
-    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;\r
-    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;\r
-    typedef digraph_iterator<NT,AT,NRef,NPtr> this_iterator;\r
-    typedef NRef reference;\r
-    typedef NPtr pointer;\r
-\r
-    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
-    digraph_iterator(void);\r
-    ~digraph_iterator(void);\r
-\r
-    // Type conversion methods allow const_iterator and iterator to be converted\r
-    // convert an iterator/const_iterator to a const_iterator\r
-    const_iterator constify(void) const;\r
-    // convert an iterator/const_iterator to an iterator\r
-    iterator deconstify(void) const;\r
-\r
-    // increment/decrement operators used to step through the set of all nodes in a graph\r
-    // it is only legal to increment a valid iterator\r
-    // pre-increment\r
-    this_iterator& operator ++ (void)\r
-      throw(null_dereference,end_dereference);\r
-    // post-increment\r
-    this_iterator operator ++ (int)\r
-      throw(null_dereference,end_dereference);\r
-    // pre-decrement\r
-    this_iterator& operator -- (void)\r
-      throw(null_dereference,end_dereference);\r
-    // post-decrement\r
-    this_iterator operator -- (int)\r
-      throw(null_dereference,end_dereference);\r
-\r
-    // test useful for testing whether iteration has completed and for inclusion in other containers\r
-    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()\r
-    bool operator == (const this_iterator& r) const;\r
-    bool operator != (const this_iterator& r) const;\r
-    bool operator < (const this_iterator& r) const;\r
-\r
-    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
-    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
-    reference operator*(void) const\r
-      throw(null_dereference,end_dereference);\r
-    pointer operator->(void) const\r
-      throw(null_dereference,end_dereference);\r
-\r
-  public:\r
-    // constructor used by digraph to create a non-null iterator\r
-    explicit digraph_iterator(digraph_node<NT,AT>* node);\r
-    // constructor used by digraph to create an end iterator\r
-    explicit digraph_iterator(const digraph<NT,AT>* owner);\r
-    // used to create an alias of an iterator\r
-    explicit digraph_iterator(const safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >& iterator);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  class digraph_arc_iterator : public safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >\r
-  {\r
-  public:\r
-    friend class digraph<NT,AT>;\r
-\r
-    // local type definitions\r
-    // an iterator points to an object whilst a const_iterator points to a const object\r
-    typedef digraph_arc_iterator<NT,AT,AT&,AT*> iterator;\r
-    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_iterator;\r
-    typedef digraph_arc_iterator<NT,AT,ARef,APtr> this_iterator;\r
-    typedef ARef reference;\r
-    typedef APtr pointer;\r
-\r
-    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
-    digraph_arc_iterator(void);\r
-    ~digraph_arc_iterator(void);\r
-\r
-    // Type conversion methods allow const_iterator and iterator to be converted\r
-    // convert an iterator/const_iterator to a const_iterator\r
-    const_iterator constify(void) const;\r
-    // convert an iterator/const_iterator to an iterator\r
-    iterator deconstify(void) const;\r
-\r
-    // increment/decrement operators used to step through the set of all nodes in a graph\r
-    // it is only legal to increment a valid iterator\r
-    // pre-increment\r
-    this_iterator& operator ++ (void)\r
-      throw(null_dereference,end_dereference);\r
-    // post-increment\r
-    this_iterator operator ++ (int)\r
-      throw(null_dereference,end_dereference);\r
-    // pre-decrement\r
-    this_iterator& operator -- (void)\r
-      throw(null_dereference,end_dereference);\r
-    // post-decrement\r
-    this_iterator operator -- (int)\r
-      throw(null_dereference,end_dereference);\r
-\r
-    // test useful for testing whether iteration has completed and for inclusion in other containers\r
-    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()\r
-    bool operator == (const this_iterator&) const;\r
-    bool operator != (const this_iterator&) const;\r
-    bool operator < (const this_iterator&) const;\r
-\r
-    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
-    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
-    reference operator*(void) const\r
-      throw(null_dereference,end_dereference);\r
-    pointer operator->(void) const\r
-      throw(null_dereference,end_dereference);\r
-\r
-  public:\r
-    // constructor used by digraph to create a non-null iterator\r
-    explicit digraph_arc_iterator(digraph_arc<NT,AT>* arc);\r
-    // constructor used by digraph to create an end iterator\r
-    explicit digraph_arc_iterator(const digraph<NT,AT>* owner);\r
-    // used to create an alias of an iterator\r
-    explicit digraph_arc_iterator(const safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >& iterator);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // The Graph class\r
-  // NT is the Node type and AT is the Arc type\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT>\r
-  class digraph\r
-  {\r
-  public:\r
-    // STL-like typedefs for the types and iterators\r
-    typedef NT node_type;\r
-    typedef AT arc_type;\r
-    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;\r
-    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;\r
-    typedef digraph_arc_iterator<NT,AT,AT&,AT*> arc_iterator;\r
-    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_arc_iterator;\r
-\r
-    // supplementary types used throughout\r
-\r
-    // a path is represented as a vector of arcs so the forward traversal is\r
-    // done by going from begin() to end() or 0 to size-1 - of course a backward\r
-    // traversal can be done by traversing the vector backwards\r
-    typedef std::vector<arc_iterator> arc_vector;\r
-    typedef std::vector<const_arc_iterator> const_arc_vector;\r
-    const_arc_vector constify_arcs(const arc_vector&) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    arc_vector deconstify_arcs(const const_arc_vector&) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // a path vector is a vector of paths used to represent all the paths from one node to another\r
-    // there is no particular ordering to the paths in the vector\r
-    typedef std::vector<arc_vector> path_vector;\r
-    typedef std::vector<const_arc_vector> const_path_vector;\r
-    const_path_vector constify_paths(const path_vector&) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    path_vector deconstify_paths(const const_path_vector&) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // a node vector is a simple vector of nodes used to represent the reachable sets\r
-    // there is no particular ordering to the nodes in the vector\r
-    typedef std::vector<iterator> node_vector;\r
-    typedef std::vector<const_iterator> const_node_vector;\r
-    const_node_vector constify_nodes(const node_vector&) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    node_vector deconstify_nodes(const const_node_vector&) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // callback used in the path algorithms to select which arcs to consider\r
-    typedef bool (*arc_select_fn) (const digraph<NT,AT>&, const_arc_iterator);\r
-\r
-    // a value representing an unknown offset\r
-    // Note that it's static so use in the form digraph<NT,AT>::npos()\r
-    static unsigned npos(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////\r
-    // Constructors, destructors and copies\r
-\r
-    digraph(void);\r
-    ~digraph(void);\r
-\r
-    // copy constructor and assignment both copy the graph\r
-    digraph(const digraph<NT,AT>&);\r
-    digraph<NT,AT>& operator=(const digraph<NT,AT>&);\r
-\r
-    //////////////////////////////////////////////////////////////////////////\r
-    // Basic Node functions\r
-    // Nodes are referred to by iterators created when the node is inserted.\r
-    // Iterators remain valid unless the node is erased (they are list iterators, so no resize problems)\r
-    // It is also possible to walk through all the nodes using a list-like start() to end() loop\r
-    // Each node has a set of input arcs and output arcs. These are indexed by an unsigned i.e. they form a vector.\r
-    // The total number of inputs is the fanin and the total number of outputs is the fanout.\r
-    // The contents of the node (type NT) are accessed, of course, by dereferencing the node iterator.\r
-\r
-    // tests for the number of nodes and the special test for zero nodes\r
-    bool empty(void) const;\r
-    unsigned size(void) const;\r
-\r
-    // add a new node and return its iterator\r
-    iterator insert(const NT& node_data);\r
-\r
-    // remove a node and return the iterator to the next node\r
-    // erasing a node erases its arcs\r
-    iterator erase(iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    // remove all nodes\r
-    void clear(void);\r
-\r
-    // traverse all the nodes in no particular order using STL-style iteration\r
-    const_iterator begin(void) const;\r
-    iterator begin(void);\r
-    const_iterator end(void) const;\r
-    iterator end(void);\r
-\r
-    // access the inputs of this node\r
-    // the fanin is the number of inputs and the inputs are accessed using an index from 0..fanin-1\r
-    unsigned fanin(const_iterator) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    unsigned fanin(iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    const_arc_iterator input(const_iterator, unsigned) const\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-    arc_iterator input(iterator, unsigned)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-\r
-    // access the outputs of this node\r
-    // the fanout is the number of outputs and the outputs are accessed using an index from 0..fanout-1\r
-    unsigned fanout(const_iterator) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    unsigned fanout(iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    const_arc_iterator output(const_iterator, unsigned) const\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-    arc_iterator output(iterator, unsigned)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-\r
-    // convenience routines for getting the set of all inputs or all outputs as vectors\r
-    const_arc_vector inputs(const_iterator) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    arc_vector inputs(iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    const_arc_vector outputs(const_iterator) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    arc_vector outputs(iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // find the output index of an arc which goes from this node\r
-    // returns digraph<NT,AT>::npos if the arc is not an output of from\r
-    unsigned output_offset(const_iterator from, const_arc_iterator arc) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    unsigned output_offset(iterator from, arc_iterator arc)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    // ditto for an input arc\r
-    unsigned input_offset(const_iterator to, const_arc_iterator arc) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    unsigned input_offset(iterator to, arc_iterator arc)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    //////////////////////////////////////////////////////////////////////////\r
-    // Basic Arc functions\r
-    // to avoid name conflicts, arc functions have the arc_ prefix \r
-    // Arcs, like nodes, are referred to by a list iterator which is returned by the arc_insert function\r
-    // They may also be visited from arc_begin() to arc_end()\r
-    // Each arc has a from field and a to field which contain the node iterators of the endpoints of the arc\r
-    // Of course, the arc data can be accessed by simply dereferencing the iterator\r
-\r
-    // tests for the number of arcs and the special test for zero arcs\r
-    bool arc_empty (void) const;\r
-    unsigned arc_size(void) const;\r
-\r
-    // add a new arc and return its iterator\r
-    arc_iterator arc_insert(iterator from, iterator to, const AT& arc_data = AT())\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // remove an arc and return the iterator to the next arc\r
-    arc_iterator arc_erase(arc_iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    // remove all arcs\r
-    void arc_clear(void);\r
-\r
-    // traverse all the arcs in no particular order using STL-style iteration\r
-    const_arc_iterator arc_begin(void) const;\r
-    arc_iterator arc_begin(void);\r
-    const_arc_iterator arc_end(void) const;\r
-    arc_iterator arc_end(void);\r
-\r
-    // find the node that an arc points from or to\r
-    const_iterator arc_from(const_arc_iterator) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    iterator arc_from(arc_iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    const_iterator arc_to(const_arc_iterator) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    iterator arc_to(arc_iterator)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // reconnect an arc to a different from and to node\r
-    void arc_move(arc_iterator arc, iterator from, iterator to)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    // reconnect just the from node\r
-    void arc_move_from(arc_iterator arc, iterator from)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    // reconnect just the to node\r
-    void arc_move_to(arc_iterator arc, iterator to)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    // reverse the arc direction so that to becomes from and vice-versa\r
-    void arc_flip(arc_iterator arc)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // Adjacency algorithms\r
-\r
-    // test whether the nodes are adjacent i.e. whether there is an arc going from from to to\r
-    bool adjacent(const_iterator from, const_iterator to) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    bool adjacent(iterator from, iterator to)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // as above, but returns the arc that makes the nodes adjacent\r
-    // returns the first arc if there's more than one, returns arc_end() if there are none\r
-    const_arc_iterator adjacent_arc(const_iterator from, const_iterator to) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    arc_iterator adjacent_arc(iterator from, iterator to)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // as above, but returns the set of all arcs that make two nodes adjacent (there may be more than one)\r
-    // returns an empty vector if there are none\r
-    const_arc_vector adjacent_arcs(const_iterator from, const_iterator to) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    arc_vector adjacent_arcs(iterator from, iterator to)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // return the adjacency sets for the node inputs or outputs, i.e. the set of nodes adjacent to this node\r
-    // each adjacent node will only be entered once even if there are multiple arcs between the nodes\r
-    const_node_vector input_adjacencies(const_iterator to) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    node_vector input_adjacencies(iterator to)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    const_node_vector output_adjacencies(const_iterator from) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    node_vector output_adjacencies(iterator from)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // Topographical Sort Algorithm\r
-    // This generates a node ordering such that each node is visited after its fanin nodes.\r
-\r
-    // This only generates a valid ordering for a DAG. \r
-\r
-    // The return value is a pair : \r
-    //  - the node vector which is a set of iterators to the nodes in sorted order\r
-    //  - the arc vector is the set of backward ards that were broken to achieve the sort\r
-    // If the arc vector is empty then the graph formed a DAG.\r
-\r
-    // The arc selection callback can be used to ignore arcs that are not part\r
-    // of the ordering, i.e. arcs that are meant to be backwards arcs\r
-\r
-    std::pair<const_node_vector,const_arc_vector> sort(arc_select_fn = 0) const;\r
-    std::pair<node_vector,arc_vector> sort(arc_select_fn = 0);\r
-\r
-    // Simplified variant of above for graphs that are known to be DAGs.\r
-    // If the sort fails due to backward arcs, the\r
-    // return vector is empty. Note that this will also be empty if the graph\r
-    // has no nodes in it, so use the empty() method to differentiate.\r
-\r
-    const_node_vector dag_sort(arc_select_fn = 0) const;\r
-    node_vector dag_sort(arc_select_fn = 0);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // Basic Path Algorithms\r
-    // A path is a series of arcs - you can use arc_from and arc_to to convert\r
-    // that into a series of nodes. All the path algorithms take an arc_select\r
-    // which allows arcs to be selected or rejected for consideration in a path.\r
-\r
-    // A selection callback function is applied to each arc in the traversal and\r
-    // returns true if the arc is to be selected and false if the arc is to be\r
-    // rejected. If no function is provided the arc is selected. If you want to\r
-    // use arc selection you should create a function with the type profile given\r
-    // by the arc_select_fn type. The select function is passed both the graph and\r
-    // the arc iterator so that it is possible to select an arc on the basis of\r
-    // the nodes it is connected to.\r
-\r
-    // Note: I used a callback because the STL-like predicate idea wasn't working for me...\r
-\r
-    // test for the existence of a path from from to to\r
-    bool path_exists(const_iterator from, const_iterator to, arc_select_fn = 0) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    bool path_exists(iterator from, iterator to, arc_select_fn = 0)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // get the set of all paths from from to to\r
-    const_path_vector all_paths(const_iterator from, const_iterator to, arc_select_fn = 0) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    path_vector all_paths(iterator from, iterator to, arc_select_fn = 0)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // get the set of all nodes that can be reached by any path from from\r
-    const_node_vector reachable_nodes(const_iterator from, arc_select_fn = 0) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    node_vector reachable_nodes(iterator from, arc_select_fn = 0)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // get the set of all nodes that can reach to to by any path\r
-    const_node_vector reaching_nodes(const_iterator to, arc_select_fn = 0) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    node_vector reaching_nodes(iterator to, arc_select_fn = 0)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // Unweighted Shortest path algorithms\r
-\r
-    // find the shortest path from from to to\r
-    // This is an unweighted shortest path algorithm, i.e. the weight of each\r
-    // arc is assumed to be 1, so just counts the number of arcs\r
-    // if there is more than one shortest path it returns the first one\r
-    // If there are no paths, returns an empty path\r
-    const_arc_vector shortest_path(const_iterator from, const_iterator to, arc_select_fn = 0) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    arc_vector shortest_path(iterator from, iterator to, arc_select_fn = 0)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // find the set of shortest paths from from to any other node in the graph\r
-    // that is reachable (i.e. for which path_exists() is true)\r
-    // This is an unweighted shortest path, so just counts the number of arcs\r
-    // if there is more than one shortest path to a node it returns the first one\r
-    // If there are no paths, returns an empty list\r
-    const_path_vector shortest_paths(const_iterator from, arc_select_fn = 0) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    path_vector shortest_paths(iterator from, arc_select_fn = 0)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-  private:\r
-    friend class digraph_iterator<NT,AT,NT&,NT*>;\r
-    friend class digraph_iterator<NT,AT,const NT&,const NT*>;\r
-    friend class digraph_arc_iterator<NT,AT,AT&,AT*>;\r
-    friend class digraph_arc_iterator<NT,AT,const AT&, const AT*>;\r
-\r
-    typedef std::set<const_iterator> const_iterator_set;\r
-    typedef TYPENAME const_iterator_set::iterator const_iterator_set_iterator;\r
-\r
-    bool path_exists_r(const_iterator from, const_iterator to, const_iterator_set& visited, arc_select_fn) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    void all_paths_r(const_iterator from, const_iterator to, const_arc_vector& so_far, const_path_vector& result, arc_select_fn) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    void reachable_nodes_r(const_iterator from, const_iterator_set& visited, arc_select_fn) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    void reaching_nodes_r(const_iterator to, const_iterator_set& visited, arc_select_fn) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    digraph_node<NT,AT>* m_nodes_begin;\r
-    digraph_node<NT,AT>* m_nodes_end;\r
-    digraph_arc<NT,AT>* m_arcs_begin;\r
-    digraph_arc<NT,AT>* m_arcs_end;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "digraph.tpp"\r
-#endif\r
+#ifndef STLPLUS_DIGRAPH
+#define STLPLUS_DIGRAPH
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   STL-style Directed graph template component
+//   Digraph stands for directed-graph, i.e. all arcs have a direction
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include "safe_iterator.hpp"
+#include "exceptions.hpp"
+#include <vector>
+#include <map>
+#include <set>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Internals
+
+  template<typename NT, typename AT> class digraph_node;
+  template<typename NT, typename AT> class digraph_arc;
+  template<typename NT, typename AT> class digraph;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // The Digraph iterator classes
+  // a digraph_iterator points to a node whilst a digraph_arc_iterator points to an arc
+  // Note that these are redefined as:
+  //   digraph<NT,AT>::iterator           - points to a non-const node
+  //   digraph<NT,AT>::const_iterator     - points to a const node
+  //   digraph<NT,AT>::arc_iterator       - points to a non-const arc
+  //   digraph<NT,AT>::const_arc_iterator - points to a const arc
+  // and this is the form in which they should be used
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  class digraph_iterator : public safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >
+  {
+  public:
+    friend class digraph<NT,AT>;
+
+    // local type definitions
+    // an iterator points to an object whilst a const_iterator points to a const object
+    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;
+    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;
+    typedef digraph_iterator<NT,AT,NRef,NPtr> this_iterator;
+    typedef NRef reference;
+    typedef NPtr pointer;
+
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
+    digraph_iterator(void);
+    ~digraph_iterator(void);
+
+    // Type conversion methods allow const_iterator and iterator to be converted
+    // convert an iterator/const_iterator to a const_iterator
+    const_iterator constify(void) const;
+    // convert an iterator/const_iterator to an iterator
+    iterator deconstify(void) const;
+
+    // increment/decrement operators used to step through the set of all nodes in a graph
+    // it is only legal to increment a valid iterator
+    // pre-increment
+    this_iterator& operator ++ (void)
+      throw(null_dereference,end_dereference);
+    // post-increment
+    this_iterator operator ++ (int)
+      throw(null_dereference,end_dereference);
+    // pre-decrement
+    this_iterator& operator -- (void)
+      throw(null_dereference,end_dereference);
+    // post-decrement
+    this_iterator operator -- (int)
+      throw(null_dereference,end_dereference);
+
+    // test useful for testing whether iteration has completed and for inclusion in other containers
+    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()
+    bool operator == (const this_iterator& r) const;
+    bool operator != (const this_iterator& r) const;
+    bool operator < (const this_iterator& r) const;
+
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element
+    // it is illegal to dereference an invalid (i.e. null or end) iterator
+    reference operator*(void) const
+      throw(null_dereference,end_dereference);
+    pointer operator->(void) const
+      throw(null_dereference,end_dereference);
+
+  public:
+    // constructor used by digraph to create a non-null iterator
+    explicit digraph_iterator(digraph_node<NT,AT>* node);
+    // constructor used by digraph to create an end iterator
+    explicit digraph_iterator(const digraph<NT,AT>* owner);
+    // used to create an alias of an iterator
+    explicit digraph_iterator(const safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >& iterator);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  class digraph_arc_iterator : public safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >
+  {
+  public:
+    friend class digraph<NT,AT>;
+
+    // local type definitions
+    // an iterator points to an object whilst a const_iterator points to a const object
+    typedef digraph_arc_iterator<NT,AT,AT&,AT*> iterator;
+    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_iterator;
+    typedef digraph_arc_iterator<NT,AT,ARef,APtr> this_iterator;
+    typedef ARef reference;
+    typedef APtr pointer;
+
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
+    digraph_arc_iterator(void);
+    ~digraph_arc_iterator(void);
+
+    // Type conversion methods allow const_iterator and iterator to be converted
+    // convert an iterator/const_iterator to a const_iterator
+    const_iterator constify(void) const;
+    // convert an iterator/const_iterator to an iterator
+    iterator deconstify(void) const;
+
+    // increment/decrement operators used to step through the set of all nodes in a graph
+    // it is only legal to increment a valid iterator
+    // pre-increment
+    this_iterator& operator ++ (void)
+      throw(null_dereference,end_dereference);
+    // post-increment
+    this_iterator operator ++ (int)
+      throw(null_dereference,end_dereference);
+    // pre-decrement
+    this_iterator& operator -- (void)
+      throw(null_dereference,end_dereference);
+    // post-decrement
+    this_iterator operator -- (int)
+      throw(null_dereference,end_dereference);
+
+    // test useful for testing whether iteration has completed and for inclusion in other containers
+    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()
+    bool operator == (const this_iterator&) const;
+    bool operator != (const this_iterator&) const;
+    bool operator < (const this_iterator&) const;
+
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element
+    // it is illegal to dereference an invalid (i.e. null or end) iterator
+    reference operator*(void) const
+      throw(null_dereference,end_dereference);
+    pointer operator->(void) const
+      throw(null_dereference,end_dereference);
+
+  public:
+    // constructor used by digraph to create a non-null iterator
+    explicit digraph_arc_iterator(digraph_arc<NT,AT>* arc);
+    // constructor used by digraph to create an end iterator
+    explicit digraph_arc_iterator(const digraph<NT,AT>* owner);
+    // used to create an alias of an iterator
+    explicit digraph_arc_iterator(const safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >& iterator);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // The Graph class
+  // NT is the Node type and AT is the Arc type
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename NT, typename AT>
+  class digraph
+  {
+  public:
+    // STL-like typedefs for the types and iterators
+    typedef NT node_type;
+    typedef AT arc_type;
+    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;
+    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;
+    typedef digraph_arc_iterator<NT,AT,AT&,AT*> arc_iterator;
+    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_arc_iterator;
+
+    // supplementary types used throughout
+
+    // a path is represented as a vector of arcs so the forward traversal is
+    // done by going from begin() to end() or 0 to size-1 - of course a backward
+    // traversal can be done by traversing the vector backwards
+    typedef std::vector<arc_iterator> arc_vector;
+    typedef std::vector<const_arc_iterator> const_arc_vector;
+    const_arc_vector constify_arcs(const arc_vector&) const
+      throw(wrong_object,null_dereference,end_dereference);
+    arc_vector deconstify_arcs(const const_arc_vector&) const
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // a path vector is a vector of paths used to represent all the paths from one node to another
+    // there is no particular ordering to the paths in the vector
+    typedef std::vector<arc_vector> path_vector;
+    typedef std::vector<const_arc_vector> const_path_vector;
+    const_path_vector constify_paths(const path_vector&) const
+      throw(wrong_object,null_dereference,end_dereference);
+    path_vector deconstify_paths(const const_path_vector&) const
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // a node vector is a simple vector of nodes used to represent the reachable sets
+    // there is no particular ordering to the nodes in the vector
+    typedef std::vector<iterator> node_vector;
+    typedef std::vector<const_iterator> const_node_vector;
+    const_node_vector constify_nodes(const node_vector&) const
+      throw(wrong_object,null_dereference,end_dereference);
+    node_vector deconstify_nodes(const const_node_vector&) const
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // callback used in the path algorithms to select which arcs to consider
+    typedef bool (*arc_select_fn) (const digraph<NT,AT>&, const_arc_iterator);
+
+    // a value representing an unknown offset
+    // Note that it's static so use in the form digraph<NT,AT>::npos()
+    static unsigned npos(void);
+
+    //////////////////////////////////////////////////////////////////////////
+    // Constructors, destructors and copies
+
+    digraph(void);
+    ~digraph(void);
+
+    // copy constructor and assignment both copy the graph
+    digraph(const digraph<NT,AT>&);
+    digraph<NT,AT>& operator=(const digraph<NT,AT>&);
+
+    //////////////////////////////////////////////////////////////////////////
+    // Basic Node functions
+    // Nodes are referred to by iterators created when the node is inserted.
+    // Iterators remain valid unless the node is erased (they are list iterators, so no resize problems)
+    // It is also possible to walk through all the nodes using a list-like start() to end() loop
+    // Each node has a set of input arcs and output arcs. These are indexed by an unsigned i.e. they form a vector.
+    // The total number of inputs is the fanin and the total number of outputs is the fanout.
+    // The contents of the node (type NT) are accessed, of course, by dereferencing the node iterator.
+
+    // tests for the number of nodes and the special test for zero nodes
+    bool empty(void) const;
+    unsigned size(void) const;
+
+    // add a new node and return its iterator
+    iterator insert(const NT& node_data);
+
+    // remove a node and return the iterator to the next node
+    // erasing a node erases its arcs
+    iterator erase(iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+    // remove all nodes
+    void clear(void);
+
+    // traverse all the nodes in no particular order using STL-style iteration
+    const_iterator begin(void) const;
+    iterator begin(void);
+    const_iterator end(void) const;
+    iterator end(void);
+
+    // access the inputs of this node
+    // the fanin is the number of inputs and the inputs are accessed using an index from 0..fanin-1
+    unsigned fanin(const_iterator) const
+      throw(wrong_object,null_dereference,end_dereference);
+    unsigned fanin(iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+    const_arc_iterator input(const_iterator, unsigned) const
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+    arc_iterator input(iterator, unsigned)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+
+    // access the outputs of this node
+    // the fanout is the number of outputs and the outputs are accessed using an index from 0..fanout-1
+    unsigned fanout(const_iterator) const
+      throw(wrong_object,null_dereference,end_dereference);
+    unsigned fanout(iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+    const_arc_iterator output(const_iterator, unsigned) const
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+    arc_iterator output(iterator, unsigned)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+
+    // convenience routines for getting the set of all inputs or all outputs as vectors
+    const_arc_vector inputs(const_iterator) const
+      throw(wrong_object,null_dereference,end_dereference);
+    arc_vector inputs(iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+    const_arc_vector outputs(const_iterator) const
+      throw(wrong_object,null_dereference,end_dereference);
+    arc_vector outputs(iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // find the output index of an arc which goes from this node
+    // returns digraph<NT,AT>::npos if the arc is not an output of from
+    unsigned output_offset(const_iterator from, const_arc_iterator arc) const
+      throw(wrong_object,null_dereference,end_dereference);
+    unsigned output_offset(iterator from, arc_iterator arc)
+      throw(wrong_object,null_dereference,end_dereference);
+    // ditto for an input arc
+    unsigned input_offset(const_iterator to, const_arc_iterator arc) const
+      throw(wrong_object,null_dereference,end_dereference);
+    unsigned input_offset(iterator to, arc_iterator arc)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    //////////////////////////////////////////////////////////////////////////
+    // Basic Arc functions
+    // to avoid name conflicts, arc functions have the arc_ prefix 
+    // Arcs, like nodes, are referred to by a list iterator which is returned by the arc_insert function
+    // They may also be visited from arc_begin() to arc_end()
+    // Each arc has a from field and a to field which contain the node iterators of the endpoints of the arc
+    // Of course, the arc data can be accessed by simply dereferencing the iterator
+
+    // tests for the number of arcs and the special test for zero arcs
+    bool arc_empty (void) const;
+    unsigned arc_size(void) const;
+
+    // add a new arc and return its iterator
+    arc_iterator arc_insert(iterator from, iterator to, const AT& arc_data = AT())
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // remove an arc and return the iterator to the next arc
+    arc_iterator arc_erase(arc_iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+    // remove all arcs
+    void arc_clear(void);
+
+    // traverse all the arcs in no particular order using STL-style iteration
+    const_arc_iterator arc_begin(void) const;
+    arc_iterator arc_begin(void);
+    const_arc_iterator arc_end(void) const;
+    arc_iterator arc_end(void);
+
+    // find the node that an arc points from or to
+    const_iterator arc_from(const_arc_iterator) const
+      throw(wrong_object,null_dereference,end_dereference);
+    iterator arc_from(arc_iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+    const_iterator arc_to(const_arc_iterator) const
+      throw(wrong_object,null_dereference,end_dereference);
+    iterator arc_to(arc_iterator)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // reconnect an arc to a different from and to node
+    void arc_move(arc_iterator arc, iterator from, iterator to)
+      throw(wrong_object,null_dereference,end_dereference);
+    // reconnect just the from node
+    void arc_move_from(arc_iterator arc, iterator from)
+      throw(wrong_object,null_dereference,end_dereference);
+    // reconnect just the to node
+    void arc_move_to(arc_iterator arc, iterator to)
+      throw(wrong_object,null_dereference,end_dereference);
+    // reverse the arc direction so that to becomes from and vice-versa
+    void arc_flip(arc_iterator arc)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Adjacency algorithms
+
+    // test whether the nodes are adjacent i.e. whether there is an arc going from from to to
+    bool adjacent(const_iterator from, const_iterator to) const
+      throw(wrong_object,null_dereference,end_dereference);
+    bool adjacent(iterator from, iterator to)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // as above, but returns the arc that makes the nodes adjacent
+    // returns the first arc if there's more than one, returns arc_end() if there are none
+    const_arc_iterator adjacent_arc(const_iterator from, const_iterator to) const
+      throw(wrong_object,null_dereference,end_dereference);
+    arc_iterator adjacent_arc(iterator from, iterator to)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // as above, but returns the set of all arcs that make two nodes adjacent (there may be more than one)
+    // returns an empty vector if there are none
+    const_arc_vector adjacent_arcs(const_iterator from, const_iterator to) const
+      throw(wrong_object,null_dereference,end_dereference);
+    arc_vector adjacent_arcs(iterator from, iterator to)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // return the adjacency sets for the node inputs or outputs, i.e. the set of nodes adjacent to this node
+    // each adjacent node will only be entered once even if there are multiple arcs between the nodes
+    const_node_vector input_adjacencies(const_iterator to) const
+      throw(wrong_object,null_dereference,end_dereference);
+    node_vector input_adjacencies(iterator to)
+      throw(wrong_object,null_dereference,end_dereference);
+    const_node_vector output_adjacencies(const_iterator from) const
+      throw(wrong_object,null_dereference,end_dereference);
+    node_vector output_adjacencies(iterator from)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Topographical Sort Algorithm
+    // This generates a node ordering such that each node is visited after its fanin nodes.
+
+    // This only generates a valid ordering for a DAG. 
+
+    // The return value is a pair : 
+    //  - the node vector which is a set of iterators to the nodes in sorted order
+    //  - the arc vector is the set of backward ards that were broken to achieve the sort
+    // If the arc vector is empty then the graph formed a DAG.
+
+    // The arc selection callback can be used to ignore arcs that are not part
+    // of the ordering, i.e. arcs that are meant to be backwards arcs
+
+    std::pair<const_node_vector,const_arc_vector> sort(arc_select_fn = 0) const;
+    std::pair<node_vector,arc_vector> sort(arc_select_fn = 0);
+
+    // Simplified variant of above for graphs that are known to be DAGs.
+    // If the sort fails due to backward arcs, the
+    // return vector is empty. Note that this will also be empty if the graph
+    // has no nodes in it, so use the empty() method to differentiate.
+
+    const_node_vector dag_sort(arc_select_fn = 0) const;
+    node_vector dag_sort(arc_select_fn = 0);
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Basic Path Algorithms
+    // A path is a series of arcs - you can use arc_from and arc_to to convert
+    // that into a series of nodes. All the path algorithms take an arc_select
+    // which allows arcs to be selected or rejected for consideration in a path.
+
+    // A selection callback function is applied to each arc in the traversal and
+    // returns true if the arc is to be selected and false if the arc is to be
+    // rejected. If no function is provided the arc is selected. If you want to
+    // use arc selection you should create a function with the type profile given
+    // by the arc_select_fn type. The select function is passed both the graph and
+    // the arc iterator so that it is possible to select an arc on the basis of
+    // the nodes it is connected to.
+
+    // Note: I used a callback because the STL-like predicate idea wasn't working for me...
+
+    // test for the existence of a path from from to to
+    bool path_exists(const_iterator from, const_iterator to, arc_select_fn = 0) const
+      throw(wrong_object,null_dereference,end_dereference);
+    bool path_exists(iterator from, iterator to, arc_select_fn = 0)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // get the set of all paths from from to to
+    const_path_vector all_paths(const_iterator from, const_iterator to, arc_select_fn = 0) const
+      throw(wrong_object,null_dereference,end_dereference);
+    path_vector all_paths(iterator from, iterator to, arc_select_fn = 0)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // get the set of all nodes that can be reached by any path from from
+    const_node_vector reachable_nodes(const_iterator from, arc_select_fn = 0) const
+      throw(wrong_object,null_dereference,end_dereference);
+    node_vector reachable_nodes(iterator from, arc_select_fn = 0)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // get the set of all nodes that can reach to to by any path
+    const_node_vector reaching_nodes(const_iterator to, arc_select_fn = 0) const
+      throw(wrong_object,null_dereference,end_dereference);
+    node_vector reaching_nodes(iterator to, arc_select_fn = 0)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // Unweighted Shortest path algorithms
+
+    // find the shortest path from from to to
+    // This is an unweighted shortest path algorithm, i.e. the weight of each
+    // arc is assumed to be 1, so just counts the number of arcs
+    // if there is more than one shortest path it returns the first one
+    // If there are no paths, returns an empty path
+    const_arc_vector shortest_path(const_iterator from, const_iterator to, arc_select_fn = 0) const
+      throw(wrong_object,null_dereference,end_dereference);
+    arc_vector shortest_path(iterator from, iterator to, arc_select_fn = 0)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // find the set of shortest paths from from to any other node in the graph
+    // that is reachable (i.e. for which path_exists() is true)
+    // This is an unweighted shortest path, so just counts the number of arcs
+    // if there is more than one shortest path to a node it returns the first one
+    // If there are no paths, returns an empty list
+    const_path_vector shortest_paths(const_iterator from, arc_select_fn = 0) const
+      throw(wrong_object,null_dereference,end_dereference);
+    path_vector shortest_paths(iterator from, arc_select_fn = 0)
+      throw(wrong_object,null_dereference,end_dereference);
+
+  private:
+    friend class digraph_iterator<NT,AT,NT&,NT*>;
+    friend class digraph_iterator<NT,AT,const NT&,const NT*>;
+    friend class digraph_arc_iterator<NT,AT,AT&,AT*>;
+    friend class digraph_arc_iterator<NT,AT,const AT&, const AT*>;
+
+    typedef std::set<const_iterator> const_iterator_set;
+    typedef TYPENAME const_iterator_set::iterator const_iterator_set_iterator;
+
+    bool path_exists_r(const_iterator from, const_iterator to, const_iterator_set& visited, arc_select_fn) const
+      throw(wrong_object,null_dereference,end_dereference);
+
+    void all_paths_r(const_iterator from, const_iterator to, const_arc_vector& so_far, const_path_vector& result, arc_select_fn) const
+      throw(wrong_object,null_dereference,end_dereference);
+
+    void reachable_nodes_r(const_iterator from, const_iterator_set& visited, arc_select_fn) const
+      throw(wrong_object,null_dereference,end_dereference);
+
+    void reaching_nodes_r(const_iterator to, const_iterator_set& visited, arc_select_fn) const
+      throw(wrong_object,null_dereference,end_dereference);
+
+    digraph_node<NT,AT>* m_nodes_begin;
+    digraph_node<NT,AT>* m_nodes_end;
+    digraph_arc<NT,AT>* m_arcs_begin;
+    digraph_arc<NT,AT>* m_arcs_end;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "digraph.tpp"
+#endif
index c10586b011e354782d713787b0f106fdef6c73f3..804954a0db72e70bd33d2c36cd32986736e1aaf6 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Note: I tried to write this using STL lists for the node and arc lists, but\r
-//   it got far too hairy. The specific problem is that I wanted a digraph\r
-//   iterator to contain a list::iterator so I needed to be able to generate a\r
-//   list::iterator from a node or arc and STL list iterators don't give you that\r
-//   functionality. I tried burgling the data structures, but that was\r
-//   non-portable between different STL implementations so needed lots of #ifdefs\r
-//   and so was mind-bogglingly awful and unreadable - in other words a\r
-//   maintenance nightmare. I gave up and impemented my own lists - not difficult.\r
-\r
-//   I use circular double-linked lists. The circular design means that both\r
-//   ends of the list are equally accessible in unit time. An empty list\r
-//   contains no objects. There is no end node in the list - unlike the STL\r
-//   lists which have a dummy node for end iterators to point to -\r
-//   conceptually the end iterator points one element beyond the end of the\r
-//   list. However, I implement the end iterator concept in the iterator\r
-//   itself, so do not need the dummy end node.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include <algorithm>\r
-#include <deque>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Internals\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename NT, typename AT>\r
-  class digraph_node\r
-  {\r
-  public:\r
-    master_iterator<digraph<NT,AT>, digraph_node<NT,AT> > m_master;\r
-    NT m_data;\r
-    digraph_node<NT,AT>* m_prev;\r
-    digraph_node<NT,AT>* m_next;\r
-    std::vector<digraph_arc<NT,AT>*> m_inputs;\r
-    std::vector<digraph_arc<NT,AT>*> m_outputs;\r
-  public:\r
-    digraph_node(const digraph<NT,AT>* owner, const NT& d = NT()) :\r
-      m_master(owner,this), m_data(d), m_prev(0), m_next(0)\r
-      {\r
-      }\r
-    ~digraph_node(void)\r
-      {\r
-      }\r
-  };\r
-\r
-  template<typename NT, typename AT>\r
-  class digraph_arc\r
-  {\r
-  public:\r
-    master_iterator<digraph<NT,AT>, digraph_arc<NT,AT> > m_master;\r
-    AT m_data;\r
-    digraph_arc<NT,AT>* m_prev;\r
-    digraph_arc<NT,AT>* m_next;\r
-    digraph_node<NT,AT>* m_from;\r
-    digraph_node<NT,AT>* m_to;\r
-    digraph_arc(const digraph<NT,AT>* owner, digraph_node<NT,AT>* from = 0, digraph_node<NT,AT>* to = 0, const AT& d = AT()) : \r
-      m_master(owner,this), m_data(d), m_prev(0), m_next(0), m_from(from), m_to(to)\r
-      {\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Iterators\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Node iterator\r
-\r
-  // construct a null iterator\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(void)\r
-  {\r
-  }\r
-\r
-  // valid iterator\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(digraph_node<NT,AT>* node) :\r
-    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(node->m_master)\r
-  {\r
-  }\r
-\r
-  // end iterator\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(const digraph<NT,AT>* owner) :\r
-    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(owner)\r
-  {\r
-  }\r
-\r
-  // alias an iterator\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(const safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >& iterator) : \r
-    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(iterator)\r
-  {\r
-  }\r
-\r
-  // destructor\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_iterator<NT,AT,NRef,NPtr>::~digraph_iterator(void)\r
-  {\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::const_iterator digraph_iterator<NT,AT,NRef,NPtr>::constify (void) const\r
-  {\r
-    return digraph_iterator<NT,AT,const NT&,const NT*>(*this);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::iterator digraph_iterator<NT,AT,NRef,NPtr>::deconstify (void) const\r
-  {\r
-    return digraph_iterator<NT,AT,NT&,NT*>(*this);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& digraph_iterator<NT,AT,NRef,NPtr>::operator ++ (void)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    if (this->node()->m_next)\r
-      this->set(this->node()->m_next->m_master);\r
-    else\r
-      this->set_end();\r
-    return *this;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator digraph_iterator<NT,AT,NRef,NPtr>::operator ++ (int)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // post-increment is defined in terms of the pre-increment\r
-    digraph_iterator<NT,AT,NRef,NPtr> result(*this);\r
-    ++(*this);\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& digraph_iterator<NT,AT,NRef,NPtr>::operator -- (void)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    if (this->node()->m_prev)\r
-      this->set(this->node()->m_prev->m_master);\r
-    else\r
-      this->set_end();\r
-    return *this;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator digraph_iterator<NT,AT,NRef,NPtr>::operator -- (int)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // post-decrement is defined in terms of the pre-decrement\r
-    digraph_iterator<NT,AT,NRef,NPtr> result(*this);\r
-    --(*this);\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  bool digraph_iterator<NT,AT,NRef,NPtr>::operator == (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const\r
-  {\r
-    return equal(r);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  bool digraph_iterator<NT,AT,NRef,NPtr>::operator != (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const\r
-  {\r
-    return !operator==(r);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  bool digraph_iterator<NT,AT,NRef,NPtr>::operator < (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const\r
-  {\r
-    return compare(r) < 0;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::reference digraph_iterator<NT,AT,NRef,NPtr>::operator*(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    return this->node()->m_data;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::pointer digraph_iterator<NT,AT,NRef,NPtr>::operator->(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return &(operator*());\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Arc Iterator\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  digraph_arc_iterator<NT,AT,ARef,APtr>::digraph_arc_iterator(void)\r
-  {\r
-  }\r
-\r
-  // valid iterator\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(digraph_arc<NT,AT>* arc) :\r
-    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(arc->m_master)\r
-  {\r
-  }\r
-\r
-  // end iterator\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(const digraph<NT,AT>* owner) :\r
-    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(owner)\r
-  {\r
-  }\r
-\r
-  // alias an iterator\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(const safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >& iterator) : \r
-    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(iterator)\r
-  {\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  digraph_arc_iterator<NT,AT,ARef,APtr>::~digraph_arc_iterator(void)\r
-  {\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,NRef,NPtr>::const_iterator digraph_arc_iterator<NT,AT,NRef,NPtr>::constify (void) const\r
-  {\r
-    return digraph_arc_iterator<NT,AT,const AT&,const AT*>(*this);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,NRef,NPtr>::iterator digraph_arc_iterator<NT,AT,NRef,NPtr>::deconstify (void) const\r
-  {\r
-    return digraph_arc_iterator<NT,AT,AT&,AT*>(*this);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& digraph_arc_iterator<NT,AT,ARef,APtr>::operator ++ (void)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    if (this->node()->m_next)\r
-      this->set(this->node()->m_next->m_master);\r
-    else\r
-      this->set_end();\r
-    return *this;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator digraph_arc_iterator<NT,AT,ARef,APtr>::operator ++ (int)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // post-increment is defined in terms of the pre-increment\r
-    digraph_arc_iterator<NT,AT,ARef,APtr> result(*this);\r
-    ++(*this);\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& digraph_arc_iterator<NT,AT,ARef,APtr>::operator -- (void)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    if (this->node()->m_prev)\r
-      this->set(this->node()->m_prev->m_master);\r
-    else\r
-      this->set_end();\r
-    return *this;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator digraph_arc_iterator<NT,AT,ARef,APtr>::operator -- (int)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // post-decrement is defined in terms of the pre-decrement\r
-    digraph_arc_iterator<NT,AT,ARef,APtr> result(*this);\r
-    --(*this);\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator == (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const\r
-  {\r
-    return equal(r);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator != (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const\r
-  {\r
-    return !operator==(r);\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator < (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const\r
-  {\r
-    return compare(r) < 0;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::reference digraph_arc_iterator<NT,AT,ARef,APtr>::operator*(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    return this->node()->m_data;\r
-  }\r
-\r
-  template<typename NT, typename AT, typename ARef, typename APtr>\r
-  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::pointer digraph_arc_iterator<NT,AT,ARef,APtr>::operator->(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return &(operator*());\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // subtype utilities\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::constify_arcs(const TYPENAME digraph<NT,AT>::arc_vector& arcs) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > result;\r
-    for (unsigned i = 0; i < arcs.size(); i++)\r
-    {\r
-      arcs[i].assert_valid(this);\r
-      result.push_back(arcs[i].constify());\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::deconstify_arcs(const TYPENAME digraph<NT,AT>::const_arc_vector& arcs) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;\r
-    for (unsigned i = 0; i < arcs.size(); i++)\r
-    {\r
-      arcs[i].assert_valid(this);\r
-      result.push_back(arcs[i].deconstify());\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_path_vector digraph<NT,AT>::constify_paths(const TYPENAME digraph<NT,AT>::path_vector& paths) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;\r
-    for (unsigned i = 0; i < paths.size(); i++)\r
-      result.push_back(constify_arcs(paths[i]));\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::path_vector digraph<NT,AT>::deconstify_paths(const TYPENAME digraph<NT,AT>::const_path_vector& paths) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > > result;\r
-    for (unsigned i = 0; i < paths.size(); i++)\r
-      result.push_back(deconstify_arcs(paths[i]));\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::constify_nodes(const TYPENAME digraph<NT,AT>::node_vector& nodes) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
-    for (unsigned i = 0; i < nodes.size(); i++)\r
-    {\r
-      nodes[i].assert_valid(this);\r
-      result.push_back(nodes[i].constify());\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::deconstify_nodes(const TYPENAME digraph<NT,AT>::const_node_vector& nodes) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<digraph_iterator<NT,AT,NT&,NT*> > result;\r
-    for (unsigned i = 0; i < nodes.size(); i++)\r
-    {\r
-      nodes[i].assert_valid(this);\r
-      result.push_back(nodes[i].deconstify());\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::npos(void)\r
-  {\r
-    return(unsigned)-1;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Constructors etc.\r
-\r
-  template<typename NT, typename AT>\r
-  digraph<NT,AT>::digraph(void) :\r
-    m_nodes_begin(0), m_nodes_end(0), m_arcs_begin(0), m_arcs_end(0)\r
-  {\r
-    // node and arc lists are circular double-linked lists\r
-    // they start out empty (no dummy end node)\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  digraph<NT,AT>::~digraph(void)\r
-  {\r
-    clear();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  digraph<NT,AT>::digraph(const digraph<NT,AT>& r) :\r
-    m_nodes_begin(0), m_nodes_end(0), m_arcs_begin(0), m_arcs_end(0)\r
-  {\r
-    *this = r;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  digraph<NT,AT>& digraph<NT,AT>::operator=(const digraph<NT,AT>& r)\r
-  {\r
-    // make it self-copy safe i.e. a=a; is a valid instruction\r
-    if (this == &r) return *this;\r
-    clear();\r
-    // first phase is to copy the nodes, creating a map of cross references from the old nodes to their new equivalents\r
-    std::map<digraph_iterator<NT,AT,const NT&,const NT*>, digraph_iterator<NT,AT,NT&,NT*> > xref;\r
-    for (digraph_iterator<NT,AT,const NT&,const NT*> n = r.begin(); n != r.end(); n++)\r
-      xref[n] = insert(*n);\r
-    // second phase is to copy the arcs, using the map to convert the old to and from nodes to the new nodes\r
-    for (digraph_arc_iterator<NT,AT, const AT&,const AT*> a = r.arc_begin(); a != r.arc_end(); a++)\r
-      arc_insert(xref[r.arc_from(a)],xref[r.arc_to(a)],*a);\r
-    return *this;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Basic Node functions\r
-\r
-  template<typename NT, typename AT>\r
-  bool digraph<NT,AT>::empty(void) const\r
-  {\r
-    return m_nodes_begin == 0;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::size(void) const\r
-  {\r
-    unsigned count = 0;\r
-    for (digraph_iterator<NT,AT,const NT&,const NT*> i = begin(); i != end(); i++)\r
-      count++;\r
-    return count;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::insert(const NT& node_data)\r
-  {\r
-    digraph_node<NT,AT>* new_node = new digraph_node<NT,AT>(this,node_data);\r
-    if (!m_nodes_end)\r
-    {\r
-      // insert into an empty list\r
-      m_nodes_begin = new_node;\r
-      m_nodes_end = new_node;\r
-    }\r
-    else\r
-    {\r
-      // insert at the end of the list\r
-      new_node->m_prev = m_nodes_end;\r
-      m_nodes_end->m_next = new_node;\r
-      m_nodes_end = new_node;\r
-    }\r
-    return digraph_iterator<NT,AT,NT&,NT*>(new_node);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::erase(TYPENAME digraph<NT,AT>::iterator iter)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    // remove all arcs connected to this node first\r
-    // use arc_erase rather than arcs.erase because that tidies up the node at the other end of the arc too\r
-    for (unsigned i = fanin(iter); i--; )\r
-      arc_erase(input(iter,i));\r
-    for (unsigned j = fanout(iter); j--; )\r
-      arc_erase(output(iter,j));\r
-    // now unlink the node from the list and delete it\r
-    if (iter.node()->m_next)\r
-      iter.node()->m_next->m_prev = iter.node()->m_prev;\r
-    if (iter.node()->m_prev)\r
-      iter.node()->m_prev->m_next = iter.node()->m_next;\r
-    digraph_node<NT,AT>* next = iter.node()->m_next;\r
-    delete iter.node();\r
-    // return the next node in the list\r
-    if (next)\r
-      return digraph_iterator<NT,AT,NT&,NT*>(next);\r
-    else\r
-      return digraph_iterator<NT,AT,NT&,NT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::clear(void)\r
-  {\r
-    // clearing the nodes also clears the arcs\r
-    for (digraph_iterator<NT,AT,NT&,NT*> i = begin(); i != end(); )\r
-      i = erase(i);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::begin(void) const\r
-  {\r
-    if (m_nodes_begin)\r
-      return digraph_iterator<NT,AT,const NT&,const NT*>(m_nodes_begin);\r
-    else\r
-      return digraph_iterator<NT,AT,const NT&,const NT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::begin(void)\r
-  {\r
-    if (m_nodes_begin)\r
-      return digraph_iterator<NT,AT,NT&,NT*>(m_nodes_begin);\r
-    else\r
-      return digraph_iterator<NT,AT,NT&,NT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::end(void) const\r
-  {\r
-    return digraph_iterator<NT,AT,const NT&,const NT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::end(void)\r
-  {\r
-    return digraph_iterator<NT,AT,NT&,NT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::fanin(TYPENAME digraph<NT,AT>::const_iterator iter) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return iter.node()->m_inputs.size();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::fanin(TYPENAME digraph<NT,AT>::iterator iter)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return iter.node()->m_inputs.size();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::input(TYPENAME digraph<NT,AT>::const_iterator iter, unsigned i) const\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    iter.assert_valid(this);\r
-    if (i >= iter.node()->m_inputs.size()) throw std::out_of_range("digraph::input");\r
-    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(iter.node()->m_inputs[i]);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::input(TYPENAME digraph<NT,AT>::iterator iter, unsigned i)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    iter.assert_valid(this);\r
-    if (i >= iter.node()->m_inputs.size()) throw std::out_of_range("digraph::input");\r
-    return digraph_arc_iterator<NT,AT,AT&,AT*>(iter.node()->m_inputs[i]);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::fanout(TYPENAME digraph<NT,AT>::const_iterator iter) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return iter.node()->m_outputs.size();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::fanout(TYPENAME digraph<NT,AT>::iterator iter)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return iter.node()->m_outputs.size();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::output(TYPENAME digraph<NT,AT>::const_iterator iter, unsigned i) const\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    iter.assert_valid(this);\r
-    if (i >= iter.node()->m_outputs.size()) throw std::out_of_range("digraph::output");\r
-    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(iter.node()->m_outputs[i]);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::output(TYPENAME digraph<NT,AT>::iterator iter, unsigned i)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    iter.assert_valid(this);\r
-    if (i >= iter.node()->m_outputs.size()) throw std::out_of_range("digraph::output");\r
-    return digraph_arc_iterator<NT,AT,AT&,AT*>(iter.node()->m_outputs[i]);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::inputs(TYPENAME digraph<NT,AT>::const_iterator node) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    node.assert_valid(this);\r
-    std::vector<digraph_arc_iterator<NT,AT,const AT&, const AT*> > result;\r
-    for (unsigned i = 0; i < fanin(node); i++)\r
-      result.push_back(input(node,i));\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::inputs(TYPENAME digraph<NT,AT>::iterator node)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    node.assert_valid(this);\r
-    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;\r
-    for (unsigned i = 0; i < fanin(node); i++)\r
-      result.push_back(input(node,i));\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::outputs(TYPENAME digraph<NT,AT>::const_iterator node) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    node.assert_valid(this);\r
-    std::vector<digraph_arc_iterator<NT,AT,const AT&, const AT*> > result;\r
-    for (unsigned i = 0; i < fanout(node); i++)\r
-      result.push_back(output(node,i));\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::outputs(TYPENAME digraph<NT,AT>::iterator node)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    node.assert_valid(this);\r
-    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;\r
-    for (unsigned i = 0; i < fanout(node); i++)\r
-      result.push_back(output(node,i));\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::output_offset(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                         TYPENAME digraph<NT,AT>::const_arc_iterator arc) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    from.assert_valid(this);\r
-    arc.assert_valid(this);\r
-    for (unsigned i = 0; i < fanout(from); i++)\r
-    {\r
-      if (output(from,i) == arc)\r
-        return i;\r
-    }\r
-    return digraph<NT,AT>::npos();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::output_offset(TYPENAME digraph<NT,AT>::iterator from,\r
-                                         TYPENAME digraph<NT,AT>::arc_iterator arc)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    from.assert_valid(this);\r
-    arc.assert_valid(this);\r
-    for (unsigned i = 0; i < fanout(from); i++)\r
-    {\r
-      if (output(from,i) == arc)\r
-        return i;\r
-    }\r
-    return digraph<NT,AT>::npos();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::input_offset(TYPENAME digraph<NT,AT>::const_iterator to,\r
-                                        TYPENAME digraph<NT,AT>::const_arc_iterator arc) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    to.assert_valid(this);\r
-    arc.assert_valid(this);\r
-    for (unsigned i = 0; i < fanin(to); i++)\r
-    {\r
-      if (input(to,i) == arc)\r
-        return i;\r
-    }\r
-    return digraph<NT,AT>::npos();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::input_offset(TYPENAME digraph<NT,AT>::iterator to,\r
-                                        TYPENAME digraph<NT,AT>::arc_iterator arc)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    to.assert_valid(this);\r
-    arc.assert_valid(this);\r
-    for (unsigned i = 0; i < fanin(to); i++)\r
-    {\r
-      if (input(to,i) == arc)\r
-        return i;\r
-    }\r
-    return digraph<NT,AT>::npos();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Basic Arc functions\r
-\r
-  template<typename NT, typename AT>\r
-  bool digraph<NT,AT>::arc_empty(void) const\r
-  {\r
-    return m_arcs_end == 0;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  unsigned digraph<NT,AT>::arc_size(void) const\r
-  {\r
-    unsigned count = 0;\r
-    for (digraph_arc_iterator<NT,AT, const AT&,const AT*> i = arc_begin(); i != arc_end(); i++)\r
-      count++;\r
-    return count;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_insert(TYPENAME digraph<NT,AT>::iterator from,\r
-                                                                   TYPENAME digraph<NT,AT>::iterator to,\r
-                                                                   const AT& arc_data)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    from.assert_valid(this);\r
-    to.assert_valid(this);\r
-    // create the new arc and link it in to the arc list\r
-    digraph_arc<NT,AT>* new_arc = new digraph_arc<NT,AT>(this, from.node(), to.node(), arc_data);\r
-    if (!m_arcs_end)\r
-    {\r
-      // insert into an empty list\r
-      m_arcs_begin = new_arc;\r
-      m_arcs_end = new_arc;\r
-    }\r
-    else\r
-    {\r
-      // insert at the end of the list\r
-      new_arc->m_prev = m_arcs_end;\r
-      m_arcs_end->m_next = new_arc;\r
-      m_arcs_end = new_arc;\r
-    }\r
-    // add this arc to the inputs and outputs of the end nodes\r
-    from.node()->m_outputs.push_back(new_arc);\r
-    to.node()->m_inputs.push_back(new_arc);\r
-    return digraph_arc_iterator<NT,AT,AT&,AT*>(new_arc);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_erase(TYPENAME digraph<NT,AT>::arc_iterator iter)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    // first remove this arc's pointers from the from/to nodes\r
-    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator i = iter.node()->m_to->m_inputs.begin(); i != iter.node()->m_to->m_inputs.end(); )\r
-    {\r
-      if (*i == iter.node())\r
-        i = iter.node()->m_to->m_inputs.erase(i);\r
-      else\r
-        i++;\r
-    }\r
-    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator o = iter.node()->m_from->m_outputs.begin(); o != iter.node()->m_from->m_outputs.end(); )\r
-    {\r
-      if (*o == iter.node())\r
-        o = iter.node()->m_from->m_outputs.erase(o);\r
-      else\r
-        o++;\r
-    }\r
-    // now unlink the arc from the list and delete it\r
-    if (iter.node()->m_next)\r
-      iter.node()->m_next->m_prev = iter.node()->m_prev;\r
-    if (iter.node()->m_prev)\r
-      iter.node()->m_prev->m_next = iter.node()->m_next;\r
-    digraph_arc<NT,AT>* next = iter.node()->m_next;\r
-    delete iter.node();\r
-    if (next)\r
-      return digraph_arc_iterator<NT,AT,AT&,AT*>(next);\r
-    else\r
-      return digraph_arc_iterator<NT,AT,AT&,AT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::arc_clear(void)\r
-  {\r
-    for (digraph_arc_iterator<NT,AT,AT&,AT*> a = arc_begin(); a != arc_end(); )\r
-      a = arc_erase(a);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::arc_begin(void) const\r
-  {\r
-    if (m_arcs_begin)\r
-      return digraph_arc_iterator<NT,AT, const AT&,const AT*>(m_arcs_begin);\r
-    else\r
-      return digraph_arc_iterator<NT,AT, const AT&,const AT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_begin(void)\r
-  {\r
-    if (m_arcs_begin)\r
-      return digraph_arc_iterator<NT,AT,AT&,AT*>(m_arcs_begin);\r
-    else\r
-      return digraph_arc_iterator<NT,AT,AT&,AT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::arc_end(void) const\r
-  {\r
-    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_end(void)\r
-  {\r
-    return digraph_arc_iterator<NT,AT,AT&,AT*>(this);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::arc_from(TYPENAME digraph<NT,AT>::const_arc_iterator iter) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return digraph_iterator<NT,AT,const NT&,const NT*>(iter.node()->m_from);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::arc_from(TYPENAME digraph<NT,AT>::arc_iterator iter)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return digraph_iterator<NT,AT,NT&,NT*>(iter.node()->m_from);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::arc_to(TYPENAME digraph<NT,AT>::const_arc_iterator iter) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return digraph_iterator<NT,AT,const NT&,const NT*>(iter.node()->m_to);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::arc_to(TYPENAME digraph<NT,AT>::arc_iterator iter)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    iter.assert_valid(this);\r
-    return digraph_iterator<NT,AT,NT&,NT*>(iter.node()->m_to);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::arc_move(TYPENAME digraph<NT,AT>::arc_iterator arc,\r
-                                TYPENAME digraph<NT,AT>::iterator from,\r
-                                TYPENAME digraph<NT,AT>::iterator to)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    arc_move_to(arc,to);\r
-    arc_move_from(arc,from);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::arc_move_from(TYPENAME digraph<NT,AT>::arc_iterator arc,\r
-                                     TYPENAME digraph<NT,AT>::iterator from)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    arc.assert_valid(this);\r
-    from.assert_valid(this);\r
-    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator o = arc.node()->m_from->m_outputs.begin(); o != arc.node()->m_from->m_outputs.end(); )\r
-    {\r
-      if (*o == arc.node())\r
-        o = arc.node()->m_from->m_outputs.erase(o);\r
-      else\r
-        o++;\r
-    }\r
-    from.node()->m_outputs.push_back(arc.node());\r
-    arc.node()->m_from = from.node();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::arc_move_to(TYPENAME digraph<NT,AT>::arc_iterator arc,\r
-                                   TYPENAME digraph<NT,AT>::iterator to)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    arc.assert_valid(this);\r
-    to.assert_valid(this);\r
-    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator i = arc.node()->m_to->m_inputs.begin(); i != arc.node()->m_to->m_inputs.end(); )\r
-    {\r
-      if (*i == arc.node())\r
-        i = arc.node()->m_to->m_inputs.erase(i);\r
-      else\r
-        i++;\r
-    }\r
-    to.node()->m_inputs.push_back(arc.node());\r
-    arc.node()->m_to = to.node();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::arc_flip(TYPENAME digraph<NT,AT>::arc_iterator arc)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    arc_move(arc,arc_to(arc),arc_from(arc));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Adjacency Algorithms\r
-\r
-  template<typename NT, typename AT>\r
-  bool digraph<NT,AT>::adjacent(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                TYPENAME digraph<NT,AT>::const_iterator to) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return adjacent_arc(from,to) != arc_end();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  bool digraph<NT,AT>::adjacent(TYPENAME digraph<NT,AT>::iterator from,\r
-                                TYPENAME digraph<NT,AT>::iterator to)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return adjacent_arc(from,to) != arc_end();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::adjacent_arc(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                                                           TYPENAME digraph<NT,AT>::const_iterator to) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    from.assert_valid(this);\r
-    to.assert_valid(this);\r
-    for (unsigned arc = 0; arc < fanout(from); arc++)\r
-    {\r
-      if (arc_to(output(from, arc)) == to)\r
-        return output(from,arc);\r
-    }\r
-    return arc_end();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::adjacent_arc(TYPENAME digraph<NT,AT>::iterator from,\r
-                                                                     TYPENAME digraph<NT,AT>::iterator to)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return adjacent_arc(from.constify(), to.constify()).deconstify();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::adjacent_arcs(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                                                          TYPENAME digraph<NT,AT>::const_iterator to) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    from.assert_valid(this);\r
-    to.assert_valid(this);\r
-    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > result;\r
-    for (unsigned arc = 0; arc < fanout(from); arc++)\r
-    {\r
-      if (arc_to(output(from, arc)) == to)\r
-        result.push_back(output(from,arc));\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::adjacent_arcs(TYPENAME digraph<NT,AT>::iterator from,\r
-                                                                    TYPENAME digraph<NT,AT>::iterator to)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_arcs(adjacent_arcs(from.constify(), to.constify()));\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::input_adjacencies(TYPENAME digraph<NT,AT>::const_iterator to) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
-    for (unsigned arc = 0; arc < fanin(to); arc++)\r
-    {\r
-      digraph_iterator<NT,AT,const NT&,const NT*> from = arc_from(input(to, arc));\r
-      if (std::find(result.begin(), result.end(), from) == result.end())\r
-        result.push_back(from);\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::input_adjacencies(TYPENAME digraph<NT,AT>::iterator to)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_nodes(input_adjacencies(to.constify()));\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::output_adjacencies(TYPENAME digraph<NT,AT>::const_iterator from) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
-    for (unsigned arc = 0; arc < fanout(from); arc++)\r
-    {\r
-      digraph_iterator<NT,AT,const NT&,const NT*> to = arc_to(output(from, arc));\r
-      if (find(result.begin(), result.end(), to) == result.end())\r
-        result.push_back(to);\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::output_adjacencies(TYPENAME digraph<NT,AT>::iterator from)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_nodes(output_adjacencies(from.constify()));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Topographical Sort Algorithms\r
-\r
-  template<typename NT, typename AT>\r
-  std::pair<TYPENAME digraph<NT,AT>::const_node_vector, TYPENAME digraph<NT,AT>::const_arc_vector>\r
-  digraph<NT,AT>::sort(TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-  {\r
-    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
-    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > errors;\r
-    // build a map containing the number of fanins to each node that must be visited before this one\r
-    std::map<digraph_iterator<NT,AT,const NT&,const NT*>,unsigned> fanin_map;\r
-    for (digraph_iterator<NT,AT,const NT&,const NT*> n = begin(); n != end(); n++)\r
-    {\r
-      unsigned predecessors = 0;\r
-      // only count predecessors connected by selected arcs\r
-      for (unsigned f = 0; f < fanin(n); f++)\r
-      {\r
-        digraph_arc_iterator<NT,AT, const AT&,const AT*> input_arc = input(n,f);\r
-        digraph_iterator<NT,AT,const NT&,const NT*> predecessor = arc_from(input_arc);\r
-        if (!select || select(*this,input_arc))\r
-          predecessors++;\r
-      }\r
-      if (predecessors == 0)\r
-      {\r
-        result.push_back(n);\r
-      }\r
-      else\r
-      {\r
-        fanin_map[n] = predecessors;\r
-      }\r
-    }\r
-    // main algorithm applies the topographical sort repeatedly. For a DAG, it\r
-    // will complete first time. However, with backward arcs, the first\r
-    // iteration will fail. The algorithm then tries breaking random arcs to try\r
-    // to get an ordering.\r
-    for(unsigned i = 0; !fanin_map.empty(); )\r
-    {\r
-      // now visit each node in traversal order, decrementing the fanin count of\r
-      // all successors. As each successor's fanin count goes to zero, it is\r
-      // appended to the result.\r
-      for (; i < result.size(); i++)\r
-      {\r
-        // Note: dereferencing gives us a node iterator\r
-        digraph_iterator<NT,AT,const NT&,const NT*> current = result[i];\r
-        for (unsigned f = 0; f < fanout(current); f++)\r
-        {\r
-          // only consider successors connected by selected arcs\r
-          digraph_arc_iterator<NT,AT, const AT&,const AT*> output_arc = output(current, f);\r
-          digraph_iterator<NT,AT,const NT&,const NT*> successor = arc_to(output_arc);\r
-          if (!select || select(*this,output_arc))\r
-          {\r
-            // don't consider arcs that have been eliminated to break a loop\r
-            if (fanin_map.find(successor) != fanin_map.end())\r
-            {\r
-              --fanin_map[successor];\r
-              if ((fanin_map[successor]) == 0)\r
-              {\r
-                result.push_back(successor);\r
-                fanin_map.erase(fanin_map.find(successor));\r
-              }\r
-            }\r
-          }\r
-        }\r
-      }\r
-      if (!fanin_map.empty())\r
-      {\r
-        // there must be backward arcs preventing completion\r
-        // try removing arcs from the sort to get a partial ordering containing all the nodes\r
-\r
-        // select an arc that is still relevant to the sort and break it\r
-        // first select a node that has non-zero fanin and its predecessor that has non-zero fanin\r
-        digraph_iterator<NT,AT,const NT&,const NT*> stuck_node = fanin_map.begin()->first;\r
-        for (unsigned f = 0; f < fanin(stuck_node); f++)\r
-        {\r
-          // now successively remove input arcs that are still part of the sort until the fanin reduces to zero\r
-          // first find a relevant arc - this must be a selected arc that has not yet been traversed by the first half of the algorithm\r
-          digraph_arc_iterator<NT,AT, const AT&,const AT*> input_arc = input(stuck_node, f);\r
-          if (!select || select(*this,input_arc))\r
-          {\r
-            digraph_iterator<NT,AT,const NT&,const NT*> predecessor = arc_from(input_arc);\r
-            if (fanin_map.find(predecessor) != fanin_map.end())\r
-            {\r
-              // found the right combination - remove this arc and then drop out of the fanin loop to restart the outer sort loop\r
-              errors.push_back(input_arc);\r
-              --fanin_map[stuck_node];\r
-              if ((fanin_map[stuck_node]) == 0)\r
-              {\r
-                result.push_back(stuck_node);\r
-                fanin_map.erase(fanin_map.find(stuck_node));\r
-                break;\r
-              }\r
-            }\r
-          }\r
-        }\r
-      }\r
-    }\r
-    return std::make_pair(result,errors);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  std::pair<TYPENAME digraph<NT,AT>::node_vector, TYPENAME digraph<NT,AT>::arc_vector>\r
-  digraph<NT,AT>::sort(TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-  {\r
-    std::pair<std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >,\r
-              std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > const_result =\r
-      const_cast<const digraph<NT,AT>*>(this)->sort(select);\r
-\r
-    std::pair<std::vector<digraph_iterator<NT,AT,NT&,NT*> >,\r
-              std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > > result =\r
-      std::make_pair(deconstify_nodes(const_result.first),deconstify_arcs(const_result.second));\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::dag_sort(TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-  {\r
-    std::pair<std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >,\r
-              std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result = sort(select);\r
-    if (result.second.empty()) return result.first;\r
-    return std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >();\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::dag_sort(TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-  {\r
-    return deconstify_nodes(const_cast<const digraph<NT,AT>*>(this)->dag_sort(select));\r
-  }\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Path Algorithms\r
-\r
-  template<typename NT, typename AT>\r
-  bool digraph<NT,AT>::path_exists_r(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                     TYPENAME digraph<NT,AT>::const_iterator to,\r
-                                     TYPENAME digraph<NT,AT>::const_iterator_set& visited,\r
-                                     TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // Recursive part of the digraph::path_exists function. This is based on a\r
-    // depth first search algorithm and stops the moment it finds a path\r
-    // regardless of its length. Simply traverse every output and recurse on that\r
-    // node until we find the to node or run out of things to recurse on. However,\r
-    // to avoid infinite recursion due to cycles in the graph, I need to maintain\r
-    // a set of visited nodes. The visited set is updated when a candidate is\r
-    // found but tested before the recursion on the candidate so that the number of\r
-    // function calls is minimised.\r
-    for (unsigned i = 0; i < fanout(from); i++)\r
-    {\r
-      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = output(from,i);\r
-      if (!select || select(*this, arc))\r
-      {\r
-        digraph_iterator<NT,AT,const NT&,const NT*> node = arc_to(arc);\r
-        // if the node is the target, return immediately\r
-        if (node == to) return true;\r
-        // update the visited set and give up if the insert fails, which indicates that the node has already been visited\r
-        if (!(visited.insert(node).second)) return false;\r
-        // now recurse - a path exists from from to to if a path exists from an adjacent node to to\r
-        if (path_exists_r(node,to,visited,select)) return true;\r
-      }\r
-    }\r
-    return false;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  bool digraph<NT,AT>::path_exists(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                   TYPENAME digraph<NT,AT>::const_iterator to, \r
-                                   TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // set up the recursion with its initial visited set and then recurse\r
-    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;\r
-    visited.insert(from);\r
-    return path_exists_r(from, to, visited, select);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  bool digraph<NT,AT>::path_exists(TYPENAME digraph<NT,AT>::iterator from,\r
-                                   TYPENAME digraph<NT,AT>::iterator to,\r
-                                   TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return path_exists(from.constify(), to.constify(), select);\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::all_paths_r(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                   TYPENAME digraph<NT,AT>::const_iterator to,\r
-                                   TYPENAME digraph<NT,AT>::const_arc_vector& so_far,\r
-                                   TYPENAME digraph<NT,AT>::const_path_vector& result,\r
-                                   TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // This is the recursive part of the all_paths function. The field so_far\r
-    // contains the path so far so that when 'to' is reached, the path is\r
-    // complete. It serves the same purpose as the visited set in the path_exists\r
-    // function except that it also preserves the path order. It also serves the\r
-    // purpose of detecting cycles and thus stopping infinite recursion. Every\r
-    // time the recursion reaches the to node, a copy of so_far is appended to the\r
-    // path set.\r
-    for (unsigned i = 0; i < fanout(from); i++)\r
-    {\r
-      digraph_arc_iterator<NT,AT, const AT&,const AT*> candidate = output(from,i);\r
-      // assert_valid that the arc is selected and then assert_valid that the candidate has not\r
-      // been visited on this path and only allow further recursion if it hasn't\r
-      if ((!select || select(*this, candidate)) && std::find(so_far.begin(), so_far.end(), candidate) == so_far.end())\r
-      {\r
-        // extend the path tracing the route to this arc\r
-        so_far.push_back(candidate);\r
-        // if the candidate arc points to the target, update the result set and prevent further recursion, otherwise recurse\r
-        if (arc_to(candidate) == to)\r
-          result.push_back(so_far);\r
-        else\r
-          all_paths_r(arc_to(candidate),to,so_far,result,select);\r
-        so_far.pop_back();\r
-      }\r
-    }\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_path_vector \r
-  digraph<NT,AT>::all_paths(TYPENAME digraph<NT,AT>::const_iterator from, \r
-                            TYPENAME digraph<NT,AT>::const_iterator to,\r
-                            TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // set up the recursion with empty data fields and then recurse\r
-    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;\r
-    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > so_far;\r
-    all_paths_r(from, to, so_far, result, select);\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::path_vector\r
-  digraph<NT,AT>::all_paths(TYPENAME digraph<NT,AT>::iterator from, \r
-                            TYPENAME digraph<NT,AT>::iterator to,\r
-                            TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_paths(all_paths(from.constify(), to.constify(), select));\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::reachable_nodes_r(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                         TYPENAME digraph<NT,AT>::const_iterator_set& visited,\r
-                                         TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // The recursive part of the reachable_nodes function.\r
-    // This is a depth-first traversal again but this time it carries on to find all the reachable nodes\r
-    // Just keep recursing on all the adjacent nodes of each node, skipping already visited nodes to avoid cycles\r
-    for (unsigned i = 0; i < fanout(from); i++)\r
-    {\r
-      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = output(from,i);\r
-      if (!select || select(*this,arc))\r
-      {\r
-        digraph_iterator<NT,AT,const NT&,const NT*> candidate = arc_to(arc);\r
-        if (visited.insert(candidate).second)\r
-          reachable_nodes_r(candidate,visited,select);\r
-      }\r
-    }\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_node_vector\r
-  digraph<NT,AT>::reachable_nodes(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                  TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // seed the recursion, marking the starting node as already visited\r
-    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;\r
-    visited.insert(from);\r
-    reachable_nodes_r(from, visited, select);\r
-    // convert the visited set into the required output form\r
-    // exclude the starting node\r
-    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
-    for (TYPENAME std::set<digraph_iterator<NT,AT,const NT&,const NT*> >::iterator i = visited.begin(); i != visited.end(); i++)\r
-      if (*i != from)\r
-        result.push_back(*i);\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::node_vector\r
-  digraph<NT,AT>::reachable_nodes(TYPENAME digraph<NT,AT>::iterator from,\r
-                                  TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_nodes(reachable_nodes(from.constify(), select));\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  void digraph<NT,AT>::reaching_nodes_r(TYPENAME digraph<NT,AT>::const_iterator to,\r
-                                        TYPENAME digraph<NT,AT>::const_iterator_set& visited,\r
-                                        TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // The recursive part of the reaching_nodes function.\r
-    // Just like the reachable_nodes_r function but it goes backwards\r
-    for (unsigned i = 0; i < fanin(to); i++)\r
-    {\r
-      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = input(to,i);\r
-      if (!select || select(*this,arc))\r
-      {\r
-        digraph_iterator<NT,AT,const NT&,const NT*> candidate = arc_from(input(to,i));\r
-        if (visited.insert(candidate).second)\r
-          reaching_nodes_r(candidate,visited,select);\r
-      }\r
-    }\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_node_vector\r
-  digraph<NT,AT>::reaching_nodes(TYPENAME digraph<NT,AT>::const_iterator to,\r
-                                 TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // seed the recursion, marking the starting node as already visited\r
-    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;\r
-    visited.insert(to);\r
-    reaching_nodes_r(to,visited,select);\r
-    // convert the visited set into the required output form\r
-    // exclude the end node\r
-    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;\r
-    for (TYPENAME std::set<digraph_iterator<NT,AT,const NT&,const NT*> >::iterator i = visited.begin(); i != visited.end(); i++)\r
-      if (*i != to)\r
-        result.push_back(*i);\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::node_vector\r
-  digraph<NT,AT>::reaching_nodes(TYPENAME digraph<NT,AT>::iterator to,\r
-                                 TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_nodes(reaching_nodes(to.constify(),select));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Shortest Path Algorithms\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_arc_vector\r
-  digraph<NT,AT>::shortest_path(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                TYPENAME digraph<NT,AT>::const_iterator to,\r
-                                TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > paths = all_paths(from,to,select);\r
-    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > shortest;\r
-    for (TYPENAME std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > >::iterator i = paths.begin(); i != paths.end(); i++)\r
-      if (shortest.empty() || i->size() < shortest.size())\r
-        shortest = *i;\r
-    return shortest;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::arc_vector\r
-  digraph<NT,AT>::shortest_path(TYPENAME digraph<NT,AT>::iterator from, \r
-                                TYPENAME digraph<NT,AT>::iterator to,\r
-                                TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_arcs(shortest_path(from.constify(),to.constify(),select));\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::const_path_vector\r
-  digraph<NT,AT>::shortest_paths(TYPENAME digraph<NT,AT>::const_iterator from,\r
-                                 TYPENAME digraph<NT,AT>::arc_select_fn select) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    from.assert_valid(this);\r
-    // This is an unweighted shortest path algorithm based on the algorithm from\r
-    // Weiss's book. This is essentially a breadth-first traversal or graph\r
-    // colouring algorithm. It is an iterative algorithm, so no recursion here! It\r
-    // works by creating a node queue initialised with the starting node. It then\r
-    // consumes the queue from front to back. For each node, it finds the\r
-    // successors and appends them to the queue. If a node is already 'known' it\r
-    // is not added - this avoids cycles. Thus the queue insert ordering\r
-    // represents the breadth-first ordering. On the way it creates a map of\r
-    // visited nodes. This is a map not a set because it also stores the arc that\r
-    // nominated this node as a shortest path. The full path can then be recreated\r
-    // from the map by just walking back through the predecessors. The depth (or\r
-    // colour) can be determined by the path length.\r
-    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;\r
-    // initialise the iteration by creating a queue and adding the start node\r
-    std::deque<digraph_iterator<NT,AT,const NT&,const NT*> > nodes;\r
-    nodes.push_back(from);\r
-    // Create a map to store the set of known nodes mapped to their predecessor\r
-    // arcs. Initialise it with the current node, which has no predecessor. Note\r
-    // that the algorithm uses the feature of digraph iterators that they can be\r
-    // null iterators and that all null iterators are equal.\r
-    typedef std::map<digraph_iterator<NT,AT,const NT&,const NT*>,\r
-                     digraph_arc_iterator<NT,AT,const AT&,const AT*> > known_map;\r
-    known_map known;\r
-    known.insert(std::make_pair(from,digraph_arc_iterator<NT,AT, const AT&,const AT*>()));\r
-    // now the iterative part of the algorithm\r
-    while(!nodes.empty())\r
-    {\r
-      // pop the queue to get the next node to process - unfortunately the STL\r
-      // deque::pop does not return the popped value\r
-      digraph_iterator<NT,AT,const NT&,const NT*> current = nodes.front();\r
-      nodes.pop_front();\r
-      // now visit all the successors\r
-      for (unsigned i = 0; i < fanout(current); i++)\r
-      {\r
-        digraph_arc_iterator<NT,AT, const AT&,const AT*> next_arc = output(current,i);\r
-        // assert_valid whether the successor arc is a selected arc and can be part of a path\r
-        if (!select || select(*this,next_arc))\r
-        {\r
-          digraph_iterator<NT,AT,const NT&,const NT*> next = arc_to(next_arc);\r
-          // Discard any successors that are known because to be known already they\r
-          // must have another shorter path. Otherwise add the successor node to the\r
-          // queue to be visited later. To minimise the overhead of map lookup I use\r
-          // the usual trick of trying to insert the node and determining whether\r
-          // the node was known by the success or failure of the insertion - this is\r
-          // a Good STL Trick (TM).\r
-          if (known.insert(std::make_pair(next,next_arc)).second)\r
-            nodes.push_back(next);\r
-        }\r
-      }\r
-    }\r
-    // The map contains the results as an unordered set of nodes, mapped to their\r
-    // predecessor arcs and weight. This now needs to be converted into a set of\r
-    // paths. This is done by starting with a node from the map, finding its\r
-    // predecessor arc and therefore its predecessor node, looking that up in the\r
-    // map to find its predecessor and so on until the start node is reached (it\r
-    // has a null predecessor). Note that the known set includes the from node\r
-    // which does not generate a path.\r
-    for (TYPENAME known_map::iterator i = known.begin(); i != known.end(); i++)\r
-    {\r
-      if (i->first != from)\r
-      {\r
-        const_arc_vector this_path;\r
-        for (TYPENAME known_map::iterator node = i; \r
-             node->second.valid(); \r
-             node = known.find(arc_from(node->second)))\r
-          this_path.insert(this_path.begin(),node->second);\r
-        result.push_back(this_path);\r
-      }\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename NT, typename AT>\r
-  TYPENAME digraph<NT,AT>::path_vector\r
-  digraph<NT,AT>::shortest_paths(TYPENAME digraph<NT,AT>::iterator from,\r
-                                 TYPENAME digraph<NT,AT>::arc_select_fn select)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return deconstify_paths(shortest_paths(from.constify(),select));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Note: I tried to write this using STL lists for the node and arc lists, but
+//   it got far too hairy. The specific problem is that I wanted a digraph
+//   iterator to contain a list::iterator so I needed to be able to generate a
+//   list::iterator from a node or arc and STL list iterators don't give you that
+//   functionality. I tried burgling the data structures, but that was
+//   non-portable between different STL implementations so needed lots of #ifdefs
+//   and so was mind-bogglingly awful and unreadable - in other words a
+//   maintenance nightmare. I gave up and impemented my own lists - not difficult.
+
+//   I use circular double-linked lists. The circular design means that both
+//   ends of the list are equally accessible in unit time. An empty list
+//   contains no objects. There is no end node in the list - unlike the STL
+//   lists which have a dummy node for end iterators to point to -
+//   conceptually the end iterator points one element beyond the end of the
+//   list. However, I implement the end iterator concept in the iterator
+//   itself, so do not need the dummy end node.
+
+////////////////////////////////////////////////////////////////////////////////
+#include <algorithm>
+#include <deque>
+
+////////////////////////////////////////////////////////////////////////////////
+// Internals
+
+namespace stlplus
+{
+
+  template<typename NT, typename AT>
+  class digraph_node
+  {
+  public:
+    master_iterator<digraph<NT,AT>, digraph_node<NT,AT> > m_master;
+    NT m_data;
+    digraph_node<NT,AT>* m_prev;
+    digraph_node<NT,AT>* m_next;
+    std::vector<digraph_arc<NT,AT>*> m_inputs;
+    std::vector<digraph_arc<NT,AT>*> m_outputs;
+  public:
+    digraph_node(const digraph<NT,AT>* owner, const NT& d = NT()) :
+      m_master(owner,this), m_data(d), m_prev(0), m_next(0)
+      {
+      }
+    ~digraph_node(void)
+      {
+      }
+  };
+
+  template<typename NT, typename AT>
+  class digraph_arc
+  {
+  public:
+    master_iterator<digraph<NT,AT>, digraph_arc<NT,AT> > m_master;
+    AT m_data;
+    digraph_arc<NT,AT>* m_prev;
+    digraph_arc<NT,AT>* m_next;
+    digraph_node<NT,AT>* m_from;
+    digraph_node<NT,AT>* m_to;
+    digraph_arc(const digraph<NT,AT>* owner, digraph_node<NT,AT>* from = 0, digraph_node<NT,AT>* to = 0, const AT& d = AT()) : 
+      m_master(owner,this), m_data(d), m_prev(0), m_next(0), m_from(from), m_to(to)
+      {
+      }
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Iterators
+  ////////////////////////////////////////////////////////////////////////////////
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Node iterator
+
+  // construct a null iterator
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(void)
+  {
+  }
+
+  // valid iterator
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(digraph_node<NT,AT>* node) :
+    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(node->m_master)
+  {
+  }
+
+  // end iterator
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(const digraph<NT,AT>* owner) :
+    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(owner)
+  {
+  }
+
+  // alias an iterator
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_iterator<NT,AT,NRef,NPtr>::digraph_iterator(const safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >& iterator) : 
+    safe_iterator<digraph<NT,AT>,digraph_node<NT,AT> >(iterator)
+  {
+  }
+
+  // destructor
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_iterator<NT,AT,NRef,NPtr>::~digraph_iterator(void)
+  {
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::const_iterator digraph_iterator<NT,AT,NRef,NPtr>::constify (void) const
+  {
+    return digraph_iterator<NT,AT,const NT&,const NT*>(*this);
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::iterator digraph_iterator<NT,AT,NRef,NPtr>::deconstify (void) const
+  {
+    return digraph_iterator<NT,AT,NT&,NT*>(*this);
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& digraph_iterator<NT,AT,NRef,NPtr>::operator ++ (void)
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    if (this->node()->m_next)
+      this->set(this->node()->m_next->m_master);
+    else
+      this->set_end();
+    return *this;
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator digraph_iterator<NT,AT,NRef,NPtr>::operator ++ (int)
+    throw(null_dereference,end_dereference)
+  {
+    // post-increment is defined in terms of the pre-increment
+    digraph_iterator<NT,AT,NRef,NPtr> result(*this);
+    ++(*this);
+    return result;
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& digraph_iterator<NT,AT,NRef,NPtr>::operator -- (void)
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    if (this->node()->m_prev)
+      this->set(this->node()->m_prev->m_master);
+    else
+      this->set_end();
+    return *this;
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator digraph_iterator<NT,AT,NRef,NPtr>::operator -- (int)
+    throw(null_dereference,end_dereference)
+  {
+    // post-decrement is defined in terms of the pre-decrement
+    digraph_iterator<NT,AT,NRef,NPtr> result(*this);
+    --(*this);
+    return result;
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  bool digraph_iterator<NT,AT,NRef,NPtr>::operator == (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const
+  {
+    return equal(r);
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  bool digraph_iterator<NT,AT,NRef,NPtr>::operator != (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const
+  {
+    return !operator==(r);
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  bool digraph_iterator<NT,AT,NRef,NPtr>::operator < (const TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::this_iterator& r) const
+  {
+    return compare(r) < 0;
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::reference digraph_iterator<NT,AT,NRef,NPtr>::operator*(void) const
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    return this->node()->m_data;
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_iterator<NT,AT,NRef,NPtr>::pointer digraph_iterator<NT,AT,NRef,NPtr>::operator->(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return &(operator*());
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Arc Iterator
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  digraph_arc_iterator<NT,AT,ARef,APtr>::digraph_arc_iterator(void)
+  {
+  }
+
+  // valid iterator
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(digraph_arc<NT,AT>* arc) :
+    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(arc->m_master)
+  {
+  }
+
+  // end iterator
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(const digraph<NT,AT>* owner) :
+    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(owner)
+  {
+  }
+
+  // alias an iterator
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  digraph_arc_iterator<NT,AT,NRef,NPtr>::digraph_arc_iterator(const safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >& iterator) : 
+    safe_iterator<digraph<NT,AT>,digraph_arc<NT,AT> >(iterator)
+  {
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  digraph_arc_iterator<NT,AT,ARef,APtr>::~digraph_arc_iterator(void)
+  {
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_arc_iterator<NT,AT,NRef,NPtr>::const_iterator digraph_arc_iterator<NT,AT,NRef,NPtr>::constify (void) const
+  {
+    return digraph_arc_iterator<NT,AT,const AT&,const AT*>(*this);
+  }
+
+  template<typename NT, typename AT, typename NRef, typename NPtr>
+  TYPENAME digraph_arc_iterator<NT,AT,NRef,NPtr>::iterator digraph_arc_iterator<NT,AT,NRef,NPtr>::deconstify (void) const
+  {
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(*this);
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& digraph_arc_iterator<NT,AT,ARef,APtr>::operator ++ (void)
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    if (this->node()->m_next)
+      this->set(this->node()->m_next->m_master);
+    else
+      this->set_end();
+    return *this;
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator digraph_arc_iterator<NT,AT,ARef,APtr>::operator ++ (int)
+    throw(null_dereference,end_dereference)
+  {
+    // post-increment is defined in terms of the pre-increment
+    digraph_arc_iterator<NT,AT,ARef,APtr> result(*this);
+    ++(*this);
+    return result;
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& digraph_arc_iterator<NT,AT,ARef,APtr>::operator -- (void)
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    if (this->node()->m_prev)
+      this->set(this->node()->m_prev->m_master);
+    else
+      this->set_end();
+    return *this;
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator digraph_arc_iterator<NT,AT,ARef,APtr>::operator -- (int)
+    throw(null_dereference,end_dereference)
+  {
+    // post-decrement is defined in terms of the pre-decrement
+    digraph_arc_iterator<NT,AT,ARef,APtr> result(*this);
+    --(*this);
+    return result;
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator == (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const
+  {
+    return equal(r);
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator != (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const
+  {
+    return !operator==(r);
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  bool digraph_arc_iterator<NT,AT,ARef,APtr>::operator < (const TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::this_iterator& r) const
+  {
+    return compare(r) < 0;
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::reference digraph_arc_iterator<NT,AT,ARef,APtr>::operator*(void) const
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    return this->node()->m_data;
+  }
+
+  template<typename NT, typename AT, typename ARef, typename APtr>
+  TYPENAME digraph_arc_iterator<NT,AT,ARef,APtr>::pointer digraph_arc_iterator<NT,AT,ARef,APtr>::operator->(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return &(operator*());
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // subtype utilities
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::constify_arcs(const TYPENAME digraph<NT,AT>::arc_vector& arcs) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > result;
+    for (unsigned i = 0; i < arcs.size(); i++)
+    {
+      arcs[i].assert_valid(this);
+      result.push_back(arcs[i].constify());
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::deconstify_arcs(const TYPENAME digraph<NT,AT>::const_arc_vector& arcs) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;
+    for (unsigned i = 0; i < arcs.size(); i++)
+    {
+      arcs[i].assert_valid(this);
+      result.push_back(arcs[i].deconstify());
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_path_vector digraph<NT,AT>::constify_paths(const TYPENAME digraph<NT,AT>::path_vector& paths) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;
+    for (unsigned i = 0; i < paths.size(); i++)
+      result.push_back(constify_arcs(paths[i]));
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::path_vector digraph<NT,AT>::deconstify_paths(const TYPENAME digraph<NT,AT>::const_path_vector& paths) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > > result;
+    for (unsigned i = 0; i < paths.size(); i++)
+      result.push_back(deconstify_arcs(paths[i]));
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::constify_nodes(const TYPENAME digraph<NT,AT>::node_vector& nodes) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;
+    for (unsigned i = 0; i < nodes.size(); i++)
+    {
+      nodes[i].assert_valid(this);
+      result.push_back(nodes[i].constify());
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::deconstify_nodes(const TYPENAME digraph<NT,AT>::const_node_vector& nodes) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<digraph_iterator<NT,AT,NT&,NT*> > result;
+    for (unsigned i = 0; i < nodes.size(); i++)
+    {
+      nodes[i].assert_valid(this);
+      result.push_back(nodes[i].deconstify());
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::npos(void)
+  {
+    return(unsigned)-1;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Constructors etc.
+
+  template<typename NT, typename AT>
+  digraph<NT,AT>::digraph(void) :
+    m_nodes_begin(0), m_nodes_end(0), m_arcs_begin(0), m_arcs_end(0)
+  {
+    // node and arc lists are circular double-linked lists
+    // they start out empty (no dummy end node)
+  }
+
+  template<typename NT, typename AT>
+  digraph<NT,AT>::~digraph(void)
+  {
+    clear();
+  }
+
+  template<typename NT, typename AT>
+  digraph<NT,AT>::digraph(const digraph<NT,AT>& r) :
+    m_nodes_begin(0), m_nodes_end(0), m_arcs_begin(0), m_arcs_end(0)
+  {
+    *this = r;
+  }
+
+  template<typename NT, typename AT>
+  digraph<NT,AT>& digraph<NT,AT>::operator=(const digraph<NT,AT>& r)
+  {
+    // make it self-copy safe i.e. a=a; is a valid instruction
+    if (this == &r) return *this;
+    clear();
+    // first phase is to copy the nodes, creating a map of cross references from the old nodes to their new equivalents
+    std::map<digraph_iterator<NT,AT,const NT&,const NT*>, digraph_iterator<NT,AT,NT&,NT*> > xref;
+    for (digraph_iterator<NT,AT,const NT&,const NT*> n = r.begin(); n != r.end(); n++)
+      xref[n] = insert(*n);
+    // second phase is to copy the arcs, using the map to convert the old to and from nodes to the new nodes
+    for (digraph_arc_iterator<NT,AT, const AT&,const AT*> a = r.arc_begin(); a != r.arc_end(); a++)
+      arc_insert(xref[r.arc_from(a)],xref[r.arc_to(a)],*a);
+    return *this;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Basic Node functions
+
+  template<typename NT, typename AT>
+  bool digraph<NT,AT>::empty(void) const
+  {
+    return m_nodes_begin == 0;
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::size(void) const
+  {
+    unsigned count = 0;
+    for (digraph_iterator<NT,AT,const NT&,const NT*> i = begin(); i != end(); i++)
+      count++;
+    return count;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::insert(const NT& node_data)
+  {
+    digraph_node<NT,AT>* new_node = new digraph_node<NT,AT>(this,node_data);
+    if (!m_nodes_end)
+    {
+      // insert into an empty list
+      m_nodes_begin = new_node;
+      m_nodes_end = new_node;
+    }
+    else
+    {
+      // insert at the end of the list
+      new_node->m_prev = m_nodes_end;
+      m_nodes_end->m_next = new_node;
+      m_nodes_end = new_node;
+    }
+    return digraph_iterator<NT,AT,NT&,NT*>(new_node);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::erase(TYPENAME digraph<NT,AT>::iterator iter)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    // remove all arcs connected to this node first
+    // use arc_erase rather than arcs.erase because that tidies up the node at the other end of the arc too
+    for (unsigned i = fanin(iter); i--; )
+      arc_erase(input(iter,i));
+    for (unsigned j = fanout(iter); j--; )
+      arc_erase(output(iter,j));
+    // now unlink the node from the list and delete it
+    if (iter.node()->m_next)
+      iter.node()->m_next->m_prev = iter.node()->m_prev;
+    if (iter.node()->m_prev)
+      iter.node()->m_prev->m_next = iter.node()->m_next;
+    digraph_node<NT,AT>* next = iter.node()->m_next;
+    delete iter.node();
+    // return the next node in the list
+    if (next)
+      return digraph_iterator<NT,AT,NT&,NT*>(next);
+    else
+      return digraph_iterator<NT,AT,NT&,NT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::clear(void)
+  {
+    // clearing the nodes also clears the arcs
+    for (digraph_iterator<NT,AT,NT&,NT*> i = begin(); i != end(); )
+      i = erase(i);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::begin(void) const
+  {
+    if (m_nodes_begin)
+      return digraph_iterator<NT,AT,const NT&,const NT*>(m_nodes_begin);
+    else
+      return digraph_iterator<NT,AT,const NT&,const NT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::begin(void)
+  {
+    if (m_nodes_begin)
+      return digraph_iterator<NT,AT,NT&,NT*>(m_nodes_begin);
+    else
+      return digraph_iterator<NT,AT,NT&,NT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::end(void) const
+  {
+    return digraph_iterator<NT,AT,const NT&,const NT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::end(void)
+  {
+    return digraph_iterator<NT,AT,NT&,NT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::fanin(TYPENAME digraph<NT,AT>::const_iterator iter) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return iter.node()->m_inputs.size();
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::fanin(TYPENAME digraph<NT,AT>::iterator iter)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return iter.node()->m_inputs.size();
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::input(TYPENAME digraph<NT,AT>::const_iterator iter, unsigned i) const
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    iter.assert_valid(this);
+    if (i >= iter.node()->m_inputs.size()) throw std::out_of_range("digraph::input");
+    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(iter.node()->m_inputs[i]);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::input(TYPENAME digraph<NT,AT>::iterator iter, unsigned i)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    iter.assert_valid(this);
+    if (i >= iter.node()->m_inputs.size()) throw std::out_of_range("digraph::input");
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(iter.node()->m_inputs[i]);
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::fanout(TYPENAME digraph<NT,AT>::const_iterator iter) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return iter.node()->m_outputs.size();
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::fanout(TYPENAME digraph<NT,AT>::iterator iter)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return iter.node()->m_outputs.size();
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::output(TYPENAME digraph<NT,AT>::const_iterator iter, unsigned i) const
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    iter.assert_valid(this);
+    if (i >= iter.node()->m_outputs.size()) throw std::out_of_range("digraph::output");
+    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(iter.node()->m_outputs[i]);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::output(TYPENAME digraph<NT,AT>::iterator iter, unsigned i)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    iter.assert_valid(this);
+    if (i >= iter.node()->m_outputs.size()) throw std::out_of_range("digraph::output");
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(iter.node()->m_outputs[i]);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::inputs(TYPENAME digraph<NT,AT>::const_iterator node) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    node.assert_valid(this);
+    std::vector<digraph_arc_iterator<NT,AT,const AT&, const AT*> > result;
+    for (unsigned i = 0; i < fanin(node); i++)
+      result.push_back(input(node,i));
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::inputs(TYPENAME digraph<NT,AT>::iterator node)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    node.assert_valid(this);
+    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;
+    for (unsigned i = 0; i < fanin(node); i++)
+      result.push_back(input(node,i));
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::outputs(TYPENAME digraph<NT,AT>::const_iterator node) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    node.assert_valid(this);
+    std::vector<digraph_arc_iterator<NT,AT,const AT&, const AT*> > result;
+    for (unsigned i = 0; i < fanout(node); i++)
+      result.push_back(output(node,i));
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::outputs(TYPENAME digraph<NT,AT>::iterator node)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    node.assert_valid(this);
+    std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > result;
+    for (unsigned i = 0; i < fanout(node); i++)
+      result.push_back(output(node,i));
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::output_offset(TYPENAME digraph<NT,AT>::const_iterator from,
+                                         TYPENAME digraph<NT,AT>::const_arc_iterator arc) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    from.assert_valid(this);
+    arc.assert_valid(this);
+    for (unsigned i = 0; i < fanout(from); i++)
+    {
+      if (output(from,i) == arc)
+        return i;
+    }
+    return digraph<NT,AT>::npos();
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::output_offset(TYPENAME digraph<NT,AT>::iterator from,
+                                         TYPENAME digraph<NT,AT>::arc_iterator arc)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    from.assert_valid(this);
+    arc.assert_valid(this);
+    for (unsigned i = 0; i < fanout(from); i++)
+    {
+      if (output(from,i) == arc)
+        return i;
+    }
+    return digraph<NT,AT>::npos();
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::input_offset(TYPENAME digraph<NT,AT>::const_iterator to,
+                                        TYPENAME digraph<NT,AT>::const_arc_iterator arc) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    to.assert_valid(this);
+    arc.assert_valid(this);
+    for (unsigned i = 0; i < fanin(to); i++)
+    {
+      if (input(to,i) == arc)
+        return i;
+    }
+    return digraph<NT,AT>::npos();
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::input_offset(TYPENAME digraph<NT,AT>::iterator to,
+                                        TYPENAME digraph<NT,AT>::arc_iterator arc)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    to.assert_valid(this);
+    arc.assert_valid(this);
+    for (unsigned i = 0; i < fanin(to); i++)
+    {
+      if (input(to,i) == arc)
+        return i;
+    }
+    return digraph<NT,AT>::npos();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Basic Arc functions
+
+  template<typename NT, typename AT>
+  bool digraph<NT,AT>::arc_empty(void) const
+  {
+    return m_arcs_end == 0;
+  }
+
+  template<typename NT, typename AT>
+  unsigned digraph<NT,AT>::arc_size(void) const
+  {
+    unsigned count = 0;
+    for (digraph_arc_iterator<NT,AT, const AT&,const AT*> i = arc_begin(); i != arc_end(); i++)
+      count++;
+    return count;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_insert(TYPENAME digraph<NT,AT>::iterator from,
+                                                                   TYPENAME digraph<NT,AT>::iterator to,
+                                                                   const AT& arc_data)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    from.assert_valid(this);
+    to.assert_valid(this);
+    // create the new arc and link it in to the arc list
+    digraph_arc<NT,AT>* new_arc = new digraph_arc<NT,AT>(this, from.node(), to.node(), arc_data);
+    if (!m_arcs_end)
+    {
+      // insert into an empty list
+      m_arcs_begin = new_arc;
+      m_arcs_end = new_arc;
+    }
+    else
+    {
+      // insert at the end of the list
+      new_arc->m_prev = m_arcs_end;
+      m_arcs_end->m_next = new_arc;
+      m_arcs_end = new_arc;
+    }
+    // add this arc to the inputs and outputs of the end nodes
+    from.node()->m_outputs.push_back(new_arc);
+    to.node()->m_inputs.push_back(new_arc);
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(new_arc);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_erase(TYPENAME digraph<NT,AT>::arc_iterator iter)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    // first remove this arc's pointers from the from/to nodes
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator i = iter.node()->m_to->m_inputs.begin(); i != iter.node()->m_to->m_inputs.end(); )
+    {
+      if (*i == iter.node())
+        i = iter.node()->m_to->m_inputs.erase(i);
+      else
+        i++;
+    }
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator o = iter.node()->m_from->m_outputs.begin(); o != iter.node()->m_from->m_outputs.end(); )
+    {
+      if (*o == iter.node())
+        o = iter.node()->m_from->m_outputs.erase(o);
+      else
+        o++;
+    }
+    // now unlink the arc from the list and delete it
+    if (iter.node()->m_next)
+      iter.node()->m_next->m_prev = iter.node()->m_prev;
+    if (iter.node()->m_prev)
+      iter.node()->m_prev->m_next = iter.node()->m_next;
+    digraph_arc<NT,AT>* next = iter.node()->m_next;
+    delete iter.node();
+    if (next)
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(next);
+    else
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::arc_clear(void)
+  {
+    for (digraph_arc_iterator<NT,AT,AT&,AT*> a = arc_begin(); a != arc_end(); )
+      a = arc_erase(a);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::arc_begin(void) const
+  {
+    if (m_arcs_begin)
+      return digraph_arc_iterator<NT,AT, const AT&,const AT*>(m_arcs_begin);
+    else
+      return digraph_arc_iterator<NT,AT, const AT&,const AT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_begin(void)
+  {
+    if (m_arcs_begin)
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(m_arcs_begin);
+    else
+      return digraph_arc_iterator<NT,AT,AT&,AT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::arc_end(void) const
+  {
+    return digraph_arc_iterator<NT,AT, const AT&,const AT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::arc_end(void)
+  {
+    return digraph_arc_iterator<NT,AT,AT&,AT*>(this);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::arc_from(TYPENAME digraph<NT,AT>::const_arc_iterator iter) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return digraph_iterator<NT,AT,const NT&,const NT*>(iter.node()->m_from);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::arc_from(TYPENAME digraph<NT,AT>::arc_iterator iter)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return digraph_iterator<NT,AT,NT&,NT*>(iter.node()->m_from);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_iterator digraph<NT,AT>::arc_to(TYPENAME digraph<NT,AT>::const_arc_iterator iter) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return digraph_iterator<NT,AT,const NT&,const NT*>(iter.node()->m_to);
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::iterator digraph<NT,AT>::arc_to(TYPENAME digraph<NT,AT>::arc_iterator iter)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    iter.assert_valid(this);
+    return digraph_iterator<NT,AT,NT&,NT*>(iter.node()->m_to);
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::arc_move(TYPENAME digraph<NT,AT>::arc_iterator arc,
+                                TYPENAME digraph<NT,AT>::iterator from,
+                                TYPENAME digraph<NT,AT>::iterator to)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    arc_move_to(arc,to);
+    arc_move_from(arc,from);
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::arc_move_from(TYPENAME digraph<NT,AT>::arc_iterator arc,
+                                     TYPENAME digraph<NT,AT>::iterator from)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    arc.assert_valid(this);
+    from.assert_valid(this);
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator o = arc.node()->m_from->m_outputs.begin(); o != arc.node()->m_from->m_outputs.end(); )
+    {
+      if (*o == arc.node())
+        o = arc.node()->m_from->m_outputs.erase(o);
+      else
+        o++;
+    }
+    from.node()->m_outputs.push_back(arc.node());
+    arc.node()->m_from = from.node();
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::arc_move_to(TYPENAME digraph<NT,AT>::arc_iterator arc,
+                                   TYPENAME digraph<NT,AT>::iterator to)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    arc.assert_valid(this);
+    to.assert_valid(this);
+    for (TYPENAME std::vector<digraph_arc<NT,AT>*>::iterator i = arc.node()->m_to->m_inputs.begin(); i != arc.node()->m_to->m_inputs.end(); )
+    {
+      if (*i == arc.node())
+        i = arc.node()->m_to->m_inputs.erase(i);
+      else
+        i++;
+    }
+    to.node()->m_inputs.push_back(arc.node());
+    arc.node()->m_to = to.node();
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::arc_flip(TYPENAME digraph<NT,AT>::arc_iterator arc)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    arc_move(arc,arc_to(arc),arc_from(arc));
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Adjacency Algorithms
+
+  template<typename NT, typename AT>
+  bool digraph<NT,AT>::adjacent(TYPENAME digraph<NT,AT>::const_iterator from,
+                                TYPENAME digraph<NT,AT>::const_iterator to) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return adjacent_arc(from,to) != arc_end();
+  }
+
+  template<typename NT, typename AT>
+  bool digraph<NT,AT>::adjacent(TYPENAME digraph<NT,AT>::iterator from,
+                                TYPENAME digraph<NT,AT>::iterator to)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return adjacent_arc(from,to) != arc_end();
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_iterator digraph<NT,AT>::adjacent_arc(TYPENAME digraph<NT,AT>::const_iterator from,
+                                                                           TYPENAME digraph<NT,AT>::const_iterator to) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    from.assert_valid(this);
+    to.assert_valid(this);
+    for (unsigned arc = 0; arc < fanout(from); arc++)
+    {
+      if (arc_to(output(from, arc)) == to)
+        return output(from,arc);
+    }
+    return arc_end();
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_iterator digraph<NT,AT>::adjacent_arc(TYPENAME digraph<NT,AT>::iterator from,
+                                                                     TYPENAME digraph<NT,AT>::iterator to)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return adjacent_arc(from.constify(), to.constify()).deconstify();
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_vector digraph<NT,AT>::adjacent_arcs(TYPENAME digraph<NT,AT>::const_iterator from,
+                                                                          TYPENAME digraph<NT,AT>::const_iterator to) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    from.assert_valid(this);
+    to.assert_valid(this);
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > result;
+    for (unsigned arc = 0; arc < fanout(from); arc++)
+    {
+      if (arc_to(output(from, arc)) == to)
+        result.push_back(output(from,arc));
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_vector digraph<NT,AT>::adjacent_arcs(TYPENAME digraph<NT,AT>::iterator from,
+                                                                    TYPENAME digraph<NT,AT>::iterator to)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_arcs(adjacent_arcs(from.constify(), to.constify()));
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::input_adjacencies(TYPENAME digraph<NT,AT>::const_iterator to) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;
+    for (unsigned arc = 0; arc < fanin(to); arc++)
+    {
+      digraph_iterator<NT,AT,const NT&,const NT*> from = arc_from(input(to, arc));
+      if (std::find(result.begin(), result.end(), from) == result.end())
+        result.push_back(from);
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::input_adjacencies(TYPENAME digraph<NT,AT>::iterator to)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_nodes(input_adjacencies(to.constify()));
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::output_adjacencies(TYPENAME digraph<NT,AT>::const_iterator from) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;
+    for (unsigned arc = 0; arc < fanout(from); arc++)
+    {
+      digraph_iterator<NT,AT,const NT&,const NT*> to = arc_to(output(from, arc));
+      if (find(result.begin(), result.end(), to) == result.end())
+        result.push_back(to);
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::output_adjacencies(TYPENAME digraph<NT,AT>::iterator from)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_nodes(output_adjacencies(from.constify()));
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Topographical Sort Algorithms
+
+  template<typename NT, typename AT>
+  std::pair<TYPENAME digraph<NT,AT>::const_node_vector, TYPENAME digraph<NT,AT>::const_arc_vector>
+  digraph<NT,AT>::sort(TYPENAME digraph<NT,AT>::arc_select_fn select) const
+  {
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > errors;
+    // build a map containing the number of fanins to each node that must be visited before this one
+    std::map<digraph_iterator<NT,AT,const NT&,const NT*>,unsigned> fanin_map;
+    for (digraph_iterator<NT,AT,const NT&,const NT*> n = begin(); n != end(); n++)
+    {
+      unsigned predecessors = 0;
+      // only count predecessors connected by selected arcs
+      for (unsigned f = 0; f < fanin(n); f++)
+      {
+        digraph_arc_iterator<NT,AT, const AT&,const AT*> input_arc = input(n,f);
+        digraph_iterator<NT,AT,const NT&,const NT*> predecessor = arc_from(input_arc);
+        if (!select || select(*this,input_arc))
+          predecessors++;
+      }
+      if (predecessors == 0)
+      {
+        result.push_back(n);
+      }
+      else
+      {
+        fanin_map[n] = predecessors;
+      }
+    }
+    // main algorithm applies the topographical sort repeatedly. For a DAG, it
+    // will complete first time. However, with backward arcs, the first
+    // iteration will fail. The algorithm then tries breaking random arcs to try
+    // to get an ordering.
+    for(unsigned i = 0; !fanin_map.empty(); )
+    {
+      // now visit each node in traversal order, decrementing the fanin count of
+      // all successors. As each successor's fanin count goes to zero, it is
+      // appended to the result.
+      for (; i < result.size(); i++)
+      {
+        // Note: dereferencing gives us a node iterator
+        digraph_iterator<NT,AT,const NT&,const NT*> current = result[i];
+        for (unsigned f = 0; f < fanout(current); f++)
+        {
+          // only consider successors connected by selected arcs
+          digraph_arc_iterator<NT,AT, const AT&,const AT*> output_arc = output(current, f);
+          digraph_iterator<NT,AT,const NT&,const NT*> successor = arc_to(output_arc);
+          if (!select || select(*this,output_arc))
+          {
+            // don't consider arcs that have been eliminated to break a loop
+            if (fanin_map.find(successor) != fanin_map.end())
+            {
+              --fanin_map[successor];
+              if ((fanin_map[successor]) == 0)
+              {
+                result.push_back(successor);
+                fanin_map.erase(fanin_map.find(successor));
+              }
+            }
+          }
+        }
+      }
+      if (!fanin_map.empty())
+      {
+        // there must be backward arcs preventing completion
+        // try removing arcs from the sort to get a partial ordering containing all the nodes
+
+        // select an arc that is still relevant to the sort and break it
+        // first select a node that has non-zero fanin and its predecessor that has non-zero fanin
+        digraph_iterator<NT,AT,const NT&,const NT*> stuck_node = fanin_map.begin()->first;
+        for (unsigned f = 0; f < fanin(stuck_node); f++)
+        {
+          // now successively remove input arcs that are still part of the sort until the fanin reduces to zero
+          // first find a relevant arc - this must be a selected arc that has not yet been traversed by the first half of the algorithm
+          digraph_arc_iterator<NT,AT, const AT&,const AT*> input_arc = input(stuck_node, f);
+          if (!select || select(*this,input_arc))
+          {
+            digraph_iterator<NT,AT,const NT&,const NT*> predecessor = arc_from(input_arc);
+            if (fanin_map.find(predecessor) != fanin_map.end())
+            {
+              // found the right combination - remove this arc and then drop out of the fanin loop to restart the outer sort loop
+              errors.push_back(input_arc);
+              --fanin_map[stuck_node];
+              if ((fanin_map[stuck_node]) == 0)
+              {
+                result.push_back(stuck_node);
+                fanin_map.erase(fanin_map.find(stuck_node));
+                break;
+              }
+            }
+          }
+        }
+      }
+    }
+    return std::make_pair(result,errors);
+  }
+
+  template<typename NT, typename AT>
+  std::pair<TYPENAME digraph<NT,AT>::node_vector, TYPENAME digraph<NT,AT>::arc_vector>
+  digraph<NT,AT>::sort(TYPENAME digraph<NT,AT>::arc_select_fn select)
+  {
+    std::pair<std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >,
+              std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > const_result =
+      const_cast<const digraph<NT,AT>*>(this)->sort(select);
+
+    std::pair<std::vector<digraph_iterator<NT,AT,NT&,NT*> >,
+              std::vector<digraph_arc_iterator<NT,AT,AT&,AT*> > > result =
+      std::make_pair(deconstify_nodes(const_result.first),deconstify_arcs(const_result.second));
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_node_vector digraph<NT,AT>::dag_sort(TYPENAME digraph<NT,AT>::arc_select_fn select) const
+  {
+    std::pair<std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >,
+              std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result = sort(select);
+    if (result.second.empty()) return result.first;
+    return std::vector<digraph_iterator<NT,AT,const NT&,const NT*> >();
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::node_vector digraph<NT,AT>::dag_sort(TYPENAME digraph<NT,AT>::arc_select_fn select)
+  {
+    return deconstify_nodes(const_cast<const digraph<NT,AT>*>(this)->dag_sort(select));
+  }
+  ////////////////////////////////////////////////////////////////////////////////
+  // Path Algorithms
+
+  template<typename NT, typename AT>
+  bool digraph<NT,AT>::path_exists_r(TYPENAME digraph<NT,AT>::const_iterator from,
+                                     TYPENAME digraph<NT,AT>::const_iterator to,
+                                     TYPENAME digraph<NT,AT>::const_iterator_set& visited,
+                                     TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // Recursive part of the digraph::path_exists function. This is based on a
+    // depth first search algorithm and stops the moment it finds a path
+    // regardless of its length. Simply traverse every output and recurse on that
+    // node until we find the to node or run out of things to recurse on. However,
+    // to avoid infinite recursion due to cycles in the graph, I need to maintain
+    // a set of visited nodes. The visited set is updated when a candidate is
+    // found but tested before the recursion on the candidate so that the number of
+    // function calls is minimised.
+    for (unsigned i = 0; i < fanout(from); i++)
+    {
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = output(from,i);
+      if (!select || select(*this, arc))
+      {
+        digraph_iterator<NT,AT,const NT&,const NT*> node = arc_to(arc);
+        // if the node is the target, return immediately
+        if (node == to) return true;
+        // update the visited set and give up if the insert fails, which indicates that the node has already been visited
+        if (!(visited.insert(node).second)) return false;
+        // now recurse - a path exists from from to to if a path exists from an adjacent node to to
+        if (path_exists_r(node,to,visited,select)) return true;
+      }
+    }
+    return false;
+  }
+
+  template<typename NT, typename AT>
+  bool digraph<NT,AT>::path_exists(TYPENAME digraph<NT,AT>::const_iterator from,
+                                   TYPENAME digraph<NT,AT>::const_iterator to, 
+                                   TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // set up the recursion with its initial visited set and then recurse
+    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;
+    visited.insert(from);
+    return path_exists_r(from, to, visited, select);
+  }
+
+  template<typename NT, typename AT>
+  bool digraph<NT,AT>::path_exists(TYPENAME digraph<NT,AT>::iterator from,
+                                   TYPENAME digraph<NT,AT>::iterator to,
+                                   TYPENAME digraph<NT,AT>::arc_select_fn select)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return path_exists(from.constify(), to.constify(), select);
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::all_paths_r(TYPENAME digraph<NT,AT>::const_iterator from,
+                                   TYPENAME digraph<NT,AT>::const_iterator to,
+                                   TYPENAME digraph<NT,AT>::const_arc_vector& so_far,
+                                   TYPENAME digraph<NT,AT>::const_path_vector& result,
+                                   TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // This is the recursive part of the all_paths function. The field so_far
+    // contains the path so far so that when 'to' is reached, the path is
+    // complete. It serves the same purpose as the visited set in the path_exists
+    // function except that it also preserves the path order. It also serves the
+    // purpose of detecting cycles and thus stopping infinite recursion. Every
+    // time the recursion reaches the to node, a copy of so_far is appended to the
+    // path set.
+    for (unsigned i = 0; i < fanout(from); i++)
+    {
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> candidate = output(from,i);
+      // assert_valid that the arc is selected and then assert_valid that the candidate has not
+      // been visited on this path and only allow further recursion if it hasn't
+      if ((!select || select(*this, candidate)) && std::find(so_far.begin(), so_far.end(), candidate) == so_far.end())
+      {
+        // extend the path tracing the route to this arc
+        so_far.push_back(candidate);
+        // if the candidate arc points to the target, update the result set and prevent further recursion, otherwise recurse
+        if (arc_to(candidate) == to)
+          result.push_back(so_far);
+        else
+          all_paths_r(arc_to(candidate),to,so_far,result,select);
+        so_far.pop_back();
+      }
+    }
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_path_vector 
+  digraph<NT,AT>::all_paths(TYPENAME digraph<NT,AT>::const_iterator from, 
+                            TYPENAME digraph<NT,AT>::const_iterator to,
+                            TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // set up the recursion with empty data fields and then recurse
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > so_far;
+    all_paths_r(from, to, so_far, result, select);
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::path_vector
+  digraph<NT,AT>::all_paths(TYPENAME digraph<NT,AT>::iterator from, 
+                            TYPENAME digraph<NT,AT>::iterator to,
+                            TYPENAME digraph<NT,AT>::arc_select_fn select)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_paths(all_paths(from.constify(), to.constify(), select));
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::reachable_nodes_r(TYPENAME digraph<NT,AT>::const_iterator from,
+                                         TYPENAME digraph<NT,AT>::const_iterator_set& visited,
+                                         TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // The recursive part of the reachable_nodes function.
+    // This is a depth-first traversal again but this time it carries on to find all the reachable nodes
+    // Just keep recursing on all the adjacent nodes of each node, skipping already visited nodes to avoid cycles
+    for (unsigned i = 0; i < fanout(from); i++)
+    {
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = output(from,i);
+      if (!select || select(*this,arc))
+      {
+        digraph_iterator<NT,AT,const NT&,const NT*> candidate = arc_to(arc);
+        if (visited.insert(candidate).second)
+          reachable_nodes_r(candidate,visited,select);
+      }
+    }
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_node_vector
+  digraph<NT,AT>::reachable_nodes(TYPENAME digraph<NT,AT>::const_iterator from,
+                                  TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // seed the recursion, marking the starting node as already visited
+    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;
+    visited.insert(from);
+    reachable_nodes_r(from, visited, select);
+    // convert the visited set into the required output form
+    // exclude the starting node
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;
+    for (TYPENAME std::set<digraph_iterator<NT,AT,const NT&,const NT*> >::iterator i = visited.begin(); i != visited.end(); i++)
+      if (*i != from)
+        result.push_back(*i);
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::node_vector
+  digraph<NT,AT>::reachable_nodes(TYPENAME digraph<NT,AT>::iterator from,
+                                  TYPENAME digraph<NT,AT>::arc_select_fn select)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_nodes(reachable_nodes(from.constify(), select));
+  }
+
+  template<typename NT, typename AT>
+  void digraph<NT,AT>::reaching_nodes_r(TYPENAME digraph<NT,AT>::const_iterator to,
+                                        TYPENAME digraph<NT,AT>::const_iterator_set& visited,
+                                        TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // The recursive part of the reaching_nodes function.
+    // Just like the reachable_nodes_r function but it goes backwards
+    for (unsigned i = 0; i < fanin(to); i++)
+    {
+      digraph_arc_iterator<NT,AT, const AT&,const AT*> arc = input(to,i);
+      if (!select || select(*this,arc))
+      {
+        digraph_iterator<NT,AT,const NT&,const NT*> candidate = arc_from(input(to,i));
+        if (visited.insert(candidate).second)
+          reaching_nodes_r(candidate,visited,select);
+      }
+    }
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_node_vector
+  digraph<NT,AT>::reaching_nodes(TYPENAME digraph<NT,AT>::const_iterator to,
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // seed the recursion, marking the starting node as already visited
+    std::set<digraph_iterator<NT,AT,const NT&,const NT*> > visited;
+    visited.insert(to);
+    reaching_nodes_r(to,visited,select);
+    // convert the visited set into the required output form
+    // exclude the end node
+    std::vector<digraph_iterator<NT,AT,const NT&,const NT*> > result;
+    for (TYPENAME std::set<digraph_iterator<NT,AT,const NT&,const NT*> >::iterator i = visited.begin(); i != visited.end(); i++)
+      if (*i != to)
+        result.push_back(*i);
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::node_vector
+  digraph<NT,AT>::reaching_nodes(TYPENAME digraph<NT,AT>::iterator to,
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_nodes(reaching_nodes(to.constify(),select));
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Shortest Path Algorithms
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_arc_vector
+  digraph<NT,AT>::shortest_path(TYPENAME digraph<NT,AT>::const_iterator from,
+                                TYPENAME digraph<NT,AT>::const_iterator to,
+                                TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > paths = all_paths(from,to,select);
+    std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > shortest;
+    for (TYPENAME std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > >::iterator i = paths.begin(); i != paths.end(); i++)
+      if (shortest.empty() || i->size() < shortest.size())
+        shortest = *i;
+    return shortest;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::arc_vector
+  digraph<NT,AT>::shortest_path(TYPENAME digraph<NT,AT>::iterator from, 
+                                TYPENAME digraph<NT,AT>::iterator to,
+                                TYPENAME digraph<NT,AT>::arc_select_fn select)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_arcs(shortest_path(from.constify(),to.constify(),select));
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::const_path_vector
+  digraph<NT,AT>::shortest_paths(TYPENAME digraph<NT,AT>::const_iterator from,
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    from.assert_valid(this);
+    // This is an unweighted shortest path algorithm based on the algorithm from
+    // Weiss's book. This is essentially a breadth-first traversal or graph
+    // colouring algorithm. It is an iterative algorithm, so no recursion here! It
+    // works by creating a node queue initialised with the starting node. It then
+    // consumes the queue from front to back. For each node, it finds the
+    // successors and appends them to the queue. If a node is already 'known' it
+    // is not added - this avoids cycles. Thus the queue insert ordering
+    // represents the breadth-first ordering. On the way it creates a map of
+    // visited nodes. This is a map not a set because it also stores the arc that
+    // nominated this node as a shortest path. The full path can then be recreated
+    // from the map by just walking back through the predecessors. The depth (or
+    // colour) can be determined by the path length.
+    std::vector<std::vector<digraph_arc_iterator<NT,AT,const AT&,const AT*> > > result;
+    // initialise the iteration by creating a queue and adding the start node
+    std::deque<digraph_iterator<NT,AT,const NT&,const NT*> > nodes;
+    nodes.push_back(from);
+    // Create a map to store the set of known nodes mapped to their predecessor
+    // arcs. Initialise it with the current node, which has no predecessor. Note
+    // that the algorithm uses the feature of digraph iterators that they can be
+    // null iterators and that all null iterators are equal.
+    typedef std::map<digraph_iterator<NT,AT,const NT&,const NT*>,
+                     digraph_arc_iterator<NT,AT,const AT&,const AT*> > known_map;
+    known_map known;
+    known.insert(std::make_pair(from,digraph_arc_iterator<NT,AT, const AT&,const AT*>()));
+    // now the iterative part of the algorithm
+    while(!nodes.empty())
+    {
+      // pop the queue to get the next node to process - unfortunately the STL
+      // deque::pop does not return the popped value
+      digraph_iterator<NT,AT,const NT&,const NT*> current = nodes.front();
+      nodes.pop_front();
+      // now visit all the successors
+      for (unsigned i = 0; i < fanout(current); i++)
+      {
+        digraph_arc_iterator<NT,AT, const AT&,const AT*> next_arc = output(current,i);
+        // assert_valid whether the successor arc is a selected arc and can be part of a path
+        if (!select || select(*this,next_arc))
+        {
+          digraph_iterator<NT,AT,const NT&,const NT*> next = arc_to(next_arc);
+          // Discard any successors that are known because to be known already they
+          // must have another shorter path. Otherwise add the successor node to the
+          // queue to be visited later. To minimise the overhead of map lookup I use
+          // the usual trick of trying to insert the node and determining whether
+          // the node was known by the success or failure of the insertion - this is
+          // a Good STL Trick (TM).
+          if (known.insert(std::make_pair(next,next_arc)).second)
+            nodes.push_back(next);
+        }
+      }
+    }
+    // The map contains the results as an unordered set of nodes, mapped to their
+    // predecessor arcs and weight. This now needs to be converted into a set of
+    // paths. This is done by starting with a node from the map, finding its
+    // predecessor arc and therefore its predecessor node, looking that up in the
+    // map to find its predecessor and so on until the start node is reached (it
+    // has a null predecessor). Note that the known set includes the from node
+    // which does not generate a path.
+    for (TYPENAME known_map::iterator i = known.begin(); i != known.end(); i++)
+    {
+      if (i->first != from)
+      {
+        const_arc_vector this_path;
+        for (TYPENAME known_map::iterator node = i; 
+             node->second.valid(); 
+             node = known.find(arc_from(node->second)))
+          this_path.insert(this_path.begin(),node->second);
+        result.push_back(this_path);
+      }
+    }
+    return result;
+  }
+
+  template<typename NT, typename AT>
+  TYPENAME digraph<NT,AT>::path_vector
+  digraph<NT,AT>::shortest_paths(TYPENAME digraph<NT,AT>::iterator from,
+                                 TYPENAME digraph<NT,AT>::arc_select_fn select)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return deconstify_paths(shortest_paths(from.constify(),select));
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 3549ff4c9022e98b570a975bd52bf18fb544cca0..19110137c5aeb8cf06e9828b2f21129db07bc270 100644 (file)
@@ -1,71 +1,71 @@
-#ifndef STLPLUS_EXCEPTIONS\r
-#define STLPLUS_EXCEPTIONS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author: Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   The set of general exceptions thrown by STLplus components\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include <stdexcept>\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Thrown if a pointer or an iterator is dereferenced when it is null\r
-\r
-  class null_dereference : public std::logic_error\r
-  {\r
-  public:\r
-    null_dereference(const std::string& description) throw() :\r
-      std::logic_error(std::string("stlplus::null_dereference: ") + description) {}\r
-    ~null_dereference(void) throw() {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Thrown if an iterator is dereferenced when it is pointing to the end element\r
-\r
-  class end_dereference : public std::logic_error\r
-  {\r
-  public:\r
-    end_dereference(const std::string& description) throw() :\r
-      std::logic_error("stlplus::end_dereference: " + description) {}\r
-    ~end_dereference(void) throw() {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Thrown if an iterator is used with the wrong container. In other words, an\r
-  // iterator is created as a pointer to a sub-object within a container. If\r
-  // that iterator is then used with a different container, this exception is\r
-  // thrown.\r
-\r
-  class wrong_object : public std::logic_error\r
-  {\r
-  public:\r
-    wrong_object(const std::string& description) throw() :\r
-      std::logic_error("stlplus::wrong_object: " + description) {}\r
-    ~wrong_object(void) throw() {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Thrown if an attempt is made to copy an object that is uncopyable\r
-\r
-  class illegal_copy : public std::logic_error\r
-  {\r
-  public:\r
-    illegal_copy(const std::string& description) throw() :\r
-      std::logic_error("stlplus::illegal_copy: " + description) {}\r
-    ~illegal_copy(void) throw() {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_EXCEPTIONS
+#define STLPLUS_EXCEPTIONS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author: Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   The set of general exceptions thrown by STLplus components
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include <stdexcept>
+#include <string>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Thrown if a pointer or an iterator is dereferenced when it is null
+
+  class null_dereference : public std::logic_error
+  {
+  public:
+    null_dereference(const std::string& description) throw() :
+      std::logic_error(std::string("stlplus::null_dereference: ") + description) {}
+    ~null_dereference(void) throw() {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Thrown if an iterator is dereferenced when it is pointing to the end element
+
+  class end_dereference : public std::logic_error
+  {
+  public:
+    end_dereference(const std::string& description) throw() :
+      std::logic_error("stlplus::end_dereference: " + description) {}
+    ~end_dereference(void) throw() {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Thrown if an iterator is used with the wrong container. In other words, an
+  // iterator is created as a pointer to a sub-object within a container. If
+  // that iterator is then used with a different container, this exception is
+  // thrown.
+
+  class wrong_object : public std::logic_error
+  {
+  public:
+    wrong_object(const std::string& description) throw() :
+      std::logic_error("stlplus::wrong_object: " + description) {}
+    ~wrong_object(void) throw() {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Thrown if an attempt is made to copy an object that is uncopyable
+
+  class illegal_copy : public std::logic_error
+  {
+  public:
+    illegal_copy(const std::string& description) throw() :
+      std::logic_error("stlplus::illegal_copy: " + description) {}
+    ~illegal_copy(void) throw() {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 36437f1671b287ffef593797dbc967e12ebd504c..46dc46ddc5c6e00da2028bc26c6e3f94ced0c9e8 100644 (file)
@@ -1,59 +1,59 @@
-#ifndef STLPLUS_FOURSOME\r
-#define STLPLUS_FOURSOME\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton, from an original by Dan Milton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   The next in the series pair->triple->foursome\r
-\r
-//   Originally called quadruple but that clashed (as did quad) with system\r
-//   libraries on some operating systems\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // the foursome class\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  struct foursome\r
-  {\r
-    typedef T1 first_type;\r
-    typedef T2 second_type;\r
-    typedef T3 third_type;\r
-    typedef T4 fourth_type;\r
-\r
-    T1 first;\r
-    T2 second;\r
-    T3 third;\r
-    T4 fourth;\r
-\r
-    foursome(void);\r
-    foursome(const T1& p1, const T2& p2, const T3& p3, const T4& p4);\r
-    foursome(const foursome<T1,T2,T3,T4>& t2);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // creation\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  foursome<T1,T2,T3,T4> make_foursome(const T1& first, const T2& second, const T3& third, const T4& fourth);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // comparison\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  bool operator == (const foursome<T1,T2,T3,T4>& left, const foursome<T1,T2,T3,T4>& right);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "foursome.tpp"\r
-#endif\r
+#ifndef STLPLUS_FOURSOME
+#define STLPLUS_FOURSOME
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton, from an original by Dan Milton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   The next in the series pair->triple->foursome
+
+//   Originally called quadruple but that clashed (as did quad) with system
+//   libraries on some operating systems
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // the foursome class
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  struct foursome
+  {
+    typedef T1 first_type;
+    typedef T2 second_type;
+    typedef T3 third_type;
+    typedef T4 fourth_type;
+
+    T1 first;
+    T2 second;
+    T3 third;
+    T4 fourth;
+
+    foursome(void);
+    foursome(const T1& p1, const T2& p2, const T3& p3, const T4& p4);
+    foursome(const foursome<T1,T2,T3,T4>& t2);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // creation
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  foursome<T1,T2,T3,T4> make_foursome(const T1& first, const T2& second, const T3& third, const T4& fourth);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // comparison
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  bool operator == (const foursome<T1,T2,T3,T4>& left, const foursome<T1,T2,T3,T4>& right);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "foursome.tpp"
+#endif
index f1dd9b39c66b2352352371e17e12f7474c2d8213..b2bfe08d4679e6bc39d3122429fd9b678a7ef6a0 100644 (file)
@@ -1,59 +1,59 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton, from an original by Dan Milton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // the foursome class\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  foursome<T1,T2,T3,T4>::foursome(void) :\r
-    first(), second(), third(), fourth()\r
-  {\r
-  }\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  foursome<T1,T2,T3,T4>::foursome(const T1& p1, const T2& p2, const T3& p3, const T4& p4) :\r
-    first(p1), second(p2), third(p3), fourth(p4)\r
-  {\r
-  }\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  foursome<T1,T2,T3,T4>::foursome(const foursome<T1,T2,T3,T4>& t2) :\r
-    first(t2.first), second(t2.second), third(t2.third), fourth(t2.fourth)\r
-  {\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // creation\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  foursome<T1,T2,T3,T4> make_foursome(const T1& first, const T2& second, const T3& third, const T4& fourth)\r
-  {\r
-    return foursome<T1,T2,T3,T4>(first,second,third,fourth);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // comparison\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4>\r
-  bool operator == (const foursome<T1,T2,T3,T4>& left, const foursome<T1,T2,T3,T4>& right)\r
-  {\r
-    // foursomes are equal if all elements are equal\r
-    return \r
-      left.first == right.first && \r
-      left.second == right.second && \r
-      left.third == right.third &&\r
-      left.fourth == right.fourth;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton, from an original by Dan Milton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // the foursome class
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  foursome<T1,T2,T3,T4>::foursome(void) :
+    first(), second(), third(), fourth()
+  {
+  }
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  foursome<T1,T2,T3,T4>::foursome(const T1& p1, const T2& p2, const T3& p3, const T4& p4) :
+    first(p1), second(p2), third(p3), fourth(p4)
+  {
+  }
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  foursome<T1,T2,T3,T4>::foursome(const foursome<T1,T2,T3,T4>& t2) :
+    first(t2.first), second(t2.second), third(t2.third), fourth(t2.fourth)
+  {
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // creation
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  foursome<T1,T2,T3,T4> make_foursome(const T1& first, const T2& second, const T3& third, const T4& fourth)
+  {
+    return foursome<T1,T2,T3,T4>(first,second,third,fourth);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // comparison
+
+  template<typename T1, typename T2, typename T3, typename T4>
+  bool operator == (const foursome<T1,T2,T3,T4>& left, const foursome<T1,T2,T3,T4>& right)
+  {
+    // foursomes are equal if all elements are equal
+    return 
+      left.first == right.first && 
+      left.second == right.second && 
+      left.third == right.third &&
+      left.fourth == right.fourth;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 19624812850a1fc0d1355f983f3972b475e2d747..13e9541f81d0cc2ff31320b60ae0f592eef590d6 100644 (file)
-#ifndef STLPLUS_HASH\r
-#define STLPLUS_HASH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A chained hash table using STL semantics\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include "exceptions.hpp"\r
-#include "safe_iterator.hpp"\r
-#include <map>\r
-#include <iostream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internals\r
-\r
-  template<typename K, typename T, class H, class E> class hash;\r
-  template<typename K, typename T, class H, class E> class hash_element;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // iterator class\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  class hash_iterator : public safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >\r
-  {\r
-  public:\r
-    friend class hash<K,T,H,E>;\r
-\r
-    // local type definitions\r
-    // an iterator points to a value whilst a const_iterator points to a const value\r
-    typedef V                                                  value_type;\r
-    typedef hash_iterator<K,T,H,E,std::pair<const K,T> >       iterator;\r
-    typedef hash_iterator<K,T,H,E,const std::pair<const K,T> > const_iterator;\r
-    typedef hash_iterator<K,T,H,E,V>                           this_iterator;\r
-    typedef V&                                                 reference;\r
-    typedef V*                                                 pointer;\r
-\r
-    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
-    // any attempt to dereference or use a null iterator is an error\r
-    // the only valid thing you can do is assign an iterator to it\r
-    hash_iterator(void);\r
-    ~hash_iterator(void);\r
-\r
-    // Type conversion methods allow const_iterator and iterator to be converted\r
-    // convert an iterator/const_iterator to a const_iterator\r
-    const_iterator constify(void) const;\r
-    // convert an iterator/const_iterator to an iterator\r
-    iterator deconstify(void) const;\r
-\r
-    // increment operators used to step through the set of all values in a hash\r
-    // it is only legal to increment a valid iterator\r
-    // there's no decrement - I've only implemented this as a unidirectional iterator\r
-    // pre-increment\r
-    this_iterator& operator ++ (void)\r
-      throw(null_dereference,end_dereference);\r
-    // post-increment\r
-    this_iterator operator ++ (int)\r
-      throw(null_dereference,end_dereference);\r
-\r
-    // test useful for testing whether iteration has completed\r
-    bool operator == (const this_iterator& r) const;\r
-    bool operator != (const this_iterator& r) const;\r
-    bool operator < (const this_iterator& r) const;\r
-\r
-    // access the value - a const_iterator gives you a const value, an iterator a non-const value\r
-    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
-    reference operator*(void) const\r
-      throw(null_dereference,end_dereference);\r
-    pointer operator->(void) const\r
-      throw(null_dereference,end_dereference);\r
-\r
-  private:\r
-    friend class hash_element<K,T,H,E>;\r
-\r
-    // constructor used by hash to create a non-null iterator\r
-    // you cannot create a valid iterator except by calling a hash method that returns one\r
-    explicit hash_iterator(hash_element<K,T,H,E>* element);\r
-    // constructor used to create an end iterator\r
-    explicit hash_iterator(const hash<K,T,H,E>* owner);\r
-    // used to create an alias of an iterator\r
-    explicit hash_iterator(const safe_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> >& iterator);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Hash class\r
-  // K = key type\r
-  // T = value type\r
-  // H = hash function object with the profile 'unsigned H(const K&)'\r
-  // E = equal function object with profile 'bool E(const K&, const K&)' defaults to equal_to which in turn calls '=='\r
-\r
-  template<typename K, typename T, class H, class E = std::equal_to<K> >\r
-  class hash\r
-  {\r
-  public:\r
-    typedef unsigned                                size_type;\r
-    typedef K                                       key_type;\r
-    typedef T                                       data_type;\r
-    typedef T                                       mapped_type;\r
-    typedef std::pair<const K, T>                   value_type;\r
-    typedef hash_iterator<K,T,H,E,value_type>       iterator;\r
-    typedef hash_iterator<K,T,H,E,const value_type> const_iterator;\r
-\r
-    // construct a hash table with specified number of bins\r
-    // the default 0 bins means leave it to the table to decide\r
-    // specifying 0 bins also enables auto-rehashing, otherwise auto-rehashing defaults off\r
-    hash(unsigned bins = 0);\r
-    ~hash(void);\r
-\r
-    // copy and equality copy the data elements but not the size of the copied table\r
-    hash(const hash&);\r
-    hash& operator = (const hash&);\r
-\r
-    // test for an empty table and for the size of a table\r
-    // efficient because the size is stored separately from the table contents\r
-    bool empty(void) const;\r
-    unsigned size(void) const;\r
-\r
-    // test for equality - two hashes are equal if they contain equal values\r
-    bool operator == (const hash&) const;\r
-    bool operator != (const hash&) const;\r
-\r
-    // switch auto-rehash on\r
-    void auto_rehash(void);\r
-    // switch auto-rehash off\r
-    void manual_rehash(void);\r
-    // force a rehash now\r
-    // default of 0 means implement built-in size calculation for rehashing (recommended - it doubles the number of bins)\r
-    void rehash(unsigned bins = 0);\r
-    // test the loading ratio, which is the size divided by the number of bins\r
-    // use this if you are doing your own rehashing\r
-    // the recommendation is to double the bins when the loading exceeds 0.5 which is what auto-rehashing does\r
-    float loading(void) const;\r
-\r
-    // test for the presence of a key\r
-    bool present(const K& key) const;\r
-    // provide map equivalent key count function (0 or 1, as not a multimap)\r
-    size_type count(const K& key) const;\r
-\r
-    // insert a new key/data pair - replaces any previous value for this key\r
-    iterator insert(const K& key, const T& data);\r
-    // insert a copy of the pair into the table (std::map compatible)\r
-    std::pair<iterator, bool> insert(const value_type& value);\r
-    // insert a new key and return the iterator so that the data can be filled in\r
-    iterator insert(const K& key);\r
-\r
-    // remove a key/data pair from the hash table\r
-    // as in map, this returns the number of elements erased\r
-    size_type erase(const K& key);\r
-    // remove an element from the hash table using an iterator\r
-    // as in map, returns an iterator to the next element\r
-    iterator erase(iterator it);\r
-    // remove all elements from the hash table\r
-    void erase(void);\r
-    // map equivalent of above\r
-    void clear(void);\r
-\r
-    // find a key and return an iterator to it\r
-    // The iterator is like a pointer to a pair<const K,T>\r
-    // end() is returned if the find fails\r
-    const_iterator find(const K& key) const;\r
-    iterator find(const K& key);\r
-\r
-    // returns the data corresponding to the key\r
-    // const version is used for const hashes and cannot change the hash, so failure causes an exception\r
-    // non-const version is for non-const hashes and is like map - it creates a new key/data pair if find fails\r
-    const T& operator[] (const K& key) const throw(std::out_of_range);\r
-    T& operator[] (const K& key);\r
-\r
-    // iterators allow the hash table to be traversed\r
-    // iterators remain valid unless an item is removed or unless a rehash happens\r
-    const_iterator begin(void) const;\r
-    iterator begin(void);\r
-    const_iterator end(void) const;\r
-    iterator end(void);\r
-\r
-    // diagnostic report shows the number of items in each bin so can be used\r
-    // to diagnose effectiveness of hash functions\r
-    void debug_report(std::ostream&) const;\r
-\r
-    // internals\r
-  private:\r
-    friend class hash_element<K,T,H,E>;\r
-    friend class hash_iterator<K,T,H,E,std::pair<const K,T> >;\r
-    friend class hash_iterator<K,T,H,E,const std::pair<const K,T> >;\r
-\r
-    unsigned m_rehash;\r
-    unsigned m_bins;\r
-    unsigned m_size;\r
-    hash_element<K,T,H,E>** m_values;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "hash.tpp"\r
-#endif\r
+#ifndef STLPLUS_HASH
+#define STLPLUS_HASH
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A chained hash table using STL semantics
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include "exceptions.hpp"
+#include "safe_iterator.hpp"
+#include <map>
+#include <iostream>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // internals
+
+  template<typename K, typename T, class H, class E> class hash;
+  template<typename K, typename T, class H, class E> class hash_element;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // iterator class
+
+  template<typename K, typename T, class H, class E, typename V>
+  class hash_iterator : public safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >
+  {
+  public:
+    friend class hash<K,T,H,E>;
+
+    // local type definitions
+    // an iterator points to a value whilst a const_iterator points to a const value
+    typedef V                                                  value_type;
+    typedef hash_iterator<K,T,H,E,std::pair<const K,T> >       iterator;
+    typedef hash_iterator<K,T,H,E,const std::pair<const K,T> > const_iterator;
+    typedef hash_iterator<K,T,H,E,V>                           this_iterator;
+    typedef V&                                                 reference;
+    typedef V*                                                 pointer;
+
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
+    // any attempt to dereference or use a null iterator is an error
+    // the only valid thing you can do is assign an iterator to it
+    hash_iterator(void);
+    ~hash_iterator(void);
+
+    // Type conversion methods allow const_iterator and iterator to be converted
+    // convert an iterator/const_iterator to a const_iterator
+    const_iterator constify(void) const;
+    // convert an iterator/const_iterator to an iterator
+    iterator deconstify(void) const;
+
+    // increment operators used to step through the set of all values in a hash
+    // it is only legal to increment a valid iterator
+    // there's no decrement - I've only implemented this as a unidirectional iterator
+    // pre-increment
+    this_iterator& operator ++ (void)
+      throw(null_dereference,end_dereference);
+    // post-increment
+    this_iterator operator ++ (int)
+      throw(null_dereference,end_dereference);
+
+    // test useful for testing whether iteration has completed
+    bool operator == (const this_iterator& r) const;
+    bool operator != (const this_iterator& r) const;
+    bool operator < (const this_iterator& r) const;
+
+    // access the value - a const_iterator gives you a const value, an iterator a non-const value
+    // it is illegal to dereference an invalid (i.e. null or end) iterator
+    reference operator*(void) const
+      throw(null_dereference,end_dereference);
+    pointer operator->(void) const
+      throw(null_dereference,end_dereference);
+
+  private:
+    friend class hash_element<K,T,H,E>;
+
+    // constructor used by hash to create a non-null iterator
+    // you cannot create a valid iterator except by calling a hash method that returns one
+    explicit hash_iterator(hash_element<K,T,H,E>* element);
+    // constructor used to create an end iterator
+    explicit hash_iterator(const hash<K,T,H,E>* owner);
+    // used to create an alias of an iterator
+    explicit hash_iterator(const safe_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> >& iterator);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Hash class
+  // K = key type
+  // T = value type
+  // H = hash function object with the profile 'unsigned H(const K&)'
+  // E = equal function object with profile 'bool E(const K&, const K&)' defaults to equal_to which in turn calls '=='
+
+  template<typename K, typename T, class H, class E = std::equal_to<K> >
+  class hash
+  {
+  public:
+    typedef unsigned                                size_type;
+    typedef K                                       key_type;
+    typedef T                                       data_type;
+    typedef T                                       mapped_type;
+    typedef std::pair<const K, T>                   value_type;
+    typedef hash_iterator<K,T,H,E,value_type>       iterator;
+    typedef hash_iterator<K,T,H,E,const value_type> const_iterator;
+
+    // construct a hash table with specified number of bins
+    // the default 0 bins means leave it to the table to decide
+    // specifying 0 bins also enables auto-rehashing, otherwise auto-rehashing defaults off
+    hash(unsigned bins = 0);
+    ~hash(void);
+
+    // copy and equality copy the data elements but not the size of the copied table
+    hash(const hash&);
+    hash& operator = (const hash&);
+
+    // test for an empty table and for the size of a table
+    // efficient because the size is stored separately from the table contents
+    bool empty(void) const;
+    unsigned size(void) const;
+
+    // test for equality - two hashes are equal if they contain equal values
+    bool operator == (const hash&) const;
+    bool operator != (const hash&) const;
+
+    // switch auto-rehash on
+    void auto_rehash(void);
+    // switch auto-rehash off
+    void manual_rehash(void);
+    // force a rehash now
+    // default of 0 means implement built-in size calculation for rehashing (recommended - it doubles the number of bins)
+    void rehash(unsigned bins = 0);
+    // test the loading ratio, which is the size divided by the number of bins
+    // use this if you are doing your own rehashing
+    // the recommendation is to double the bins when the loading exceeds 0.5 which is what auto-rehashing does
+    float loading(void) const;
+
+    // test for the presence of a key
+    bool present(const K& key) const;
+    // provide map equivalent key count function (0 or 1, as not a multimap)
+    size_type count(const K& key) const;
+
+    // insert a new key/data pair - replaces any previous value for this key
+    iterator insert(const K& key, const T& data);
+    // insert a copy of the pair into the table (std::map compatible)
+    std::pair<iterator, bool> insert(const value_type& value);
+    // insert a new key and return the iterator so that the data can be filled in
+    iterator insert(const K& key);
+
+    // remove a key/data pair from the hash table
+    // as in map, this returns the number of elements erased
+    size_type erase(const K& key);
+    // remove an element from the hash table using an iterator
+    // as in map, returns an iterator to the next element
+    iterator erase(iterator it);
+    // remove all elements from the hash table
+    void erase(void);
+    // map equivalent of above
+    void clear(void);
+
+    // find a key and return an iterator to it
+    // The iterator is like a pointer to a pair<const K,T>
+    // end() is returned if the find fails
+    const_iterator find(const K& key) const;
+    iterator find(const K& key);
+
+    // returns the data corresponding to the key
+    // const version is used for const hashes and cannot change the hash, so failure causes an exception
+    // non-const version is for non-const hashes and is like map - it creates a new key/data pair if find fails
+    const T& operator[] (const K& key) const throw(std::out_of_range);
+    T& operator[] (const K& key);
+
+    // iterators allow the hash table to be traversed
+    // iterators remain valid unless an item is removed or unless a rehash happens
+    const_iterator begin(void) const;
+    iterator begin(void);
+    const_iterator end(void) const;
+    iterator end(void);
+
+    // diagnostic report shows the number of items in each bin so can be used
+    // to diagnose effectiveness of hash functions
+    void debug_report(std::ostream&) const;
+
+    // internals
+  private:
+    friend class hash_element<K,T,H,E>;
+    friend class hash_iterator<K,T,H,E,std::pair<const K,T> >;
+    friend class hash_iterator<K,T,H,E,const std::pair<const K,T> >;
+
+    unsigned m_rehash;
+    unsigned m_bins;
+    unsigned m_size;
+    hash_element<K,T,H,E>** m_values;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "hash.tpp"
+#endif
index 9a1e4e93728c477f7d13961c678592508786ce7b..da2e39df5f5beebbb1d3908b95897aa20fc765c6 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include <iomanip>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // the element stored in the hash\r
-\r
-  template<typename K, typename T, typename H, typename E>\r
-  class hash_element\r
-  {\r
-  public:\r
-    master_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> > m_master;\r
-    std::pair<const K, T> m_value;\r
-    hash_element<K,T,H,E>* m_next;\r
-    unsigned m_hash;\r
-\r
-    hash_element(const hash<K,T,H,E>* owner, const K& key, const T& data, unsigned hash) :\r
-      m_master(owner,this), m_value(key,data), m_next(0), m_hash(hash)\r
-      {\r
-      }\r
-\r
-    hash_element(const hash<K,T,H,E>* owner, const std::pair<const K,T>& value, unsigned hash) :\r
-      m_master(owner,this), m_value(value), m_next(0), m_hash(hash)\r
-      {\r
-      }\r
-\r
-    ~hash_element(void)\r
-      {\r
-        m_next = 0;\r
-        m_hash = 0;\r
-      }\r
-\r
-    const hash<K,T,H,E>* owner(void) const\r
-      {\r
-        return m_master.owner();\r
-      }\r
-\r
-    // generate the bin number from the hash value and the owner's number of bins\r
-    unsigned bin(void) const\r
-      {\r
-        return m_hash % (owner()->m_bins);\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // iterator\r
-\r
-  // null constructor\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  hash_iterator<K,T,H,E,V>::hash_iterator(void)\r
-  {\r
-  }\r
-\r
-  // non-null constructor used from within the hash to construct a valid iterator\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  hash_iterator<K,T,H,E,V>::hash_iterator(hash_element<K,T,H,E>* element) :\r
-    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(element->m_master)\r
-  {\r
-  }\r
-\r
-  // constructor used to create an end iterator\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  hash_iterator<K,T,H,E,V>::hash_iterator(const hash<K,T,H,E>* owner) :\r
-    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(owner)\r
-  {\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  hash_iterator<K,T,H,E,V>::hash_iterator(const safe_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> >& iterator) :\r
-    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(iterator)\r
-  {\r
-  }\r
-\r
-  // destructor\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  hash_iterator<K,T,H,E,V>::~hash_iterator(void)\r
-  {\r
-  }\r
-\r
-  // mode conversions\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  TYPENAME hash_iterator<K,T,H,E,V>::const_iterator hash_iterator<K,T,H,E,V>::constify(void) const\r
-  {\r
-    return hash_iterator<K,T,H,E,const std::pair<const K,T> >(*this);\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  TYPENAME hash_iterator<K,T,H,E,V>::iterator hash_iterator<K,T,H,E,V>::deconstify(void) const\r
-  {\r
-    return hash_iterator<K,T,H,E,std::pair<const K,T> >(*this);\r
-  }\r
-\r
-  // increment operator looks for the next element in the table\r
-  // if there isn't one, then this becomes an end() iterator with m_bin = m_bins\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  TYPENAME hash_iterator<K,T,H,E,V>::this_iterator& hash_iterator<K,T,H,E,V>::operator ++ (void)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    if (this->node()->m_next)\r
-      set(this->node()->m_next->m_master);\r
-    else\r
-    {\r
-      // failing that, subsequent hash values are tried until either an element is found or there are no more bins\r
-      // in which case it becomes an end() iterator\r
-      hash_element<K,T,H,E>* element = 0;\r
-      unsigned current_bin = this->node()->bin();\r
-      for(current_bin++; !element && (current_bin < this->owner()->m_bins); current_bin++)\r
-        element = this->owner()->m_values[current_bin];\r
-      if (element)\r
-        set(element->m_master);\r
-      else\r
-        this->set_end();\r
-    }\r
-    return *this;\r
-  }\r
-\r
-  // post-increment is defined in terms of pre-increment\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  TYPENAME hash_iterator<K,T,H,E,V>::this_iterator hash_iterator<K,T,H,E,V>::operator ++ (int)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    hash_iterator<K,T,H,E,V> old(*this);\r
-    ++(*this);\r
-    return old;\r
-  }\r
-\r
-  // two iterators are equal if they point to the same element\r
-  // both iterators must be non-null and belong to the same table\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  bool hash_iterator<K,T,H,E,V>::operator == (const hash_iterator<K,T,H,E,V>& r) const\r
-  {\r
-    return equal(r);\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  bool hash_iterator<K,T,H,E,V>::operator != (const hash_iterator<K,T,H,E,V>& r) const\r
-  {\r
-    return !operator==(r);\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  bool hash_iterator<K,T,H,E,V>::operator < (const hash_iterator<K,T,H,E,V>& r) const\r
-  {\r
-    return compare(r) < 0;\r
-  }\r
-\r
-  // iterator dereferencing is only legal on a non-null iterator\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  V& hash_iterator<K,T,H,E,V>::operator*(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    return this->node()->m_value;\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E, typename V>\r
-  V* hash_iterator<K,T,H,E,V>::operator->(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return &(operator*());\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // hash\r
-\r
-  // totally arbitrary initial size used for auto-rehashed tables\r
-  static unsigned hash_default_bins = 127;\r
-\r
-  // constructor\r
-  // tests whether the user wants auto-rehash\r
-  // sets the rehash point to be a loading of 1.0 by setting it to the number of bins\r
-  // uses the user's size unless this is zero, in which case implement the default\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  hash<K,T,H,E>::hash(unsigned bins) :\r
-    m_rehash(bins), m_bins(bins > 0 ? bins : hash_default_bins), m_size(0), m_values(0)\r
-  {\r
-    m_values = new hash_element<K,T,H,E>*[m_bins];\r
-    for (unsigned i = 0; i < m_bins; i++)\r
-      m_values[i] = 0;\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  hash<K,T,H,E>::~hash(void)\r
-  {\r
-    // delete all the elements\r
-    clear();\r
-    // and delete the data structure\r
-    delete[] m_values;\r
-    m_values = 0;\r
-  }\r
-\r
-  // as usual, implement the copy constructor i.t.o. the assignment operator\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  hash<K,T,H,E>::hash(const hash<K,T,H,E>& right) :\r
-    m_rehash(right.m_rehash), m_bins(right.m_bins), m_size(0), m_values(0)\r
-  {\r
-    m_values = new hash_element<K,T,H,E>*[right.m_bins];\r
-    // copy the rehash behaviour as well as the size\r
-    for (unsigned i = 0; i < m_bins; i++)\r
-      m_values[i] = 0;\r
-    *this = right;\r
-  }\r
-\r
-  // assignment operator\r
-  // this is done by copying the elements\r
-  // the source and target hashes can be different sizes\r
-  // the hash is self-copy safe, i.e. it is legal to say x = x;\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  hash<K,T,H,E>& hash<K,T,H,E>::operator = (const hash<K,T,H,E>& r)\r
-  {\r
-    // make self-copy safe\r
-    if (&r == this) return *this;\r
-    // remove all the existing elements\r
-    clear();\r
-    // copy the elements across - remember that this is rehashing because the two\r
-    // tables can be different sizes so there is no quick way of doing this by\r
-    // copying the lists\r
-    for (hash_iterator<K,T,H,E,const std::pair<const K,T> > i = r.begin(); i != r.end(); ++i)\r
-      insert(i->first, i->second);\r
-    return *this;\r
-  }\r
-\r
-  // number of values in the hash\r
-  template<typename K, typename T, class H, class E>\r
-  bool hash<K,T,H,E>::empty(void) const\r
-  {\r
-    return m_size == 0;\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  unsigned hash<K,T,H,E>::size(void) const\r
-  {\r
-    return m_size;\r
-  }\r
-\r
-  // equality\r
-  template<typename K, typename T, class H, class E>\r
-  bool hash<K,T,H,E>::operator == (const hash<K,T,H,E>& right) const\r
-  {\r
-    // this table is the same as the right table if they are the same table!\r
-    if (&right == this) return true;\r
-    // they must be the same size to be equal\r
-    if (m_size != right.m_size) return false;\r
-    // now every key in this must be in right and have the same data\r
-    for (hash_iterator<K,T,H,E,const std::pair<const K,T> > i = begin(); i != end(); i++)\r
-    {\r
-      hash_iterator<K,T,H,E,const std::pair<const K,T> > found = right.find(i->first);\r
-      if (found == right.end()) return false;\r
-      if (!(i->second == found->second)) return false;\r
-    }\r
-    return true;\r
-  }\r
-\r
-  // set up the hash to auto-rehash at a specific size\r
-  // setting the rehash size to 0 forces manual rehashing\r
-  template<typename K, typename T, class H, class E>\r
-  void hash<K,T,H,E>::auto_rehash(void)\r
-  {\r
-    m_rehash = m_bins;\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  void hash<K,T,H,E>::manual_rehash(void)\r
-  {\r
-    m_rehash = 0;\r
-  }\r
-\r
-  // the rehash function\r
-  // builds a new hash table and moves the elements (without copying) from the old to the new\r
-  // I store the un-modulused hash value in the element for more efficient rehashing\r
-  // passing 0 to the bins parameter does auto-rehashing\r
-  // passing any other value forces the number of bins\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  void hash<K,T,H,E>::rehash(unsigned bins)\r
-  {\r
-    // user specified size: just take the user's value\r
-    // auto calculate: if the load is high, increase the size; else do nothing\r
-    unsigned new_bins = bins ? bins : m_bins;\r
-    if (bins == 0 && m_size > 0)\r
-    {\r
-      // these numbers are pretty arbitrary\r
-      // TODO - make them user-customisable?\r
-      float load = loading();\r
-      if (load > 2.0)\r
-        new_bins = (unsigned)(m_bins * load);\r
-      else if (load > 1.0)\r
-        new_bins = m_bins * 2;\r
-    }\r
-    if (new_bins == m_bins) return;\r
-    // set the new rehashing point if auto-rehashing is on\r
-    if (m_rehash) m_rehash = new_bins;\r
-    // move aside the old structure\r
-    hash_element<K,T,H,E>** old_values = m_values;\r
-    unsigned old_bins = m_bins;\r
-    // create a replacement structure\r
-    m_values = new hash_element<K,T,H,E>*[new_bins];\r
-    for (unsigned i = 0; i < new_bins; i++)\r
-      m_values[i] = 0;\r
-    m_bins = new_bins;\r
-    // move all the old elements across, rehashing each one\r
-    for (unsigned j = 0; j < old_bins; j++)\r
-    {\r
-      while(old_values[j])\r
-      {\r
-        // unhook from the old structure\r
-        hash_element<K,T,H,E>* current = old_values[j];\r
-        old_values[j] = current->m_next;\r
-        // rehash using the stored hash value\r
-        unsigned bin = current->bin();\r
-        // hook it into the new structure\r
-        current->m_next = m_values[bin];\r
-        m_values[bin] = current;\r
-      }\r
-    }\r
-    // now delete the old structure\r
-    delete[] old_values;\r
-  }\r
-\r
-  // the loading is the average number of elements per bin\r
-  // this simplifies to the total elements divided by the number of bins\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  float hash<K,T,H,E>::loading(void) const\r
-  {\r
-    return (float)m_size / (float)m_bins;\r
-  }\r
-\r
-  // remove all elements from the table\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  void hash<K,T,H,E>::erase(void)\r
-  {\r
-    // unhook the list elements and destroy them\r
-    for (unsigned i = 0; i < m_bins; i++)\r
-    {\r
-      hash_element<K,T,H,E>* current = m_values[i];\r
-      while(current)\r
-      {\r
-        hash_element<K,T,H,E>* next = current->m_next;\r
-        delete current;\r
-        current = next;\r
-      }\r
-      m_values[i] = 0;\r
-    }\r
-    m_size = 0;\r
-  }\r
-\r
-  // test for whether a key is present in the table\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  bool hash<K,T,H,E>::present(const K& key) const\r
-  {\r
-    return find(key) != end();\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::size_type hash<K,T,H,E>::count(const K& key) const\r
-  {\r
-    return present() ? 1 : 0;\r
-  }\r
-\r
-  // add a key and data element to the table - defined in terms of the general-purpose pair insert function\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::insert(const K& key, const T& data)\r
-  {\r
-    return insert(std::pair<const K,T>(key,data)).first;\r
-  }\r
-\r
-  // insert a key/data pair into the table\r
-  // this removes any old value with the same key since there is no multihash functionality\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  std::pair<TYPENAME hash<K,T,H,E>::iterator, bool> hash<K,T,H,E>::insert(const std::pair<const K,T>& value)\r
-  {\r
-    // if auto-rehash is enabled, implement the auto-rehash before inserting the new value\r
-    // the table is rehashed if this insertion makes the loading exceed 1.0\r
-    if (m_rehash && (m_size >= m_rehash)) rehash();\r
-    // calculate the new hash value\r
-    unsigned hash_value_full = H()(value.first);\r
-    unsigned bin = hash_value_full % m_bins;\r
-    bool inserted = true;\r
-    // unhook any previous value with this key\r
-    // this has been inlined from erase(key) so that the hash value is not calculated twice\r
-    hash_element<K,T,H,E>* previous = 0;\r
-    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)\r
-    {\r
-      // first check the full stored hash value\r
-      if (current->m_hash != hash_value_full) continue;\r
-\r
-      // next try the equality operator\r
-      if (!E()(current->m_value.first, value.first)) continue;\r
-\r
-      // unhook this value and destroy it\r
-      if (previous)\r
-        previous->m_next = current->m_next;\r
-      else\r
-        m_values[bin] = current->m_next;\r
-      delete current;\r
-      m_size--;\r
-\r
-      // we've overwritten a previous value\r
-      inserted = false;\r
-\r
-      // assume there can only be one match so we can give up now\r
-      break;\r
-    }\r
-    // now hook in a new list element at the start of the list for this hash value\r
-    hash_element<K,T,H,E>* new_item = new hash_element<K,T,H,E>(this, value, hash_value_full);\r
-    new_item->m_next = m_values[bin];\r
-    m_values[bin] = new_item;\r
-    // increment the size count\r
-    m_size++;\r
-    // construct an iterator from the list node, and return whether inserted\r
-    return std::make_pair(hash_iterator<K,T,H,E,std::pair<const K,T> >(new_item), inserted);\r
-  }\r
-\r
-  // insert a key with an empty data field ready to be filled in later\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::insert(const K& key)\r
-  {\r
-    return insert(key,T());\r
-  }\r
-\r
-  // remove a key from the table - return true if the key was found and removed, false if it wasn't present\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  unsigned hash<K,T,H,E>::erase(const K& key)\r
-  {\r
-    unsigned hash_value_full = H()(key);\r
-    unsigned bin = hash_value_full % m_bins;\r
-    // scan the list for an element with this key\r
-    // need to keep a previous pointer because the lists are single-linked\r
-    hash_element<K,T,H,E>* previous = 0;\r
-    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)\r
-    {\r
-      // first check the full stored hash value\r
-      if (current->m_hash != hash_value_full) continue;\r
-\r
-      // next try the equality operator\r
-      if (!E()(current->m_value.first, key)) continue;\r
-\r
-      // found this key, so unhook the element from the list\r
-      if (previous)\r
-        previous->m_next = current->m_next;\r
-      else\r
-        m_values[bin] = current->m_next;\r
-      // destroy it\r
-      delete current;\r
-      // remember to maintain the size count\r
-      m_size--;\r
-      return 1;\r
-    }\r
-    return 0;\r
-  }\r
-\r
-  // remove an element from the hash table using an iterator (std::map equivalent)\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::erase(TYPENAME hash<K,T,H,E>::iterator it)\r
-  {\r
-    // work out what the next iterator is in order to return it later\r
-    TYPENAME hash<K,T,H,E>::iterator next(it);\r
-    ++next;\r
-    // we now need to find where this item is - made difficult by the use of\r
-    // single-linked lists which means I have to search through the bin from\r
-    // the top in order to unlink from the list.\r
-    unsigned hash_value_full = it.node()->m_hash;\r
-    unsigned bin = hash_value_full % m_bins;\r
-    // scan the list for this element\r
-    // need to keep a previous pointer because the lists are single-linked\r
-    hash_element<K,T,H,E>* previous = 0;\r
-    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)\r
-    {\r
-      // direct test on the address of the element\r
-      if (current != it.node()) continue;\r
-      // found this iterator, so unhook the element from the list\r
-      if (previous)\r
-        previous->m_next = current->m_next;\r
-      else\r
-        m_values[bin] = current->m_next;\r
-      // destroy it\r
-      delete current;\r
-      current = 0;\r
-      // remember to maintain the size count\r
-      m_size--;\r
-      break;\r
-    }\r
-    return next;\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  void hash<K,T,H,E>::clear(void)\r
-  {\r
-    erase();\r
-  }\r
-\r
-  // search for a key in the table and return an iterator to it\r
-  // if the search fails, returns an end() iterator\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::find(const K& key) const\r
-  {\r
-    // scan the list for this key's hash value for the element with a matching key\r
-    unsigned hash_value_full = H()(key);\r
-    unsigned bin = hash_value_full % m_bins;\r
-    for (hash_element<K,T,H,E>* current = m_values[bin]; current; current = current->m_next)\r
-    {\r
-      if (current->m_hash == hash_value_full && E()(current->m_value.first, key))\r
-        return hash_iterator<K,T,H,E,const std::pair<const K,T> >(current);\r
-    }\r
-    return end();\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::find(const K& key)\r
-  {\r
-    // scan the list for this key's hash value for the element with a matching key\r
-    unsigned hash_value_full = H()(key);\r
-    unsigned bin = hash_value_full % m_bins;\r
-    for (hash_element<K,T,H,E>* current = m_values[bin]; current; current = current->m_next)\r
-    {\r
-      if (current->m_hash == hash_value_full && E()(current->m_value.first, key))\r
-        return hash_iterator<K,T,H,E,std::pair<const K,T> >(current);\r
-    }\r
-    return end();\r
-  }\r
-\r
-  // table lookup by key using the index operator[], returning a reference to the data field, not an iterator\r
-  // this is rather like the std::map's [] operator\r
-  // the difference is that I have a const and non-const version\r
-  // the const version will not create the element if not present already, but the non-const version will\r
-  // the non-const version is compatible with the behaviour of the map\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  const T& hash<K,T,H,E>::operator[] (const K& key) const throw(std::out_of_range)\r
-  {\r
-    // this const version cannot change the hash, so has to raise an exception if the key is missing\r
-    hash_iterator<K,T,H,E,const std::pair<const K,T> > found = find(key);\r
-    if (found == end())\r
-      throw std::out_of_range("key not found in stlplus::hash::operator[]");\r
-    return found->second;\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  T& hash<K,T,H,E>::operator[] (const K& key)\r
-  {\r
-    // this non-const version can change the hash, so creates a new element if the key is missing\r
-    hash_iterator<K,T,H,E,std::pair<const K,T> > found = find(key);\r
-    if (found == end())\r
-      found = insert(key);\r
-    return found->second;\r
-  }\r
-\r
-  // iterators\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::begin(void) const\r
-  {\r
-    // find the first element\r
-    for (unsigned bin = 0; bin < m_bins; bin++)\r
-      if (m_values[bin])\r
-        return hash_iterator<K,T,H,E,const std::pair<const K,T> >(m_values[bin]);\r
-    // if the hash is empty, return the end iterator\r
-    return end();\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::begin(void)\r
-  {\r
-    // find the first element\r
-    for (unsigned bin = 0; bin < m_bins; bin++)\r
-      if (m_values[bin])\r
-        return hash_iterator<K,T,H,E,std::pair<const K,T> >(m_values[bin]);\r
-    // if the hash is empty, return the end iterator\r
-    return end();\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::end(void) const\r
-  {\r
-    return hash_iterator<K,T,H,E,const std::pair<const K,T> >(this);\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::end(void)\r
-  {\r
-    return hash_iterator<K,T,H,E,std::pair<const K,T> >(this);\r
-  }\r
-\r
-  template<typename K, typename T, class H, class E>\r
-  void hash<K,T,H,E>::debug_report(std::ostream& str) const\r
-  {\r
-    // calculate some stats first\r
-    unsigned occupied = 0;\r
-    unsigned min_in_bin = m_size;\r
-    unsigned max_in_bin = 0;\r
-    for (unsigned i = 0; i < m_bins; i++)\r
-    {\r
-      if (m_values[i]) occupied++;\r
-      unsigned count = 0;\r
-      for (hash_element<K,T,H,E>* item = m_values[i]; item; item = item->m_next) count++;\r
-      if (count > max_in_bin) max_in_bin = count;\r
-      if (count < min_in_bin) min_in_bin = count;\r
-    }\r
-    // now print the table\r
-    str << "------------------------------------------------------------------------" << std::endl;\r
-    str << "| size:     " << m_size << std::endl;\r
-    str << "| bins:     " << m_bins << std::endl;\r
-    str << "| loading:  " << loading() << " ";\r
-    if (m_rehash)\r
-      str << "auto-rehash at " << m_rehash << std::endl;\r
-    else\r
-      str << "manual rehash" << std::endl;\r
-    str << "| occupied: " << occupied \r
-        << std::fixed << " (" << (100.0*(float)occupied/(float)m_bins) << "%)" << std::scientific\r
-        << ", min = " << min_in_bin << ", max = " << max_in_bin << std::endl;\r
-    str << "|-----------------------------------------------------------------------" << std::endl;\r
-    str << "|  bin         0     1     2     3     4     5     6     7     8     9" << std::endl;\r
-    str << "|        ---------------------------------------------------------------";\r
-    for (unsigned j = 0; j < m_bins; j++)\r
-    {\r
-      if (j % 10 == 0)\r
-      {\r
-        str << std::endl;\r
-        str << "| " << std::setw(6) << std::right << (j/10*10) << std::left << " |";\r
-      }\r
-      unsigned count = 0;\r
-      for (hash_element<K,T,H,E>* item = m_values[j]; item; item = item->m_next) count++;\r
-      if (!count)\r
-        str << "     .";\r
-      else\r
-        str << std::setw(6) << std::right << count << std::left;\r
-    }\r
-    str << std::endl;\r
-    str << "------------------------------------------------------------------------" << std::endl;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include <iomanip>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // the element stored in the hash
+
+  template<typename K, typename T, typename H, typename E>
+  class hash_element
+  {
+  public:
+    master_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> > m_master;
+    std::pair<const K, T> m_value;
+    hash_element<K,T,H,E>* m_next;
+    unsigned m_hash;
+
+    hash_element(const hash<K,T,H,E>* owner, const K& key, const T& data, unsigned hash) :
+      m_master(owner,this), m_value(key,data), m_next(0), m_hash(hash)
+      {
+      }
+
+    hash_element(const hash<K,T,H,E>* owner, const std::pair<const K,T>& value, unsigned hash) :
+      m_master(owner,this), m_value(value), m_next(0), m_hash(hash)
+      {
+      }
+
+    ~hash_element(void)
+      {
+        m_next = 0;
+        m_hash = 0;
+      }
+
+    const hash<K,T,H,E>* owner(void) const
+      {
+        return m_master.owner();
+      }
+
+    // generate the bin number from the hash value and the owner's number of bins
+    unsigned bin(void) const
+      {
+        return m_hash % (owner()->m_bins);
+      }
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // iterator
+
+  // null constructor
+  template<typename K, typename T, class H, class E, typename V>
+  hash_iterator<K,T,H,E,V>::hash_iterator(void)
+  {
+  }
+
+  // non-null constructor used from within the hash to construct a valid iterator
+  template<typename K, typename T, class H, class E, typename V>
+  hash_iterator<K,T,H,E,V>::hash_iterator(hash_element<K,T,H,E>* element) :
+    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(element->m_master)
+  {
+  }
+
+  // constructor used to create an end iterator
+  template<typename K, typename T, class H, class E, typename V>
+  hash_iterator<K,T,H,E,V>::hash_iterator(const hash<K,T,H,E>* owner) :
+    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(owner)
+  {
+  }
+
+  template<typename K, typename T, class H, class E, typename V>
+  hash_iterator<K,T,H,E,V>::hash_iterator(const safe_iterator<hash<K,T,H,E>, hash_element<K,T,H,E> >& iterator) :
+    safe_iterator<hash<K,T,H,E>,hash_element<K,T,H,E> >(iterator)
+  {
+  }
+
+  // destructor
+
+  template<typename K, typename T, class H, class E, typename V>
+  hash_iterator<K,T,H,E,V>::~hash_iterator(void)
+  {
+  }
+
+  // mode conversions
+
+  template<typename K, typename T, class H, class E, typename V>
+  TYPENAME hash_iterator<K,T,H,E,V>::const_iterator hash_iterator<K,T,H,E,V>::constify(void) const
+  {
+    return hash_iterator<K,T,H,E,const std::pair<const K,T> >(*this);
+  }
+
+  template<typename K, typename T, class H, class E, typename V>
+  TYPENAME hash_iterator<K,T,H,E,V>::iterator hash_iterator<K,T,H,E,V>::deconstify(void) const
+  {
+    return hash_iterator<K,T,H,E,std::pair<const K,T> >(*this);
+  }
+
+  // increment operator looks for the next element in the table
+  // if there isn't one, then this becomes an end() iterator with m_bin = m_bins
+  template<typename K, typename T, class H, class E, typename V>
+  TYPENAME hash_iterator<K,T,H,E,V>::this_iterator& hash_iterator<K,T,H,E,V>::operator ++ (void)
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    if (this->node()->m_next)
+      set(this->node()->m_next->m_master);
+    else
+    {
+      // failing that, subsequent hash values are tried until either an element is found or there are no more bins
+      // in which case it becomes an end() iterator
+      hash_element<K,T,H,E>* element = 0;
+      unsigned current_bin = this->node()->bin();
+      for(current_bin++; !element && (current_bin < this->owner()->m_bins); current_bin++)
+        element = this->owner()->m_values[current_bin];
+      if (element)
+        set(element->m_master);
+      else
+        this->set_end();
+    }
+    return *this;
+  }
+
+  // post-increment is defined in terms of pre-increment
+  template<typename K, typename T, class H, class E, typename V>
+  TYPENAME hash_iterator<K,T,H,E,V>::this_iterator hash_iterator<K,T,H,E,V>::operator ++ (int)
+    throw(null_dereference,end_dereference)
+  {
+    hash_iterator<K,T,H,E,V> old(*this);
+    ++(*this);
+    return old;
+  }
+
+  // two iterators are equal if they point to the same element
+  // both iterators must be non-null and belong to the same table
+  template<typename K, typename T, class H, class E, typename V>
+  bool hash_iterator<K,T,H,E,V>::operator == (const hash_iterator<K,T,H,E,V>& r) const
+  {
+    return equal(r);
+  }
+
+  template<typename K, typename T, class H, class E, typename V>
+  bool hash_iterator<K,T,H,E,V>::operator != (const hash_iterator<K,T,H,E,V>& r) const
+  {
+    return !operator==(r);
+  }
+
+  template<typename K, typename T, class H, class E, typename V>
+  bool hash_iterator<K,T,H,E,V>::operator < (const hash_iterator<K,T,H,E,V>& r) const
+  {
+    return compare(r) < 0;
+  }
+
+  // iterator dereferencing is only legal on a non-null iterator
+  template<typename K, typename T, class H, class E, typename V>
+  V& hash_iterator<K,T,H,E,V>::operator*(void) const
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    return this->node()->m_value;
+  }
+
+  template<typename K, typename T, class H, class E, typename V>
+  V* hash_iterator<K,T,H,E,V>::operator->(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return &(operator*());
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // hash
+
+  // totally arbitrary initial size used for auto-rehashed tables
+  static unsigned hash_default_bins = 127;
+
+  // constructor
+  // tests whether the user wants auto-rehash
+  // sets the rehash point to be a loading of 1.0 by setting it to the number of bins
+  // uses the user's size unless this is zero, in which case implement the default
+
+  template<typename K, typename T, class H, class E>
+  hash<K,T,H,E>::hash(unsigned bins) :
+    m_rehash(bins), m_bins(bins > 0 ? bins : hash_default_bins), m_size(0), m_values(0)
+  {
+    m_values = new hash_element<K,T,H,E>*[m_bins];
+    for (unsigned i = 0; i < m_bins; i++)
+      m_values[i] = 0;
+  }
+
+  template<typename K, typename T, class H, class E>
+  hash<K,T,H,E>::~hash(void)
+  {
+    // delete all the elements
+    clear();
+    // and delete the data structure
+    delete[] m_values;
+    m_values = 0;
+  }
+
+  // as usual, implement the copy constructor i.t.o. the assignment operator
+
+  template<typename K, typename T, class H, class E>
+  hash<K,T,H,E>::hash(const hash<K,T,H,E>& right) :
+    m_rehash(right.m_rehash), m_bins(right.m_bins), m_size(0), m_values(0)
+  {
+    m_values = new hash_element<K,T,H,E>*[right.m_bins];
+    // copy the rehash behaviour as well as the size
+    for (unsigned i = 0; i < m_bins; i++)
+      m_values[i] = 0;
+    *this = right;
+  }
+
+  // assignment operator
+  // this is done by copying the elements
+  // the source and target hashes can be different sizes
+  // the hash is self-copy safe, i.e. it is legal to say x = x;
+
+  template<typename K, typename T, class H, class E>
+  hash<K,T,H,E>& hash<K,T,H,E>::operator = (const hash<K,T,H,E>& r)
+  {
+    // make self-copy safe
+    if (&r == this) return *this;
+    // remove all the existing elements
+    clear();
+    // copy the elements across - remember that this is rehashing because the two
+    // tables can be different sizes so there is no quick way of doing this by
+    // copying the lists
+    for (hash_iterator<K,T,H,E,const std::pair<const K,T> > i = r.begin(); i != r.end(); ++i)
+      insert(i->first, i->second);
+    return *this;
+  }
+
+  // number of values in the hash
+  template<typename K, typename T, class H, class E>
+  bool hash<K,T,H,E>::empty(void) const
+  {
+    return m_size == 0;
+  }
+
+  template<typename K, typename T, class H, class E>
+  unsigned hash<K,T,H,E>::size(void) const
+  {
+    return m_size;
+  }
+
+  // equality
+  template<typename K, typename T, class H, class E>
+  bool hash<K,T,H,E>::operator == (const hash<K,T,H,E>& right) const
+  {
+    // this table is the same as the right table if they are the same table!
+    if (&right == this) return true;
+    // they must be the same size to be equal
+    if (m_size != right.m_size) return false;
+    // now every key in this must be in right and have the same data
+    for (hash_iterator<K,T,H,E,const std::pair<const K,T> > i = begin(); i != end(); i++)
+    {
+      hash_iterator<K,T,H,E,const std::pair<const K,T> > found = right.find(i->first);
+      if (found == right.end()) return false;
+      if (!(i->second == found->second)) return false;
+    }
+    return true;
+  }
+
+  // set up the hash to auto-rehash at a specific size
+  // setting the rehash size to 0 forces manual rehashing
+  template<typename K, typename T, class H, class E>
+  void hash<K,T,H,E>::auto_rehash(void)
+  {
+    m_rehash = m_bins;
+  }
+
+  template<typename K, typename T, class H, class E>
+  void hash<K,T,H,E>::manual_rehash(void)
+  {
+    m_rehash = 0;
+  }
+
+  // the rehash function
+  // builds a new hash table and moves the elements (without copying) from the old to the new
+  // I store the un-modulused hash value in the element for more efficient rehashing
+  // passing 0 to the bins parameter does auto-rehashing
+  // passing any other value forces the number of bins
+
+  template<typename K, typename T, class H, class E>
+  void hash<K,T,H,E>::rehash(unsigned bins)
+  {
+    // user specified size: just take the user's value
+    // auto calculate: if the load is high, increase the size; else do nothing
+    unsigned new_bins = bins ? bins : m_bins;
+    if (bins == 0 && m_size > 0)
+    {
+      // these numbers are pretty arbitrary
+      // TODO - make them user-customisable?
+      float load = loading();
+      if (load > 2.0)
+        new_bins = (unsigned)(m_bins * load);
+      else if (load > 1.0)
+        new_bins = m_bins * 2;
+    }
+    if (new_bins == m_bins) return;
+    // set the new rehashing point if auto-rehashing is on
+    if (m_rehash) m_rehash = new_bins;
+    // move aside the old structure
+    hash_element<K,T,H,E>** old_values = m_values;
+    unsigned old_bins = m_bins;
+    // create a replacement structure
+    m_values = new hash_element<K,T,H,E>*[new_bins];
+    for (unsigned i = 0; i < new_bins; i++)
+      m_values[i] = 0;
+    m_bins = new_bins;
+    // move all the old elements across, rehashing each one
+    for (unsigned j = 0; j < old_bins; j++)
+    {
+      while(old_values[j])
+      {
+        // unhook from the old structure
+        hash_element<K,T,H,E>* current = old_values[j];
+        old_values[j] = current->m_next;
+        // rehash using the stored hash value
+        unsigned bin = current->bin();
+        // hook it into the new structure
+        current->m_next = m_values[bin];
+        m_values[bin] = current;
+      }
+    }
+    // now delete the old structure
+    delete[] old_values;
+  }
+
+  // the loading is the average number of elements per bin
+  // this simplifies to the total elements divided by the number of bins
+
+  template<typename K, typename T, class H, class E>
+  float hash<K,T,H,E>::loading(void) const
+  {
+    return (float)m_size / (float)m_bins;
+  }
+
+  // remove all elements from the table
+
+  template<typename K, typename T, class H, class E>
+  void hash<K,T,H,E>::erase(void)
+  {
+    // unhook the list elements and destroy them
+    for (unsigned i = 0; i < m_bins; i++)
+    {
+      hash_element<K,T,H,E>* current = m_values[i];
+      while(current)
+      {
+        hash_element<K,T,H,E>* next = current->m_next;
+        delete current;
+        current = next;
+      }
+      m_values[i] = 0;
+    }
+    m_size = 0;
+  }
+
+  // test for whether a key is present in the table
+
+  template<typename K, typename T, class H, class E>
+  bool hash<K,T,H,E>::present(const K& key) const
+  {
+    return find(key) != end();
+  }
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::size_type hash<K,T,H,E>::count(const K& key) const
+  {
+    return present() ? 1 : 0;
+  }
+
+  // add a key and data element to the table - defined in terms of the general-purpose pair insert function
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::insert(const K& key, const T& data)
+  {
+    return insert(std::pair<const K,T>(key,data)).first;
+  }
+
+  // insert a key/data pair into the table
+  // this removes any old value with the same key since there is no multihash functionality
+
+  template<typename K, typename T, class H, class E>
+  std::pair<TYPENAME hash<K,T,H,E>::iterator, bool> hash<K,T,H,E>::insert(const std::pair<const K,T>& value)
+  {
+    // if auto-rehash is enabled, implement the auto-rehash before inserting the new value
+    // the table is rehashed if this insertion makes the loading exceed 1.0
+    if (m_rehash && (m_size >= m_rehash)) rehash();
+    // calculate the new hash value
+    unsigned hash_value_full = H()(value.first);
+    unsigned bin = hash_value_full % m_bins;
+    bool inserted = true;
+    // unhook any previous value with this key
+    // this has been inlined from erase(key) so that the hash value is not calculated twice
+    hash_element<K,T,H,E>* previous = 0;
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)
+    {
+      // first check the full stored hash value
+      if (current->m_hash != hash_value_full) continue;
+
+      // next try the equality operator
+      if (!E()(current->m_value.first, value.first)) continue;
+
+      // unhook this value and destroy it
+      if (previous)
+        previous->m_next = current->m_next;
+      else
+        m_values[bin] = current->m_next;
+      delete current;
+      m_size--;
+
+      // we've overwritten a previous value
+      inserted = false;
+
+      // assume there can only be one match so we can give up now
+      break;
+    }
+    // now hook in a new list element at the start of the list for this hash value
+    hash_element<K,T,H,E>* new_item = new hash_element<K,T,H,E>(this, value, hash_value_full);
+    new_item->m_next = m_values[bin];
+    m_values[bin] = new_item;
+    // increment the size count
+    m_size++;
+    // construct an iterator from the list node, and return whether inserted
+    return std::make_pair(hash_iterator<K,T,H,E,std::pair<const K,T> >(new_item), inserted);
+  }
+
+  // insert a key with an empty data field ready to be filled in later
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::insert(const K& key)
+  {
+    return insert(key,T());
+  }
+
+  // remove a key from the table - return true if the key was found and removed, false if it wasn't present
+
+  template<typename K, typename T, class H, class E>
+  unsigned hash<K,T,H,E>::erase(const K& key)
+  {
+    unsigned hash_value_full = H()(key);
+    unsigned bin = hash_value_full % m_bins;
+    // scan the list for an element with this key
+    // need to keep a previous pointer because the lists are single-linked
+    hash_element<K,T,H,E>* previous = 0;
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)
+    {
+      // first check the full stored hash value
+      if (current->m_hash != hash_value_full) continue;
+
+      // next try the equality operator
+      if (!E()(current->m_value.first, key)) continue;
+
+      // found this key, so unhook the element from the list
+      if (previous)
+        previous->m_next = current->m_next;
+      else
+        m_values[bin] = current->m_next;
+      // destroy it
+      delete current;
+      // remember to maintain the size count
+      m_size--;
+      return 1;
+    }
+    return 0;
+  }
+
+  // remove an element from the hash table using an iterator (std::map equivalent)
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::erase(TYPENAME hash<K,T,H,E>::iterator it)
+  {
+    // work out what the next iterator is in order to return it later
+    TYPENAME hash<K,T,H,E>::iterator next(it);
+    ++next;
+    // we now need to find where this item is - made difficult by the use of
+    // single-linked lists which means I have to search through the bin from
+    // the top in order to unlink from the list.
+    unsigned hash_value_full = it.node()->m_hash;
+    unsigned bin = hash_value_full % m_bins;
+    // scan the list for this element
+    // need to keep a previous pointer because the lists are single-linked
+    hash_element<K,T,H,E>* previous = 0;
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; previous = current, current = current->m_next)
+    {
+      // direct test on the address of the element
+      if (current != it.node()) continue;
+      // found this iterator, so unhook the element from the list
+      if (previous)
+        previous->m_next = current->m_next;
+      else
+        m_values[bin] = current->m_next;
+      // destroy it
+      delete current;
+      current = 0;
+      // remember to maintain the size count
+      m_size--;
+      break;
+    }
+    return next;
+  }
+
+  template<typename K, typename T, class H, class E>
+  void hash<K,T,H,E>::clear(void)
+  {
+    erase();
+  }
+
+  // search for a key in the table and return an iterator to it
+  // if the search fails, returns an end() iterator
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::find(const K& key) const
+  {
+    // scan the list for this key's hash value for the element with a matching key
+    unsigned hash_value_full = H()(key);
+    unsigned bin = hash_value_full % m_bins;
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; current = current->m_next)
+    {
+      if (current->m_hash == hash_value_full && E()(current->m_value.first, key))
+        return hash_iterator<K,T,H,E,const std::pair<const K,T> >(current);
+    }
+    return end();
+  }
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::find(const K& key)
+  {
+    // scan the list for this key's hash value for the element with a matching key
+    unsigned hash_value_full = H()(key);
+    unsigned bin = hash_value_full % m_bins;
+    for (hash_element<K,T,H,E>* current = m_values[bin]; current; current = current->m_next)
+    {
+      if (current->m_hash == hash_value_full && E()(current->m_value.first, key))
+        return hash_iterator<K,T,H,E,std::pair<const K,T> >(current);
+    }
+    return end();
+  }
+
+  // table lookup by key using the index operator[], returning a reference to the data field, not an iterator
+  // this is rather like the std::map's [] operator
+  // the difference is that I have a const and non-const version
+  // the const version will not create the element if not present already, but the non-const version will
+  // the non-const version is compatible with the behaviour of the map
+
+  template<typename K, typename T, class H, class E>
+  const T& hash<K,T,H,E>::operator[] (const K& key) const throw(std::out_of_range)
+  {
+    // this const version cannot change the hash, so has to raise an exception if the key is missing
+    hash_iterator<K,T,H,E,const std::pair<const K,T> > found = find(key);
+    if (found == end())
+      throw std::out_of_range("key not found in stlplus::hash::operator[]");
+    return found->second;
+  }
+
+  template<typename K, typename T, class H, class E>
+  T& hash<K,T,H,E>::operator[] (const K& key)
+  {
+    // this non-const version can change the hash, so creates a new element if the key is missing
+    hash_iterator<K,T,H,E,std::pair<const K,T> > found = find(key);
+    if (found == end())
+      found = insert(key);
+    return found->second;
+  }
+
+  // iterators
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::begin(void) const
+  {
+    // find the first element
+    for (unsigned bin = 0; bin < m_bins; bin++)
+      if (m_values[bin])
+        return hash_iterator<K,T,H,E,const std::pair<const K,T> >(m_values[bin]);
+    // if the hash is empty, return the end iterator
+    return end();
+  }
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::begin(void)
+  {
+    // find the first element
+    for (unsigned bin = 0; bin < m_bins; bin++)
+      if (m_values[bin])
+        return hash_iterator<K,T,H,E,std::pair<const K,T> >(m_values[bin]);
+    // if the hash is empty, return the end iterator
+    return end();
+  }
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::const_iterator hash<K,T,H,E>::end(void) const
+  {
+    return hash_iterator<K,T,H,E,const std::pair<const K,T> >(this);
+  }
+
+  template<typename K, typename T, class H, class E>
+  TYPENAME hash<K,T,H,E>::iterator hash<K,T,H,E>::end(void)
+  {
+    return hash_iterator<K,T,H,E,std::pair<const K,T> >(this);
+  }
+
+  template<typename K, typename T, class H, class E>
+  void hash<K,T,H,E>::debug_report(std::ostream& str) const
+  {
+    // calculate some stats first
+    unsigned occupied = 0;
+    unsigned min_in_bin = m_size;
+    unsigned max_in_bin = 0;
+    for (unsigned i = 0; i < m_bins; i++)
+    {
+      if (m_values[i]) occupied++;
+      unsigned count = 0;
+      for (hash_element<K,T,H,E>* item = m_values[i]; item; item = item->m_next) count++;
+      if (count > max_in_bin) max_in_bin = count;
+      if (count < min_in_bin) min_in_bin = count;
+    }
+    // now print the table
+    str << "------------------------------------------------------------------------" << std::endl;
+    str << "| size:     " << m_size << std::endl;
+    str << "| bins:     " << m_bins << std::endl;
+    str << "| loading:  " << loading() << " ";
+    if (m_rehash)
+      str << "auto-rehash at " << m_rehash << std::endl;
+    else
+      str << "manual rehash" << std::endl;
+    str << "| occupied: " << occupied 
+        << std::fixed << " (" << (100.0*(float)occupied/(float)m_bins) << "%)" << std::scientific
+        << ", min = " << min_in_bin << ", max = " << max_in_bin << std::endl;
+    str << "|-----------------------------------------------------------------------" << std::endl;
+    str << "|  bin         0     1     2     3     4     5     6     7     8     9" << std::endl;
+    str << "|        ---------------------------------------------------------------";
+    for (unsigned j = 0; j < m_bins; j++)
+    {
+      if (j % 10 == 0)
+      {
+        str << std::endl;
+        str << "| " << std::setw(6) << std::right << (j/10*10) << std::left << " |";
+      }
+      unsigned count = 0;
+      for (hash_element<K,T,H,E>* item = m_values[j]; item; item = item->m_next) count++;
+      if (!count)
+        str << "     .";
+      else
+        str << std::setw(6) << std::right << count << std::left;
+    }
+    str << std::endl;
+    str << "------------------------------------------------------------------------" << std::endl;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
index b76a99862a22ba8283f9cb1f8ce63374b5718fb5..9a0fa69c46fe7c36cbb1a753c5fbbf82314777e8 100644 (file)
@@ -1,63 +1,63 @@
-#ifndef STLPLUS_MATRIX\r
-#define STLPLUS_MATRIX\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   General-purpose 2D matrix data structure \r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T> class matrix\r
-  {\r
-  public:\r
-    matrix(unsigned rows = 0, unsigned cols = 0, const T& fill = T()) throw();\r
-    ~matrix(void) throw();\r
-\r
-    matrix(const matrix&) throw();\r
-    matrix& operator =(const matrix&) throw();\r
-\r
-    void resize(unsigned rows, unsigned cols, const T& fill = T()) throw();\r
-\r
-    unsigned rows(void) const throw();\r
-    unsigned columns(void) const throw();\r
-\r
-    void erase(const T& fill = T()) throw();\r
-    void erase(unsigned row, unsigned col, const T& fill = T()) throw(std::out_of_range);\r
-    void insert(unsigned row, unsigned col, const T&) throw(std::out_of_range);\r
-    const T& item(unsigned row, unsigned col) const throw(std::out_of_range);\r
-    T& item(unsigned row, unsigned col) throw(std::out_of_range);\r
-    const T& operator()(unsigned row, unsigned col) const throw(std::out_of_range);\r
-    T& operator()(unsigned row, unsigned col) throw(std::out_of_range);\r
-\r
-    void fill(const T& item = T()) throw();\r
-    void fill_column(unsigned col, const T& item = T()) throw(std::out_of_range);\r
-    void fill_row(unsigned row, const T& item = T()) throw(std::out_of_range);\r
-    void fill_leading_diagonal(const T& item = T()) throw();\r
-    void fill_trailing_diagonal(const T& item = T()) throw();\r
-    void make_identity(const T& one, const T& zero = T()) throw();\r
-\r
-    void transpose(void) throw();\r
-\r
-  private:\r
-    unsigned m_rows;\r
-    unsigned m_cols;\r
-    T** m_data;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "matrix.tpp"\r
-#endif\r
+#ifndef STLPLUS_MATRIX
+#define STLPLUS_MATRIX
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   General-purpose 2D matrix data structure 
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T> class matrix
+  {
+  public:
+    matrix(unsigned rows = 0, unsigned cols = 0, const T& fill = T()) throw();
+    ~matrix(void) throw();
+
+    matrix(const matrix&) throw();
+    matrix& operator =(const matrix&) throw();
+
+    void resize(unsigned rows, unsigned cols, const T& fill = T()) throw();
+
+    unsigned rows(void) const throw();
+    unsigned columns(void) const throw();
+
+    void erase(const T& fill = T()) throw();
+    void erase(unsigned row, unsigned col, const T& fill = T()) throw(std::out_of_range);
+    void insert(unsigned row, unsigned col, const T&) throw(std::out_of_range);
+    const T& item(unsigned row, unsigned col) const throw(std::out_of_range);
+    T& item(unsigned row, unsigned col) throw(std::out_of_range);
+    const T& operator()(unsigned row, unsigned col) const throw(std::out_of_range);
+    T& operator()(unsigned row, unsigned col) throw(std::out_of_range);
+
+    void fill(const T& item = T()) throw();
+    void fill_column(unsigned col, const T& item = T()) throw(std::out_of_range);
+    void fill_row(unsigned row, const T& item = T()) throw(std::out_of_range);
+    void fill_leading_diagonal(const T& item = T()) throw();
+    void fill_trailing_diagonal(const T& item = T()) throw();
+    void make_identity(const T& one, const T& zero = T()) throw();
+
+    void transpose(void) throw();
+
+  private:
+    unsigned m_rows;
+    unsigned m_cols;
+    T** m_data;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "matrix.tpp"
+#endif
index 65ec77975ee6ffb99ff6b3fcd8bd57e2238f7ff5..1e2f785b9fd97c6e93c0ec88aff080f8130d2c89 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  matrix<T>::matrix(unsigned rows, unsigned cols, const T& fill) throw()\r
-  {\r
-    m_rows = 0;\r
-    m_cols = 0;\r
-    m_data = 0;\r
-    resize(rows,cols,fill);\r
-  }\r
-\r
-  template<typename T>\r
-  matrix<T>::~matrix(void) throw()\r
-  {\r
-    for (unsigned row = 0; row < m_rows; row++)\r
-      delete[] m_data[row];\r
-    delete[] m_data;\r
-  }\r
-\r
-  template<typename T>\r
-  matrix<T>::matrix(const matrix<T>& r) throw()\r
-  {\r
-    m_rows = 0;\r
-    m_cols = 0;\r
-    m_data = 0;\r
-    *this = r;\r
-  }\r
-\r
-  template<typename T>\r
-  matrix<T>& matrix<T>::operator =(const matrix<T>& right) throw()\r
-  {\r
-    // clear the old values\r
-    for (unsigned row = 0; row < m_rows; row++)\r
-      delete[] m_data[row];\r
-    delete[] m_data;\r
-    m_rows = 0;\r
-    m_cols = 0;\r
-    m_data = 0;\r
-    // now reconstruct with the new\r
-    resize(right.m_rows, right.m_cols);\r
-    for (unsigned row = 0; row < m_rows; row++)\r
-      for (unsigned col = 0; col < m_cols; col++)\r
-        m_data[row][col] = right.m_data[row][col];\r
-    return *this;\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::resize(unsigned rows, unsigned cols, const T& fill) throw()\r
-  {\r
-    // a grid is an array of rows, where each row is an array of T\r
-    // a zero-row or zero-column matrix has a null grid\r
-    // TODO - make this exception-safe - new could throw here and that would cause a memory leak\r
-    T** new_grid = 0;\r
-    if (rows && cols)\r
-    {\r
-      new_grid = new T*[rows];\r
-      for (unsigned row = 0; row < rows; row++)\r
-      {\r
-        new_grid[row] = new T[cols];\r
-        // copy old items to the new grid but only within the bounds of the intersection of the old and new grids\r
-        // fill the rest of the grid with the initial value\r
-        for (unsigned col = 0; col < cols; col++)\r
-          if (row < m_rows && col < m_cols)\r
-            new_grid[row][col] = m_data[row][col];\r
-          else\r
-            new_grid[row][col] = fill;\r
-      }\r
-    }\r
-    // destroy the old grid\r
-    for (unsigned row = 0; row < m_rows; row++)\r
-      delete[] m_data[row];\r
-    delete[] m_data;\r
-    // move the new data into the matrix\r
-    m_data = new_grid;\r
-    m_rows = rows;\r
-    m_cols = cols;\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned matrix<T>::rows(void) const throw()\r
-  {\r
-    return m_rows;\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned matrix<T>::columns(void) const throw()\r
-  {\r
-    return m_cols;\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::erase(const T& fill) throw()\r
-  {\r
-    for (unsigned row = 0; row < m_rows; row++)\r
-      for (unsigned col = 0; col < m_cols; col++)\r
-        insert(row,col,fill);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::erase(unsigned row, unsigned col, const T& fill) throw(std::out_of_range)\r
-  {\r
-    insert(row,col,fill);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::insert(unsigned row, unsigned col, const T& element) throw(std::out_of_range)\r
-  {\r
-    if (row >= m_rows) throw std::out_of_range("matrix::insert row");\r
-    if (col >= m_cols) throw std::out_of_range("matrix::insert col");\r
-    m_data[row][col] = element;\r
-  }\r
-\r
-  template<typename T>\r
-  const T& matrix<T>::item(unsigned row, unsigned col) const throw(std::out_of_range)\r
-  {\r
-    if (row >= m_rows) throw std::out_of_range("matrix::item row");\r
-    if (col >= m_cols) throw std::out_of_range("matrix::item col");\r
-    return m_data[row][col];\r
-  }\r
-\r
-  template<typename T>\r
-  T& matrix<T>::item(unsigned row, unsigned col) throw(std::out_of_range)\r
-  {\r
-    if (row >= m_rows) throw std::out_of_range("matrix::item row");\r
-    if (col >= m_cols) throw std::out_of_range("matrix::item col");\r
-    return m_data[row][col];\r
-  }\r
-\r
-  template<typename T>\r
-  const T& matrix<T>::operator()(unsigned row, unsigned col) const throw(std::out_of_range)\r
-  {\r
-    if (row >= m_rows) throw std::out_of_range("matrix::operator() row");\r
-    if (col >= m_cols) throw std::out_of_range("matrix::operator() col");\r
-    return m_data[row][col];\r
-  }\r
-\r
-  template<typename T>\r
-  T& matrix<T>::operator()(unsigned row, unsigned col) throw(std::out_of_range)\r
-  {\r
-    if (row >= m_rows) throw std::out_of_range("matrix::operator() row");\r
-    if (col >= m_cols) throw std::out_of_range("matrix::operator() col");\r
-    return m_data[row][col];\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::fill(const T& item) throw()\r
-  {\r
-    erase(item);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::fill_column(unsigned col, const T& item) throw (std::out_of_range)\r
-  {\r
-    if (col >= m_cols) throw std::out_of_range("matrix::fill_column");\r
-    for (unsigned row = 0; row < m_rows; row++)\r
-      insert(row, col, item);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::fill_row(unsigned row, const T& item) throw (std::out_of_range)\r
-  {\r
-    if (row >= m_rows) throw std::out_of_range("matrix::fill_row");\r
-    for (unsigned col = 0; col < m_cols; col++)\r
-      insert(row, col, item);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::fill_leading_diagonal(const T& item) throw()\r
-  {\r
-    for (unsigned i = 0; i < m_cols && i < m_rows; i++)\r
-      insert(i, i, item);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::fill_trailing_diagonal(const T& item) throw()\r
-  {\r
-    for (unsigned i = 0; i < m_cols && i < m_rows; i++)\r
-      insert(i, m_cols-i-1, item);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::make_identity(const T& one, const T& zero) throw()\r
-  {\r
-    fill(zero);\r
-    fill_leading_diagonal(one);\r
-  }\r
-\r
-  template<typename T>\r
-  void matrix<T>::transpose(void) throw()\r
-  {\r
-    // no gain in manipulating this, since building a new matrix is no less efficient\r
-    matrix<T> transposed(columns(), rows());\r
-    for (unsigned row = 0; row < rows(); row++)\r
-      for (unsigned col = 0; col < columns(); col++)\r
-        transposed.insert(col,row,item(row,col));\r
-    // TODO - avoid an extra copy by swapping the member data here\r
-    *this = transposed;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T>
+  matrix<T>::matrix(unsigned rows, unsigned cols, const T& fill) throw()
+  {
+    m_rows = 0;
+    m_cols = 0;
+    m_data = 0;
+    resize(rows,cols,fill);
+  }
+
+  template<typename T>
+  matrix<T>::~matrix(void) throw()
+  {
+    for (unsigned row = 0; row < m_rows; row++)
+      delete[] m_data[row];
+    delete[] m_data;
+  }
+
+  template<typename T>
+  matrix<T>::matrix(const matrix<T>& r) throw()
+  {
+    m_rows = 0;
+    m_cols = 0;
+    m_data = 0;
+    *this = r;
+  }
+
+  template<typename T>
+  matrix<T>& matrix<T>::operator =(const matrix<T>& right) throw()
+  {
+    // clear the old values
+    for (unsigned row = 0; row < m_rows; row++)
+      delete[] m_data[row];
+    delete[] m_data;
+    m_rows = 0;
+    m_cols = 0;
+    m_data = 0;
+    // now reconstruct with the new
+    resize(right.m_rows, right.m_cols);
+    for (unsigned row = 0; row < m_rows; row++)
+      for (unsigned col = 0; col < m_cols; col++)
+        m_data[row][col] = right.m_data[row][col];
+    return *this;
+  }
+
+  template<typename T>
+  void matrix<T>::resize(unsigned rows, unsigned cols, const T& fill) throw()
+  {
+    // a grid is an array of rows, where each row is an array of T
+    // a zero-row or zero-column matrix has a null grid
+    // TODO - make this exception-safe - new could throw here and that would cause a memory leak
+    T** new_grid = 0;
+    if (rows && cols)
+    {
+      new_grid = new T*[rows];
+      for (unsigned row = 0; row < rows; row++)
+      {
+        new_grid[row] = new T[cols];
+        // copy old items to the new grid but only within the bounds of the intersection of the old and new grids
+        // fill the rest of the grid with the initial value
+        for (unsigned col = 0; col < cols; col++)
+          if (row < m_rows && col < m_cols)
+            new_grid[row][col] = m_data[row][col];
+          else
+            new_grid[row][col] = fill;
+      }
+    }
+    // destroy the old grid
+    for (unsigned row = 0; row < m_rows; row++)
+      delete[] m_data[row];
+    delete[] m_data;
+    // move the new data into the matrix
+    m_data = new_grid;
+    m_rows = rows;
+    m_cols = cols;
+  }
+
+  template<typename T>
+  unsigned matrix<T>::rows(void) const throw()
+  {
+    return m_rows;
+  }
+
+  template<typename T>
+  unsigned matrix<T>::columns(void) const throw()
+  {
+    return m_cols;
+  }
+
+  template<typename T>
+  void matrix<T>::erase(const T& fill) throw()
+  {
+    for (unsigned row = 0; row < m_rows; row++)
+      for (unsigned col = 0; col < m_cols; col++)
+        insert(row,col,fill);
+  }
+
+  template<typename T>
+  void matrix<T>::erase(unsigned row, unsigned col, const T& fill) throw(std::out_of_range)
+  {
+    insert(row,col,fill);
+  }
+
+  template<typename T>
+  void matrix<T>::insert(unsigned row, unsigned col, const T& element) throw(std::out_of_range)
+  {
+    if (row >= m_rows) throw std::out_of_range("matrix::insert row");
+    if (col >= m_cols) throw std::out_of_range("matrix::insert col");
+    m_data[row][col] = element;
+  }
+
+  template<typename T>
+  const T& matrix<T>::item(unsigned row, unsigned col) const throw(std::out_of_range)
+  {
+    if (row >= m_rows) throw std::out_of_range("matrix::item row");
+    if (col >= m_cols) throw std::out_of_range("matrix::item col");
+    return m_data[row][col];
+  }
+
+  template<typename T>
+  T& matrix<T>::item(unsigned row, unsigned col) throw(std::out_of_range)
+  {
+    if (row >= m_rows) throw std::out_of_range("matrix::item row");
+    if (col >= m_cols) throw std::out_of_range("matrix::item col");
+    return m_data[row][col];
+  }
+
+  template<typename T>
+  const T& matrix<T>::operator()(unsigned row, unsigned col) const throw(std::out_of_range)
+  {
+    if (row >= m_rows) throw std::out_of_range("matrix::operator() row");
+    if (col >= m_cols) throw std::out_of_range("matrix::operator() col");
+    return m_data[row][col];
+  }
+
+  template<typename T>
+  T& matrix<T>::operator()(unsigned row, unsigned col) throw(std::out_of_range)
+  {
+    if (row >= m_rows) throw std::out_of_range("matrix::operator() row");
+    if (col >= m_cols) throw std::out_of_range("matrix::operator() col");
+    return m_data[row][col];
+  }
+
+  template<typename T>
+  void matrix<T>::fill(const T& item) throw()
+  {
+    erase(item);
+  }
+
+  template<typename T>
+  void matrix<T>::fill_column(unsigned col, const T& item) throw (std::out_of_range)
+  {
+    if (col >= m_cols) throw std::out_of_range("matrix::fill_column");
+    for (unsigned row = 0; row < m_rows; row++)
+      insert(row, col, item);
+  }
+
+  template<typename T>
+  void matrix<T>::fill_row(unsigned row, const T& item) throw (std::out_of_range)
+  {
+    if (row >= m_rows) throw std::out_of_range("matrix::fill_row");
+    for (unsigned col = 0; col < m_cols; col++)
+      insert(row, col, item);
+  }
+
+  template<typename T>
+  void matrix<T>::fill_leading_diagonal(const T& item) throw()
+  {
+    for (unsigned i = 0; i < m_cols && i < m_rows; i++)
+      insert(i, i, item);
+  }
+
+  template<typename T>
+  void matrix<T>::fill_trailing_diagonal(const T& item) throw()
+  {
+    for (unsigned i = 0; i < m_cols && i < m_rows; i++)
+      insert(i, m_cols-i-1, item);
+  }
+
+  template<typename T>
+  void matrix<T>::make_identity(const T& one, const T& zero) throw()
+  {
+    fill(zero);
+    fill_leading_diagonal(one);
+  }
+
+  template<typename T>
+  void matrix<T>::transpose(void) throw()
+  {
+    // no gain in manipulating this, since building a new matrix is no less efficient
+    matrix<T> transposed(columns(), rows());
+    for (unsigned row = 0; row < rows(); row++)
+      for (unsigned col = 0; col < columns(); col++)
+        transposed.insert(col,row,item(row,col));
+    // TODO - avoid an extra copy by swapping the member data here
+    *this = transposed;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
index 33817e2b54a816d1f77c4edfcc93f08655fc4d69..1dd41c06ec18e93f272b3767db9ad80eb2458d22 100644 (file)
-#ifndef STLPLUS_NTREE\r
-#define STLPLUS_NTREE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A templated n-ary tree data structure. STL-like but the definition of\r
-//   iterators is really only applicable to one-dimensional structures. I use\r
-//   iterators to access tree nodes, but there is no increment or decrement\r
-//   operators for them. I also define prefix and postfix traversal iterators\r
-//   which do have increment.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include "exceptions.hpp"\r
-#include "safe_iterator.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Internals\r
-\r
-  template<typename T> class ntree_node;\r
-  template<typename T> class ntree;\r
-  template<typename T, typename TRef, typename TPtr> class ntree_iterator;\r
-  template<typename T, typename TRef, typename TPtr> class ntree_prefix_iterator;\r
-  template<typename T, typename TRef, typename TPtr> class ntree_postfix_iterator;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Iterators\r
-\r
-  // Simple iterators which are just used as pointers to tree nodes. These have\r
-  // no increment or decrement operations defined. An uninitialised iterator is\r
-  // null - similarly, if you ask for the root of an empty tree or the parent of\r
-  // the root node then you get a null iterator.\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  class ntree_iterator : public safe_iterator<ntree<T>,ntree_node<T> >\r
-  {\r
-  public:\r
-    // local type definitions\r
-    // an iterator points to an object whilst a const_iterator points to a const object\r
-    typedef ntree_iterator<T,T&,T*> iterator;\r
-    typedef ntree_iterator<T,const T&,const T*> const_iterator;\r
-    typedef ntree_iterator<T,TRef,TPtr> this_iterator;\r
-    typedef TRef reference;\r
-    typedef TPtr pointer;\r
-\r
-    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
-    ntree_iterator(void);\r
-    ~ntree_iterator(void);\r
-\r
-    // Type conversion methods allow const_iterator and iterator to be converted\r
-    const_iterator constify(void) const;\r
-    iterator deconstify(void) const;\r
-\r
-    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed\r
-    bool operator == (const this_iterator& r) const;\r
-    bool operator != (const this_iterator& r) const;\r
-    bool operator < (const this_iterator& r) const;\r
-\r
-    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
-    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
-    reference operator*(void) const\r
-      throw(null_dereference,end_dereference);\r
-    pointer operator->(void) const\r
-      throw(null_dereference,end_dereference);\r
-\r
-    friend class ntree<T>;\r
-    friend class ntree_prefix_iterator<T,TRef,TPtr>;\r
-    friend class ntree_postfix_iterator<T,TRef,TPtr>;\r
-\r
-  public:\r
-    // Note: I had to make this public to get round a compiler problem - it should be private\r
-    // you cannot create a valid iterator except by calling an ntree method that returns one\r
-    // constructor used by ntree to create a non-null iterator\r
-    explicit ntree_iterator(ntree_node<T>* node);\r
-    // constructor used by ntree to create an end iterator\r
-    explicit ntree_iterator(const ntree<T>* owner);\r
-    // used to create an alias of an iterator\r
-    explicit ntree_iterator(const safe_iterator<ntree<T>, ntree_node<T> >& iterator);\r
-  };\r
-\r
-  // Traversal iterators are like iterators but they have increment operators (++)\r
-  // - prefix_iterator visits the nodes of the tree in prefix order\r
-  // - postfix_iterator visits the nodes of the tree in postfix order.\r
-  // There is no such thing as infix order for an n-ary tree and you cannot\r
-  // traverse backwards with these iterators. These follow the STL convention in\r
-  // that you iterate from a begin to an end - in this case ntree exports\r
-  // prefix_begin()/prefix_end() and postfix_begin()/postfix_end(). You can\r
-  // simplify these iterators to the basic iterator above for functions that\r
-  // require a simple iterator.\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  class ntree_prefix_iterator\r
-  {\r
-  public:\r
-    typedef ntree_prefix_iterator<T,T&,T*>             iterator;\r
-    typedef ntree_prefix_iterator<T,const T&,const T*> const_iterator;\r
-    typedef ntree_prefix_iterator<T,TRef,TPtr>         this_iterator;\r
-    typedef ntree_iterator<T,TRef,TPtr>                simple_iterator;\r
-    typedef TRef                                       reference;\r
-    typedef TPtr                                       pointer;\r
-\r
-    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
-    ntree_prefix_iterator(void);\r
-    ~ntree_prefix_iterator(void);\r
-\r
-    // tests\r
-    // a null iterator is one that has not been initialised with a value yet\r
-    // i.e. you just declared it but didn't assign to it\r
-    bool null(void) const;\r
-    // an end iterator is one that points to the end element of the list of nodes\r
-    // in STL conventions this is one past the last valid element and must not be dereferenced\r
-    bool end(void) const;\r
-    // a valid iterator is one that can be dereferenced\r
-    // i.e. non-null and non-end\r
-    bool valid(void) const;\r
-\r
-    // Type conversion methods allow const_iterator and iterator to be converted\r
-    // convert an iterator/const_iterator to a const_iterator\r
-    const_iterator constify(void) const;\r
-    iterator deconstify(void) const;\r
-\r
-    // generate a simple iterator from a traversal iterator\r
-    ntree_iterator<T,TRef,TPtr> simplify(void) const;\r
-\r
-    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed\r
-    bool operator == (const this_iterator& r) const;\r
-    bool operator != (const this_iterator& r) const;\r
-    bool operator < (const this_iterator& r) const;\r
-\r
-    // increment/decrement operators used to step through the set of all nodes in a graph\r
-    // it is only legal to increment a valid iterator\r
-    // pre-increment\r
-    this_iterator& operator ++ (void)\r
-      throw(null_dereference,end_dereference);\r
-    // post-increment\r
-    this_iterator operator ++ (int)\r
-      throw(null_dereference,end_dereference);\r
-\r
-    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
-    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
-    reference operator*(void) const\r
-      throw(null_dereference,end_dereference);\r
-    pointer operator->(void) const\r
-      throw(null_dereference,end_dereference);\r
-\r
-    friend class ntree<T>;\r
-    friend class ntree_iterator<T,TRef,TPtr>;\r
-\r
-  private:\r
-    ntree_iterator<T,TRef,TPtr> m_iterator;\r
-\r
-    explicit ntree_prefix_iterator(const ntree_iterator<T,TRef,TPtr>& i);\r
-    const ntree_iterator<T,TRef,TPtr>& get_iterator(void) const;\r
-    ntree_iterator<T,TRef,TPtr>& get_iterator(void);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  class ntree_postfix_iterator\r
-  {\r
-  public:\r
-    typedef ntree_postfix_iterator<T,T&,T*>             iterator;\r
-    typedef ntree_postfix_iterator<T,const T&,const T*> const_iterator;\r
-    typedef ntree_postfix_iterator<T,TRef,TPtr>         this_iterator;\r
-    typedef ntree_iterator<T,TRef,TPtr>                 simple_iterator;\r
-    typedef TRef                                        reference;\r
-    typedef TPtr                                        pointer;\r
-\r
-    // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
-    ntree_postfix_iterator(void);\r
-    ~ntree_postfix_iterator(void);\r
-\r
-    // tests\r
-    // a null iterator is one that has not been initialised with a value yet\r
-    // i.e. you just declared it but didn't assign to it\r
-    bool null(void) const;\r
-    // an end iterator is one that points to the end element of the list of nodes\r
-    // in STL conventions this is one past the last valid element and must not be dereferenced\r
-    bool end(void) const;\r
-    // a valid iterator is one that can be dereferenced\r
-    // i.e. non-null and non-end\r
-    bool valid(void) const;\r
-\r
-    // Type conversion methods allow const_iterator and iterator to be converted\r
-    // convert an iterator/const_iterator to a const_iterator\r
-    const_iterator constify(void) const;\r
-    iterator deconstify(void) const;\r
-\r
-    // generate a simple iterator from a traversal iterator\r
-    ntree_iterator<T,TRef,TPtr> simplify(void) const;\r
-\r
-    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed\r
-    bool operator == (const this_iterator& r) const;\r
-    bool operator != (const this_iterator& r) const;\r
-    bool operator < (const this_iterator& r) const;\r
-\r
-    // increment/decrement operators used to step through the set of all nodes in a graph\r
-    // it is only legal to increment a valid iterator\r
-    // pre-increment\r
-    this_iterator& operator ++ (void)\r
-      throw(null_dereference,end_dereference);\r
-    // post-increment\r
-    this_iterator operator ++ (int)\r
-      throw(null_dereference,end_dereference);\r
-\r
-    // access the node data - a const_iterator gives you a const element, an iterator a non-const element\r
-    // it is illegal to dereference an invalid (i.e. null or end) iterator\r
-    reference operator*(void) const\r
-      throw(null_dereference,end_dereference);\r
-    pointer operator->(void) const\r
-      throw(null_dereference,end_dereference);\r
-\r
-    friend class ntree<T>;\r
-    friend class ntree_iterator<T,TRef,TPtr>;\r
-\r
-  private:\r
-    ntree_iterator<T,TRef,TPtr> m_iterator;\r
-\r
-    explicit ntree_postfix_iterator(const ntree_iterator<T,TRef,TPtr>& i);\r
-    const ntree_iterator<T,TRef,TPtr>& get_iterator(void) const;\r
-    ntree_iterator<T,TRef,TPtr>& get_iterator(void);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // The Ntree class\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  class ntree\r
-  {\r
-  public:\r
-    // STL-like typedefs for the types and iterators\r
-    typedef T value_type;\r
-\r
-    typedef ntree_iterator<T,T&,T*> iterator;\r
-    typedef ntree_iterator<T,const T&,const T*> const_iterator;\r
-\r
-    typedef ntree_prefix_iterator<T,T&,T*> prefix_iterator;\r
-    typedef ntree_prefix_iterator<T,const T&,const T*> const_prefix_iterator;\r
-\r
-    typedef ntree_postfix_iterator<T,T&,T*> postfix_iterator;\r
-    typedef ntree_postfix_iterator<T,const T&,const T*> const_postfix_iterator;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // Constructors, destructors and copies\r
-\r
-    ntree(void);\r
-    ~ntree(void);\r
-\r
-    // copy constructor and assignment both copy the tree\r
-    ntree(const ntree<T>&);\r
-    ntree<T>& operator=(const ntree<T>&);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // size tests\r
-\r
-    // tests on whole tree\r
-    bool empty(void) const;\r
-    unsigned size(void) const;\r
-\r
-    // tests for number of nodes in subtree starting at node\r
-    unsigned size(const const_iterator& node) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    unsigned size(const iterator& node)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    // test for depth of tree from root to node\r
-    unsigned depth(const const_iterator& node) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    unsigned depth(const iterator& node)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // direct traversal\r
-\r
-    const_iterator root(void) const;\r
-    iterator root(void);\r
-\r
-    unsigned children(const const_iterator& node) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    unsigned children(const iterator& node)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    const_iterator child(const const_iterator& node, unsigned child) const\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-    iterator child(const iterator& node, unsigned child)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-\r
-    const_iterator parent(const const_iterator& node) const\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    iterator parent(const iterator& node)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // iterator traversal\r
-\r
-    const_prefix_iterator prefix_begin(void) const;\r
-    prefix_iterator prefix_begin(void);\r
-    const_prefix_iterator prefix_end(void) const;\r
-    prefix_iterator prefix_end(void);\r
-\r
-    const_postfix_iterator postfix_begin(void) const;\r
-    postfix_iterator postfix_begin(void);\r
-    const_postfix_iterator postfix_end(void) const;\r
-    postfix_iterator postfix_end(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // modification\r
-\r
-    iterator insert(const T&);\r
-\r
-    iterator insert(const iterator& node, unsigned child, const T&)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-    iterator append(const iterator& node, const T&) \r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    iterator insert(const iterator& node, unsigned child, const ntree<T>&)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-    iterator append(const iterator& node, const ntree<T>&)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    iterator push(const iterator& node, const T&) \r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    void pop(const iterator& node, unsigned child) \r
-      throw(wrong_object,null_dereference,end_dereference);\r
-\r
-    void erase(void);\r
-    void erase(const iterator& node)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    void erase(const iterator& node, unsigned child)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-\r
-    ntree<T> subtree(void);\r
-    ntree<T> subtree(const iterator& node)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    ntree<T> subtree(const iterator& node, unsigned child)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-\r
-    ntree<T> cut(void);\r
-    ntree<T> cut(const iterator& node)\r
-      throw(wrong_object,null_dereference,end_dereference);\r
-    ntree<T> cut(const iterator& node, unsigned child)\r
-      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-\r
-  private:\r
-    ntree_node<T>* m_root;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "ntree.tpp"\r
-#endif\r
+#ifndef STLPLUS_NTREE
+#define STLPLUS_NTREE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A templated n-ary tree data structure. STL-like but the definition of
+//   iterators is really only applicable to one-dimensional structures. I use
+//   iterators to access tree nodes, but there is no increment or decrement
+//   operators for them. I also define prefix and postfix traversal iterators
+//   which do have increment.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include "exceptions.hpp"
+#include "safe_iterator.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Internals
+
+  template<typename T> class ntree_node;
+  template<typename T> class ntree;
+  template<typename T, typename TRef, typename TPtr> class ntree_iterator;
+  template<typename T, typename TRef, typename TPtr> class ntree_prefix_iterator;
+  template<typename T, typename TRef, typename TPtr> class ntree_postfix_iterator;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Iterators
+
+  // Simple iterators which are just used as pointers to tree nodes. These have
+  // no increment or decrement operations defined. An uninitialised iterator is
+  // null - similarly, if you ask for the root of an empty tree or the parent of
+  // the root node then you get a null iterator.
+
+  template<typename T, typename TRef, typename TPtr>
+  class ntree_iterator : public safe_iterator<ntree<T>,ntree_node<T> >
+  {
+  public:
+    // local type definitions
+    // an iterator points to an object whilst a const_iterator points to a const object
+    typedef ntree_iterator<T,T&,T*> iterator;
+    typedef ntree_iterator<T,const T&,const T*> const_iterator;
+    typedef ntree_iterator<T,TRef,TPtr> this_iterator;
+    typedef TRef reference;
+    typedef TPtr pointer;
+
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
+    ntree_iterator(void);
+    ~ntree_iterator(void);
+
+    // Type conversion methods allow const_iterator and iterator to be converted
+    const_iterator constify(void) const;
+    iterator deconstify(void) const;
+
+    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed
+    bool operator == (const this_iterator& r) const;
+    bool operator != (const this_iterator& r) const;
+    bool operator < (const this_iterator& r) const;
+
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element
+    // it is illegal to dereference an invalid (i.e. null or end) iterator
+    reference operator*(void) const
+      throw(null_dereference,end_dereference);
+    pointer operator->(void) const
+      throw(null_dereference,end_dereference);
+
+    friend class ntree<T>;
+    friend class ntree_prefix_iterator<T,TRef,TPtr>;
+    friend class ntree_postfix_iterator<T,TRef,TPtr>;
+
+  public:
+    // Note: I had to make this public to get round a compiler problem - it should be private
+    // you cannot create a valid iterator except by calling an ntree method that returns one
+    // constructor used by ntree to create a non-null iterator
+    explicit ntree_iterator(ntree_node<T>* node);
+    // constructor used by ntree to create an end iterator
+    explicit ntree_iterator(const ntree<T>* owner);
+    // used to create an alias of an iterator
+    explicit ntree_iterator(const safe_iterator<ntree<T>, ntree_node<T> >& iterator);
+  };
+
+  // Traversal iterators are like iterators but they have increment operators (++)
+  // - prefix_iterator visits the nodes of the tree in prefix order
+  // - postfix_iterator visits the nodes of the tree in postfix order.
+  // There is no such thing as infix order for an n-ary tree and you cannot
+  // traverse backwards with these iterators. These follow the STL convention in
+  // that you iterate from a begin to an end - in this case ntree exports
+  // prefix_begin()/prefix_end() and postfix_begin()/postfix_end(). You can
+  // simplify these iterators to the basic iterator above for functions that
+  // require a simple iterator.
+
+  template<typename T, typename TRef, typename TPtr>
+  class ntree_prefix_iterator
+  {
+  public:
+    typedef ntree_prefix_iterator<T,T&,T*>             iterator;
+    typedef ntree_prefix_iterator<T,const T&,const T*> const_iterator;
+    typedef ntree_prefix_iterator<T,TRef,TPtr>         this_iterator;
+    typedef ntree_iterator<T,TRef,TPtr>                simple_iterator;
+    typedef TRef                                       reference;
+    typedef TPtr                                       pointer;
+
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
+    ntree_prefix_iterator(void);
+    ~ntree_prefix_iterator(void);
+
+    // tests
+    // a null iterator is one that has not been initialised with a value yet
+    // i.e. you just declared it but didn't assign to it
+    bool null(void) const;
+    // an end iterator is one that points to the end element of the list of nodes
+    // in STL conventions this is one past the last valid element and must not be dereferenced
+    bool end(void) const;
+    // a valid iterator is one that can be dereferenced
+    // i.e. non-null and non-end
+    bool valid(void) const;
+
+    // Type conversion methods allow const_iterator and iterator to be converted
+    // convert an iterator/const_iterator to a const_iterator
+    const_iterator constify(void) const;
+    iterator deconstify(void) const;
+
+    // generate a simple iterator from a traversal iterator
+    ntree_iterator<T,TRef,TPtr> simplify(void) const;
+
+    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed
+    bool operator == (const this_iterator& r) const;
+    bool operator != (const this_iterator& r) const;
+    bool operator < (const this_iterator& r) const;
+
+    // increment/decrement operators used to step through the set of all nodes in a graph
+    // it is only legal to increment a valid iterator
+    // pre-increment
+    this_iterator& operator ++ (void)
+      throw(null_dereference,end_dereference);
+    // post-increment
+    this_iterator operator ++ (int)
+      throw(null_dereference,end_dereference);
+
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element
+    // it is illegal to dereference an invalid (i.e. null or end) iterator
+    reference operator*(void) const
+      throw(null_dereference,end_dereference);
+    pointer operator->(void) const
+      throw(null_dereference,end_dereference);
+
+    friend class ntree<T>;
+    friend class ntree_iterator<T,TRef,TPtr>;
+
+  private:
+    ntree_iterator<T,TRef,TPtr> m_iterator;
+
+    explicit ntree_prefix_iterator(const ntree_iterator<T,TRef,TPtr>& i);
+    const ntree_iterator<T,TRef,TPtr>& get_iterator(void) const;
+    ntree_iterator<T,TRef,TPtr>& get_iterator(void);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T, typename TRef, typename TPtr>
+  class ntree_postfix_iterator
+  {
+  public:
+    typedef ntree_postfix_iterator<T,T&,T*>             iterator;
+    typedef ntree_postfix_iterator<T,const T&,const T*> const_iterator;
+    typedef ntree_postfix_iterator<T,TRef,TPtr>         this_iterator;
+    typedef ntree_iterator<T,TRef,TPtr>                 simple_iterator;
+    typedef TRef                                        reference;
+    typedef TPtr                                        pointer;
+
+    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
+    ntree_postfix_iterator(void);
+    ~ntree_postfix_iterator(void);
+
+    // tests
+    // a null iterator is one that has not been initialised with a value yet
+    // i.e. you just declared it but didn't assign to it
+    bool null(void) const;
+    // an end iterator is one that points to the end element of the list of nodes
+    // in STL conventions this is one past the last valid element and must not be dereferenced
+    bool end(void) const;
+    // a valid iterator is one that can be dereferenced
+    // i.e. non-null and non-end
+    bool valid(void) const;
+
+    // Type conversion methods allow const_iterator and iterator to be converted
+    // convert an iterator/const_iterator to a const_iterator
+    const_iterator constify(void) const;
+    iterator deconstify(void) const;
+
+    // generate a simple iterator from a traversal iterator
+    ntree_iterator<T,TRef,TPtr> simplify(void) const;
+
+    // tests useful for putting iterators into other STL structures and for testing whether iteration has completed
+    bool operator == (const this_iterator& r) const;
+    bool operator != (const this_iterator& r) const;
+    bool operator < (const this_iterator& r) const;
+
+    // increment/decrement operators used to step through the set of all nodes in a graph
+    // it is only legal to increment a valid iterator
+    // pre-increment
+    this_iterator& operator ++ (void)
+      throw(null_dereference,end_dereference);
+    // post-increment
+    this_iterator operator ++ (int)
+      throw(null_dereference,end_dereference);
+
+    // access the node data - a const_iterator gives you a const element, an iterator a non-const element
+    // it is illegal to dereference an invalid (i.e. null or end) iterator
+    reference operator*(void) const
+      throw(null_dereference,end_dereference);
+    pointer operator->(void) const
+      throw(null_dereference,end_dereference);
+
+    friend class ntree<T>;
+    friend class ntree_iterator<T,TRef,TPtr>;
+
+  private:
+    ntree_iterator<T,TRef,TPtr> m_iterator;
+
+    explicit ntree_postfix_iterator(const ntree_iterator<T,TRef,TPtr>& i);
+    const ntree_iterator<T,TRef,TPtr>& get_iterator(void) const;
+    ntree_iterator<T,TRef,TPtr>& get_iterator(void);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // The Ntree class
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T>
+  class ntree
+  {
+  public:
+    // STL-like typedefs for the types and iterators
+    typedef T value_type;
+
+    typedef ntree_iterator<T,T&,T*> iterator;
+    typedef ntree_iterator<T,const T&,const T*> const_iterator;
+
+    typedef ntree_prefix_iterator<T,T&,T*> prefix_iterator;
+    typedef ntree_prefix_iterator<T,const T&,const T*> const_prefix_iterator;
+
+    typedef ntree_postfix_iterator<T,T&,T*> postfix_iterator;
+    typedef ntree_postfix_iterator<T,const T&,const T*> const_postfix_iterator;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // Constructors, destructors and copies
+
+    ntree(void);
+    ~ntree(void);
+
+    // copy constructor and assignment both copy the tree
+    ntree(const ntree<T>&);
+    ntree<T>& operator=(const ntree<T>&);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // size tests
+
+    // tests on whole tree
+    bool empty(void) const;
+    unsigned size(void) const;
+
+    // tests for number of nodes in subtree starting at node
+    unsigned size(const const_iterator& node) const
+      throw(wrong_object,null_dereference,end_dereference);
+    unsigned size(const iterator& node)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    // test for depth of tree from root to node
+    unsigned depth(const const_iterator& node) const
+      throw(wrong_object,null_dereference,end_dereference);
+    unsigned depth(const iterator& node)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // direct traversal
+
+    const_iterator root(void) const;
+    iterator root(void);
+
+    unsigned children(const const_iterator& node) const
+      throw(wrong_object,null_dereference,end_dereference);
+    unsigned children(const iterator& node)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    const_iterator child(const const_iterator& node, unsigned child) const
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+    iterator child(const iterator& node, unsigned child)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+
+    const_iterator parent(const const_iterator& node) const
+      throw(wrong_object,null_dereference,end_dereference);
+    iterator parent(const iterator& node)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // iterator traversal
+
+    const_prefix_iterator prefix_begin(void) const;
+    prefix_iterator prefix_begin(void);
+    const_prefix_iterator prefix_end(void) const;
+    prefix_iterator prefix_end(void);
+
+    const_postfix_iterator postfix_begin(void) const;
+    postfix_iterator postfix_begin(void);
+    const_postfix_iterator postfix_end(void) const;
+    postfix_iterator postfix_end(void);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // modification
+
+    iterator insert(const T&);
+
+    iterator insert(const iterator& node, unsigned child, const T&)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+    iterator append(const iterator& node, const T&) 
+      throw(wrong_object,null_dereference,end_dereference);
+
+    iterator insert(const iterator& node, unsigned child, const ntree<T>&)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+    iterator append(const iterator& node, const ntree<T>&)
+      throw(wrong_object,null_dereference,end_dereference);
+
+    iterator push(const iterator& node, const T&) 
+      throw(wrong_object,null_dereference,end_dereference);
+    void pop(const iterator& node, unsigned child) 
+      throw(wrong_object,null_dereference,end_dereference);
+
+    void erase(void);
+    void erase(const iterator& node)
+      throw(wrong_object,null_dereference,end_dereference);
+    void erase(const iterator& node, unsigned child)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+
+    ntree<T> subtree(void);
+    ntree<T> subtree(const iterator& node)
+      throw(wrong_object,null_dereference,end_dereference);
+    ntree<T> subtree(const iterator& node, unsigned child)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+
+    ntree<T> cut(void);
+    ntree<T> cut(const iterator& node)
+      throw(wrong_object,null_dereference,end_dereference);
+    ntree<T> cut(const iterator& node, unsigned child)
+      throw(wrong_object,null_dereference,end_dereference,std::out_of_range);
+
+    //////////////////////////////////////////////////////////////////////////////
+
+  private:
+    ntree_node<T>* m_root;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "ntree.tpp"
+#endif
index 6fd019d9f30b7eee6fe71ebd682e9667172060c4..1467aa8c72331ef4ffbda13a357ad7dc71b6ef9f 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include <vector>\r
-#include <algorithm>\r
-\r
-namespace stlplus \r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // ntree_node\r
-\r
-  template<typename T>\r
-  class ntree_node\r
-  {\r
-  public:\r
-    master_iterator<ntree<T>, ntree_node<T> > m_master;\r
-    T m_data;\r
-    ntree_node<T>* m_parent;\r
-    std::vector<ntree_node<T>*> m_children;\r
-\r
-  public:\r
-    ntree_node(const ntree<T>* owner, const T& data = T()) :\r
-      m_master(owner,this), m_data(data), m_parent(0)\r
-      {\r
-      }\r
-\r
-    void change_owner(const ntree<T>* owner)\r
-      {\r
-        m_master.change_owner(owner);\r
-        for (TYPENAME std::vector<ntree_node<T>*>::iterator i = m_children.begin(); i != m_children.end(); i++)\r
-          (*i)->change_owner(owner);\r
-      }\r
-\r
-    ~ntree_node(void)\r
-      {\r
-        m_parent = 0;\r
-        for (TYPENAME std::vector<ntree_node<T>*>::iterator i = m_children.begin(); i != m_children.end(); i++)\r
-          delete *i;\r
-      }\r
-\r
-  };\r
-\r
-  template<typename T>\r
-  static ntree_node<T>* ntree_copy(const ntree<T>* new_owner, ntree_node<T>* root)\r
-  {\r
-    if (!root) return 0;\r
-    ntree_node<T>* new_tree = new ntree_node<T>(new_owner, root->m_data);\r
-    for (TYPENAME std::vector<ntree_node<T>*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++)\r
-    {\r
-      ntree_node<T>* new_child = ntree_copy(new_owner, *i);\r
-      new_tree->m_children.push_back(new_child);\r
-      new_child->m_parent = new_tree;\r
-    }\r
-    return new_tree;\r
-  }\r
-\r
-  template<typename T>\r
-  static unsigned ntree_size(ntree_node<T>* root)\r
-  {\r
-    if (!root) return 0;\r
-    unsigned result = 1;\r
-    for (TYPENAME std::vector<ntree_node<T>*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++)\r
-      result += ntree_size(*i);\r
-    return result;\r
-  }\r
-\r
-  template<typename T>\r
-  static unsigned ntree_depth(ntree_node<T>* root)\r
-  {\r
-    unsigned depth = 0;\r
-    for (ntree_node<T>* i = root; i; i = i->m_parent)\r
-      depth++;\r
-    return depth;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // ntree_iterator\r
-\r
-  // constructor to create a null iterator - you must assign a valid value to this iterator before using it\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr>::ntree_iterator(void)\r
-  {\r
-  }\r
-\r
-  // used to create an alias of an iterator\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr>::ntree_iterator(const safe_iterator<ntree<T>, ntree_node<T> >& iterator) :\r
-    safe_iterator<ntree<T>,ntree_node<T> >(iterator)\r
-  {\r
-  }\r
-\r
-  // constructor used by ntree to create a non-null iterator\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr>::ntree_iterator(ntree_node<T>* node) :\r
-    safe_iterator<ntree<T>,ntree_node<T> >(node->m_master)\r
-  {\r
-  }\r
-\r
-  // constructor used by ntree to create an end iterator\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr>::ntree_iterator(const ntree<T>* owner) :\r
-    safe_iterator<ntree<T>,ntree_node<T> >(owner)\r
-  {\r
-  }\r
-\r
-  // destructor\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr>::~ntree_iterator(void)\r
-  {\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_iterator<T,TRef,TPtr>::const_iterator ntree_iterator<T,TRef,TPtr>::constify(void) const\r
-  {\r
-    return ntree_iterator<T,const T&,const T*>(*this);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_iterator<T,TRef,TPtr>::iterator ntree_iterator<T,TRef,TPtr>::deconstify(void) const\r
-  {\r
-    return ntree_iterator<T,T&,T*>(*this);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return equal(r);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return !operator==(r);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return compare(r) < 0;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_iterator<T,TRef,TPtr>::reference ntree_iterator<T,TRef,TPtr>::operator*(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    this->assert_valid();\r
-    return this->node()->m_data;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_iterator<T,TRef,TPtr>::pointer ntree_iterator<T,TRef,TPtr>::operator->(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return &(operator*());\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // ntree_prefix_iterator\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_prefix_iterator<T,TRef,TPtr>::ntree_prefix_iterator(void)\r
-  {\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_prefix_iterator<T,TRef,TPtr>::~ntree_prefix_iterator(void)\r
-  {\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_prefix_iterator<T,TRef,TPtr>::ntree_prefix_iterator(const ntree_iterator<T,TRef,TPtr>& i) :\r
-    m_iterator(i)\r
-  {\r
-    // this is initialised with the root node\r
-    // which is also the first node in prefix traversal order\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_prefix_iterator<T,TRef,TPtr>::null(void) const\r
-  {\r
-    return m_iterator.null();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_prefix_iterator<T,TRef,TPtr>::end(void) const\r
-  {\r
-    return m_iterator.end();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_prefix_iterator<T,TRef,TPtr>::valid(void) const\r
-  {\r
-    return m_iterator.valid();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::const_iterator ntree_prefix_iterator<T,TRef,TPtr>::constify(void) const\r
-  {\r
-    return ntree_prefix_iterator<T,const T&,const T*>(m_iterator);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::iterator ntree_prefix_iterator<T,TRef,TPtr>::deconstify(void) const\r
-  {\r
-    return ntree_prefix_iterator<T,T&,T*>(m_iterator);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr> ntree_prefix_iterator<T,TRef,TPtr>::simplify(void) const\r
-  {\r
-    return m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_prefix_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return m_iterator == r.m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_prefix_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return m_iterator != r.m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_prefix_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return m_iterator < r.m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& ntree_prefix_iterator<T,TRef,TPtr>::operator ++ (void)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // pre-increment operator\r
-    // algorithm: if there are any children, visit child 0, otherwise, go to\r
-    // parent and deduce which child the start node was of that parent - if\r
-    // there are further children, go into the next one. Otherwise, go up the\r
-    // tree and test again for further children. Return null if there are no\r
-    // further nodes\r
-    m_iterator.assert_valid();\r
-    ntree_node<T>* old_node = m_iterator.node();\r
-    if (!old_node->m_children.empty())\r
-    {\r
-      // simply take the first child of this node\r
-      m_iterator.set(old_node->m_children[0]->m_master);\r
-    }\r
-    else\r
-    {\r
-      // this loop walks up the parent pointers\r
-      // either it will walk off the top and exit or a new node will be found and the loop will exit\r
-      for (;;)\r
-      {\r
-        // go up a level\r
-        ntree_node<T>* parent = old_node->m_parent;\r
-        if (!parent)\r
-        {\r
-          // we've walked off the top of the tree, so return end\r
-          m_iterator.set_end();\r
-          break;\r
-        }\r
-        else\r
-        {\r
-          // otherwise walk down the next child - if there is one\r
-          // find which index the old node was relative to this node\r
-          TYPENAME std::vector<ntree_node<T>*>::iterator found = \r
-            std::find(parent->m_children.begin(), parent->m_children.end(), old_node);\r
-          // if this was found, then see if there is another and if so return that\r
-          found++;\r
-          if (found != parent->m_children.end())\r
-          {\r
-            // visit the next child\r
-            m_iterator.set((*found)->m_master);\r
-            break;\r
-          }\r
-          else\r
-          {\r
-            // keep going up\r
-            old_node = parent;\r
-          }\r
-        }\r
-      }\r
-    }\r
-    return *this;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator ntree_prefix_iterator<T,TRef,TPtr>::operator ++ (int)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // post-increment is defined in terms of the pre-increment\r
-    ntree_prefix_iterator<T,TRef,TPtr> result(*this);\r
-    ++(*this);\r
-    return result;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::reference ntree_prefix_iterator<T,TRef,TPtr>::operator*(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return m_iterator.operator*();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::pointer ntree_prefix_iterator<T,TRef,TPtr>::operator->(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return m_iterator.operator->();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  const ntree_iterator<T,TRef,TPtr>& ntree_prefix_iterator<T,TRef,TPtr>::get_iterator(void) const\r
-  {\r
-    return m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr>& ntree_prefix_iterator<T,TRef,TPtr>::get_iterator(void)\r
-  {\r
-    return m_iterator;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // ntree_postfix_iterator\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_postfix_iterator<T,TRef,TPtr>::ntree_postfix_iterator(void)\r
-  {\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_postfix_iterator<T,TRef,TPtr>::~ntree_postfix_iterator(void)\r
-  {\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_postfix_iterator<T,TRef,TPtr>::ntree_postfix_iterator(const ntree_iterator<T,TRef,TPtr>& i) :\r
-    m_iterator(i)\r
-  {\r
-    // this is initialised with the root node\r
-    // initially traverse to the first node to be visited\r
-    if (m_iterator.valid())\r
-    {\r
-      ntree_node<T>* node = m_iterator.node();\r
-      while (!node->m_children.empty())\r
-        node = node->m_children[0];\r
-      m_iterator.set(node->m_master);\r
-    }\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_postfix_iterator<T,TRef,TPtr>::null(void) const\r
-  {\r
-    return m_iterator.null();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_postfix_iterator<T,TRef,TPtr>::end(void) const\r
-  {\r
-    return m_iterator.end();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_postfix_iterator<T,TRef,TPtr>::valid(void) const\r
-  {\r
-    return m_iterator.valid();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::const_iterator ntree_postfix_iterator<T,TRef,TPtr>::constify(void) const\r
-  {\r
-    return ntree_postfix_iterator<T,const T&,const T*>(m_iterator);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::iterator ntree_postfix_iterator<T,TRef,TPtr>::deconstify(void) const\r
-  {\r
-    return ntree_postfix_iterator<T,T&,T*>(m_iterator);\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr> ntree_postfix_iterator<T,TRef,TPtr>::simplify(void) const\r
-  {\r
-    return m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_postfix_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return m_iterator == r.m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_postfix_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return m_iterator != r.m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  bool ntree_postfix_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const\r
-  {\r
-    return m_iterator < r.m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& ntree_postfix_iterator<T,TRef,TPtr>::operator ++ (void)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // pre-increment operator\r
-    // algorithm: this node has been visited, therefore all children must have\r
-    // already been visited. So go to parent. Return null if the parent is null.\r
-    // Otherwise deduce which child the start node was of that parent - if there\r
-    // are further children, go into the next one and then walk down any\r
-    // subsequent first-child pointers to the bottom. Otherwise, if there are no\r
-    // children then the parent node is the next in the traversal.\r
-    m_iterator.assert_valid();\r
-    // go up a level\r
-    ntree_node<T>* old_node = m_iterator.node();\r
-    ntree_node<T>* parent = old_node->m_parent;\r
-    if (!parent)\r
-    {\r
-      // we've walked off the top of the tree, so return end\r
-      m_iterator.set_end();\r
-    }\r
-    else\r
-    {\r
-      // otherwise find which index the old node was relative to this node\r
-      TYPENAME std::vector<ntree_node<T>*>::iterator found =\r
-        std::find(parent->m_children.begin(), parent->m_children.end(), old_node);\r
-      // if this was found, then see if there is another\r
-      found++;\r
-      if (found != parent->m_children.end())\r
-      {\r
-        // if so traverse to it and walk down the leftmost child pointers to the bottom of the new sub-tree\r
-        ntree_node<T>* new_node = *found;\r
-        while (!new_node->m_children.empty())\r
-          new_node = new_node->m_children[0];\r
-        m_iterator.set(new_node->m_master);\r
-      }\r
-      else\r
-      {\r
-        // the parent's children have all been visited - so the parent is visited\r
-        m_iterator.set(parent->m_master);\r
-      }\r
-    }\r
-    return *this;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator ntree_postfix_iterator<T,TRef,TPtr>::operator ++ (int)\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    // post-increment is defined in terms of the pre-increment\r
-    ntree_postfix_iterator<T,TRef,TPtr> result(*this);\r
-    ++(*this);\r
-    return result;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::reference ntree_postfix_iterator<T,TRef,TPtr>::operator*(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return m_iterator.operator*();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::pointer ntree_postfix_iterator<T,TRef,TPtr>::operator->(void) const\r
-    throw(null_dereference,end_dereference)\r
-  {\r
-    return m_iterator.operator->();\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  const ntree_iterator<T,TRef,TPtr>& ntree_postfix_iterator<T,TRef,TPtr>::get_iterator(void) const\r
-  {\r
-    return m_iterator;\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  ntree_iterator<T,TRef,TPtr>& ntree_postfix_iterator<T,TRef,TPtr>::get_iterator(void)\r
-  {\r
-    return m_iterator;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // ntree\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  ntree<T>::ntree(void) : m_root(0)\r
-  {\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T>::~ntree(void)\r
-  {\r
-    if (m_root) delete m_root;\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T>::ntree(const ntree<T>& r) : m_root(0)\r
-  {\r
-    *this = r;\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T>& ntree<T>::operator=(const ntree<T>& r)\r
-  {\r
-    if (m_root) delete m_root;\r
-    m_root = ntree_copy(this, r.m_root);\r
-    return *this;\r
-  }\r
-\r
-  template<typename T>\r
-  bool ntree<T>::empty(void) const\r
-  {\r
-    return m_root == 0;\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned ntree<T>::size(void) const\r
-  {\r
-    return ntree_size(m_root);\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned ntree<T>::size(const TYPENAME ntree<T>::const_iterator& i) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    return ntree_size(i.node());\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned ntree<T>::size(const TYPENAME ntree<T>::iterator& i)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    return ntree_size(i.node());\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned ntree<T>::depth(const TYPENAME ntree<T>::const_iterator& i) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    return ntree_depth(i.node());\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned ntree<T>::depth(const TYPENAME ntree<T>::iterator& i)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    return ntree_depth(i.node());\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::const_iterator ntree<T>::root(void) const\r
-  {\r
-    if (!m_root) return ntree_iterator<T,const T&,const T*>(this);\r
-    return ntree_iterator<T,const T&,const T*>(m_root);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::root(void)\r
-  {\r
-    if (!m_root) return ntree_iterator<T,T&,T*>(this);\r
-    return ntree_iterator<T,T&,T*>(m_root);\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned ntree<T>::children(const TYPENAME ntree<T>::const_iterator& i) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    return i.node()->m_children.size();\r
-  }\r
-\r
-  template<typename T>\r
-  unsigned ntree<T>::children(const ntree_iterator<T,T&,T*>& i)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    return i.node()->m_children.size();\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::const_iterator ntree<T>::child(const TYPENAME ntree<T>::const_iterator& i, unsigned child) const\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    i.assert_valid(this);\r
-    if (child >= children(i)) throw std::out_of_range("stlplus::ntree");\r
-    return ntree_iterator<T,const T&,const T*>(i.node()->m_children[child]);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::child(const TYPENAME ntree<T>::iterator& i, unsigned child)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    i.assert_valid(this);\r
-    if (child >= children(i)) throw std::out_of_range("stlplus::ntree");\r
-    return ntree_iterator<T,T&,T*>(i.node()->m_children[child]);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::const_iterator ntree<T>::parent(const TYPENAME ntree<T>::const_iterator& i) const\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    ntree_node<T>* parent = i.node()->m_parent;\r
-    if (!parent) return ntree_iterator<T,const T&,const T*>(this);\r
-    return ntree_iterator<T,const T&,const T*>(parent);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::parent(const TYPENAME ntree<T>::iterator& i)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    i.assert_valid(this);\r
-    ntree_node<T>* parent = i.node()->m_parent;\r
-    if (!parent) return ntree_iterator<T,T&,T*>(this);\r
-    return ntree_iterator<T,T&,T*>(parent);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::const_prefix_iterator ntree<T>::prefix_begin(void) const\r
-  {\r
-    return ntree_prefix_iterator<T,const T&,const T*>(root());\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::prefix_iterator ntree<T>::prefix_begin(void)\r
-  {\r
-    return ntree_prefix_iterator<T,T&,T*>(root());\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::const_prefix_iterator ntree<T>::prefix_end(void) const\r
-  {\r
-    return ntree_prefix_iterator<T,const T&,const T*>(ntree_iterator<T,const T&,const T*>(this));\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::prefix_iterator ntree<T>::prefix_end(void)\r
-  {\r
-    return ntree_prefix_iterator<T,T&,T*>(ntree_iterator<T,T&,T*>(this));\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::const_postfix_iterator ntree<T>::postfix_begin(void) const\r
-  {\r
-    return ntree_postfix_iterator<T,const T&,const T*>(root());\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::postfix_iterator ntree<T>::postfix_begin(void)\r
-  {\r
-    return ntree_postfix_iterator<T,T&,T*>(root());\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::const_postfix_iterator ntree<T>::postfix_end(void) const\r
-  {\r
-    return ntree_postfix_iterator<T,const T&,const T*>(ntree_iterator<T,const T&,const T*>(this));\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::postfix_iterator ntree<T>::postfix_end(void)\r
-  {\r
-    return ntree_postfix_iterator<T,T&,T*>(ntree_iterator<T,T&,T*>(this));\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::insert(const T& data)\r
-  {\r
-    // insert a new node as the root\r
-    return insert(ntree_iterator<T,T&,T*>(this), 0, data);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::insert(const TYPENAME ntree<T>::iterator& i, unsigned offset, const T& data)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    // if i is the end iterator, this means insert a new root\r
-    if (i.end())\r
-      erase();\r
-    else\r
-    {\r
-      i.assert_valid(this);\r
-      if (offset > children(i)) throw std::out_of_range("stlplus::ntree");\r
-    }\r
-    ntree_node<T>* new_node = new ntree_node<T>(this,data);\r
-    if (i.end())\r
-    {\r
-      m_root = new_node;\r
-    }\r
-    else\r
-    {\r
-      i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node);\r
-      new_node->m_parent = i.node();\r
-    }\r
-    return ntree_iterator<T,T&,T*>(new_node);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::append(const TYPENAME ntree<T>::iterator& i, const T& data)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return insert(i, i.node()->m_children.size(), data);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::insert(const TYPENAME ntree<T>::iterator& i, unsigned offset, const ntree<T>& tree)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    // insert a whole tree as a child of i\r
-    i.assert_valid(this);\r
-    if (offset > children(i)) throw std::out_of_range("stlplus::ntree");\r
-    ntree_node<T>* new_node = ntree_copy(this, tree.m_root);\r
-    i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node);\r
-    new_node->m_parent = i.node();\r
-    return ntree_iterator<T,T&,T*>(new_node);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::append(const TYPENAME ntree<T>::iterator& i, const ntree<T>& tree)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    return insert(i, children(i), tree);\r
-  }\r
-\r
-  template<typename T>\r
-  TYPENAME ntree<T>::iterator ntree<T>::push(const TYPENAME ntree<T>::iterator& node, const T& data)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // insert a new node to replace the existing node in the tree\r
-    // making the original node the child of the new node\r
-    // i.e. (node) becomes (new)->(node)\r
-    // afterwards, the iterator still points to the old node, now the child\r
-    // returns the iterator to the new node\r
-    node.assert_valid(this);\r
-    ntree_node<T>* new_node = new ntree_node<T>(this,data);\r
-    if (node.node() == m_root)\r
-    {\r
-      // pushing the root node\r
-      m_root = new_node;\r
-      new_node->m_parent = 0;\r
-    }\r
-    else\r
-    {\r
-      // pushing a sub-node\r
-      *(std::find(node.node()->m_parent->m_children.begin(), node.node()->m_parent->m_children.end(), node.node())) = new_node;\r
-      new_node->m_parent = node.node()->m_parent;\r
-    }\r
-    // link up the old node as the child of the new node\r
-    new_node->m_children.insert(new_node->m_children.begin(),node.node());\r
-    node.node()->m_parent = new_node;\r
-    return ntree_iterator<T,T&,T*>(new_node);\r
-  }\r
-\r
-  template<typename T>\r
-  void ntree<T>::pop(const TYPENAME ntree<T>::iterator& parent, unsigned offset)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    // inverse of push\r
-    // removes the specified child of the parent node, adding its children to the parent node at the same offset\r
-    parent.assert_valid(this);\r
-    ntree_node<T>* node = parent.node();\r
-    if (offset >= node->m_children.size()) throw std::out_of_range("stlplus::ntree");\r
-    // move the grandchildren first\r
-    ntree_node<T>* child = parent.node()->m_children[offset];\r
-    while (!child->m_children.empty())\r
-    {\r
-      // remove the last grandchild and insert into node just after the child to be removed\r
-      ntree_node<T>* grandchild = child->m_children[child->m_children.size()-1];\r
-      child->m_children.pop_back();\r
-      node->m_children.insert(node->m_children.begin()+offset+1, grandchild);\r
-      grandchild->m_parent = node;\r
-    }\r
-    // now remove the child\r
-    node->m_children.erase(node->m_children.begin()+offset);\r
-    delete child;\r
-  }\r
-\r
-  template<typename T>\r
-  void ntree<T>::erase(void)\r
-  {\r
-    // erase the whole tree\r
-    erase(root());\r
-  }\r
-\r
-  template<typename T>\r
-  void ntree<T>::erase(const TYPENAME ntree<T>::iterator& i)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    if (!i.end())\r
-    {\r
-      // erase this node and its subtree\r
-      // do this by erasing this child of its parent\r
-      // handle the case of erasing the root\r
-      i.assert_valid(this);\r
-      ntree_node<T>* node = i.node();\r
-      if (node == m_root)\r
-      {\r
-        delete m_root;\r
-        m_root = 0;\r
-      }\r
-      else\r
-      {\r
-        ntree_node<T>* parent = node->m_parent;\r
-        // impossible for parent to be null - should assert this\r
-        TYPENAME std::vector<ntree_node<T>*>::iterator found = \r
-          std::find(parent->m_children.begin(), parent->m_children.end(), node);\r
-        // impossible for find to fail - should assert this\r
-        parent->m_children.erase(found);\r
-        delete node;\r
-      }\r
-    }\r
-  }\r
-\r
-  template<typename T>\r
-  void ntree<T>::erase(const TYPENAME ntree<T>::iterator& i, unsigned offset)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    erase(child(i, offset));\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T> ntree<T>::subtree(void)\r
-  {\r
-    return subtree(root());\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T> ntree<T>::subtree(const TYPENAME ntree<T>::iterator& i)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    ntree<T> result;\r
-    if (!i.end())\r
-    {\r
-      i.assert_valid(this);\r
-      result.m_root = ntree_copy(&result, i.node());\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T> ntree<T>::subtree(const TYPENAME ntree<T>::iterator& i, unsigned offset)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    return subtree(child(i, offset));\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T> ntree<T>::cut(void)\r
-  {\r
-    return cut(root());\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T> ntree<T>::cut(const TYPENAME ntree<T>::iterator& i)\r
-    throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    ntree<T> result;\r
-    if (!i.end())\r
-    {\r
-      i.assert_valid(this);\r
-      ntree_node<T>* node = i.node();\r
-      if (node == m_root)\r
-      {\r
-        result.m_root = m_root;\r
-        m_root = 0;\r
-      }\r
-      else\r
-      {\r
-        ntree_node<T>* parent = node->m_parent;\r
-        // impossible for parent to be null - should assert this\r
-        TYPENAME std::vector<ntree_node<T>*>::iterator found = \r
-          std::find(parent->m_children.begin(), parent->m_children.end(), node);\r
-        // impossible for find to fail - should assert this\r
-        result.m_root = *found;\r
-        parent->m_children.erase(found);\r
-      }\r
-      if (result.m_root)\r
-      {\r
-        result.m_root->m_parent = 0;\r
-        result.m_root->set_new_owner(&result);\r
-      }\r
-    }\r
-    return result;\r
-  }\r
-\r
-  template<typename T>\r
-  ntree<T> ntree<T>::cut(const TYPENAME ntree<T>::iterator& i, unsigned offset)\r
-    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)\r
-  {\r
-    return cut(child(i, offset));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include <vector>
+#include <algorithm>
+
+namespace stlplus 
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // ntree_node
+
+  template<typename T>
+  class ntree_node
+  {
+  public:
+    master_iterator<ntree<T>, ntree_node<T> > m_master;
+    T m_data;
+    ntree_node<T>* m_parent;
+    std::vector<ntree_node<T>*> m_children;
+
+  public:
+    ntree_node(const ntree<T>* owner, const T& data = T()) :
+      m_master(owner,this), m_data(data), m_parent(0)
+      {
+      }
+
+    void change_owner(const ntree<T>* owner)
+      {
+        m_master.change_owner(owner);
+        for (TYPENAME std::vector<ntree_node<T>*>::iterator i = m_children.begin(); i != m_children.end(); i++)
+          (*i)->change_owner(owner);
+      }
+
+    ~ntree_node(void)
+      {
+        m_parent = 0;
+        for (TYPENAME std::vector<ntree_node<T>*>::iterator i = m_children.begin(); i != m_children.end(); i++)
+          delete *i;
+      }
+
+  };
+
+  template<typename T>
+  static ntree_node<T>* ntree_copy(const ntree<T>* new_owner, ntree_node<T>* root)
+  {
+    if (!root) return 0;
+    ntree_node<T>* new_tree = new ntree_node<T>(new_owner, root->m_data);
+    for (TYPENAME std::vector<ntree_node<T>*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++)
+    {
+      ntree_node<T>* new_child = ntree_copy(new_owner, *i);
+      new_tree->m_children.push_back(new_child);
+      new_child->m_parent = new_tree;
+    }
+    return new_tree;
+  }
+
+  template<typename T>
+  static unsigned ntree_size(ntree_node<T>* root)
+  {
+    if (!root) return 0;
+    unsigned result = 1;
+    for (TYPENAME std::vector<ntree_node<T>*>::iterator i = root->m_children.begin(); i != root->m_children.end(); i++)
+      result += ntree_size(*i);
+    return result;
+  }
+
+  template<typename T>
+  static unsigned ntree_depth(ntree_node<T>* root)
+  {
+    unsigned depth = 0;
+    for (ntree_node<T>* i = root; i; i = i->m_parent)
+      depth++;
+    return depth;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // ntree_iterator
+
+  // constructor to create a null iterator - you must assign a valid value to this iterator before using it
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(void)
+  {
+  }
+
+  // used to create an alias of an iterator
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(const safe_iterator<ntree<T>, ntree_node<T> >& iterator) :
+    safe_iterator<ntree<T>,ntree_node<T> >(iterator)
+  {
+  }
+
+  // constructor used by ntree to create a non-null iterator
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(ntree_node<T>* node) :
+    safe_iterator<ntree<T>,ntree_node<T> >(node->m_master)
+  {
+  }
+
+  // constructor used by ntree to create an end iterator
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr>::ntree_iterator(const ntree<T>* owner) :
+    safe_iterator<ntree<T>,ntree_node<T> >(owner)
+  {
+  }
+
+  // destructor
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr>::~ntree_iterator(void)
+  {
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_iterator<T,TRef,TPtr>::const_iterator ntree_iterator<T,TRef,TPtr>::constify(void) const
+  {
+    return ntree_iterator<T,const T&,const T*>(*this);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_iterator<T,TRef,TPtr>::iterator ntree_iterator<T,TRef,TPtr>::deconstify(void) const
+  {
+    return ntree_iterator<T,T&,T*>(*this);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return equal(r);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return !operator==(r);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return compare(r) < 0;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_iterator<T,TRef,TPtr>::reference ntree_iterator<T,TRef,TPtr>::operator*(void) const
+    throw(null_dereference,end_dereference)
+  {
+    this->assert_valid();
+    return this->node()->m_data;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_iterator<T,TRef,TPtr>::pointer ntree_iterator<T,TRef,TPtr>::operator->(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return &(operator*());
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // ntree_prefix_iterator
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_prefix_iterator<T,TRef,TPtr>::ntree_prefix_iterator(void)
+  {
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_prefix_iterator<T,TRef,TPtr>::~ntree_prefix_iterator(void)
+  {
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_prefix_iterator<T,TRef,TPtr>::ntree_prefix_iterator(const ntree_iterator<T,TRef,TPtr>& i) :
+    m_iterator(i)
+  {
+    // this is initialised with the root node
+    // which is also the first node in prefix traversal order
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_prefix_iterator<T,TRef,TPtr>::null(void) const
+  {
+    return m_iterator.null();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_prefix_iterator<T,TRef,TPtr>::end(void) const
+  {
+    return m_iterator.end();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_prefix_iterator<T,TRef,TPtr>::valid(void) const
+  {
+    return m_iterator.valid();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::const_iterator ntree_prefix_iterator<T,TRef,TPtr>::constify(void) const
+  {
+    return ntree_prefix_iterator<T,const T&,const T*>(m_iterator);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::iterator ntree_prefix_iterator<T,TRef,TPtr>::deconstify(void) const
+  {
+    return ntree_prefix_iterator<T,T&,T*>(m_iterator);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr> ntree_prefix_iterator<T,TRef,TPtr>::simplify(void) const
+  {
+    return m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_prefix_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return m_iterator == r.m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_prefix_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return m_iterator != r.m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_prefix_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return m_iterator < r.m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator& ntree_prefix_iterator<T,TRef,TPtr>::operator ++ (void)
+    throw(null_dereference,end_dereference)
+  {
+    // pre-increment operator
+    // algorithm: if there are any children, visit child 0, otherwise, go to
+    // parent and deduce which child the start node was of that parent - if
+    // there are further children, go into the next one. Otherwise, go up the
+    // tree and test again for further children. Return null if there are no
+    // further nodes
+    m_iterator.assert_valid();
+    ntree_node<T>* old_node = m_iterator.node();
+    if (!old_node->m_children.empty())
+    {
+      // simply take the first child of this node
+      m_iterator.set(old_node->m_children[0]->m_master);
+    }
+    else
+    {
+      // this loop walks up the parent pointers
+      // either it will walk off the top and exit or a new node will be found and the loop will exit
+      for (;;)
+      {
+        // go up a level
+        ntree_node<T>* parent = old_node->m_parent;
+        if (!parent)
+        {
+          // we've walked off the top of the tree, so return end
+          m_iterator.set_end();
+          break;
+        }
+        else
+        {
+          // otherwise walk down the next child - if there is one
+          // find which index the old node was relative to this node
+          TYPENAME std::vector<ntree_node<T>*>::iterator found = 
+            std::find(parent->m_children.begin(), parent->m_children.end(), old_node);
+          // if this was found, then see if there is another and if so return that
+          found++;
+          if (found != parent->m_children.end())
+          {
+            // visit the next child
+            m_iterator.set((*found)->m_master);
+            break;
+          }
+          else
+          {
+            // keep going up
+            old_node = parent;
+          }
+        }
+      }
+    }
+    return *this;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::this_iterator ntree_prefix_iterator<T,TRef,TPtr>::operator ++ (int)
+    throw(null_dereference,end_dereference)
+  {
+    // post-increment is defined in terms of the pre-increment
+    ntree_prefix_iterator<T,TRef,TPtr> result(*this);
+    ++(*this);
+    return result;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::reference ntree_prefix_iterator<T,TRef,TPtr>::operator*(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return m_iterator.operator*();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_prefix_iterator<T,TRef,TPtr>::pointer ntree_prefix_iterator<T,TRef,TPtr>::operator->(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return m_iterator.operator->();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  const ntree_iterator<T,TRef,TPtr>& ntree_prefix_iterator<T,TRef,TPtr>::get_iterator(void) const
+  {
+    return m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr>& ntree_prefix_iterator<T,TRef,TPtr>::get_iterator(void)
+  {
+    return m_iterator;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // ntree_postfix_iterator
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_postfix_iterator<T,TRef,TPtr>::ntree_postfix_iterator(void)
+  {
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_postfix_iterator<T,TRef,TPtr>::~ntree_postfix_iterator(void)
+  {
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_postfix_iterator<T,TRef,TPtr>::ntree_postfix_iterator(const ntree_iterator<T,TRef,TPtr>& i) :
+    m_iterator(i)
+  {
+    // this is initialised with the root node
+    // initially traverse to the first node to be visited
+    if (m_iterator.valid())
+    {
+      ntree_node<T>* node = m_iterator.node();
+      while (!node->m_children.empty())
+        node = node->m_children[0];
+      m_iterator.set(node->m_master);
+    }
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_postfix_iterator<T,TRef,TPtr>::null(void) const
+  {
+    return m_iterator.null();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_postfix_iterator<T,TRef,TPtr>::end(void) const
+  {
+    return m_iterator.end();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_postfix_iterator<T,TRef,TPtr>::valid(void) const
+  {
+    return m_iterator.valid();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::const_iterator ntree_postfix_iterator<T,TRef,TPtr>::constify(void) const
+  {
+    return ntree_postfix_iterator<T,const T&,const T*>(m_iterator);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::iterator ntree_postfix_iterator<T,TRef,TPtr>::deconstify(void) const
+  {
+    return ntree_postfix_iterator<T,T&,T*>(m_iterator);
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr> ntree_postfix_iterator<T,TRef,TPtr>::simplify(void) const
+  {
+    return m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_postfix_iterator<T,TRef,TPtr>::operator == (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return m_iterator == r.m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_postfix_iterator<T,TRef,TPtr>::operator != (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return m_iterator != r.m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  bool ntree_postfix_iterator<T,TRef,TPtr>::operator < (const TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& r) const
+  {
+    return m_iterator < r.m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator& ntree_postfix_iterator<T,TRef,TPtr>::operator ++ (void)
+    throw(null_dereference,end_dereference)
+  {
+    // pre-increment operator
+    // algorithm: this node has been visited, therefore all children must have
+    // already been visited. So go to parent. Return null if the parent is null.
+    // Otherwise deduce which child the start node was of that parent - if there
+    // are further children, go into the next one and then walk down any
+    // subsequent first-child pointers to the bottom. Otherwise, if there are no
+    // children then the parent node is the next in the traversal.
+    m_iterator.assert_valid();
+    // go up a level
+    ntree_node<T>* old_node = m_iterator.node();
+    ntree_node<T>* parent = old_node->m_parent;
+    if (!parent)
+    {
+      // we've walked off the top of the tree, so return end
+      m_iterator.set_end();
+    }
+    else
+    {
+      // otherwise find which index the old node was relative to this node
+      TYPENAME std::vector<ntree_node<T>*>::iterator found =
+        std::find(parent->m_children.begin(), parent->m_children.end(), old_node);
+      // if this was found, then see if there is another
+      found++;
+      if (found != parent->m_children.end())
+      {
+        // if so traverse to it and walk down the leftmost child pointers to the bottom of the new sub-tree
+        ntree_node<T>* new_node = *found;
+        while (!new_node->m_children.empty())
+          new_node = new_node->m_children[0];
+        m_iterator.set(new_node->m_master);
+      }
+      else
+      {
+        // the parent's children have all been visited - so the parent is visited
+        m_iterator.set(parent->m_master);
+      }
+    }
+    return *this;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::this_iterator ntree_postfix_iterator<T,TRef,TPtr>::operator ++ (int)
+    throw(null_dereference,end_dereference)
+  {
+    // post-increment is defined in terms of the pre-increment
+    ntree_postfix_iterator<T,TRef,TPtr> result(*this);
+    ++(*this);
+    return result;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::reference ntree_postfix_iterator<T,TRef,TPtr>::operator*(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return m_iterator.operator*();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  TYPENAME ntree_postfix_iterator<T,TRef,TPtr>::pointer ntree_postfix_iterator<T,TRef,TPtr>::operator->(void) const
+    throw(null_dereference,end_dereference)
+  {
+    return m_iterator.operator->();
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  const ntree_iterator<T,TRef,TPtr>& ntree_postfix_iterator<T,TRef,TPtr>::get_iterator(void) const
+  {
+    return m_iterator;
+  }
+
+  template<typename T, typename TRef, typename TPtr>
+  ntree_iterator<T,TRef,TPtr>& ntree_postfix_iterator<T,TRef,TPtr>::get_iterator(void)
+  {
+    return m_iterator;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////////////////
+  // ntree
+  ////////////////////////////////////////////////////////////////////////////////
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T>
+  ntree<T>::ntree(void) : m_root(0)
+  {
+  }
+
+  template<typename T>
+  ntree<T>::~ntree(void)
+  {
+    if (m_root) delete m_root;
+  }
+
+  template<typename T>
+  ntree<T>::ntree(const ntree<T>& r) : m_root(0)
+  {
+    *this = r;
+  }
+
+  template<typename T>
+  ntree<T>& ntree<T>::operator=(const ntree<T>& r)
+  {
+    if (m_root) delete m_root;
+    m_root = ntree_copy(this, r.m_root);
+    return *this;
+  }
+
+  template<typename T>
+  bool ntree<T>::empty(void) const
+  {
+    return m_root == 0;
+  }
+
+  template<typename T>
+  unsigned ntree<T>::size(void) const
+  {
+    return ntree_size(m_root);
+  }
+
+  template<typename T>
+  unsigned ntree<T>::size(const TYPENAME ntree<T>::const_iterator& i) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    return ntree_size(i.node());
+  }
+
+  template<typename T>
+  unsigned ntree<T>::size(const TYPENAME ntree<T>::iterator& i)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    return ntree_size(i.node());
+  }
+
+  template<typename T>
+  unsigned ntree<T>::depth(const TYPENAME ntree<T>::const_iterator& i) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    return ntree_depth(i.node());
+  }
+
+  template<typename T>
+  unsigned ntree<T>::depth(const TYPENAME ntree<T>::iterator& i)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    return ntree_depth(i.node());
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::const_iterator ntree<T>::root(void) const
+  {
+    if (!m_root) return ntree_iterator<T,const T&,const T*>(this);
+    return ntree_iterator<T,const T&,const T*>(m_root);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::root(void)
+  {
+    if (!m_root) return ntree_iterator<T,T&,T*>(this);
+    return ntree_iterator<T,T&,T*>(m_root);
+  }
+
+  template<typename T>
+  unsigned ntree<T>::children(const TYPENAME ntree<T>::const_iterator& i) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    return i.node()->m_children.size();
+  }
+
+  template<typename T>
+  unsigned ntree<T>::children(const ntree_iterator<T,T&,T*>& i)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    return i.node()->m_children.size();
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::const_iterator ntree<T>::child(const TYPENAME ntree<T>::const_iterator& i, unsigned child) const
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    i.assert_valid(this);
+    if (child >= children(i)) throw std::out_of_range("stlplus::ntree");
+    return ntree_iterator<T,const T&,const T*>(i.node()->m_children[child]);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::child(const TYPENAME ntree<T>::iterator& i, unsigned child)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    i.assert_valid(this);
+    if (child >= children(i)) throw std::out_of_range("stlplus::ntree");
+    return ntree_iterator<T,T&,T*>(i.node()->m_children[child]);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::const_iterator ntree<T>::parent(const TYPENAME ntree<T>::const_iterator& i) const
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    ntree_node<T>* parent = i.node()->m_parent;
+    if (!parent) return ntree_iterator<T,const T&,const T*>(this);
+    return ntree_iterator<T,const T&,const T*>(parent);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::parent(const TYPENAME ntree<T>::iterator& i)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    i.assert_valid(this);
+    ntree_node<T>* parent = i.node()->m_parent;
+    if (!parent) return ntree_iterator<T,T&,T*>(this);
+    return ntree_iterator<T,T&,T*>(parent);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::const_prefix_iterator ntree<T>::prefix_begin(void) const
+  {
+    return ntree_prefix_iterator<T,const T&,const T*>(root());
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::prefix_iterator ntree<T>::prefix_begin(void)
+  {
+    return ntree_prefix_iterator<T,T&,T*>(root());
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::const_prefix_iterator ntree<T>::prefix_end(void) const
+  {
+    return ntree_prefix_iterator<T,const T&,const T*>(ntree_iterator<T,const T&,const T*>(this));
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::prefix_iterator ntree<T>::prefix_end(void)
+  {
+    return ntree_prefix_iterator<T,T&,T*>(ntree_iterator<T,T&,T*>(this));
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::const_postfix_iterator ntree<T>::postfix_begin(void) const
+  {
+    return ntree_postfix_iterator<T,const T&,const T*>(root());
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::postfix_iterator ntree<T>::postfix_begin(void)
+  {
+    return ntree_postfix_iterator<T,T&,T*>(root());
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::const_postfix_iterator ntree<T>::postfix_end(void) const
+  {
+    return ntree_postfix_iterator<T,const T&,const T*>(ntree_iterator<T,const T&,const T*>(this));
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::postfix_iterator ntree<T>::postfix_end(void)
+  {
+    return ntree_postfix_iterator<T,T&,T*>(ntree_iterator<T,T&,T*>(this));
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::insert(const T& data)
+  {
+    // insert a new node as the root
+    return insert(ntree_iterator<T,T&,T*>(this), 0, data);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::insert(const TYPENAME ntree<T>::iterator& i, unsigned offset, const T& data)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    // if i is the end iterator, this means insert a new root
+    if (i.end())
+      erase();
+    else
+    {
+      i.assert_valid(this);
+      if (offset > children(i)) throw std::out_of_range("stlplus::ntree");
+    }
+    ntree_node<T>* new_node = new ntree_node<T>(this,data);
+    if (i.end())
+    {
+      m_root = new_node;
+    }
+    else
+    {
+      i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node);
+      new_node->m_parent = i.node();
+    }
+    return ntree_iterator<T,T&,T*>(new_node);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::append(const TYPENAME ntree<T>::iterator& i, const T& data)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return insert(i, i.node()->m_children.size(), data);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::insert(const TYPENAME ntree<T>::iterator& i, unsigned offset, const ntree<T>& tree)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    // insert a whole tree as a child of i
+    i.assert_valid(this);
+    if (offset > children(i)) throw std::out_of_range("stlplus::ntree");
+    ntree_node<T>* new_node = ntree_copy(this, tree.m_root);
+    i.node()->m_children.insert(i.node()->m_children.begin()+offset,new_node);
+    new_node->m_parent = i.node();
+    return ntree_iterator<T,T&,T*>(new_node);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::append(const TYPENAME ntree<T>::iterator& i, const ntree<T>& tree)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    return insert(i, children(i), tree);
+  }
+
+  template<typename T>
+  TYPENAME ntree<T>::iterator ntree<T>::push(const TYPENAME ntree<T>::iterator& node, const T& data)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // insert a new node to replace the existing node in the tree
+    // making the original node the child of the new node
+    // i.e. (node) becomes (new)->(node)
+    // afterwards, the iterator still points to the old node, now the child
+    // returns the iterator to the new node
+    node.assert_valid(this);
+    ntree_node<T>* new_node = new ntree_node<T>(this,data);
+    if (node.node() == m_root)
+    {
+      // pushing the root node
+      m_root = new_node;
+      new_node->m_parent = 0;
+    }
+    else
+    {
+      // pushing a sub-node
+      *(std::find(node.node()->m_parent->m_children.begin(), node.node()->m_parent->m_children.end(), node.node())) = new_node;
+      new_node->m_parent = node.node()->m_parent;
+    }
+    // link up the old node as the child of the new node
+    new_node->m_children.insert(new_node->m_children.begin(),node.node());
+    node.node()->m_parent = new_node;
+    return ntree_iterator<T,T&,T*>(new_node);
+  }
+
+  template<typename T>
+  void ntree<T>::pop(const TYPENAME ntree<T>::iterator& parent, unsigned offset)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    // inverse of push
+    // removes the specified child of the parent node, adding its children to the parent node at the same offset
+    parent.assert_valid(this);
+    ntree_node<T>* node = parent.node();
+    if (offset >= node->m_children.size()) throw std::out_of_range("stlplus::ntree");
+    // move the grandchildren first
+    ntree_node<T>* child = parent.node()->m_children[offset];
+    while (!child->m_children.empty())
+    {
+      // remove the last grandchild and insert into node just after the child to be removed
+      ntree_node<T>* grandchild = child->m_children[child->m_children.size()-1];
+      child->m_children.pop_back();
+      node->m_children.insert(node->m_children.begin()+offset+1, grandchild);
+      grandchild->m_parent = node;
+    }
+    // now remove the child
+    node->m_children.erase(node->m_children.begin()+offset);
+    delete child;
+  }
+
+  template<typename T>
+  void ntree<T>::erase(void)
+  {
+    // erase the whole tree
+    erase(root());
+  }
+
+  template<typename T>
+  void ntree<T>::erase(const TYPENAME ntree<T>::iterator& i)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    if (!i.end())
+    {
+      // erase this node and its subtree
+      // do this by erasing this child of its parent
+      // handle the case of erasing the root
+      i.assert_valid(this);
+      ntree_node<T>* node = i.node();
+      if (node == m_root)
+      {
+        delete m_root;
+        m_root = 0;
+      }
+      else
+      {
+        ntree_node<T>* parent = node->m_parent;
+        // impossible for parent to be null - should assert this
+        TYPENAME std::vector<ntree_node<T>*>::iterator found = 
+          std::find(parent->m_children.begin(), parent->m_children.end(), node);
+        // impossible for find to fail - should assert this
+        parent->m_children.erase(found);
+        delete node;
+      }
+    }
+  }
+
+  template<typename T>
+  void ntree<T>::erase(const TYPENAME ntree<T>::iterator& i, unsigned offset)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    erase(child(i, offset));
+  }
+
+  template<typename T>
+  ntree<T> ntree<T>::subtree(void)
+  {
+    return subtree(root());
+  }
+
+  template<typename T>
+  ntree<T> ntree<T>::subtree(const TYPENAME ntree<T>::iterator& i)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    ntree<T> result;
+    if (!i.end())
+    {
+      i.assert_valid(this);
+      result.m_root = ntree_copy(&result, i.node());
+    }
+    return result;
+  }
+
+  template<typename T>
+  ntree<T> ntree<T>::subtree(const TYPENAME ntree<T>::iterator& i, unsigned offset)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    return subtree(child(i, offset));
+  }
+
+  template<typename T>
+  ntree<T> ntree<T>::cut(void)
+  {
+    return cut(root());
+  }
+
+  template<typename T>
+  ntree<T> ntree<T>::cut(const TYPENAME ntree<T>::iterator& i)
+    throw(wrong_object,null_dereference,end_dereference)
+  {
+    ntree<T> result;
+    if (!i.end())
+    {
+      i.assert_valid(this);
+      ntree_node<T>* node = i.node();
+      if (node == m_root)
+      {
+        result.m_root = m_root;
+        m_root = 0;
+      }
+      else
+      {
+        ntree_node<T>* parent = node->m_parent;
+        // impossible for parent to be null - should assert this
+        TYPENAME std::vector<ntree_node<T>*>::iterator found = 
+          std::find(parent->m_children.begin(), parent->m_children.end(), node);
+        // impossible for find to fail - should assert this
+        result.m_root = *found;
+        parent->m_children.erase(found);
+      }
+      if (result.m_root)
+      {
+        result.m_root->m_parent = 0;
+        result.m_root->set_new_owner(&result);
+      }
+    }
+    return result;
+  }
+
+  template<typename T>
+  ntree<T> ntree<T>::cut(const TYPENAME ntree<T>::iterator& i, unsigned offset)
+    throw(wrong_object,null_dereference,end_dereference,std::out_of_range)
+  {
+    return cut(child(i, offset));
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
index 5bf80fba537b146c1649f98a21f8520ff44e6cf4..74126878247eded69f19959f38b507e4b59f8c3b 100644 (file)
-#ifndef STLPLUS_SAFE_ITERATOR\r
-#define STLPLUS_SAFE_ITERATOR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   The STLplus safe_iterator superclasses. This implements the STLplus safe\r
-//   iterator principles. Data structures can then be built using subclasses\r
-//   of safe_iterator for their iterator objects and they will inherit the\r
-//   safe iterator behaviour.\r
-\r
-//   The data structure must contain a master iterator for each node in the\r
-//   structure. When an iterator is returned to the user, it must be created\r
-//   by the master iterator. When a node is removed from the data structure,\r
-//   its master iterator is destroyed. This sets all iterators pointing to the\r
-//   master iterator to end iterators.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include "exceptions.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internals\r
-\r
-  template<typename O, typename N>\r
-  class safe_iterator_body;\r
-\r
-  template<typename O, typename N>\r
-  class safe_iterator;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Master Iterator\r
-  // Create one of these in each node in the data structure\r
-  // Generate iterators by obtaining a safe-iterator object from the master iterator\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename O, typename N>\r
-  class master_iterator\r
-  {\r
-  public:\r
-\r
-    // construct a valid master iterator connected to the node\r
-    master_iterator(const O* owner, N* node) throw();\r
-\r
-    // destructor - disconnects all iterators from the node\r
-    ~master_iterator(void) throw();\r
-\r
-    // dereference\r
-    N* node(void) const throw();\r
-    const O* owner(void) const throw();\r
-\r
-    // when you move a node from one owner to another, call this on the node's master iterator\r
-    // this effectively moves all other iterators to the node so that they are owned by the new owner too\r
-    void change_owner(const O* owner) throw();\r
-\r
-    friend class safe_iterator<O,N>;\r
-  private:\r
-    master_iterator(const master_iterator&) throw();\r
-    master_iterator& operator=(const master_iterator&) throw();\r
-    safe_iterator_body<O,N>* m_body;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Safe Iterator\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename O, typename N>\r
-  class safe_iterator\r
-  {\r
-  public:\r
-\r
-    // construct a null iterator\r
-    safe_iterator(void) throw();\r
-\r
-    // construct a valid iterator by aliasing from the owner node's master iterator\r
-    safe_iterator(const master_iterator<O,N>&) throw();\r
-\r
-    // copy constructor does aliasing\r
-    safe_iterator(const safe_iterator<O,N>&) throw();\r
-\r
-    // alias an iterator by assignment\r
-    safe_iterator<O,N>& operator=(const safe_iterator<O,N>&) throw();\r
-\r
-    // destructor\r
-    ~safe_iterator(void) throw();\r
-\r
-    // reassignment to another node used in increment/decrement operation\r
-    void set(const master_iterator<O,N>&) throw();\r
-\r
-    // dereference\r
-    N* node(void) const throw();\r
-    const O* owner(void) const throw();\r
-\r
-    // change to a null iterator - i.e. one that does not belong to any object\r
-    // this does not affect any other iterators pointing to the same node\r
-    void set_null(void) throw();\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // operations for clients that do not have a master end iterator\r
-    // alternatively, have a master end iterator as part of the container\r
-    // and call constructor(master_end) or set(master_end)\r
-\r
-    // construct an end iterator\r
-    safe_iterator(const O* owner) throw();\r
-\r
-    // change to an end iterator - e.g. as a result of incrementing off the end\r
-    void set_end(void) throw();\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // tests\r
-\r
-    // comparison\r
-    bool equal(const safe_iterator<O,N>& right) const throw();\r
-    int compare(const safe_iterator<O,N>& right) const throw();\r
-\r
-    // a null iterator is one that has not been initialised with a value yet\r
-    // i.e. you just declared it but didn't assign to it\r
-    bool null(void) const throw();\r
-\r
-    // an end iterator is one that points to the end element of the list of nodes\r
-    // in STL conventions this is one past the last valid element and must not be dereferenced\r
-    bool end(void) const throw();\r
-\r
-    // a valid iterator is one that can be dereferenced\r
-    // i.e. non-null and non-end\r
-    bool valid(void) const throw();\r
-\r
-    // check the rules for a valid iterator that can be dereferenced\r
-    // optionally also check that the iterator is owned by the owner\r
-    void assert_valid(void) const throw(null_dereference,end_dereference);\r
-    void assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference);\r
-    // assert the rules for a non-null iterator - i.e. valid or end, values that occur in increment operations\r
-    void assert_non_null(void) const throw(null_dereference);\r
-    // assert that this iterator is owned by this container\r
-    void assert_owner(const O* owner) const throw(wrong_object);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-\r
-    friend class master_iterator<O,N>;\r
-  private:\r
-    safe_iterator_body<O,N>* m_body;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "safe_iterator.tpp"\r
-#endif\r
+#ifndef STLPLUS_SAFE_ITERATOR
+#define STLPLUS_SAFE_ITERATOR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   The STLplus safe_iterator superclasses. This implements the STLplus safe
+//   iterator principles. Data structures can then be built using subclasses
+//   of safe_iterator for their iterator objects and they will inherit the
+//   safe iterator behaviour.
+
+//   The data structure must contain a master iterator for each node in the
+//   structure. When an iterator is returned to the user, it must be created
+//   by the master iterator. When a node is removed from the data structure,
+//   its master iterator is destroyed. This sets all iterators pointing to the
+//   master iterator to end iterators.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include "exceptions.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // internals
+
+  template<typename O, typename N>
+  class safe_iterator_body;
+
+  template<typename O, typename N>
+  class safe_iterator;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Master Iterator
+  // Create one of these in each node in the data structure
+  // Generate iterators by obtaining a safe-iterator object from the master iterator
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename O, typename N>
+  class master_iterator
+  {
+  public:
+
+    // construct a valid master iterator connected to the node
+    master_iterator(const O* owner, N* node) throw();
+
+    // destructor - disconnects all iterators from the node
+    ~master_iterator(void) throw();
+
+    // dereference
+    N* node(void) const throw();
+    const O* owner(void) const throw();
+
+    // when you move a node from one owner to another, call this on the node's master iterator
+    // this effectively moves all other iterators to the node so that they are owned by the new owner too
+    void change_owner(const O* owner) throw();
+
+    friend class safe_iterator<O,N>;
+  private:
+    master_iterator(const master_iterator&) throw();
+    master_iterator& operator=(const master_iterator&) throw();
+    safe_iterator_body<O,N>* m_body;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Safe Iterator
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename O, typename N>
+  class safe_iterator
+  {
+  public:
+
+    // construct a null iterator
+    safe_iterator(void) throw();
+
+    // construct a valid iterator by aliasing from the owner node's master iterator
+    safe_iterator(const master_iterator<O,N>&) throw();
+
+    // copy constructor does aliasing
+    safe_iterator(const safe_iterator<O,N>&) throw();
+
+    // alias an iterator by assignment
+    safe_iterator<O,N>& operator=(const safe_iterator<O,N>&) throw();
+
+    // destructor
+    ~safe_iterator(void) throw();
+
+    // reassignment to another node used in increment/decrement operation
+    void set(const master_iterator<O,N>&) throw();
+
+    // dereference
+    N* node(void) const throw();
+    const O* owner(void) const throw();
+
+    // change to a null iterator - i.e. one that does not belong to any object
+    // this does not affect any other iterators pointing to the same node
+    void set_null(void) throw();
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // operations for clients that do not have a master end iterator
+    // alternatively, have a master end iterator as part of the container
+    // and call constructor(master_end) or set(master_end)
+
+    // construct an end iterator
+    safe_iterator(const O* owner) throw();
+
+    // change to an end iterator - e.g. as a result of incrementing off the end
+    void set_end(void) throw();
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // tests
+
+    // comparison
+    bool equal(const safe_iterator<O,N>& right) const throw();
+    int compare(const safe_iterator<O,N>& right) const throw();
+
+    // a null iterator is one that has not been initialised with a value yet
+    // i.e. you just declared it but didn't assign to it
+    bool null(void) const throw();
+
+    // an end iterator is one that points to the end element of the list of nodes
+    // in STL conventions this is one past the last valid element and must not be dereferenced
+    bool end(void) const throw();
+
+    // a valid iterator is one that can be dereferenced
+    // i.e. non-null and non-end
+    bool valid(void) const throw();
+
+    // check the rules for a valid iterator that can be dereferenced
+    // optionally also check that the iterator is owned by the owner
+    void assert_valid(void) const throw(null_dereference,end_dereference);
+    void assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference);
+    // assert the rules for a non-null iterator - i.e. valid or end, values that occur in increment operations
+    void assert_non_null(void) const throw(null_dereference);
+    // assert that this iterator is owned by this container
+    void assert_owner(const O* owner) const throw(wrong_object);
+
+    ////////////////////////////////////////////////////////////////////////////////
+
+    friend class master_iterator<O,N>;
+  private:
+    safe_iterator_body<O,N>* m_body;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "safe_iterator.tpp"
+#endif
index 14d89b992b30b7af42868fd3a2411c222d93bba9..3296482fd6b46d28c214f2225ea167a6a8103fc9 100644 (file)
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // body class implements the aliasing behaviour\r
-\r
-  template<typename O, typename N>\r
-  class safe_iterator_body\r
-  {\r
-  private:\r
-    const O* m_owner;\r
-    N* m_node;\r
-    unsigned m_count;\r
-\r
-  public:\r
-\r
-    safe_iterator_body(const O* owner, N* node) throw() : \r
-      m_owner(owner), m_node(node), m_count(1)\r
-      {\r
-//         std::cerr << "constructing " \r
-//                   << std::hex << ((unsigned long)this) \r
-//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
-//                   << ":" << std::dec << m_count << std::endl;\r
-      }\r
-\r
-    ~safe_iterator_body(void) throw()\r
-      {\r
-//         std::cerr << "destroying " \r
-//                   << std::hex << ((unsigned long)this) \r
-//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
-//                   << ":" << std::dec << m_count << std::endl;\r
-        m_owner = 0;\r
-        m_node = 0;\r
-      }\r
-\r
-    unsigned count(void) const\r
-      {\r
-        return m_count;\r
-      }\r
-\r
-    void increment(void)\r
-      {\r
-        ++m_count;\r
-//         std::cerr << "incremented " \r
-//                   << std::hex << ((unsigned long)this) \r
-//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
-//                   << ":" << std::dec << m_count << std::endl;\r
-      }\r
-\r
-    bool decrement(void)\r
-      {\r
-        --m_count;\r
-//         std::cerr << "decremented " \r
-//                   << std::hex << ((unsigned long)this) \r
-//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)\r
-//                   << ":" << std::dec << m_count << std::endl;\r
-        return m_count == 0;\r
-      }\r
-\r
-    N* node(void) const throw()\r
-      {\r
-        return m_node;\r
-      }\r
-\r
-    const O* owner(void) const throw()\r
-      {\r
-        return m_owner;\r
-      }\r
-\r
-    void change_owner(const O* owner)\r
-      {\r
-        m_owner = owner;\r
-      }\r
-\r
-    bool equal(const safe_iterator_body<O,N>* right) const throw()\r
-      {\r
-//        return m_node == right->m_node;\r
-        return compare(right) == 0;\r
-      }\r
-\r
-    int compare(const safe_iterator_body<O,N>* right) const throw()\r
-      {\r
-        return ((long)m_node) - ((long)right->m_node);\r
-      }\r
-\r
-    bool null(void) const throw()\r
-      {\r
-        return m_owner == 0;\r
-      }\r
-\r
-    bool end(void) const throw()\r
-      {\r
-        return m_owner != 0 && m_node == 0;\r
-      }\r
-\r
-    bool valid(void) const throw()\r
-      {\r
-        return m_owner != 0 && m_node != 0;\r
-      }\r
-\r
-    void set_end(void) throw()\r
-      {\r
-        m_node = 0;\r
-      }\r
-\r
-    void set_null(void) throw()\r
-      {\r
-        m_owner = 0;\r
-        m_node = 0;\r
-      }\r
-\r
-    void assert_valid(void) const throw(null_dereference,end_dereference)\r
-      {\r
-        if (null())\r
-          throw null_dereference("stlplus::safe_iterator");\r
-        if (end())\r
-          throw end_dereference("stlplus::safe_iterator");\r
-      }\r
-\r
-    void assert_non_null(void) const throw(null_dereference)\r
-      {\r
-        if (null())\r
-          throw null_dereference("stlplus::safe_iterator");\r
-      }\r
-\r
-    void assert_owner(const O* owner) const throw(wrong_object)\r
-      {\r
-        if (owner != m_owner)\r
-          throw wrong_object("stlplus::safe_iterator");\r
-      }\r
-  };\r
-\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Master Iterator\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // construct a valid iterator\r
-  template<typename O, typename N>\r
-  master_iterator<O,N>::master_iterator(const O* owner, N* node) throw() :\r
-    m_body(new safe_iterator_body<O,N>(owner,node))\r
-  {\r
-  }\r
-\r
-  // destructor - disconnect all iterators from the node\r
-  // this usually happens when the node is deleted and must invalidate all aliases\r
-  template<typename O, typename N>\r
-  master_iterator<O,N>::~master_iterator(void) throw()\r
-  {\r
-    m_body->set_end();\r
-    if(m_body->decrement())\r
-    {\r
-      delete m_body;\r
-      m_body = 0;\r
-    }\r
-  }\r
-\r
-  // dereference\r
-  template<typename O, typename N>\r
-  N* master_iterator<O,N>::node(void) const throw()\r
-  {\r
-    return m_body->node();\r
-  }\r
-\r
-  template<typename O, typename N>\r
-  const O* master_iterator<O,N>::owner(void) const throw()\r
-  {\r
-    return m_body->owner();\r
-  }\r
-\r
-  // when you move a node from one owner to another, call this on the node's iterator\r
-  // this effectively moves all iterators to the node so that they are owned by the new owner too\r
-  template<typename O, typename N>\r
-  void master_iterator<O,N>::change_owner(const O* owner) throw()\r
-  {\r
-    m_body->change_owner(owner);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Safe Iterator\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // construct a null iterator\r
-  // later assignment of a valid iterator to this is done by using step\r
-  template<typename O, typename N>\r
-  safe_iterator<O,N>::safe_iterator(void) throw() : \r
-    m_body(new safe_iterator_body<O,N>(0,0))\r
-  {\r
-  }\r
-\r
-  // construct a valid iterator by aliasing from the owner node's master iterator\r
-  template<typename O, typename N>\r
-  safe_iterator<O,N>::safe_iterator(const master_iterator<O,N>& r) throw() :\r
-    m_body(0)\r
-  {\r
-    m_body = r.m_body;\r
-    m_body->increment();\r
-  }\r
-\r
-  // construct a valid iterator by aliasing from the owner node's master iterator\r
-  template<typename O, typename N>\r
-  safe_iterator<O,N>::safe_iterator(const safe_iterator<O,N>& r) throw() :\r
-    m_body(0)\r
-  {\r
-    m_body = r.m_body;\r
-    m_body->increment();\r
-  }\r
-\r
-  // assignment implements dealiasing followed by aliasing\r
-  template<typename O, typename N>\r
-  safe_iterator<O,N>& safe_iterator<O,N>::operator=(const safe_iterator<O,N>& r) throw()\r
-  {\r
-    if (m_body != r.m_body)\r
-    {\r
-      if (m_body->decrement())\r
-        delete m_body;\r
-      m_body = r.m_body;\r
-      m_body->increment();\r
-    }\r
-    return *this;\r
-  }\r
-\r
-  // destructor - implements dealiasing\r
-  template<typename O, typename N>\r
-  safe_iterator<O,N>::~safe_iterator(void) throw()\r
-  {\r
-    if(m_body->decrement())\r
-    {\r
-      delete m_body;\r
-      m_body = 0;\r
-    }\r
-  }\r
-\r
-\r
-  // increment/decrement operation\r
-  // implements dealiasing followed by aliasing\r
-  template<typename O, typename N>\r
-  void safe_iterator<O,N>::set(const master_iterator<O,N>& r) throw()\r
-  {\r
-    if (m_body != r.m_body)\r
-    {\r
-      if (m_body->decrement())\r
-        delete m_body;\r
-      m_body = r.m_body;\r
-      m_body->increment();\r
-    }\r
-  }\r
-\r
-  // dereference\r
-  template<typename O, typename N>\r
-  N* safe_iterator<O,N>::node(void) const throw()\r
-  {\r
-    return m_body->node();\r
-  }\r
-\r
-  template<typename O, typename N>\r
-  const O* safe_iterator<O,N>::owner(void) const throw()\r
-  {\r
-    return m_body->owner();\r
-  }\r
-\r
-  // change to a null iterator - i.e. one that doees not belong to any object\r
-  // this does not affect any other iterators pointing to the same node\r
-  template<typename O, typename N>\r
-  void safe_iterator<O,N>::set_null(void) throw()\r
-  {\r
-    if (m_body->count() == 1)\r
-    {\r
-      // no aliases, so just make this null\r
-      m_body->set_null();\r
-    }\r
-    else\r
-    {\r
-      // create a new body which is null so as not to affect any other aliases\r
-      m_body->decrement();\r
-      m_body = new safe_iterator_body<O,N>(0,0);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // operations for clients that do not have a master end iterator\r
-  // alternatively, have a master end iterator as part of the container\r
-  // and call constructor(master_end) or step(master_end)\r
-\r
-  // construct an end iterator\r
-  template<typename O, typename N>\r
-  safe_iterator<O,N>::safe_iterator(const O* owner) throw() :\r
-    m_body(new safe_iterator_body<O,N>(owner,0))\r
-  {\r
-  }\r
-\r
-  // change to an end iterator - e.g. as a result of incrementing off the end\r
-  template<typename O, typename N>\r
-  void safe_iterator<O,N>::set_end(void) throw()\r
-  {\r
-    if (m_body->count() == 1)\r
-    {\r
-      // no aliases, so just make this an end iterator\r
-      m_body->set_end();\r
-    }\r
-    else\r
-    {\r
-      // create a new body which is null so as not to affect any other aliases\r
-      m_body->decrement();\r
-      m_body = new safe_iterator_body<O,N>(owner(),0);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // tests\r
-\r
-  // comparison\r
-  template<typename O, typename N>\r
-  bool safe_iterator<O,N>::equal(const safe_iterator<O,N>& right) const throw()\r
-  {\r
-    return compare(right) == 0;\r
-  }\r
-\r
-  template<typename O, typename N>\r
-  int safe_iterator<O,N>::compare(const safe_iterator<O,N>& right) const throw()\r
-  {\r
-    if (m_body == right.m_body) return 0;\r
-    return m_body->compare(right.m_body);\r
-  }\r
-\r
-  // a null iterator is one that has not been initialised with a value yet\r
-  template<typename O, typename N>\r
-  bool safe_iterator<O,N>::null(void) const throw()\r
-  {\r
-    return m_body->null();\r
-  }\r
-\r
-  // an end iterator is one that points to the end element of the list of nodes\r
-  template<typename O, typename N>\r
-  bool safe_iterator<O,N>::end(void) const throw()\r
-  {\r
-    return m_body->end();\r
-  }\r
-\r
-  // a valid iterator is one that can be dereferenced\r
-  template<typename O, typename N>\r
-  bool safe_iterator<O,N>::valid(void) const throw()\r
-  {\r
-    return m_body->valid();\r
-  }\r
-\r
-  // check the rules for a valid iterator that can be dereferenced\r
-  template<typename O, typename N>\r
-  void safe_iterator<O,N>::assert_valid(void) const throw(null_dereference,end_dereference)\r
-  {\r
-    m_body->assert_valid();\r
-  }\r
-\r
-  template<typename O, typename N>\r
-  void safe_iterator<O,N>::assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference)\r
-  {\r
-    m_body->assert_valid();\r
-    m_body->assert_owner(owner);\r
-  }\r
-\r
-  template<typename O, typename N>\r
-  void safe_iterator<O,N>::assert_non_null(void) const throw(null_dereference)\r
-  {\r
-    m_body->assert_non_null();\r
-  }\r
-\r
-  template<typename O, typename N>\r
-  void safe_iterator<O,N>::assert_owner(const O* owner) const throw(wrong_object)\r
-  {\r
-    m_body->assert_owner(owner);\r
-  }\r
-\r
-} // end namespace stlplus\r
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // body class implements the aliasing behaviour
+
+  template<typename O, typename N>
+  class safe_iterator_body
+  {
+  private:
+    const O* m_owner;
+    N* m_node;
+    unsigned m_count;
+
+  public:
+
+    safe_iterator_body(const O* owner, N* node) throw() : 
+      m_owner(owner), m_node(node), m_count(1)
+      {
+//         std::cerr << "constructing " 
+//                   << std::hex << ((unsigned long)this) 
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)
+//                   << ":" << std::dec << m_count << std::endl;
+      }
+
+    ~safe_iterator_body(void) throw()
+      {
+//         std::cerr << "destroying " 
+//                   << std::hex << ((unsigned long)this) 
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)
+//                   << ":" << std::dec << m_count << std::endl;
+        m_owner = 0;
+        m_node = 0;
+      }
+
+    unsigned count(void) const
+      {
+        return m_count;
+      }
+
+    void increment(void)
+      {
+        ++m_count;
+//         std::cerr << "incremented " 
+//                   << std::hex << ((unsigned long)this) 
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)
+//                   << ":" << std::dec << m_count << std::endl;
+      }
+
+    bool decrement(void)
+      {
+        --m_count;
+//         std::cerr << "decremented " 
+//                   << std::hex << ((unsigned long)this) 
+//                   << " => " << ((unsigned long)m_owner) << ":" << ((unsigned long)m_node)
+//                   << ":" << std::dec << m_count << std::endl;
+        return m_count == 0;
+      }
+
+    N* node(void) const throw()
+      {
+        return m_node;
+      }
+
+    const O* owner(void) const throw()
+      {
+        return m_owner;
+      }
+
+    void change_owner(const O* owner)
+      {
+        m_owner = owner;
+      }
+
+    bool equal(const safe_iterator_body<O,N>* right) const throw()
+      {
+//        return m_node == right->m_node;
+        return compare(right) == 0;
+      }
+
+    int compare(const safe_iterator_body<O,N>* right) const throw()
+      {
+        return ((long)m_node) - ((long)right->m_node);
+      }
+
+    bool null(void) const throw()
+      {
+        return m_owner == 0;
+      }
+
+    bool end(void) const throw()
+      {
+        return m_owner != 0 && m_node == 0;
+      }
+
+    bool valid(void) const throw()
+      {
+        return m_owner != 0 && m_node != 0;
+      }
+
+    void set_end(void) throw()
+      {
+        m_node = 0;
+      }
+
+    void set_null(void) throw()
+      {
+        m_owner = 0;
+        m_node = 0;
+      }
+
+    void assert_valid(void) const throw(null_dereference,end_dereference)
+      {
+        if (null())
+          throw null_dereference("stlplus::safe_iterator");
+        if (end())
+          throw end_dereference("stlplus::safe_iterator");
+      }
+
+    void assert_non_null(void) const throw(null_dereference)
+      {
+        if (null())
+          throw null_dereference("stlplus::safe_iterator");
+      }
+
+    void assert_owner(const O* owner) const throw(wrong_object)
+      {
+        if (owner != m_owner)
+          throw wrong_object("stlplus::safe_iterator");
+      }
+  };
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Master Iterator
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // construct a valid iterator
+  template<typename O, typename N>
+  master_iterator<O,N>::master_iterator(const O* owner, N* node) throw() :
+    m_body(new safe_iterator_body<O,N>(owner,node))
+  {
+  }
+
+  // destructor - disconnect all iterators from the node
+  // this usually happens when the node is deleted and must invalidate all aliases
+  template<typename O, typename N>
+  master_iterator<O,N>::~master_iterator(void) throw()
+  {
+    m_body->set_end();
+    if(m_body->decrement())
+    {
+      delete m_body;
+      m_body = 0;
+    }
+  }
+
+  // dereference
+  template<typename O, typename N>
+  N* master_iterator<O,N>::node(void) const throw()
+  {
+    return m_body->node();
+  }
+
+  template<typename O, typename N>
+  const O* master_iterator<O,N>::owner(void) const throw()
+  {
+    return m_body->owner();
+  }
+
+  // when you move a node from one owner to another, call this on the node's iterator
+  // this effectively moves all iterators to the node so that they are owned by the new owner too
+  template<typename O, typename N>
+  void master_iterator<O,N>::change_owner(const O* owner) throw()
+  {
+    m_body->change_owner(owner);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Safe Iterator
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // construct a null iterator
+  // later assignment of a valid iterator to this is done by using step
+  template<typename O, typename N>
+  safe_iterator<O,N>::safe_iterator(void) throw() : 
+    m_body(new safe_iterator_body<O,N>(0,0))
+  {
+  }
+
+  // construct a valid iterator by aliasing from the owner node's master iterator
+  template<typename O, typename N>
+  safe_iterator<O,N>::safe_iterator(const master_iterator<O,N>& r) throw() :
+    m_body(0)
+  {
+    m_body = r.m_body;
+    m_body->increment();
+  }
+
+  // construct a valid iterator by aliasing from the owner node's master iterator
+  template<typename O, typename N>
+  safe_iterator<O,N>::safe_iterator(const safe_iterator<O,N>& r) throw() :
+    m_body(0)
+  {
+    m_body = r.m_body;
+    m_body->increment();
+  }
+
+  // assignment implements dealiasing followed by aliasing
+  template<typename O, typename N>
+  safe_iterator<O,N>& safe_iterator<O,N>::operator=(const safe_iterator<O,N>& r) throw()
+  {
+    if (m_body != r.m_body)
+    {
+      if (m_body->decrement())
+        delete m_body;
+      m_body = r.m_body;
+      m_body->increment();
+    }
+    return *this;
+  }
+
+  // destructor - implements dealiasing
+  template<typename O, typename N>
+  safe_iterator<O,N>::~safe_iterator(void) throw()
+  {
+    if(m_body->decrement())
+    {
+      delete m_body;
+      m_body = 0;
+    }
+  }
+
+
+  // increment/decrement operation
+  // implements dealiasing followed by aliasing
+  template<typename O, typename N>
+  void safe_iterator<O,N>::set(const master_iterator<O,N>& r) throw()
+  {
+    if (m_body != r.m_body)
+    {
+      if (m_body->decrement())
+        delete m_body;
+      m_body = r.m_body;
+      m_body->increment();
+    }
+  }
+
+  // dereference
+  template<typename O, typename N>
+  N* safe_iterator<O,N>::node(void) const throw()
+  {
+    return m_body->node();
+  }
+
+  template<typename O, typename N>
+  const O* safe_iterator<O,N>::owner(void) const throw()
+  {
+    return m_body->owner();
+  }
+
+  // change to a null iterator - i.e. one that doees not belong to any object
+  // this does not affect any other iterators pointing to the same node
+  template<typename O, typename N>
+  void safe_iterator<O,N>::set_null(void) throw()
+  {
+    if (m_body->count() == 1)
+    {
+      // no aliases, so just make this null
+      m_body->set_null();
+    }
+    else
+    {
+      // create a new body which is null so as not to affect any other aliases
+      m_body->decrement();
+      m_body = new safe_iterator_body<O,N>(0,0);
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // operations for clients that do not have a master end iterator
+  // alternatively, have a master end iterator as part of the container
+  // and call constructor(master_end) or step(master_end)
+
+  // construct an end iterator
+  template<typename O, typename N>
+  safe_iterator<O,N>::safe_iterator(const O* owner) throw() :
+    m_body(new safe_iterator_body<O,N>(owner,0))
+  {
+  }
+
+  // change to an end iterator - e.g. as a result of incrementing off the end
+  template<typename O, typename N>
+  void safe_iterator<O,N>::set_end(void) throw()
+  {
+    if (m_body->count() == 1)
+    {
+      // no aliases, so just make this an end iterator
+      m_body->set_end();
+    }
+    else
+    {
+      // create a new body which is null so as not to affect any other aliases
+      m_body->decrement();
+      m_body = new safe_iterator_body<O,N>(owner(),0);
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // tests
+
+  // comparison
+  template<typename O, typename N>
+  bool safe_iterator<O,N>::equal(const safe_iterator<O,N>& right) const throw()
+  {
+    return compare(right) == 0;
+  }
+
+  template<typename O, typename N>
+  int safe_iterator<O,N>::compare(const safe_iterator<O,N>& right) const throw()
+  {
+    if (m_body == right.m_body) return 0;
+    return m_body->compare(right.m_body);
+  }
+
+  // a null iterator is one that has not been initialised with a value yet
+  template<typename O, typename N>
+  bool safe_iterator<O,N>::null(void) const throw()
+  {
+    return m_body->null();
+  }
+
+  // an end iterator is one that points to the end element of the list of nodes
+  template<typename O, typename N>
+  bool safe_iterator<O,N>::end(void) const throw()
+  {
+    return m_body->end();
+  }
+
+  // a valid iterator is one that can be dereferenced
+  template<typename O, typename N>
+  bool safe_iterator<O,N>::valid(void) const throw()
+  {
+    return m_body->valid();
+  }
+
+  // check the rules for a valid iterator that can be dereferenced
+  template<typename O, typename N>
+  void safe_iterator<O,N>::assert_valid(void) const throw(null_dereference,end_dereference)
+  {
+    m_body->assert_valid();
+  }
+
+  template<typename O, typename N>
+  void safe_iterator<O,N>::assert_valid(const O* owner) const throw(wrong_object,null_dereference,end_dereference)
+  {
+    m_body->assert_valid();
+    m_body->assert_owner(owner);
+  }
+
+  template<typename O, typename N>
+  void safe_iterator<O,N>::assert_non_null(void) const throw(null_dereference)
+  {
+    m_body->assert_non_null();
+  }
+
+  template<typename O, typename N>
+  void safe_iterator<O,N>::assert_owner(const O* owner) const throw(wrong_object)
+  {
+    m_body->assert_owner(owner);
+  }
+
+} // end namespace stlplus
index 08fff036eb91612865a8207b777e57deaa91e303..72d1db7e16d0bf15efed1cd6c9dba1103fd1efb3 100644 (file)
-#ifndef STLPLUS_SIMPLE_PTR\r
-#define STLPLUS_SIMPLE_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Daniel Milton, Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Daniel Milton, Andy Rushton 2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A smart pointer is a memory-managing pointer to an object. If you like, it\r
-//   is a zero-dimensional container.\r
-\r
-//   Assignment of smart pointers result in multiple aliases of the same object.\r
-//   The term alias is used to differentiate from conventional pointers because\r
-//   the semantics are different.\r
-\r
-//   Aliases can be turned into copies if the pointed-to class supports copying.\r
-\r
-//   These simple_ptr classes from DJDM have slightly different semantics than\r
-//   the smart_ptr classes of AJR. There are no cross-pointer side effects\r
-//   that occur when the pointer is cleared. The clear() function is effectively\r
-//   equivalent to the clear_unique() function of the smart_ptr. The only way\r
-//   that a "referenced" object will be deleted is if all simple_ptr's that\r
-//   reference the object are cleared (by deletion, manual clearing or reassignment).\r
-\r
-//   Also, the simple pointer cannot contain a reference to a shared null pointer\r
-//   (which occurs as a side-effect of clearing a multiply referenced object in\r
-//   the smart_ptr classes). Which means that if you have a null simple_ptr, then\r
-//   the assignment of any other null simple_ptr will NOT reassign the reference of\r
-//   any other simple_ptr. Hence, the simple_ptr class acts a little more like a\r
-//   normal pointer (with fewer side effects), with the added bonus of containment.\r
-\r
-//   Due to the way that the simple_ptr contains the data, it also allows the\r
-//   addition of various casting functions, while still keeping the managed data\r
-//   containment functionality of the underlying object. This means that you can\r
-//   have two simple_ptr's of different template types, both pointing to the same\r
-//   data (if the differing template types are derivatives of each other).\r
-\r
-//   The base class is simple_ptr_base which defines the common interface. Then\r
-//   there are three subclasses which have the same interface but different copy\r
-//   semantics:\r
-\r
-//   - simple_ptr        for simple types and classes which have copy constructors\r
-//   - simple_ptr_clone  for polymorphic class hierarchies which are copied using a clone method\r
-//   - simple_ptr_nocopy for any class that cannot or should not be copied\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include "exceptions.hpp"\r
-#include "copy_functors.hpp"\r
-#include <map>\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Base class\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename C>\r
-  class simple_ptr_base\r
-  {\r
-  public:\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // member type definitions\r
-\r
-    typedef T value_type;\r
-    typedef T& reference;\r
-    typedef const T& const_reference;\r
-    typedef C value_copy;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // constructors and destructors\r
-\r
-    // create a null pointer\r
-    simple_ptr_base(void);\r
-\r
-    // create a pointer containing a *copy* of the object using the template parameter C\r
-    // this copy is taken because the pointer class maintains a dynamically allocated object\r
-    // and the T& may not be (usually is not) dynamically allocated\r
-    explicit simple_ptr_base(const T& data) throw(illegal_copy);\r
-\r
-    // create a pointer containing a dynamically created object\r
-    // Note: the object must be allocated *by the user* with new\r
-    // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))\r
-    explicit simple_ptr_base(T* data);\r
-\r
-    // copy constructor implements aliasing so no copy is made\r
-    // note that the copy constructor should NOT be explicit, as this breaks\r
-    // the returning of pointer objects from functions (at least within GCC 4.4)\r
-    simple_ptr_base(const simple_ptr_base<T,C>& r);\r
-\r
-    // assignment operator - required, else the output of GCC suffers segmentation faults\r
-    simple_ptr_base<T,C>& operator=(const simple_ptr_base<T,C>& r);\r
-\r
-    // destructor decrements the reference count and delete only when the last reference is destroyed\r
-    ~simple_ptr_base(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // logical tests to see if there is anything contained in the pointer since it can be null\r
-\r
-    // there are two forms:explicit and implicit\r
-    // implicit: if(!r) or if(r)\r
-    // explicit: if(r.null()) or if(r.present())\r
-    operator bool(void) const;\r
-    bool operator!(void) const;\r
-    bool present(void) const;\r
-    bool null(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // dereference operators and functions\r
-\r
-    // dereference the smart pointer to get the object - use in the form *p1\r
-    T& operator*(void) throw(null_dereference);\r
-    const T& operator*(void) const throw(null_dereference);\r
-\r
-    // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()\r
-    T* operator->(void) throw(null_dereference);\r
-    const T* operator->(void) const throw(null_dereference);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // explicit function forms of the above assignment and dereference operators\r
-\r
-    // set the value - note that this does a copy using the C template parameter\r
-    void set_value(const T& data) throw(illegal_copy);\r
-    // get the value\r
-    T& value(void) throw(null_dereference);\r
-    const T& value(void) const throw(null_dereference);\r
-\r
-    // set the pointer\r
-    // deletes the previous pointer and adopts the passed pointer instead\r
-    // Note: the object must be allocated *by the user* with new\r
-    // Warning: it is very easy to break the memory management with this operation\r
-    void set(T* data = 0);\r
-    // get the pointer\r
-    T* pointer(void);\r
-    const T* pointer(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // functions to manage aliases\r
-\r
-    // make this an alias of the passed object\r
-    void alias(const simple_ptr_base<T,C>&);\r
-\r
-    // test whether two pointers point to the same object(known as aliasing the object)\r
-    // used in the form if(a.aliases(b))\r
-    bool aliases(const simple_ptr_base<T,C>&) const;\r
-\r
-    // find the number of aliases - used when you need to know whether an\r
-    // object is still referred to from elsewhere (rare!)\r
-    unsigned alias_count(void) const;\r
-\r
-    // clear the reference to the object, but only delete the object if there are no\r
-    // other references to that object. Hence, this does not affect other pointers\r
-    // that are pointing to the same object.\r
-    void clear(void);\r
-\r
-    // This is just an alias of the clear() function, provided for completeness of\r
-    // the interface when acting as a replacement for the smart_ptr classes\r
-    void clear_unique(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // functions that involve copying\r
-\r
-    // these functions use the copy functor passed as the template parameter C\r
-    // to copy the object with the right copy semantics. If the copy functor\r
-    // is no_copy, an exception will be thrown.\r
-\r
-    // make this pointer unique with respect to any other references to the same object\r
-    // if this pointer is already unique, it does nothing - otherwise it copies the object\r
-    void make_unique(void) throw(illegal_copy);\r
-\r
-    // make this pointer a unique copy of the parameter\r
-    // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2\r
-    void copy(const simple_ptr_base<T,C>&) throw(illegal_copy);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // functions that involve casting\r
-\r
-#ifdef STLPLUS_MEMBER_TEMPLATES\r
-\r
-    // dynamic cast of underlying pointer to a derived/parent\r
-    template<typename T2> simple_ptr_base<T2,C> dyn_cast(void) const;\r
-\r
-    // static cast of underlying pointer to a derived/parent\r
-    template<typename T2> simple_ptr_base<T2,C> stat_cast(void) const;\r
-\r
-    // cast of underlying pointer to a base - while keeping the same ref-counted object\r
-    template<typename T2> simple_ptr_base<T2,C> cast(void) const;\r
-\r
-#endif\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-\r
-  protected:\r
-    T* m_pointer;\r
-    unsigned* m_count;\r
-\r
-  public:\r
-    // internal use only - had to make them public because they need to be\r
-    // accessed by routines that could not be made friends\r
-    // can't have a handle due to the way the simple pointer stores it's data\r
-    // in separate counter and pointer objects\r
-    unsigned* _count(void) const;\r
-    T* _pointer(void) const;\r
-    void _make_alias(T* pointer, unsigned* count);\r
-\r
-  private:\r
-    void increment(void);\r
-    bool decrement(void);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // simple_ptr        for simple types and classes which have copy constructors\r
-\r
-  template <typename T>\r
-  class simple_ptr : public simple_ptr_base<T, constructor_copy<T> >\r
-  {\r
-  public:\r
-    simple_ptr(void) {}\r
-    explicit simple_ptr(const T& data) : simple_ptr_base<T, constructor_copy<T> >(data) {}\r
-    explicit simple_ptr(T* data) : simple_ptr_base<T, constructor_copy<T> >(data) {}\r
-    simple_ptr<T>& operator=(const T& data) {set_value(data); return *this;}\r
-    simple_ptr<T>& operator=(T* data) {set(data); return *this;}\r
-    ~simple_ptr(void) {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr_clone  for polymorphic class hierarchies which have a clone method\r
-\r
-  template <typename T>\r
-  class simple_ptr_clone : public simple_ptr_base<T, clone_copy<T> >\r
-  {\r
-  public:\r
-    simple_ptr_clone(void) {}\r
-    explicit simple_ptr_clone(const T& data) : simple_ptr_base<T, clone_copy<T> >(data) {}\r
-    explicit simple_ptr_clone(T* data) : simple_ptr_base<T, clone_copy<T> >(data) {}\r
-    simple_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}\r
-    simple_ptr_clone<T>& operator=(T* data) {set(data); return *this;}\r
-    ~simple_ptr_clone(void) {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr_nocopy for any class that cannot or should not be copied\r
-\r
-  template <typename T>\r
-  class simple_ptr_nocopy : public simple_ptr_base<T, no_copy<T> >\r
-  {\r
-  public:\r
-    simple_ptr_nocopy(void) {}\r
-    explicit simple_ptr_nocopy(const T& data) : simple_ptr_base<T, no_copy<T> >(data) {}\r
-    explicit simple_ptr_nocopy(T* data) : simple_ptr_base<T, no_copy<T> >(data) {}\r
-    simple_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}\r
-    simple_ptr_nocopy<T>& operator=(T* data) {set(data); return *this;}\r
-    ~simple_ptr_nocopy(void) {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "simple_ptr.tpp"\r
-#endif\r
+#ifndef STLPLUS_SIMPLE_PTR
+#define STLPLUS_SIMPLE_PTR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Daniel Milton, Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Daniel Milton, Andy Rushton 2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A smart pointer is a memory-managing pointer to an object. If you like, it
+//   is a zero-dimensional container.
+
+//   Assignment of smart pointers result in multiple aliases of the same object.
+//   The term alias is used to differentiate from conventional pointers because
+//   the semantics are different.
+
+//   Aliases can be turned into copies if the pointed-to class supports copying.
+
+//   These simple_ptr classes from DJDM have slightly different semantics than
+//   the smart_ptr classes of AJR. There are no cross-pointer side effects
+//   that occur when the pointer is cleared. The clear() function is effectively
+//   equivalent to the clear_unique() function of the smart_ptr. The only way
+//   that a "referenced" object will be deleted is if all simple_ptr's that
+//   reference the object are cleared (by deletion, manual clearing or reassignment).
+
+//   Also, the simple pointer cannot contain a reference to a shared null pointer
+//   (which occurs as a side-effect of clearing a multiply referenced object in
+//   the smart_ptr classes). Which means that if you have a null simple_ptr, then
+//   the assignment of any other null simple_ptr will NOT reassign the reference of
+//   any other simple_ptr. Hence, the simple_ptr class acts a little more like a
+//   normal pointer (with fewer side effects), with the added bonus of containment.
+
+//   Due to the way that the simple_ptr contains the data, it also allows the
+//   addition of various casting functions, while still keeping the managed data
+//   containment functionality of the underlying object. This means that you can
+//   have two simple_ptr's of different template types, both pointing to the same
+//   data (if the differing template types are derivatives of each other).
+
+//   The base class is simple_ptr_base which defines the common interface. Then
+//   there are three subclasses which have the same interface but different copy
+//   semantics:
+
+//   - simple_ptr        for simple types and classes which have copy constructors
+//   - simple_ptr_clone  for polymorphic class hierarchies which are copied using a clone method
+//   - simple_ptr_nocopy for any class that cannot or should not be copied
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include "exceptions.hpp"
+#include "copy_functors.hpp"
+#include <map>
+#include <string>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Base class
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T, typename C>
+  class simple_ptr_base
+  {
+  public:
+    //////////////////////////////////////////////////////////////////////////////
+    // member type definitions
+
+    typedef T value_type;
+    typedef T& reference;
+    typedef const T& const_reference;
+    typedef C value_copy;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // constructors and destructors
+
+    // create a null pointer
+    simple_ptr_base(void);
+
+    // create a pointer containing a *copy* of the object using the template parameter C
+    // this copy is taken because the pointer class maintains a dynamically allocated object
+    // and the T& may not be (usually is not) dynamically allocated
+    explicit simple_ptr_base(const T& data) throw(illegal_copy);
+
+    // create a pointer containing a dynamically created object
+    // Note: the object must be allocated *by the user* with new
+    // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))
+    explicit simple_ptr_base(T* data);
+
+    // copy constructor implements aliasing so no copy is made
+    // note that the copy constructor should NOT be explicit, as this breaks
+    // the returning of pointer objects from functions (at least within GCC 4.4)
+    simple_ptr_base(const simple_ptr_base<T,C>& r);
+
+    // assignment operator - required, else the output of GCC suffers segmentation faults
+    simple_ptr_base<T,C>& operator=(const simple_ptr_base<T,C>& r);
+
+    // destructor decrements the reference count and delete only when the last reference is destroyed
+    ~simple_ptr_base(void);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // logical tests to see if there is anything contained in the pointer since it can be null
+
+    // there are two forms:explicit and implicit
+    // implicit: if(!r) or if(r)
+    // explicit: if(r.null()) or if(r.present())
+    operator bool(void) const;
+    bool operator!(void) const;
+    bool present(void) const;
+    bool null(void) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // dereference operators and functions
+
+    // dereference the smart pointer to get the object - use in the form *p1
+    T& operator*(void) throw(null_dereference);
+    const T& operator*(void) const throw(null_dereference);
+
+    // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
+    T* operator->(void) throw(null_dereference);
+    const T* operator->(void) const throw(null_dereference);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // explicit function forms of the above assignment and dereference operators
+
+    // set the value - note that this does a copy using the C template parameter
+    void set_value(const T& data) throw(illegal_copy);
+    // get the value
+    T& value(void) throw(null_dereference);
+    const T& value(void) const throw(null_dereference);
+
+    // set the pointer
+    // deletes the previous pointer and adopts the passed pointer instead
+    // Note: the object must be allocated *by the user* with new
+    // Warning: it is very easy to break the memory management with this operation
+    void set(T* data = 0);
+    // get the pointer
+    T* pointer(void);
+    const T* pointer(void) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // functions to manage aliases
+
+    // make this an alias of the passed object
+    void alias(const simple_ptr_base<T,C>&);
+
+    // test whether two pointers point to the same object(known as aliasing the object)
+    // used in the form if(a.aliases(b))
+    bool aliases(const simple_ptr_base<T,C>&) const;
+
+    // find the number of aliases - used when you need to know whether an
+    // object is still referred to from elsewhere (rare!)
+    unsigned alias_count(void) const;
+
+    // clear the reference to the object, but only delete the object if there are no
+    // other references to that object. Hence, this does not affect other pointers
+    // that are pointing to the same object.
+    void clear(void);
+
+    // This is just an alias of the clear() function, provided for completeness of
+    // the interface when acting as a replacement for the smart_ptr classes
+    void clear_unique(void);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // functions that involve copying
+
+    // these functions use the copy functor passed as the template parameter C
+    // to copy the object with the right copy semantics. If the copy functor
+    // is no_copy, an exception will be thrown.
+
+    // make this pointer unique with respect to any other references to the same object
+    // if this pointer is already unique, it does nothing - otherwise it copies the object
+    void make_unique(void) throw(illegal_copy);
+
+    // make this pointer a unique copy of the parameter
+    // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
+    void copy(const simple_ptr_base<T,C>&) throw(illegal_copy);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // functions that involve casting
+
+#ifdef STLPLUS_MEMBER_TEMPLATES
+
+    // dynamic cast of underlying pointer to a derived/parent
+    template<typename T2> simple_ptr_base<T2,C> dyn_cast(void) const;
+
+    // static cast of underlying pointer to a derived/parent
+    template<typename T2> simple_ptr_base<T2,C> stat_cast(void) const;
+
+    // cast of underlying pointer to a base - while keeping the same ref-counted object
+    template<typename T2> simple_ptr_base<T2,C> cast(void) const;
+
+#endif
+
+    //////////////////////////////////////////////////////////////////////////////
+
+  protected:
+    T* m_pointer;
+    unsigned* m_count;
+
+  public:
+    // internal use only - had to make them public because they need to be
+    // accessed by routines that could not be made friends
+    // can't have a handle due to the way the simple pointer stores it's data
+    // in separate counter and pointer objects
+    unsigned* _count(void) const;
+    T* _pointer(void) const;
+    void _make_alias(T* pointer, unsigned* count);
+
+  private:
+    void increment(void);
+    bool decrement(void);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // simple_ptr        for simple types and classes which have copy constructors
+
+  template <typename T>
+  class simple_ptr : public simple_ptr_base<T, constructor_copy<T> >
+  {
+  public:
+    simple_ptr(void) {}
+    explicit simple_ptr(const T& data) : simple_ptr_base<T, constructor_copy<T> >(data) {}
+    explicit simple_ptr(T* data) : simple_ptr_base<T, constructor_copy<T> >(data) {}
+    simple_ptr<T>& operator=(const T& data) {set_value(data); return *this;}
+    simple_ptr<T>& operator=(T* data) {set(data); return *this;}
+    ~simple_ptr(void) {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // smart_ptr_clone  for polymorphic class hierarchies which have a clone method
+
+  template <typename T>
+  class simple_ptr_clone : public simple_ptr_base<T, clone_copy<T> >
+  {
+  public:
+    simple_ptr_clone(void) {}
+    explicit simple_ptr_clone(const T& data) : simple_ptr_base<T, clone_copy<T> >(data) {}
+    explicit simple_ptr_clone(T* data) : simple_ptr_base<T, clone_copy<T> >(data) {}
+    simple_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}
+    simple_ptr_clone<T>& operator=(T* data) {set(data); return *this;}
+    ~simple_ptr_clone(void) {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // smart_ptr_nocopy for any class that cannot or should not be copied
+
+  template <typename T>
+  class simple_ptr_nocopy : public simple_ptr_base<T, no_copy<T> >
+  {
+  public:
+    simple_ptr_nocopy(void) {}
+    explicit simple_ptr_nocopy(const T& data) : simple_ptr_base<T, no_copy<T> >(data) {}
+    explicit simple_ptr_nocopy(T* data) : simple_ptr_base<T, no_copy<T> >(data) {}
+    simple_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}
+    simple_ptr_nocopy<T>& operator=(T* data) {set(data); return *this;}
+    ~simple_ptr_nocopy(void) {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "simple_ptr.tpp"
+#endif
index 13f55967c7ec00ea4c9150524e0589b4c95dd445..ead6744035fe76fe087ceb32928789fe94802840 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Daniel Milton\r
-//   Copyright: (c) Daniel Milton           2002-2009\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // simple_ptr_base class\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // constructors, assignments and destructors\r
-\r
-  // create a null pointer\r
-  template <typename T, typename C>\r
-  simple_ptr_base<T,C>::simple_ptr_base(void) :\r
-    m_pointer(0),\r
-    m_count(new unsigned(1))\r
-  {\r
-  }\r
-\r
-  // create a pointer containing a *copy* of the object pointer\r
-  template <typename T, typename C>\r
-  simple_ptr_base<T,C>::simple_ptr_base(const T& data) throw(illegal_copy) :\r
-    m_pointer(C()(data)),\r
-    m_count(new unsigned(1))\r
-  {\r
-  }\r
-\r
-  // create a pointer containing a dynamically created object\r
-  // Note: the object must be allocated *by the user* with new\r
-  // constructor form - must be called in the form simple_ptr<type> x(new type(args))\r
-  template <typename T, typename C>\r
-  simple_ptr_base<T,C>::simple_ptr_base(T* data) :\r
-    m_pointer(data),\r
-    m_count(new unsigned(1))\r
-  {\r
-  }\r
-\r
-  // copy constructor implements counted referencing - no copy is made\r
-  template <typename T, typename C>\r
-  simple_ptr_base<T,C>::simple_ptr_base(const simple_ptr_base<T,C>& r) :\r
-    m_pointer(r.m_pointer),\r
-    m_count(r.m_count)\r
-  {\r
-    increment();\r
-  }\r
-\r
-  // assignment operator - required, else the output of GCC suffers segmentation faults\r
-  template <typename T, typename C>\r
-  simple_ptr_base<T,C>& simple_ptr_base<T,C>::operator=(const simple_ptr_base<T,C>& r)\r
-  {\r
-    alias(r);\r
-    return *this;\r
-  }\r
-\r
-  // destructor decrements the reference count and delete only when the last reference is destroyed\r
-  template <typename T, typename C>\r
-  simple_ptr_base<T,C>::~simple_ptr_base(void)\r
-  {\r
-    if(decrement()) \r
-    {\r
-      delete m_pointer;\r
-      delete m_count;\r
-    }\r
-  }\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // logical tests to see if there is anything contained in the pointer since it can be null\r
-\r
-  template <typename T, typename C>\r
-  bool simple_ptr_base<T,C>::null(void) const\r
-  {\r
-    return m_pointer==0;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  bool simple_ptr_base<T,C>::present(void) const\r
-  {\r
-    return m_pointer!=0;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  bool simple_ptr_base<T,C>::operator!(void) const\r
-  {\r
-    return m_pointer==0;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  simple_ptr_base<T,C>::operator bool(void) const\r
-  {\r
-    return m_pointer!=0;\r
-  }\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // dereference operators and functions\r
-\r
-  template <typename T, typename C>\r
-  T& simple_ptr_base<T,C>::operator*(void) throw(null_dereference)\r
-  {\r
-    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator*");\r
-    return *m_pointer;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T& simple_ptr_base<T,C>::operator*(void) const throw(null_dereference)\r
-  {\r
-    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator*");\r
-    return *m_pointer;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  T* simple_ptr_base<T,C>::operator->(void) throw(null_dereference)\r
-  {\r
-    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator->");\r
-    return m_pointer;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T* simple_ptr_base<T,C>::operator->(void) const throw(null_dereference)\r
-  {\r
-    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator->");\r
-    return m_pointer;\r
-  }\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // explicit function forms of the above assignment dereference operators\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::set_value(const T& data) throw(illegal_copy)\r
-  {\r
-    set(C()(data));\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  T& simple_ptr_base<T,C>::value(void) throw(null_dereference)\r
-  {\r
-    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::value");\r
-    return *m_pointer;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T& simple_ptr_base<T,C>::value(void) const throw(null_dereference)\r
-  {\r
-    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::value");\r
-    return *m_pointer;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::set(T* data)\r
-  {\r
-    unsigned& count = *m_count;\r
-    if (count<=1)\r
-      delete m_pointer;\r
-    else\r
-    {\r
-      --count;\r
-      m_count = new unsigned(1);\r
-    }\r
-    m_pointer = data;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  T* simple_ptr_base<T,C>::pointer(void)\r
-  {\r
-    return m_pointer;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T* simple_ptr_base<T,C>::pointer(void) const\r
-  {\r
-    return m_pointer;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // functions to manage counted referencing\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::increment(void)\r
-  {\r
-    ++(*m_count);\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  bool simple_ptr_base<T,C>::decrement(void)\r
-  {\r
-    unsigned& count = *m_count;\r
-    --count;\r
-    return count == 0;\r
-  }\r
-\r
-  // make this an alias of the passed object\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::alias(const simple_ptr_base<T,C>& r)\r
-  {\r
-    // make it alias-copy safe - this means that I don't try to do the\r
-    // assignment if r is either the same object or an alias of it\r
-    if (m_pointer==r.m_pointer) return;\r
-    if(decrement()) {\r
-      delete m_pointer;\r
-      delete m_count;\r
-    }\r
-    m_pointer = r.m_pointer;\r
-    m_count = r.m_count;\r
-    increment();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  bool simple_ptr_base<T,C>::aliases(const simple_ptr_base<T,C>& r) const\r
-  {\r
-    return m_count == r.m_count;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  unsigned simple_ptr_base<T,C>::alias_count(void) const\r
-  {\r
-    return *m_count;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::clear(void)\r
-  {\r
-    set(0);\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::clear_unique(void)\r
-  {\r
-    set(0);    // no difference between clear and clear_unique with the simple_ptr\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::make_unique(void) throw(illegal_copy)\r
-  {\r
-    unsigned& count = *m_count;\r
-    if (count <= 1) return;\r
-    --count;\r
-    if (m_pointer) m_pointer = C()(*m_pointer);\r
-    m_count = new unsigned(1);\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::copy(const simple_ptr_base<T,C>& data) throw(illegal_copy)\r
-  {\r
-    alias(data);\r
-    make_unique();\r
-  }\r
-\r
-#ifdef STLPLUS_MEMBER_TEMPLATES\r
-\r
-  // dynamic cast of underlying pointer to a derived/parent\r
-  template <typename T, typename C>\r
-  template <typename T2>\r
-  simple_ptr_base<T2,C> simple_ptr_base<T,C>::dyn_cast(void) const\r
-  {\r
-    simple_ptr_base<T2,C> rtn;\r
-    rtn.m_pointer = dynamic_cast<T2*>(m_pointer);\r
-    if (rtn.m_pointer) {\r
-      delete rtn.m_count;\r
-      rtn.m_count = m_count;\r
-      rtn.increment();\r
-    }\r
-    return rtn;\r
-  }\r
-\r
-  // static cast of underlying pointer to a derived/parent\r
-  template <typename T, typename C>\r
-  template <typename T2>\r
-  simple_ptr_base<T2,C> simple_ptr_base<T,C>::stat_cast(void) const\r
-  {\r
-    simple_ptr_base<T2,C> rtn;\r
-    rtn.m_pointer = static_cast<T2*>(m_pointer);\r
-    if (rtn.m_pointer) {\r
-      delete rtn.m_count;\r
-      rtn.m_count = m_count;\r
-      rtn.increment();\r
-    }\r
-    return rtn;\r
-  }\r
-\r
-  // cast of underlying pointer to a base - while keeping the same ref-counted object\r
-  template <typename T, typename C>\r
-  template <typename T2>\r
-  simple_ptr_base<T2,C> simple_ptr_base<T,C>::cast(void) const\r
-  {\r
-    simple_ptr_base<T2,C> rtn;\r
-    rtn.m_pointer = (T2*)m_pointer;\r
-    if (rtn.m_pointer) {\r
-      delete rtn.m_count;\r
-      rtn.m_count = m_count;\r
-      rtn.increment();\r
-    }\r
-    return rtn;\r
-  }\r
-\r
-#endif\r
-\r
-  // internal function for distinguishing unique simple_ptr objects\r
-  // used for example in persistence routines\r
-\r
-  template <typename T, typename C>\r
-  unsigned* simple_ptr_base<T,C>::_count(void) const\r
-  {\r
-    return m_count;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  T* simple_ptr_base<T,C>::_pointer(void) const\r
-  {\r
-    return m_pointer;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void simple_ptr_base<T,C>::_make_alias(T* pointer, unsigned* count)\r
-  {\r
-    // make it alias-copy safe - this means that I don't try to do the\r
-    // assignment if r is either the same object or an alias of it\r
-    if (m_count != count)\r
-    {\r
-      if(decrement())\r
-      {\r
-        delete m_pointer;\r
-        delete m_count;\r
-      }\r
-      m_pointer = pointer;\r
-      m_count = count;\r
-      increment();\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Daniel Milton
+//   Copyright: (c) Daniel Milton           2002-2009
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // simple_ptr_base class
+  ////////////////////////////////////////////////////////////////////////////////
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // constructors, assignments and destructors
+
+  // create a null pointer
+  template <typename T, typename C>
+  simple_ptr_base<T,C>::simple_ptr_base(void) :
+    m_pointer(0),
+    m_count(new unsigned(1))
+  {
+  }
+
+  // create a pointer containing a *copy* of the object pointer
+  template <typename T, typename C>
+  simple_ptr_base<T,C>::simple_ptr_base(const T& data) throw(illegal_copy) :
+    m_pointer(C()(data)),
+    m_count(new unsigned(1))
+  {
+  }
+
+  // create a pointer containing a dynamically created object
+  // Note: the object must be allocated *by the user* with new
+  // constructor form - must be called in the form simple_ptr<type> x(new type(args))
+  template <typename T, typename C>
+  simple_ptr_base<T,C>::simple_ptr_base(T* data) :
+    m_pointer(data),
+    m_count(new unsigned(1))
+  {
+  }
+
+  // copy constructor implements counted referencing - no copy is made
+  template <typename T, typename C>
+  simple_ptr_base<T,C>::simple_ptr_base(const simple_ptr_base<T,C>& r) :
+    m_pointer(r.m_pointer),
+    m_count(r.m_count)
+  {
+    increment();
+  }
+
+  // assignment operator - required, else the output of GCC suffers segmentation faults
+  template <typename T, typename C>
+  simple_ptr_base<T,C>& simple_ptr_base<T,C>::operator=(const simple_ptr_base<T,C>& r)
+  {
+    alias(r);
+    return *this;
+  }
+
+  // destructor decrements the reference count and delete only when the last reference is destroyed
+  template <typename T, typename C>
+  simple_ptr_base<T,C>::~simple_ptr_base(void)
+  {
+    if(decrement()) 
+    {
+      delete m_pointer;
+      delete m_count;
+    }
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // logical tests to see if there is anything contained in the pointer since it can be null
+
+  template <typename T, typename C>
+  bool simple_ptr_base<T,C>::null(void) const
+  {
+    return m_pointer==0;
+  }
+
+  template <typename T, typename C>
+  bool simple_ptr_base<T,C>::present(void) const
+  {
+    return m_pointer!=0;
+  }
+
+  template <typename T, typename C>
+  bool simple_ptr_base<T,C>::operator!(void) const
+  {
+    return m_pointer==0;
+  }
+
+  template <typename T, typename C>
+  simple_ptr_base<T,C>::operator bool(void) const
+  {
+    return m_pointer!=0;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // dereference operators and functions
+
+  template <typename T, typename C>
+  T& simple_ptr_base<T,C>::operator*(void) throw(null_dereference)
+  {
+    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator*");
+    return *m_pointer;
+  }
+
+  template <typename T, typename C>
+  const T& simple_ptr_base<T,C>::operator*(void) const throw(null_dereference)
+  {
+    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator*");
+    return *m_pointer;
+  }
+
+  template <typename T, typename C>
+  T* simple_ptr_base<T,C>::operator->(void) throw(null_dereference)
+  {
+    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator->");
+    return m_pointer;
+  }
+
+  template <typename T, typename C>
+  const T* simple_ptr_base<T,C>::operator->(void) const throw(null_dereference)
+  {
+    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::operator->");
+    return m_pointer;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // explicit function forms of the above assignment dereference operators
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::set_value(const T& data) throw(illegal_copy)
+  {
+    set(C()(data));
+  }
+
+  template <typename T, typename C>
+  T& simple_ptr_base<T,C>::value(void) throw(null_dereference)
+  {
+    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::value");
+    return *m_pointer;
+  }
+
+  template <typename T, typename C>
+  const T& simple_ptr_base<T,C>::value(void) const throw(null_dereference)
+  {
+    if (!m_pointer) throw null_dereference("null pointer dereferenced in simple_ptr::value");
+    return *m_pointer;
+  }
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::set(T* data)
+  {
+    unsigned& count = *m_count;
+    if (count<=1)
+      delete m_pointer;
+    else
+    {
+      --count;
+      m_count = new unsigned(1);
+    }
+    m_pointer = data;
+  }
+
+  template <typename T, typename C>
+  T* simple_ptr_base<T,C>::pointer(void)
+  {
+    return m_pointer;
+  }
+
+  template <typename T, typename C>
+  const T* simple_ptr_base<T,C>::pointer(void) const
+  {
+    return m_pointer;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // functions to manage counted referencing
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::increment(void)
+  {
+    ++(*m_count);
+  }
+
+  template <typename T, typename C>
+  bool simple_ptr_base<T,C>::decrement(void)
+  {
+    unsigned& count = *m_count;
+    --count;
+    return count == 0;
+  }
+
+  // make this an alias of the passed object
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::alias(const simple_ptr_base<T,C>& r)
+  {
+    // make it alias-copy safe - this means that I don't try to do the
+    // assignment if r is either the same object or an alias of it
+    if (m_pointer==r.m_pointer) return;
+    if(decrement()) {
+      delete m_pointer;
+      delete m_count;
+    }
+    m_pointer = r.m_pointer;
+    m_count = r.m_count;
+    increment();
+  }
+
+  template <typename T, typename C>
+  bool simple_ptr_base<T,C>::aliases(const simple_ptr_base<T,C>& r) const
+  {
+    return m_count == r.m_count;
+  }
+
+  template <typename T, typename C>
+  unsigned simple_ptr_base<T,C>::alias_count(void) const
+  {
+    return *m_count;
+  }
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::clear(void)
+  {
+    set(0);
+  }
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::clear_unique(void)
+  {
+    set(0);    // no difference between clear and clear_unique with the simple_ptr
+  }
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::make_unique(void) throw(illegal_copy)
+  {
+    unsigned& count = *m_count;
+    if (count <= 1) return;
+    --count;
+    if (m_pointer) m_pointer = C()(*m_pointer);
+    m_count = new unsigned(1);
+  }
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::copy(const simple_ptr_base<T,C>& data) throw(illegal_copy)
+  {
+    alias(data);
+    make_unique();
+  }
+
+#ifdef STLPLUS_MEMBER_TEMPLATES
+
+  // dynamic cast of underlying pointer to a derived/parent
+  template <typename T, typename C>
+  template <typename T2>
+  simple_ptr_base<T2,C> simple_ptr_base<T,C>::dyn_cast(void) const
+  {
+    simple_ptr_base<T2,C> rtn;
+    rtn.m_pointer = dynamic_cast<T2*>(m_pointer);
+    if (rtn.m_pointer) {
+      delete rtn.m_count;
+      rtn.m_count = m_count;
+      rtn.increment();
+    }
+    return rtn;
+  }
+
+  // static cast of underlying pointer to a derived/parent
+  template <typename T, typename C>
+  template <typename T2>
+  simple_ptr_base<T2,C> simple_ptr_base<T,C>::stat_cast(void) const
+  {
+    simple_ptr_base<T2,C> rtn;
+    rtn.m_pointer = static_cast<T2*>(m_pointer);
+    if (rtn.m_pointer) {
+      delete rtn.m_count;
+      rtn.m_count = m_count;
+      rtn.increment();
+    }
+    return rtn;
+  }
+
+  // cast of underlying pointer to a base - while keeping the same ref-counted object
+  template <typename T, typename C>
+  template <typename T2>
+  simple_ptr_base<T2,C> simple_ptr_base<T,C>::cast(void) const
+  {
+    simple_ptr_base<T2,C> rtn;
+    rtn.m_pointer = (T2*)m_pointer;
+    if (rtn.m_pointer) {
+      delete rtn.m_count;
+      rtn.m_count = m_count;
+      rtn.increment();
+    }
+    return rtn;
+  }
+
+#endif
+
+  // internal function for distinguishing unique simple_ptr objects
+  // used for example in persistence routines
+
+  template <typename T, typename C>
+  unsigned* simple_ptr_base<T,C>::_count(void) const
+  {
+    return m_count;
+  }
+
+  template <typename T, typename C>
+  T* simple_ptr_base<T,C>::_pointer(void) const
+  {
+    return m_pointer;
+  }
+
+  template <typename T, typename C>
+  void simple_ptr_base<T,C>::_make_alias(T* pointer, unsigned* count)
+  {
+    // make it alias-copy safe - this means that I don't try to do the
+    // assignment if r is either the same object or an alias of it
+    if (m_count != count)
+    {
+      if(decrement())
+      {
+        delete m_pointer;
+        delete m_count;
+      }
+      m_pointer = pointer;
+      m_count = count;
+      increment();
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
index 2d37e2e4314f5f7fc9a3539f2a23f89e75ac7a9e..0170771b663fb25ed7b73fb0dad7a23995865e68 100644 (file)
-#ifndef STLPLUS_SMART_PTR\r
-#define STLPLUS_SMART_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A smart pointer is a memory-managing pointer to an object. If you like, it\r
-//   is a zero-dimensional container.\r
-\r
-//   Assignment of smart pointers result in multiple aliases of the same object.\r
-//   The term alias is used to differentiate from conventional pointers because\r
-//   the semantics are different.\r
-\r
-//   Aliases can be turned into copies if the pointed-to class supports copying.\r
-\r
-//   The base class is smart_ptr_base which defines the common interface. Then\r
-//   there are three subclasses which have the same interface but different copy\r
-//   semantics:\r
-\r
-//   - smart_ptr        for simple types and classes which have copy constructors\r
-//   - smart_ptr_clone  for polymorphic class hierarchies which are copied using a clone method\r
-//   - smart_ptr_nocopy for any class that cannot or should not be copied\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-#include "exceptions.hpp"\r
-#include "copy_functors.hpp"\r
-#include <map>\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internals\r
-\r
-  template<typename T> class smart_ptr_holder;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Base class\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename C>\r
-  class smart_ptr_base\r
-  {\r
-  public:\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // member type definitions\r
-\r
-    typedef T value_type;\r
-    typedef T& reference;\r
-    typedef const T& const_reference;\r
-    typedef C value_copy;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // constructors and destructors\r
-\r
-    // create a null pointer\r
-    smart_ptr_base(void);\r
-\r
-    // create a pointer containing a *copy* of the object using the template parameter C\r
-    // this copy is taken because the pointer class maintains a dynamically allocated object\r
-    // and the T& may not be (usually is not) dynamically allocated\r
-    explicit smart_ptr_base(const T& data) throw(illegal_copy);\r
-\r
-    // create a pointer containing a dynamically created object\r
-    // Note: the object must be allocated *by the user* with new\r
-    // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))\r
-    explicit smart_ptr_base(T* data);\r
-\r
-    // copy constructor implements aliasing so no copy is made\r
-    // note that the copy constructor should NOT be explicit, as this breaks\r
-    // the returning of pointer objects from functions (at least within GCC 4.4)\r
-    smart_ptr_base(const smart_ptr_base<T,C>& r);\r
-\r
-    // assignment operator - required, else the output of GCC suffers segmentation faults\r
-    smart_ptr_base<T,C>& operator=(const smart_ptr_base<T,C>& r);\r
-\r
-    // destructor decrements the reference count and delete only when the last reference is destroyed\r
-    ~smart_ptr_base(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // logical tests to see if there is anything contained in the pointer since it can be null\r
-\r
-    // there are two forms:explicit and implicit\r
-    // implicit: if(!r) or if(r)\r
-    // explicit: if(r.null()) or if(r.present())\r
-    operator bool(void) const;\r
-    bool operator!(void) const;\r
-    bool present(void) const;\r
-    bool null(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // dereference operators and functions\r
-\r
-    // dereference the smart pointer to get the object - use in the form *p1\r
-    T& operator*(void) throw(null_dereference);\r
-    const T& operator*(void) const throw(null_dereference);\r
-\r
-    // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()\r
-    T* operator->(void) throw(null_dereference);\r
-    const T* operator->(void) const throw(null_dereference);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // explicit function forms of the above assignment and dereference operators\r
-\r
-    // set the value - note that this does a copy using the C template parameter\r
-    void set_value(const T& data) throw(illegal_copy);\r
-    // get the value\r
-    T& value(void) throw(null_dereference);\r
-    const T& value(void) const throw(null_dereference);\r
-\r
-    // set the pointer\r
-    // deletes the previous pointer and adopts the passed pointer instead\r
-    // Note: the object must be allocated *by the user* with new\r
-    // Warning: it is very easy to break the memory management with this operation\r
-    void set(T* data = 0);\r
-    // get the pointer\r
-    T* pointer(void);\r
-    const T* pointer(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // functions to manage aliases\r
-\r
-    // make this an alias of the passed object\r
-    void alias(const smart_ptr_base<T,C>&);\r
-\r
-    // test whether two pointers point to the same object(known as aliasing the object)\r
-    // used in the form if(a.aliases(b))\r
-    bool aliases(const smart_ptr_base<T,C>&) const;\r
-\r
-    // find the number of aliases - used when you need to know whether an\r
-    // object is still referred to from elsewhere (rare!)\r
-    unsigned alias_count(void) const;\r
-\r
-    // delete the object and make the pointer null - does not make it unique\r
-    // first, so all other pointers to this will be null too\r
-    void clear(void);\r
-\r
-    // make the pointer unique and null in one step - does not affect other\r
-    // pointers that were pointing to the same object\r
-    void clear_unique(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // functions that involve copying\r
-\r
-    // these functions use the copy functor passed as the template parameter C\r
-    // to copy the object with the right copy semantics. If the copy functor\r
-    // is no_copy, an exception will be thrown.\r
-\r
-    // make this pointer unique with respect to any other references to the same object\r
-    // if this pointer is already unique, it does nothing - otherwise it copies the object\r
-    void make_unique(void) throw(illegal_copy);\r
-\r
-    // make this pointer a unique copy of the parameter\r
-    // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2\r
-    void copy(const smart_ptr_base<T,C>&) throw(illegal_copy);\r
-\r
-  protected:\r
-    smart_ptr_holder<T>* m_holder;\r
-\r
-  public:\r
-    // internal use only - had to make them public because they need to be\r
-    // accessed by routines that could not be made friends\r
-    smart_ptr_holder<T>* _handle(void) const;\r
-    void _make_alias(smart_ptr_holder<T>* handle);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr        for simple types and classes which have copy constructors\r
-\r
-  template <typename T>\r
-  class smart_ptr : public smart_ptr_base<T, constructor_copy<T> >\r
-  {\r
-  public:\r
-    smart_ptr(void) {}\r
-    explicit smart_ptr(const T& data) : smart_ptr_base<T, constructor_copy<T> >(data) {}\r
-    explicit smart_ptr(T* data) : smart_ptr_base<T, constructor_copy<T> >(data) {}\r
-    smart_ptr<T>& operator=(const T& data) {set_value(data); return *this;}\r
-    smart_ptr<T>& operator=(T* data) {set(data); return *this;}\r
-    ~smart_ptr(void) {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr_clone  for polymorphic class hierarchies which have a clone method\r
-\r
-  template <typename T>\r
-  class smart_ptr_clone : public smart_ptr_base<T, clone_copy<T> >\r
-  {\r
-  public:\r
-    smart_ptr_clone(void) {}\r
-    explicit smart_ptr_clone(const T& data) : smart_ptr_base<T, clone_copy<T> >(data) {}\r
-    explicit smart_ptr_clone(T* data) : smart_ptr_base<T, clone_copy<T> >(data) {}\r
-    smart_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}\r
-    smart_ptr_clone<T>& operator=(T* data) {set(data); return *this;}\r
-    ~smart_ptr_clone(void) {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr_nocopy for any class that cannot or should not be copied\r
-\r
-  template <typename T>\r
-  class smart_ptr_nocopy : public smart_ptr_base<T, no_copy<T> >\r
-  {\r
-  public:\r
-    smart_ptr_nocopy(void) {}\r
-    explicit smart_ptr_nocopy(const T& data) : smart_ptr_base<T, no_copy<T> >(data) {}\r
-    explicit smart_ptr_nocopy(T* data) : smart_ptr_base<T, no_copy<T> >(data) {}\r
-    smart_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}\r
-    smart_ptr_nocopy<T>& operator=(T* data) {set(data); return *this;}\r
-    ~smart_ptr_nocopy(void) {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "smart_ptr.tpp"\r
-#endif\r
+#ifndef STLPLUS_SMART_PTR
+#define STLPLUS_SMART_PTR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A smart pointer is a memory-managing pointer to an object. If you like, it
+//   is a zero-dimensional container.
+
+//   Assignment of smart pointers result in multiple aliases of the same object.
+//   The term alias is used to differentiate from conventional pointers because
+//   the semantics are different.
+
+//   Aliases can be turned into copies if the pointed-to class supports copying.
+
+//   The base class is smart_ptr_base which defines the common interface. Then
+//   there are three subclasses which have the same interface but different copy
+//   semantics:
+
+//   - smart_ptr        for simple types and classes which have copy constructors
+//   - smart_ptr_clone  for polymorphic class hierarchies which are copied using a clone method
+//   - smart_ptr_nocopy for any class that cannot or should not be copied
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+#include "exceptions.hpp"
+#include "copy_functors.hpp"
+#include <map>
+#include <string>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // internals
+
+  template<typename T> class smart_ptr_holder;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Base class
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T, typename C>
+  class smart_ptr_base
+  {
+  public:
+    //////////////////////////////////////////////////////////////////////////////
+    // member type definitions
+
+    typedef T value_type;
+    typedef T& reference;
+    typedef const T& const_reference;
+    typedef C value_copy;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // constructors and destructors
+
+    // create a null pointer
+    smart_ptr_base(void);
+
+    // create a pointer containing a *copy* of the object using the template parameter C
+    // this copy is taken because the pointer class maintains a dynamically allocated object
+    // and the T& may not be (usually is not) dynamically allocated
+    explicit smart_ptr_base(const T& data) throw(illegal_copy);
+
+    // create a pointer containing a dynamically created object
+    // Note: the object must be allocated *by the user* with new
+    // constructor form - must be called in the form smart_ptr_base<type> x(new type(args))
+    explicit smart_ptr_base(T* data);
+
+    // copy constructor implements aliasing so no copy is made
+    // note that the copy constructor should NOT be explicit, as this breaks
+    // the returning of pointer objects from functions (at least within GCC 4.4)
+    smart_ptr_base(const smart_ptr_base<T,C>& r);
+
+    // assignment operator - required, else the output of GCC suffers segmentation faults
+    smart_ptr_base<T,C>& operator=(const smart_ptr_base<T,C>& r);
+
+    // destructor decrements the reference count and delete only when the last reference is destroyed
+    ~smart_ptr_base(void);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // logical tests to see if there is anything contained in the pointer since it can be null
+
+    // there are two forms:explicit and implicit
+    // implicit: if(!r) or if(r)
+    // explicit: if(r.null()) or if(r.present())
+    operator bool(void) const;
+    bool operator!(void) const;
+    bool present(void) const;
+    bool null(void) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // dereference operators and functions
+
+    // dereference the smart pointer to get the object - use in the form *p1
+    T& operator*(void) throw(null_dereference);
+    const T& operator*(void) const throw(null_dereference);
+
+    // used as a prefix to a member access to the contained object e.g. p1->print() calls T::print()
+    T* operator->(void) throw(null_dereference);
+    const T* operator->(void) const throw(null_dereference);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // explicit function forms of the above assignment and dereference operators
+
+    // set the value - note that this does a copy using the C template parameter
+    void set_value(const T& data) throw(illegal_copy);
+    // get the value
+    T& value(void) throw(null_dereference);
+    const T& value(void) const throw(null_dereference);
+
+    // set the pointer
+    // deletes the previous pointer and adopts the passed pointer instead
+    // Note: the object must be allocated *by the user* with new
+    // Warning: it is very easy to break the memory management with this operation
+    void set(T* data = 0);
+    // get the pointer
+    T* pointer(void);
+    const T* pointer(void) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // functions to manage aliases
+
+    // make this an alias of the passed object
+    void alias(const smart_ptr_base<T,C>&);
+
+    // test whether two pointers point to the same object(known as aliasing the object)
+    // used in the form if(a.aliases(b))
+    bool aliases(const smart_ptr_base<T,C>&) const;
+
+    // find the number of aliases - used when you need to know whether an
+    // object is still referred to from elsewhere (rare!)
+    unsigned alias_count(void) const;
+
+    // delete the object and make the pointer null - does not make it unique
+    // first, so all other pointers to this will be null too
+    void clear(void);
+
+    // make the pointer unique and null in one step - does not affect other
+    // pointers that were pointing to the same object
+    void clear_unique(void);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // functions that involve copying
+
+    // these functions use the copy functor passed as the template parameter C
+    // to copy the object with the right copy semantics. If the copy functor
+    // is no_copy, an exception will be thrown.
+
+    // make this pointer unique with respect to any other references to the same object
+    // if this pointer is already unique, it does nothing - otherwise it copies the object
+    void make_unique(void) throw(illegal_copy);
+
+    // make this pointer a unique copy of the parameter
+    // useful for expressions like p1.copy(p2) which makes p1 a pointer to a unique copy of the contents of p2
+    void copy(const smart_ptr_base<T,C>&) throw(illegal_copy);
+
+  protected:
+    smart_ptr_holder<T>* m_holder;
+
+  public:
+    // internal use only - had to make them public because they need to be
+    // accessed by routines that could not be made friends
+    smart_ptr_holder<T>* _handle(void) const;
+    void _make_alias(smart_ptr_holder<T>* handle);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // smart_ptr        for simple types and classes which have copy constructors
+
+  template <typename T>
+  class smart_ptr : public smart_ptr_base<T, constructor_copy<T> >
+  {
+  public:
+    smart_ptr(void) {}
+    explicit smart_ptr(const T& data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
+    explicit smart_ptr(T* data) : smart_ptr_base<T, constructor_copy<T> >(data) {}
+    smart_ptr<T>& operator=(const T& data) {set_value(data); return *this;}
+    smart_ptr<T>& operator=(T* data) {set(data); return *this;}
+    ~smart_ptr(void) {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // smart_ptr_clone  for polymorphic class hierarchies which have a clone method
+
+  template <typename T>
+  class smart_ptr_clone : public smart_ptr_base<T, clone_copy<T> >
+  {
+  public:
+    smart_ptr_clone(void) {}
+    explicit smart_ptr_clone(const T& data) : smart_ptr_base<T, clone_copy<T> >(data) {}
+    explicit smart_ptr_clone(T* data) : smart_ptr_base<T, clone_copy<T> >(data) {}
+    smart_ptr_clone<T>& operator=(const T& data) {set_value(data); return *this;}
+    smart_ptr_clone<T>& operator=(T* data) {set(data); return *this;}
+    ~smart_ptr_clone(void) {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // smart_ptr_nocopy for any class that cannot or should not be copied
+
+  template <typename T>
+  class smart_ptr_nocopy : public smart_ptr_base<T, no_copy<T> >
+  {
+  public:
+    smart_ptr_nocopy(void) {}
+    explicit smart_ptr_nocopy(const T& data) : smart_ptr_base<T, no_copy<T> >(data) {}
+    explicit smart_ptr_nocopy(T* data) : smart_ptr_base<T, no_copy<T> >(data) {}
+    smart_ptr_nocopy<T>& operator=(const T& data) {set_value(data); return *this;}
+    smart_ptr_nocopy<T>& operator=(T* data) {set(data); return *this;}
+    ~smart_ptr_nocopy(void) {}
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "smart_ptr.tpp"
+#endif
index ce72da22879a0af1d403fa64804c11591a400ac0..3af02101e92303c3cddf66b78a4fbe70730a16e6 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internal holder data structure\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  class smart_ptr_holder\r
-  {\r
-  private:\r
-    unsigned m_count;\r
-    T* m_data;\r
-\r
-    // make these private to disallow copying because the holder doesn't know how to copy\r
-    smart_ptr_holder(const smart_ptr_holder& s) :\r
-      m_count(0), m_data(0)\r
-      {\r
-      }\r
-\r
-    smart_ptr_holder& operator=(const smart_ptr_holder& s)\r
-      {\r
-        return *this;\r
-      }\r
-\r
-  public:\r
-    smart_ptr_holder(T* p = 0) :\r
-      m_count(1), m_data(p)\r
-      {\r
-      }\r
-\r
-    ~smart_ptr_holder(void)\r
-      {\r
-        clear();\r
-      }\r
-\r
-    unsigned count(void) const\r
-      {\r
-        return m_count;\r
-      }\r
-\r
-    void increment(void)\r
-      {\r
-        ++m_count;\r
-      }\r
-\r
-    bool decrement(void)\r
-      {\r
-        --m_count;\r
-        return m_count == 0;\r
-      }\r
-\r
-    bool null(void)\r
-      {\r
-        return m_data == 0;\r
-      }\r
-\r
-    void clear(void)\r
-      {\r
-        if(m_data)\r
-          delete m_data;\r
-        m_data = 0;\r
-      }\r
-\r
-    void set(T* p = 0)\r
-      {\r
-        clear();\r
-        m_data = p;\r
-      }\r
-\r
-    T*& pointer(void)\r
-      {\r
-        return m_data;\r
-      }\r
-\r
-    const T* pointer(void) const\r
-      {\r
-        return m_data;\r
-      }\r
-\r
-    T& value(void)\r
-      {\r
-        return *m_data;\r
-      }\r
-\r
-    const T& value(void) const\r
-      {\r
-        return *m_data;\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr_base class\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // constructors, assignments and destructors\r
-\r
-  // create a null pointer\r
-  template <typename T, typename C>\r
-  smart_ptr_base<T,C>::smart_ptr_base(void) :\r
-    m_holder(new smart_ptr_holder<T>)\r
-  {\r
-  }\r
-\r
-  // create a pointer containing a *copy* of the object pointer\r
-  template <typename T, typename C>\r
-  smart_ptr_base<T,C>::smart_ptr_base(const T& data) throw(illegal_copy) :\r
-    m_holder(new smart_ptr_holder<T>)\r
-  {\r
-    m_holder->set(C()(data));\r
-  }\r
-\r
-  // create a pointer containing a dynamically created object\r
-  // Note: the object must be allocated *by the user* with new\r
-  // constructor form - must be called in the form smart_ptr<type> x(new type(args))\r
-  template <typename T, typename C>\r
-  smart_ptr_base<T,C>::smart_ptr_base(T* data) :\r
-    m_holder(new smart_ptr_holder<T>)\r
-  {\r
-    m_holder->set(data);\r
-  }\r
-\r
-  // copy constructor implements counted referencing - no copy is made\r
-  template <typename T, typename C>\r
-  smart_ptr_base<T,C>::smart_ptr_base(const smart_ptr_base<T,C>& r) :\r
-    m_holder(0)\r
-  {\r
-    m_holder = r.m_holder;\r
-    m_holder->increment();\r
-  }\r
-\r
-       // assignment operator - required, else the output of GCC suffers segmentation faults\r
-  template <typename T, typename C>\r
-  smart_ptr_base<T,C>& smart_ptr_base<T,C>::operator=(const smart_ptr_base<T,C>& r) \r
-  {\r
-    alias(r);\r
-    return *this;\r
-  }\r
-\r
-  // destructor decrements the reference count and delete only when the last reference is destroyed\r
-  template <typename T, typename C>\r
-  smart_ptr_base<T,C>::~smart_ptr_base(void)\r
-  {\r
-    if(m_holder->decrement())\r
-      delete m_holder;\r
-  }\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // logical tests to see if there is anything contained in the pointer since it can be null\r
-\r
-  template <typename T, typename C>\r
-  bool smart_ptr_base<T,C>::null(void) const\r
-  {\r
-    return m_holder->null();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  bool smart_ptr_base<T,C>::present(void) const\r
-  {\r
-    return !m_holder->null();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  bool smart_ptr_base<T,C>::operator!(void) const\r
-  {\r
-    return m_holder->null();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  smart_ptr_base<T,C>::operator bool(void) const\r
-  {\r
-    return !m_holder->null();\r
-  }\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // dereference operators and functions\r
-\r
-  template <typename T, typename C>\r
-  T& smart_ptr_base<T,C>::operator*(void) throw(null_dereference)\r
-  {\r
-    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator*");\r
-    return m_holder->value();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T& smart_ptr_base<T,C>::operator*(void) const throw(null_dereference)\r
-  {\r
-    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator*");\r
-    return m_holder->value();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  T* smart_ptr_base<T,C>::operator->(void) throw(null_dereference)\r
-  {\r
-    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator->");\r
-    return m_holder->pointer();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T* smart_ptr_base<T,C>::operator->(void) const throw(null_dereference)\r
-  {\r
-    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator->");\r
-    return m_holder->pointer();\r
-  }\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // explicit function forms of the above assignment dereference operators\r
-\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::set_value(const T& data) throw(illegal_copy)\r
-  {\r
-    m_holder->set(C()(data));\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  T& smart_ptr_base<T,C>::value(void) throw(null_dereference)\r
-  {\r
-    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::value");\r
-    return m_holder->value();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T& smart_ptr_base<T,C>::value(void) const throw(null_dereference)\r
-  {\r
-    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::value");\r
-    return m_holder->value();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::set(T* data)\r
-  {\r
-    m_holder->set(data);\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  T* smart_ptr_base<T,C>::pointer(void)\r
-  {\r
-    return m_holder->pointer();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  const T* smart_ptr_base<T,C>::pointer(void) const\r
-  {\r
-    return m_holder->pointer();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // functions to manage counted referencing\r
-\r
-  // make this an alias of the passed object\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::alias(const smart_ptr_base<T,C>& r)\r
-  {\r
-    _make_alias(r.m_holder);\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  bool smart_ptr_base<T,C>::aliases(const smart_ptr_base<T,C>& r) const\r
-  {\r
-    return m_holder == r.m_holder;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  unsigned smart_ptr_base<T,C>::alias_count(void) const\r
-  {\r
-    return m_holder->count();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::clear(void)\r
-  {\r
-    m_holder->clear();\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::clear_unique(void)\r
-  {\r
-    if (m_holder->count() == 1)\r
-      m_holder->clear();\r
-    else\r
-    {\r
-      m_holder->decrement();\r
-      m_holder = 0;\r
-      m_holder = new smart_ptr_holder<T>;\r
-    }\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::make_unique(void) throw(illegal_copy)\r
-  {\r
-    if (m_holder->count() > 1)\r
-    {\r
-      smart_ptr_holder<T>* old_holder = m_holder;\r
-      m_holder->decrement();\r
-      m_holder = 0;\r
-      m_holder = new smart_ptr_holder<T>;\r
-      if (old_holder->pointer())\r
-        m_holder->set(C()(old_holder->value()));\r
-    }\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::copy(const smart_ptr_base<T,C>& data) throw(illegal_copy)\r
-  {\r
-    alias(data);\r
-    make_unique();\r
-  }\r
-\r
-  // internal function for distinguishing unique smart_ptr objects\r
-  // used for example in persistence routines\r
-\r
-  template <typename T, typename C>\r
-  smart_ptr_holder<T>* smart_ptr_base<T,C>::_handle(void) const\r
-  {\r
-    return m_holder;\r
-  }\r
-\r
-  template <typename T, typename C>\r
-  void smart_ptr_base<T,C>::_make_alias(smart_ptr_holder<T>* r_holder)\r
-  {\r
-    // make it alias-copy safe - this means that I don't try to do the\r
-    // assignment if r is either the same object or an alias of it\r
-    if (m_holder != r_holder)\r
-    {\r
-      if (m_holder->decrement())\r
-        delete m_holder;\r
-      m_holder = r_holder;\r
-      m_holder->increment();\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // internal holder data structure
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T>
+  class smart_ptr_holder
+  {
+  private:
+    unsigned m_count;
+    T* m_data;
+
+    // make these private to disallow copying because the holder doesn't know how to copy
+    smart_ptr_holder(const smart_ptr_holder& s) :
+      m_count(0), m_data(0)
+      {
+      }
+
+    smart_ptr_holder& operator=(const smart_ptr_holder& s)
+      {
+        return *this;
+      }
+
+  public:
+    smart_ptr_holder(T* p = 0) :
+      m_count(1), m_data(p)
+      {
+      }
+
+    ~smart_ptr_holder(void)
+      {
+        clear();
+      }
+
+    unsigned count(void) const
+      {
+        return m_count;
+      }
+
+    void increment(void)
+      {
+        ++m_count;
+      }
+
+    bool decrement(void)
+      {
+        --m_count;
+        return m_count == 0;
+      }
+
+    bool null(void)
+      {
+        return m_data == 0;
+      }
+
+    void clear(void)
+      {
+        if(m_data)
+          delete m_data;
+        m_data = 0;
+      }
+
+    void set(T* p = 0)
+      {
+        clear();
+        m_data = p;
+      }
+
+    T*& pointer(void)
+      {
+        return m_data;
+      }
+
+    const T* pointer(void) const
+      {
+        return m_data;
+      }
+
+    T& value(void)
+      {
+        return *m_data;
+      }
+
+    const T& value(void) const
+      {
+        return *m_data;
+      }
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // smart_ptr_base class
+  ////////////////////////////////////////////////////////////////////////////////
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // constructors, assignments and destructors
+
+  // create a null pointer
+  template <typename T, typename C>
+  smart_ptr_base<T,C>::smart_ptr_base(void) :
+    m_holder(new smart_ptr_holder<T>)
+  {
+  }
+
+  // create a pointer containing a *copy* of the object pointer
+  template <typename T, typename C>
+  smart_ptr_base<T,C>::smart_ptr_base(const T& data) throw(illegal_copy) :
+    m_holder(new smart_ptr_holder<T>)
+  {
+    m_holder->set(C()(data));
+  }
+
+  // create a pointer containing a dynamically created object
+  // Note: the object must be allocated *by the user* with new
+  // constructor form - must be called in the form smart_ptr<type> x(new type(args))
+  template <typename T, typename C>
+  smart_ptr_base<T,C>::smart_ptr_base(T* data) :
+    m_holder(new smart_ptr_holder<T>)
+  {
+    m_holder->set(data);
+  }
+
+  // copy constructor implements counted referencing - no copy is made
+  template <typename T, typename C>
+  smart_ptr_base<T,C>::smart_ptr_base(const smart_ptr_base<T,C>& r) :
+    m_holder(0)
+  {
+    m_holder = r.m_holder;
+    m_holder->increment();
+  }
+
+       // assignment operator - required, else the output of GCC suffers segmentation faults
+  template <typename T, typename C>
+  smart_ptr_base<T,C>& smart_ptr_base<T,C>::operator=(const smart_ptr_base<T,C>& r) 
+  {
+    alias(r);
+    return *this;
+  }
+
+  // destructor decrements the reference count and delete only when the last reference is destroyed
+  template <typename T, typename C>
+  smart_ptr_base<T,C>::~smart_ptr_base(void)
+  {
+    if(m_holder->decrement())
+      delete m_holder;
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // logical tests to see if there is anything contained in the pointer since it can be null
+
+  template <typename T, typename C>
+  bool smart_ptr_base<T,C>::null(void) const
+  {
+    return m_holder->null();
+  }
+
+  template <typename T, typename C>
+  bool smart_ptr_base<T,C>::present(void) const
+  {
+    return !m_holder->null();
+  }
+
+  template <typename T, typename C>
+  bool smart_ptr_base<T,C>::operator!(void) const
+  {
+    return m_holder->null();
+  }
+
+  template <typename T, typename C>
+  smart_ptr_base<T,C>::operator bool(void) const
+  {
+    return !m_holder->null();
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // dereference operators and functions
+
+  template <typename T, typename C>
+  T& smart_ptr_base<T,C>::operator*(void) throw(null_dereference)
+  {
+    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator*");
+    return m_holder->value();
+  }
+
+  template <typename T, typename C>
+  const T& smart_ptr_base<T,C>::operator*(void) const throw(null_dereference)
+  {
+    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator*");
+    return m_holder->value();
+  }
+
+  template <typename T, typename C>
+  T* smart_ptr_base<T,C>::operator->(void) throw(null_dereference)
+  {
+    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator->");
+    return m_holder->pointer();
+  }
+
+  template <typename T, typename C>
+  const T* smart_ptr_base<T,C>::operator->(void) const throw(null_dereference)
+  {
+    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::operator->");
+    return m_holder->pointer();
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // explicit function forms of the above assignment dereference operators
+
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::set_value(const T& data) throw(illegal_copy)
+  {
+    m_holder->set(C()(data));
+  }
+
+  template <typename T, typename C>
+  T& smart_ptr_base<T,C>::value(void) throw(null_dereference)
+  {
+    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::value");
+    return m_holder->value();
+  }
+
+  template <typename T, typename C>
+  const T& smart_ptr_base<T,C>::value(void) const throw(null_dereference)
+  {
+    if (m_holder->null()) throw null_dereference("null pointer dereferenced in smart_ptr::value");
+    return m_holder->value();
+  }
+
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::set(T* data)
+  {
+    m_holder->set(data);
+  }
+
+  template <typename T, typename C>
+  T* smart_ptr_base<T,C>::pointer(void)
+  {
+    return m_holder->pointer();
+  }
+
+  template <typename T, typename C>
+  const T* smart_ptr_base<T,C>::pointer(void) const
+  {
+    return m_holder->pointer();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // functions to manage counted referencing
+
+  // make this an alias of the passed object
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::alias(const smart_ptr_base<T,C>& r)
+  {
+    _make_alias(r.m_holder);
+  }
+
+  template <typename T, typename C>
+  bool smart_ptr_base<T,C>::aliases(const smart_ptr_base<T,C>& r) const
+  {
+    return m_holder == r.m_holder;
+  }
+
+  template <typename T, typename C>
+  unsigned smart_ptr_base<T,C>::alias_count(void) const
+  {
+    return m_holder->count();
+  }
+
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::clear(void)
+  {
+    m_holder->clear();
+  }
+
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::clear_unique(void)
+  {
+    if (m_holder->count() == 1)
+      m_holder->clear();
+    else
+    {
+      m_holder->decrement();
+      m_holder = 0;
+      m_holder = new smart_ptr_holder<T>;
+    }
+  }
+
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::make_unique(void) throw(illegal_copy)
+  {
+    if (m_holder->count() > 1)
+    {
+      smart_ptr_holder<T>* old_holder = m_holder;
+      m_holder->decrement();
+      m_holder = 0;
+      m_holder = new smart_ptr_holder<T>;
+      if (old_holder->pointer())
+        m_holder->set(C()(old_holder->value()));
+    }
+  }
+
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::copy(const smart_ptr_base<T,C>& data) throw(illegal_copy)
+  {
+    alias(data);
+    make_unique();
+  }
+
+  // internal function for distinguishing unique smart_ptr objects
+  // used for example in persistence routines
+
+  template <typename T, typename C>
+  smart_ptr_holder<T>* smart_ptr_base<T,C>::_handle(void) const
+  {
+    return m_holder;
+  }
+
+  template <typename T, typename C>
+  void smart_ptr_base<T,C>::_make_alias(smart_ptr_holder<T>* r_holder)
+  {
+    // make it alias-copy safe - this means that I don't try to do the
+    // assignment if r is either the same object or an alias of it
+    if (m_holder != r_holder)
+    {
+      if (m_holder->decrement())
+        delete m_holder;
+      m_holder = r_holder;
+      m_holder->increment();
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
index 9546ccef6123eff6c774612e2762c246d8910b94..bf501f53dc74486fbc481313747cb232a882f1ef 100644 (file)
@@ -1,54 +1,54 @@
-#ifndef STLPLUS_TRIPLE\r
-#define STLPLUS_TRIPLE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton, from an original by Dan Milton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Similar to the STL pair but with three elements\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "containers_fixes.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // the triple class\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  struct triple\r
-  {\r
-    typedef T1 first_type;\r
-    typedef T2 second_type;\r
-    typedef T3 third_type;\r
-\r
-    T1 first;\r
-    T2 second;\r
-    T3 third;\r
-\r
-    triple(void);\r
-    triple(const T1& p1, const T2& p2, const T3& p3);\r
-    triple(const triple<T1,T2,T3>& t2);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // creation\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  triple<T1,T2,T3> make_triple(const T1& first, const T2& second, const T3& third);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // comparison\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  bool operator == (const triple<T1,T2,T3>& left, const triple<T1,T2,T3>& right);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "triple.tpp"\r
-#endif\r
+#ifndef STLPLUS_TRIPLE
+#define STLPLUS_TRIPLE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton, from an original by Dan Milton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Similar to the STL pair but with three elements
+
+////////////////////////////////////////////////////////////////////////////////
+#include "containers_fixes.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // the triple class
+
+  template<typename T1, typename T2, typename T3>
+  struct triple
+  {
+    typedef T1 first_type;
+    typedef T2 second_type;
+    typedef T3 third_type;
+
+    T1 first;
+    T2 second;
+    T3 third;
+
+    triple(void);
+    triple(const T1& p1, const T2& p2, const T3& p3);
+    triple(const triple<T1,T2,T3>& t2);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // creation
+
+  template<typename T1, typename T2, typename T3>
+  triple<T1,T2,T3> make_triple(const T1& first, const T2& second, const T3& third);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // comparison
+
+  template<typename T1, typename T2, typename T3>
+  bool operator == (const triple<T1,T2,T3>& left, const triple<T1,T2,T3>& right);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "triple.tpp"
+#endif
index 60e94aa616f881434222faf590a8197ea1c43b32..3c1fa30d40e365863de9009bb5df794dabf9d055 100644 (file)
@@ -1,56 +1,56 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton, from an original by Dan Milton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // the triple class\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  triple<T1,T2,T3>::triple(void) :\r
-    first(), second(), third()\r
-  {\r
-  }\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  triple<T1,T2,T3>::triple(const T1& p1, const T2& p2, const T3& p3) :\r
-    first(p1), second(p2), third(p3)\r
-  {\r
-  }\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  triple<T1,T2,T3>::triple(const triple<T1,T2,T3>& t2) :\r
-    first(t2.first), second(t2.second), third(t2.third)\r
-  {\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // creation\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  triple<T1,T2,T3> make_triple(const T1& first, const T2& second, const T3& third)\r
-  {\r
-    return triple<T1,T2,T3>(first,second,third);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // comparison\r
-\r
-  template<typename T1, typename T2, typename T3>\r
-  bool operator == (const triple<T1,T2,T3>& left, const triple<T1,T2,T3>& right)\r
-  {\r
-    // triples are equal if all elements are equal\r
-    return left.first == right.first && left.second == right.second && left.third == right.third;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton, from an original by Dan Milton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // the triple class
+
+  template<typename T1, typename T2, typename T3>
+  triple<T1,T2,T3>::triple(void) :
+    first(), second(), third()
+  {
+  }
+
+  template<typename T1, typename T2, typename T3>
+  triple<T1,T2,T3>::triple(const T1& p1, const T2& p2, const T3& p3) :
+    first(p1), second(p2), third(p3)
+  {
+  }
+
+  template<typename T1, typename T2, typename T3>
+  triple<T1,T2,T3>::triple(const triple<T1,T2,T3>& t2) :
+    first(t2.first), second(t2.second), third(t2.third)
+  {
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // creation
+
+  template<typename T1, typename T2, typename T3>
+  triple<T1,T2,T3> make_triple(const T1& first, const T2& second, const T3& third)
+  {
+    return triple<T1,T2,T3>(first,second,third);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // comparison
+
+  template<typename T1, typename T2, typename T3>
+  bool operator == (const triple<T1,T2,T3>& left, const triple<T1,T2,T3>& right)
+  {
+    // triples are equal if all elements are equal
+    return left.first == right.first && left.second == right.second && left.third == right.third;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
diff --git a/src/stlplus/messages/stlplus_messages.txt b/src/stlplus/messages/stlplus_messages.txt
deleted file mode 100644 (file)
index 548a999..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# messages required by the CLI parser (see cli_parser.hpp)\r
-CLI_VALUE_MISSING                option @0 requires a value - end of line was reached instead\r
-CLI_UNRECOGNISED_OPTION          @0 is not a recognised option for this command\r
-CLI_NO_VALUES                    argument @0 is invalid - this program doesn't take command-line arguments\r
-CLI_USAGE_PROGRAM                usage:\n\t@0 { arguments }\r
-CLI_USAGE_DEFINITIONS            arguments:\r
-CLI_USAGE_VALUES                 values:\r
-CLI_USAGE_VALUE_RESULT           \t@0 : from @1\r
-CLI_USAGE_SWITCH_RESULT          \t-@0 : from @1\r
-CLI_USAGE_OPTION_RESULT          \t-@0 @1 : from @2\r
-CLI_INI_HEADER                   configuration files:\r
-CLI_INI_FILE_PRESENT             \t@0\r
-CLI_INI_FILE_ABSENT              \t@0 (not found)\r
-CLI_INI_VARIABLE                 unknown variable "@0" found in Ini file\r
diff --git a/src/stlplus/persistence/persistence.hpp b/src/stlplus/persistence/persistence.hpp
deleted file mode 100644 (file)
index 6a47838..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef STLPLUS_PERSISTENCE\r
-#define STLPLUS_PERSISTENCE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Header that includes all the persistence routines in one go\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistent_contexts.hpp"\r
-#include "persistent_shortcuts.hpp"\r
-#include "persistent_basic.hpp"\r
-#include "persistent_pointers.hpp"\r
-#include "persistent_stl.hpp"\r
-#include "persistent_stlplus.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistence_fixes.hpp b/src/stlplus/persistence/persistence_fixes.hpp
deleted file mode 100644 (file)
index d540ade..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef STLPLUS_PERSISTENCE_FIXES\r
-#define STLPLUS_PERSISTENCE_FIXES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Contains work arounds for OS or Compiler specific problems\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Unnecessary compiler warnings\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef _MSC_VER\r
-// Microsoft Visual Studio\r
-// shut up the following irritating warnings\r
-//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)\r
-//   4305 - VC6, identifier type was converted to a smaller type\r
-//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)\r
-//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it\r
-//   4290 - VC6, C++ exception specification ignored\r
-//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)\r
-//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program\r
-//   4996 - VC8, 'xxxx' was declared deprecated\r
-#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4675 4996)\r
-#endif\r
-\r
-#ifdef __BORLANDC__\r
-// Borland\r
-// Shut up the following irritating warnings\r
-//   8026 - Functions with exception specifications are not expanded inline\r
-//   8027 - Functions with xxx are not expanded inline\r
-#pragma warn -8026\r
-#pragma warn -8027\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent.hpp b/src/stlplus/persistence/persistent.hpp
deleted file mode 100644 (file)
index 7ddfe4e..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef STLPLUS_PERSISTENT\r
-#define STLPLUS_PERSISTENT\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Interface class inherited by classes using the interface approach to polymorphism\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_exceptions.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  class dump_context;\r
-  class restore_context;\r
-\r
-  class persistent\r
-  {\r
-  public:\r
-    virtual void dump(dump_context&) const throw(persistent_dump_failed) = 0;\r
-    virtual void restore(restore_context&) throw(persistent_restore_failed) = 0;\r
-    virtual persistent* clone(void) const = 0;\r
-    virtual ~persistent(void) {}\r
-  };\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_basic.hpp b/src/stlplus/persistence/persistent_basic.hpp
deleted file mode 100644 (file)
index 2ffc30f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_BASIC\r
-#define STLPLUS_PERSISTENT_BASIC\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of basic types\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistent_bool.hpp"\r
-#include "persistent_cstring.hpp"\r
-#include "persistent_enum.hpp"\r
-#include "persistent_float.hpp"\r
-#include "persistent_int.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_bitset.hpp b/src/stlplus/persistence/persistent_bitset.hpp
deleted file mode 100644 (file)
index 3f684e4..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_BITSET\r
-#define STLPLUS_PERSISTENT_BITSET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL bitset\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <bitset>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<size_t N>\r
-  void dump_bitset(dump_context&, const std::bitset<N>& data) throw(persistent_dump_failed);\r
-\r
-  template<size_t N>\r
-  void restore_bitset(restore_context&, std::bitset<N>& data) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_bitset.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_bitset.tpp b/src/stlplus/persistence/persistent_bitset.tpp
deleted file mode 100644 (file)
index e6b4d54..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // format: data msB first, packed into bytes with lowest index at the byte's lsb\r
-\r
-  // Note: the interface does not provide access to the internal storage and yet\r
-  // to be efficient the std::bitset must be packed as bytes. Thus I have to do it the\r
-  // hard way.\r
-\r
-  template<size_t N>\r
-  void dump_bitset(dump_context& context, const std::bitset<N>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    size_t bits = data.size();\r
-    size_t bytes = (bits+7)/8;\r
-    for (size_t B = bytes; B--; )\r
-    {\r
-      unsigned char ch = 0;\r
-      for (size_t b = 0; b < 8; b++)\r
-      {\r
-        size_t bit = B*8+b;\r
-        if (bit < bits && data.test(bit))\r
-          ch |= (0x01 << b);\r
-      }\r
-      dump_unsigned_char(context,ch);\r
-    }\r
-  }\r
-\r
-  template<size_t N>\r
-  void restore_bitset(restore_context& context, std::bitset<N>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    size_t bits = data.size();\r
-    size_t bytes = (bits+7)/8;\r
-    for (size_t B = bytes; B--; )\r
-    {\r
-      unsigned char ch = 0;\r
-      restore_unsigned_char(context,ch);\r
-      for (size_t b = 0; b < 8; b++)\r
-      {\r
-        size_t bit = B*8+b;\r
-        if (bit >= bits) break;\r
-        data.set(bit, ch & (0x01 << b) ? true : false);\r
-      }\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_bool.cpp b/src/stlplus/persistence/persistent_bool.cpp
deleted file mode 100644 (file)
index dde1828..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_bool.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// bool is dumped and restored as an unsigned char\r
-void stlplus::dump_bool(stlplus::dump_context& context, const bool& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  context.put((unsigned char)data);\r
-}\r
-\r
-void stlplus::restore_bool(restore_context& context, bool& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  data = context.get() != 0;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/persistence/persistent_bool.hpp b/src/stlplus/persistence/persistent_bool.hpp
deleted file mode 100644 (file)
index 5fbe237..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_BOOL\r
-#define STLPLUS_PERSISTENT_BOOL\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of bool\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void dump_bool(dump_context&, const bool& data) throw(persistent_dump_failed);\r
-  void restore_bool(restore_context&, bool& data) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_callback.hpp b/src/stlplus/persistence/persistent_callback.hpp
deleted file mode 100644 (file)
index 034f43e..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_CALLBACK\r
-#define STLPLUS_PERSISTENT_CALLBACK\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence for pointers to polymorphic classes using the callback approach.\r
-\r
-//   This works on a set of classes. Each subclass has a set of callback\r
-//   (non-method) functions that enable create/dump/restore operations. Each\r
-//   subclass must be registered with the persistence dump/restore context so\r
-//   that the system knows how to handle it.\r
-\r
-//   This approach is suited to classes that cannot be modified to add\r
-//   persistence methods. See persistent_interface for a more C++-like way of\r
-//   handling polymorphism.\r
-\r
-//   Objects are always dumped/restored as pointers to the superclass T.\r
-\r
-//   Multiple pointers to the same object are handled in the same way as for\r
-//   simple pointers\r
-\r
-//   Only classes registered with the context can be dumped and restored as\r
-//   polymorphic types - see dump_context::register_callback and\r
-//   restore_context::register_callback. Attempting to use any unrecognised class\r
-//   will throw an exception.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T>\r
-  void dump_callback(dump_context&, const T* const data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_callback(restore_context&, T*& data)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_callback.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_callback.tpp b/src/stlplus/persistence/persistent_callback.tpp
deleted file mode 100644 (file)
index 0773dad..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Polymorphous classes using the callback approach\r
-\r
-//   format: magic [ key data ]\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  void dump_callback(dump_context& context, const T* const data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    try\r
-    {\r
-      // register the address and get the magic key for it\r
-      std::pair<bool,unsigned> mapping = context.pointer_map(data);\r
-      dump_unsigned(context,mapping.second);\r
-      // if the address is null, then that is all that we need to do\r
-      // however, if it is non-null and this is the first sight of the address, dump the contents\r
-      if (data && !mapping.first)\r
-      {\r
-        // callback method - get the callback data and perform the dump\r
-        // this will throw persistent_illegal_type if not recognised, thus the try block\r
-        dump_context::callback_data callback = context.lookup_callback(typeid(*data));\r
-        // dump the magic key for the type\r
-        dump_unsigned(context, callback.first);\r
-        // now call the callback that dumps the subclass\r
-        callback.second(context,data);\r
-      }\r
-    }\r
-    catch (const persistent_illegal_type& except)\r
-    {\r
-      // convert this to a simpler dump failed exception\r
-      throw persistent_dump_failed(except.what());\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  void restore_callback(restore_context& context, T*& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    try\r
-    {\r
-      // first delete any previous object pointed to since the restore creates the object of the right subclass\r
-      if (data)\r
-      {\r
-        delete data;\r
-        data = 0;\r
-      }\r
-      // get the magic key\r
-      unsigned magic = 0;\r
-      restore_unsigned(context,magic);\r
-      // now lookup the magic key to see if this pointer has already been restored\r
-      // null pointers are always flagged as already restored\r
-      std::pair<bool,void*> address = context.pointer_map(magic);\r
-      if (address.first)\r
-      {\r
-        // seen before, so simply map it to the existing address\r
-        data = (T*)address.second;\r
-      }\r
-      else\r
-      {\r
-        // now restore the magic key that denotes the particular subclass\r
-        unsigned key = 0;\r
-        restore_unsigned(context, key);\r
-        // callback approach\r
-        // call the create callback to create an object of the right type\r
-        // then call the restore callback to get the contents\r
-        // this will throw persistent_illegal_type if not recognised - this is caught below\r
-        restore_context::callback_data callbacks = context.lookup_callback(key);\r
-        data = (T*)callbacks.first();\r
-        // add this pointer to the set of already seen objects\r
-        // note that the address is mapped before it is dumped so that self-referential structures dump correctly\r
-        context.pointer_add(magic,data);\r
-        callbacks.second(context,data);\r
-      }\r
-    }\r
-    catch (const persistent_illegal_type& exception)\r
-    {\r
-      // convert this to a simpler dump failed exception\r
-      throw persistent_restore_failed(exception.what());\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_complex.hpp b/src/stlplus/persistence/persistent_complex.hpp
deleted file mode 100644 (file)
index 4c02215..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_COMPLEX\r
-#define STLPLUS_PERSISTENT_COMPLEX\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Set of persistence routines for the STL classes\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <complex>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename D>\r
-  void dump_complex(dump_context&, const std::complex<T>& data, D dump_fn) throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename R>\r
-  void restore_complex(restore_context&, std::complex<T>& data, R restore_fn) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_complex.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_complex.tpp b/src/stlplus/persistence/persistent_complex.tpp
deleted file mode 100644 (file)
index 7db9bc4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename D>\r
-  void dump_complex(dump_context& context, const std::complex<T>& data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_fn(context,data.real());\r
-    dump_fn(context,data.imag());\r
-  }\r
-\r
-  template<typename T, typename R>\r
-  void restore_complex(restore_context& context, std::complex<T>& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    T re, im;\r
-    restore_fn(context,re);\r
-    restore_fn(context,im);\r
-    data = std::complex<T>(re, im);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_contexts.cpp b/src/stlplus/persistence/persistent_contexts.cpp
deleted file mode 100644 (file)
index 008fa9f..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Author:    Andy Rushton\r
-// Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-// License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_contexts.hpp"\r
-#include "persistent.hpp"\r
-#include <map>\r
-#include <string>\r
-#include <stdio.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // File format version\r
-\r
-  // This relates to the layout of basic types - if I change the file layout of,\r
-  // say, int or vector, then this will change\r
-\r
-  // Early versions of the persistence routines did not have this - they are no longer supported\r
-  // - Change from version 1 to 2: changed the persistent representation of inf\r
-\r
-  unsigned char PersistentVersion = 2;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // avoid creating dependencies on other libraries\r
-\r
-  static std::string to_string(int number)\r
-  {\r
-    // use sprintf in a very controlled way that cannot overrun\r
-    char* buffer = new char[50];\r
-    sprintf(buffer, "%i", number);\r
-    std::string result = buffer;\r
-    delete buffer;\r
-    return result;\r
-  }\r
-\r
-  static bool little_endian(void)\r
-  {\r
-    // TODO - find a compile-time way of doing this\r
-    int sample = 1;\r
-    char* sample_bytes = (char*)&sample;\r
-    return sample_bytes[0] != 0;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // dump context classes\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class dump_context_body\r
-  {\r
-  public:\r
-    typedef std::map<const void*,unsigned> magic_map;\r
-    typedef std::map<std::string,dump_context::callback_data> callback_map;\r
-    typedef std::map<std::string,unsigned> interface_map;\r
-\r
-    unsigned m_max_key;\r
-    unsigned char m_version;\r
-    bool m_little_endian;\r
-    std::ostream* m_device;\r
-    magic_map m_pointers;\r
-    callback_map m_callbacks;\r
-    interface_map m_interfaces;\r
-\r
-    dump_context_body(std::ostream& device, unsigned char version) throw(persistent_dump_failed) : \r
-      m_max_key(0), m_version(version), m_little_endian(stlplus::little_endian()), m_device(&device)\r
-      {\r
-        // write the version number as a single byte\r
-        put(version);\r
-        // map a null pointer onto magic number zero\r
-        m_pointers[0] = 0;\r
-        // test whether the version number is supported\r
-        if (m_version != 1 && m_version != 2)\r
-          throw persistent_dump_failed(std::string("wrong version: ") + to_string(m_version));\r
-      }\r
-\r
-    void put(unsigned char data) throw(persistent_dump_failed)\r
-      {\r
-        if (!m_device->put(data))\r
-          throw persistent_dump_failed(std::string("output device error"));\r
-      }\r
-\r
-    const std::ostream& device(void) const\r
-      {\r
-        return *m_device;\r
-      }\r
-\r
-    unsigned char version(void) const\r
-      {\r
-        return m_version;\r
-      }\r
-\r
-    bool little_endian(void) const\r
-      {\r
-        return m_little_endian;\r
-      }\r
-\r
-    std::pair<bool,unsigned> pointer_map(const void* const pointer)\r
-      {\r
-        magic_map::iterator found = m_pointers.find(pointer);\r
-        if (found == m_pointers.end())\r
-        {\r
-          // add a new mapping\r
-          unsigned magic = m_pointers.size();\r
-          m_pointers[pointer] = magic;\r
-          return std::pair<bool,unsigned>(false,magic);\r
-        }\r
-        // return the old mapping\r
-        return std::pair<bool,unsigned>(true,found->second);\r
-      }\r
-\r
-    unsigned register_callback(const std::type_info& info, dump_context::dump_callback callback)\r
-      {\r
-        std::string key = info.name();\r
-        unsigned data = ++m_max_key;\r
-        m_callbacks[key] = std::make_pair(data,callback);\r
-        return data;\r
-      }\r
-\r
-    bool is_callback(const std::type_info& info) const\r
-      {\r
-        return m_callbacks.find(info.name()) != m_callbacks.end();\r
-      }\r
-\r
-    dump_context::callback_data lookup_callback(const std::type_info& info) const throw(persistent_illegal_type)\r
-      {\r
-        std::string key = info.name();\r
-        callback_map::const_iterator found = m_callbacks.find(key);\r
-        if (found == m_callbacks.end())\r
-          throw persistent_illegal_type(key);\r
-        return found->second;\r
-      }\r
-\r
-    unsigned register_interface(const std::type_info& info)\r
-      {\r
-        std::string key = info.name();\r
-        unsigned data = ++m_max_key;\r
-        m_interfaces[key] = data;\r
-        return data;\r
-      }\r
-\r
-    bool is_interface(const std::type_info& info) const\r
-      {\r
-        return m_interfaces.find(info.name()) != m_interfaces.end();\r
-      }\r
-\r
-    unsigned lookup_interface(const std::type_info& info) const throw(persistent_illegal_type)\r
-      {\r
-        std::string key = info.name();\r
-        interface_map::const_iterator found = m_interfaces.find(key);\r
-        if (found == m_interfaces.end())\r
-          throw persistent_illegal_type(key);\r
-        return found->second;\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  dump_context::dump_context(std::ostream& device, unsigned char version) throw(persistent_dump_failed) : m_body(0)\r
-  {\r
-    m_body = new dump_context_body(device,version);\r
-  }\r
-\r
-  dump_context::~dump_context(void)\r
-  {\r
-    delete m_body;\r
-  }\r
-\r
-  void dump_context::put(unsigned char data) throw(persistent_dump_failed)\r
-  {\r
-    m_body->put(data);\r
-  }\r
-\r
-  const std::ostream& dump_context::device(void) const\r
-  {\r
-    return m_body->device();\r
-  }\r
-\r
-  unsigned char dump_context::version(void) const\r
-  {\r
-    return m_body->version();\r
-  }\r
-\r
-  bool dump_context::little_endian(void) const\r
-  {\r
-    return m_body->little_endian();\r
-  }\r
-\r
-  std::pair<bool,unsigned> dump_context::pointer_map(const void* const pointer)\r
-  {\r
-    return m_body->pointer_map(pointer);\r
-  }\r
-\r
-  unsigned dump_context::register_callback(const std::type_info& info, dump_context::dump_callback callback)\r
-  {\r
-    return m_body->register_callback(info,callback);\r
-  }\r
-\r
-  bool dump_context::is_callback(const std::type_info& info) const\r
-  {\r
-    return m_body->is_callback(info);\r
-  }\r
-\r
-  dump_context::callback_data dump_context::lookup_callback(const std::type_info& info) const throw(persistent_illegal_type)\r
-  {\r
-    return m_body->lookup_callback(info);\r
-  }\r
-\r
-  unsigned dump_context::register_interface(const std::type_info& info)\r
-  {\r
-    return m_body->register_interface(info);\r
-  }\r
-\r
-  bool dump_context::is_interface(const std::type_info& info) const\r
-  {\r
-    return m_body->is_interface(info);\r
-  }\r
-\r
-  unsigned dump_context::lookup_interface(const std::type_info& info) const throw(persistent_illegal_type)\r
-  {\r
-    return m_body->lookup_interface(info);\r
-  }\r
-\r
-  void dump_context::register_all(dump_context::installer installer)\r
-  {\r
-    if (installer) installer(*this);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // restore context classes\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class restore_context_body\r
-  {\r
-  public:\r
-    typedef persistent* persistent_ptr;\r
-    typedef std::map<unsigned,void*> magic_map;\r
-    typedef std::map<unsigned,restore_context::callback_data> callback_map;\r
-    typedef std::map<unsigned,persistent_ptr> interface_map;\r
-\r
-    unsigned m_max_key;\r
-    unsigned char m_version;\r
-    bool m_little_endian;\r
-    std::istream* m_device;\r
-    magic_map m_pointers;\r
-    callback_map m_callbacks;\r
-    interface_map m_interfaces;\r
-\r
-    restore_context_body(std::istream& device) throw(persistent_restore_failed) : \r
-      m_max_key(0), m_little_endian(stlplus::little_endian()), m_device(&device)\r
-      {\r
-        // map a null pointer onto magic number zero\r
-        m_pointers[0] = 0;\r
-        // get the dump version and see if we support it\r
-        m_version = (unsigned char)get();\r
-        if (m_version != 1 && m_version != 2)\r
-          throw persistent_restore_failed(std::string("wrong version: ") + to_string(m_version));\r
-      }\r
-\r
-    ~restore_context_body(void)\r
-      {\r
-        // need to delete all interfaces\r
-        // I used to use smart_ptr_clone for storing them but I want to disconnect as many dependencies as possible\r
-        for (unsigned i = 0; i < m_interfaces.size(); i++)\r
-          delete m_interfaces[i];\r
-      }\r
-\r
-    const std::istream& device(void) const\r
-      {\r
-        return *m_device;\r
-      }\r
-\r
-    unsigned char version(void) const\r
-      {\r
-        return m_version;\r
-      }\r
-\r
-    bool little_endian(void) const\r
-      {\r
-        return m_little_endian;\r
-      }\r
-\r
-    int get(void) throw(persistent_restore_failed)\r
-      {\r
-        int result = m_device->get();\r
-        if (!m_device->good())\r
-          throw persistent_restore_failed(std::string("device error or premature end of file"));\r
-        return result;\r
-      }\r
-\r
-    std::pair<bool,void*> pointer_map(unsigned magic)\r
-      {\r
-        magic_map::iterator found = m_pointers.find(magic);\r
-        if (found == m_pointers.end())\r
-        {\r
-          // this magic number has never been seen before\r
-          return std::pair<bool,void*>(false,0);\r
-        }\r
-        return std::pair<bool,void*>(true,found->second);\r
-      }\r
-\r
-    void pointer_add(unsigned magic, void* new_pointer)\r
-      {\r
-        m_pointers[magic] = new_pointer;\r
-      }\r
-\r
-    unsigned register_callback(restore_context::create_callback create, restore_context::restore_callback restore)\r
-      {\r
-        unsigned key = ++m_max_key;\r
-        m_callbacks[key] = std::make_pair(create,restore);\r
-        return key;\r
-      }\r
-\r
-    bool is_callback(unsigned key) const\r
-      {\r
-        return m_callbacks.find(key) != m_callbacks.end();\r
-      }\r
-\r
-    restore_context::callback_data lookup_callback(unsigned key) const throw(persistent_illegal_type)\r
-      {\r
-        callback_map::const_iterator found = m_callbacks.find(key);\r
-        if (found == m_callbacks.end())\r
-          throw persistent_illegal_type(key);\r
-        return found->second;\r
-      }\r
-\r
-    unsigned register_interface(persistent* sample)\r
-      {\r
-        unsigned key = ++m_max_key;\r
-        m_interfaces[key] = sample;\r
-        return key;\r
-      }\r
-\r
-    bool is_interface(unsigned key) const\r
-      {\r
-        return m_interfaces.find(key) != m_interfaces.end();\r
-      }\r
-\r
-    persistent* lookup_interface(unsigned key) const throw(persistent_illegal_type)\r
-      {\r
-        interface_map::const_iterator found = m_interfaces.find(key);\r
-        if (found == m_interfaces.end())\r
-          throw persistent_illegal_type(key);\r
-        return found->second;\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  restore_context::restore_context(std::istream& device) throw(persistent_restore_failed) : \r
-    m_body(0)\r
-  {\r
-    m_body = new restore_context_body(device);\r
-  }\r
-\r
-  restore_context::~restore_context(void)\r
-  {\r
-    delete m_body;\r
-  }\r
-\r
-  const std::istream& restore_context::device(void) const\r
-  {\r
-    return m_body->device();\r
-  }\r
-\r
-  unsigned char restore_context::version(void) const\r
-  {\r
-    return m_body->version();\r
-  }\r
-\r
-  bool restore_context::little_endian(void) const\r
-  {\r
-    return m_body->little_endian();\r
-  }\r
-\r
-  int restore_context::get(void) throw(persistent_restore_failed)\r
-  {\r
-    return m_body->get();\r
-  }\r
-\r
-  std::pair<bool,void*> restore_context::pointer_map(unsigned magic)\r
-  {\r
-    return m_body->pointer_map(magic);\r
-  }\r
-\r
-  void restore_context::pointer_add(unsigned magic, void* new_pointer)\r
-  {\r
-    m_body->pointer_add(magic,new_pointer);\r
-  }\r
-\r
-  unsigned restore_context::register_callback(restore_context::create_callback create, restore_context::restore_callback restore)\r
-  {\r
-    return m_body->register_callback(create,restore);\r
-  }\r
-\r
-  bool restore_context::is_callback(unsigned key) const\r
-  {\r
-    return m_body->is_callback(key);\r
-  }\r
-\r
-  restore_context::callback_data restore_context::lookup_callback(unsigned key) const throw(persistent_illegal_type)\r
-  {\r
-    return m_body->lookup_callback(key);\r
-  }\r
-\r
-  unsigned restore_context::register_interface(persistent* sample)\r
-  {\r
-    return m_body->register_interface(sample);\r
-  }\r
-\r
-  bool restore_context::is_interface(unsigned key) const\r
-  {\r
-    return m_body->is_interface(key);\r
-  }\r
-\r
-  persistent* restore_context::lookup_interface(unsigned key) const throw(persistent_illegal_type)\r
-  {\r
-    return m_body->lookup_interface(key);\r
-  }\r
-\r
-  void restore_context::register_all(restore_context::installer installer)\r
-  {\r
-    if (installer) installer(*this);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
diff --git a/src/stlplus/persistence/persistent_contexts.hpp b/src/stlplus/persistence/persistent_contexts.hpp
deleted file mode 100644 (file)
index dfef17b..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_CONTEXTS\r
-#define STLPLUS_PERSISTENT_CONTEXTS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Core context classes used to control the persistent dump/restore operations\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistence_fixes.hpp"\r
-#include "persistent.hpp"\r
-#include <iostream>\r
-#include <map>\r
-#include <typeinfo>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Internals\r
-\r
-  class dump_context_body;\r
-  class restore_context_body;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // The format version number currently supported\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  extern unsigned char PersistentVersion;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // dump_context controls the formatting of a persistent dump\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class dump_context\r
-  {\r
-    friend class persistent;\r
-  public:\r
-    //////////////////////////////////////////////////////////////////////////////\r
-\r
-    // device must be in binary mode\r
-    dump_context(std::ostream& device, unsigned char version = PersistentVersion) throw(persistent_dump_failed);\r
-    ~dump_context(void);\r
-\r
-    // low level output used to dump a byte\r
-    void put(unsigned char data) throw(persistent_dump_failed);\r
-\r
-    // access the device, for example to check the error status\r
-    const std::ostream& device(void) const;\r
-\r
-    // recover the version number of the dumped output\r
-    unsigned char version(void) const;\r
-\r
-    // test whether the current platform uses little-endian or big-endian addressing of bytes\r
-    // this is used in dump/restore of integers and is exported so that other routines can use it\r
-    bool little_endian(void) const;\r
-\r
-    // Assist functions for Pointers\r
-    // the return pair value is a flag saying whether this is a new pointer and the magic key to dump to file\r
-    std::pair<bool,unsigned> pointer_map(const void* const pointer);\r
-\r
-    // Assist functions for Polymorphous classes (i.e. subclasses) using callback approach\r
-    typedef void (*dump_callback)(dump_context&,const void*);\r
-    unsigned register_callback(const std::type_info& info, dump_callback);\r
-    bool is_callback(const std::type_info& info) const;\r
-    typedef std::pair<unsigned,dump_callback> callback_data;\r
-    callback_data lookup_callback(const std::type_info&) const throw(persistent_illegal_type);\r
-\r
-    // Assist functions for Polymorphous classes (i.e. subclasses) using interface approach\r
-    unsigned register_interface(const std::type_info& info);\r
-    bool is_interface(const std::type_info& info) const;\r
-    unsigned lookup_interface(const std::type_info&) const throw(persistent_illegal_type);\r
-\r
-    // Register all Polymorphous classes using either approach by calling an installer callback\r
-    typedef void (*installer)(dump_context&);\r
-    void register_all(installer);\r
-\r
-  private:\r
-    friend class dump_context_body;\r
-    dump_context_body* m_body;\r
-\r
-    // disallow copying by making assignment and copy constructor private\r
-    dump_context(const dump_context&);\r
-    dump_context& operator=(const dump_context&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // restore_context controls the reading of the persistent data during a restore\r
-\r
-  class restore_context\r
-  {\r
-    friend class persistent;\r
-  public:\r
-    //////////////////////////////////////////////////////////////////////////////\r
-\r
-    // device must be in binary mode\r
-    restore_context(std::istream& device) throw(persistent_restore_failed);\r
-    ~restore_context(void);\r
-\r
-    // low level input used to restore a byte\r
-    int get(void) throw(persistent_restore_failed);\r
-\r
-    // access the device, for example to check the error status\r
-    const std::istream& device(void) const;\r
-\r
-    // access the version number of the input being restored\r
-    unsigned char version(void) const;\r
-\r
-    // test whether the current platform uses little-endian or big-endian addressing of bytes\r
-    // this is used in dump/restore of integers\r
-    bool little_endian(void) const;\r
-\r
-    // Assist functions for Pointers\r
-    std::pair<bool,void*> pointer_map(unsigned magic);\r
-    void pointer_add(unsigned magic, void* new_pointer);\r
-\r
-    // Assist functions for Polymorphous classes using the callback approach\r
-    typedef void* (*create_callback)(void);\r
-    typedef void (*restore_callback)(restore_context&,void*);\r
-    unsigned register_callback(create_callback,restore_callback);\r
-    bool is_callback(unsigned) const;\r
-    typedef std::pair<create_callback, restore_callback> callback_data;\r
-    callback_data lookup_callback(unsigned) const throw(persistent_illegal_type);\r
-\r
-    // Assist functions for Polymorphous classes using the interface approach\r
-    unsigned register_interface(persistent*);\r
-    bool is_interface(unsigned) const;\r
-    persistent* lookup_interface(unsigned) const throw(persistent_illegal_type);\r
-\r
-    // Register all Polymorphous classes using either approach by calling an installer callback\r
-    typedef void (*installer)(restore_context&);\r
-    void register_all(installer);\r
-\r
-  private:\r
-    friend class restore_context_body;\r
-    restore_context_body* m_body;\r
-\r
-    typedef std::pair<unsigned,persistent*> interface_data;\r
-\r
-    // disallow copying by making assignment and copy constructor private\r
-    restore_context(const restore_context&);\r
-    restore_context& operator=(const restore_context&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_cstring.cpp b/src/stlplus/persistence/persistent_cstring.cpp
deleted file mode 100644 (file)
index a829b9a..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistent_cstring.hpp"\r
-#include "persistent_int.hpp"\r
-#include <string.h>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Null-terminated char arrays\r
-// Format: address [ size data ]\r
-\r
-void stlplus::dump_cstring(stlplus::dump_context& context, const char* data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  // register the address and get the magic key for it\r
-  std::pair<bool,unsigned> mapping = context.pointer_map(data);\r
-  stlplus::dump_unsigned(context,mapping.second);\r
-  // if the address is null, then that is all that we need to do\r
-  // however, if it is non-null and this is the first sight of the address, dump the contents\r
-  if (data && !mapping.first)\r
-  {\r
-    unsigned size = strlen(data);\r
-    stlplus::dump_unsigned(context,size);\r
-    for (unsigned i = 0; i < size; i++)\r
-      stlplus::dump_char(context,data[i]);\r
-  }\r
-}\r
-\r
-void stlplus::restore_cstring(restore_context& context, char*& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  // destroy any previous contents\r
-  if (data)\r
-  {\r
-    delete[] data;\r
-    data = 0;\r
-  }\r
-  // get the magic key\r
-  unsigned magic = 0;\r
-  stlplus::restore_unsigned(context,magic);\r
-  // now lookup the magic key to see if this pointer has already been restored\r
-  // null pointers are always flagged as already restored\r
-  std::pair<bool,void*> address = context.pointer_map(magic);\r
-  if (!address.first)\r
-  {\r
-    // this pointer has never been seen before and is non-null\r
-    // restore the string\r
-    unsigned size = 0;\r
-    stlplus::restore_unsigned(context,size);\r
-    data = new char[size+1];\r
-    for (unsigned i = 0; i < size; i++)\r
-      stlplus::restore_char(context,data[i]);\r
-    data[size] = '\0';\r
-    // add this pointer to the set of already seen objects\r
-    context.pointer_add(magic,data);\r
-  }\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/persistence/persistent_cstring.hpp b/src/stlplus/persistence/persistent_cstring.hpp
deleted file mode 100644 (file)
index 8e3e94a..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_CSTRING\r
-#define STLPLUS_PERSISTENT_CSTRING\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of C-style char* strings\r
-\r
-//   These are handled differently to other pointer types\r
-\r
-//   Warning! This means that pointers to char cannot be supported, since there\r
-//   is no type difference between a pointer to char and a C-style array of char.\r
-\r
-//   Warning! The restore deletes any old value of the data parameter and\r
-//   allocates a new char* which is (just) big enough and assigns it to the data\r
-//   field. This is because there is no way of knowing how long a char* is so\r
-//   the passed parameter is not safe to use. The allocation is done using\r
-//   standard new. If the data field is non-null on entry it will be deleted by\r
-//   standard delete. Best to make it null in the first place.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void dump_cstring(dump_context&, const char* data) throw(persistent_dump_failed);\r
-  void restore_cstring(restore_context&, char*& data) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_deque.hpp b/src/stlplus/persistence/persistent_deque.hpp
deleted file mode 100644 (file)
index 2a47180..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_DEQUE\r
-#define STLPLUS_PERSISTENT_DEQUE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of the STL deque\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <deque>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename D>\r
-  void dump_deque(dump_context&, const std::deque<T>& data, D dump_fn) throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename R>\r
-  void restore_deque(restore_context&, std::deque<T>& data, R restore_fn) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_deque.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_deque.tpp b/src/stlplus/persistence/persistent_deque.tpp
deleted file mode 100644 (file)
index 26854ce..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename D>\r
-  void dump_deque(dump_context& context, const std::deque<T>& data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (typename std::deque<T>::const_iterator i = data.begin(); i != data.end(); i++)\r
-      dump_fn(context,*i);\r
-  }\r
-\r
-  template<typename T, typename R>\r
-  void restore_deque(restore_context& context, std::deque<T>& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.clear();\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    for (unsigned i = 0; i < size; i++)\r
-    {\r
-      data.push_back(T());\r
-      restore_fn(context,data.back());\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_digraph.hpp b/src/stlplus/persistence/persistent_digraph.hpp
deleted file mode 100644 (file)
index fcc57a0..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_DIGRAPH\r
-#define STLPLUS_PERSISTENT_DIGRAPH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STLplus digraph\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "digraph.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // digraph\r
-\r
-  template<typename NT, typename AT, typename DN, typename DA>\r
-  void dump_digraph(dump_context&, const digraph<NT,AT>& data, DN dump_node, DA dump_arc)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename NT, typename AT, typename RN, typename RA>\r
-  void restore_digraph(restore_context&, digraph<NT,AT>& data, RN restore_node, RA restore_arc)\r
-    throw(persistent_restore_failed);\r
-\r
-  // node iterator\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void dump_digraph_iterator(dump_context& str, const digraph_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void restore_digraph_iterator(restore_context& str, digraph_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_restore_failed);\r
-\r
-  // arc iterator\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void dump_digraph_arc_iterator(dump_context& str, const digraph_arc_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void restore_digraph_arc_iterator(restore_context& str, digraph_arc_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_digraph.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_digraph.tpp b/src/stlplus/persistence/persistent_digraph.tpp
deleted file mode 100644 (file)
index 3ff94a5..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-#include "persistent_xref.hpp"\r
-\r
-namespace stlplus\r
-{\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT, typename DN, typename DA>\r
-  void dump_digraph(dump_context& context, const digraph<NT,AT>& data,\r
-                    DN dump_node, DA dump_arc)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // dump a magic key to the address of the graph for use in persistence of iterators\r
-    // and register it as a dumped address\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(&data);\r
-    if (mapping.first) throw persistent_dump_failed("digraph: already dumped this graph");\r
-    dump_unsigned(context,mapping.second);\r
-    // dump the nodes\r
-    dump_unsigned(context,data.size());\r
-    for (typename digraph<NT,AT>::const_iterator node = data.begin(); node != data.end(); node++)\r
-    {\r
-      // nodes are keyed by the magic key to the node address\r
-      // this key is then used in dumping the arc from/to pointers\r
-      std::pair<bool,unsigned> node_mapping = context.pointer_map(node.node());\r
-      if (node_mapping.first) throw persistent_dump_failed("digraph: already dumped this node");\r
-      dump_unsigned(context,node_mapping.second);\r
-      // finally, dump the node contents\r
-      dump_node(context,*node);\r
-    }\r
-    // dump the arcs\r
-    dump_unsigned(context,data.arc_size());\r
-    for (typename digraph<NT,AT>::const_arc_iterator arc = data.arc_begin(); arc != data.arc_end(); arc++)\r
-    {\r
-      // dump the magic key to the arc address\r
-      // this is used by iterator persistence too\r
-      std::pair<bool,unsigned> arc_mapping = context.pointer_map(arc.node());\r
-      if (arc_mapping.first) throw persistent_dump_failed("digraph: already dumped this arc");\r
-      dump_unsigned(context,arc_mapping.second);\r
-      // now dump the from/to pointers as cross-references\r
-      dump_xref(context,data.arc_from(arc).node());\r
-      dump_xref(context,data.arc_to(arc).node());\r
-      // now dump the arc's data\r
-      dump_arc(context,*arc);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT, typename RN, typename RA>\r
-  void restore_digraph(restore_context& context, digraph<NT,AT>& data,\r
-                       RN restore_node, RA restore_arc)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.clear();\r
-    // restore the graph's magic key and map it onto the graph's address\r
-    // this is used in the persistence of iterators\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    context.pointer_add(magic,&data);\r
-    // restore the nodes\r
-    unsigned nodes = 0;\r
-    restore_unsigned(context, nodes);\r
-    for (unsigned n = 0; n < nodes; n++)\r
-    {\r
-      unsigned node_magic = 0;\r
-      restore_unsigned(context,node_magic);\r
-      // create a new node and map the magic key onto the new address\r
-      typename digraph<NT,AT>::iterator node = data.insert(NT());\r
-      context.pointer_add(node_magic,node.node());\r
-      // now restore the user's data\r
-      restore_node(context,*node);\r
-    }\r
-    // restore the arcs\r
-    unsigned arcs = 0;\r
-    restore_unsigned(context, arcs);\r
-    for (unsigned a = 0; a < arcs; a++)\r
-    {\r
-      unsigned arc_magic = 0;\r
-      restore_unsigned(context,arc_magic);\r
-      // restore the from and to cross-references\r
-      digraph_node<NT,AT>* from = 0;\r
-      digraph_node<NT,AT>* to = 0;\r
-      restore_xref(context,from);\r
-      restore_xref(context,to);\r
-      // create an arc with these from/to pointers\r
-      digraph_arc_iterator<NT,AT,AT&,AT*> arc = \r
-        data.arc_insert(digraph_iterator<NT,AT,NT&,NT*>(from), \r
-                        digraph_iterator<NT,AT,NT&,NT*>(to));\r
-      context.pointer_add(arc_magic,arc.node());\r
-      // restore the user data\r
-      restore_arc(context,*arc);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void dump_digraph_iterator(dump_context& context, \r
-                             const digraph_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_xref(context,data.owner());\r
-    dump_xref(context,data.node());\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void restore_digraph_iterator(restore_context& context, \r
-                                digraph_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    digraph<NT,AT>* owner = 0;\r
-    digraph_node<NT,AT>* node = 0;\r
-    restore_xref(context,owner);\r
-    restore_xref(context,node);\r
-    data = digraph_iterator<NT,AT,NRef,NPtr>(node);\r
-    data.assert_owner(owner);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void dump_digraph_arc_iterator(dump_context& context,\r
-                                 const digraph_arc_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_xref(context,data.owner());\r
-    dump_xref(context,data.node());\r
-  }\r
-\r
-  template<typename NT, typename AT, typename NRef, typename NPtr>\r
-  void restore_digraph_arc_iterator(restore_context& context, \r
-                                    digraph_arc_iterator<NT,AT,NRef,NPtr>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    digraph<NT,AT>* owner = 0;\r
-    digraph_arc<NT,AT>* arc = 0;\r
-    restore_xref(context,owner);\r
-    restore_xref(context,arc);\r
-    data = digraph_arc_iterator<NT,AT,NRef,NPtr>(arc);\r
-    data.assert_owner(owner);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_enum.hpp b/src/stlplus/persistence/persistent_enum.hpp
deleted file mode 100644 (file)
index ddce1b4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_ENUM\r
-#define STLPLUS_PERSISTENT_ENUM\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of enumeration types\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T>\r
-  void dump_enum(dump_context&, const T& data) throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_enum(restore_context&, T& data) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_enum.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_enum.tpp b/src/stlplus/persistence/persistent_enum.tpp
deleted file mode 100644 (file)
index 9778688..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // enumeration types\r
-\r
-  template<typename T>\r
-  void dump_enum(dump_context& context, const T& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,(unsigned)data);\r
-  }\r
-\r
-  template<typename T>\r
-  void restore_enum(restore_context& context, T& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    unsigned value = 0;\r
-    restore_unsigned(context, value);\r
-    data = (T)value;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_exceptions.cpp b/src/stlplus/persistence/persistent_exceptions.cpp
deleted file mode 100644 (file)
index d233826..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistent_exceptions.hpp"\r
-#include <stdio.h>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-static std::string to_string(int number)\r
-{\r
-  // use sprintf in a very controlled way that cannot overrun\r
-  char* buffer = new char[50];\r
-  sprintf(buffer, "%i", number);\r
-  std::string result = buffer;\r
-  delete buffer;\r
-  return result;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// exceptions\r
-\r
-stlplus::persistent_illegal_type::persistent_illegal_type(const std::string& type) throw() : \r
-  std::logic_error(std::string("illegal type: ") + type)\r
-{\r
-}\r
-\r
-stlplus::persistent_illegal_type::persistent_illegal_type(unsigned key) throw() : \r
-  std::logic_error(std::string("illegal key: ") + to_string((int)key))\r
-{\r
-}\r
-\r
-stlplus::persistent_illegal_type::~persistent_illegal_type(void) throw()\r
-{\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-stlplus::persistent_dump_failed::persistent_dump_failed(const std::string& message) throw() :\r
-  std::runtime_error(std::string("dump failed: ") + message)\r
-{\r
-}\r
-\r
-stlplus::persistent_dump_failed::~persistent_dump_failed(void) throw()\r
-{\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-stlplus::persistent_restore_failed::persistent_restore_failed(const std::string& message) throw() :\r
-  std::runtime_error(std::string("restore failed: ") + message)\r
-{\r
-}\r
-\r
-stlplus::persistent_restore_failed::~persistent_restore_failed(void) throw()\r
-{\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/persistence/persistent_exceptions.hpp b/src/stlplus/persistence/persistent_exceptions.hpp
deleted file mode 100644 (file)
index 2e2a861..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_EXCEPTIONS\r
-#define STLPLUS_PERSISTENT_EXCEPTIONS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Exceptions thrown by persistence routines\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include <stdexcept>\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // exception thrown if you try to dump or restore an illegal polymorphic type\r
-  class persistent_illegal_type : public std::logic_error\r
-  {\r
-  public:\r
-    persistent_illegal_type(const std::string& type) throw();\r
-    persistent_illegal_type(unsigned key) throw();\r
-    ~persistent_illegal_type(void) throw();\r
-  };\r
-\r
-  // exception thrown if a dump fails for any reason - but typically because the output stream couldn't take the data\r
-  class persistent_dump_failed : public std::runtime_error\r
-  {\r
-  public:\r
-    persistent_dump_failed(const std::string& message) throw();\r
-    ~persistent_dump_failed(void) throw();\r
-  };\r
-\r
-  // exception thrown if you try to restore from an out of date or unrecognised byte stream\r
-  class persistent_restore_failed : public std::runtime_error\r
-  {\r
-  public:\r
-    persistent_restore_failed(const std::string& message) throw();\r
-    ~persistent_restore_failed(void) throw();\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_float.cpp b/src/stlplus/persistence/persistent_float.cpp
deleted file mode 100644 (file)
index 59a6678..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_float.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Macro for mapping either endian data onto little-endian addressing to make\r
-// my life easier in writing this code! I think better in little-endian mode\r
-// so the macro does nothing in that mode but maps little-endian onto\r
-// big-endian addressing in big-endian mode\r
-// TODO - make this compile-time configurable\r
-\r
-#define INDEX(index) ((context.little_endian()) ? (index) : ((bytes) - (index) - 1))\r
-\r
-/////////////////////////////////////////////////////////////////////\r
-// floating point types\r
-// format: {size}{byte}*size\r
-// ordering is msB first\r
-\r
-// this uses a similar mechanism to integer dumps. However, it is not clear how\r
-// the big-endian and little-endian argument applies to multi-word data so\r
-// this may need reworking by splitting into words and then bytes.\r
-\r
-namespace stlplus\r
-{\r
-\r
-  static void dump_float(stlplus::dump_context& context, unsigned bytes, unsigned char* data)\r
-    throw(stlplus::persistent_dump_failed)\r
-  {\r
-    unsigned i = bytes;\r
-    // put the size\r
-    context.put((unsigned char)i);\r
-    // and put the bytes\r
-    while(i--)\r
-      context.put(data[INDEX(i)]);\r
-  }\r
-\r
-  static void restore_float(stlplus::restore_context& context, unsigned bytes, unsigned char* data)\r
-    throw(stlplus::persistent_restore_failed)\r
-  {\r
-    // get the dumped size from the file\r
-    unsigned dumped_bytes = (unsigned)context.get();\r
-    // get the bytes from the file\r
-    unsigned i = dumped_bytes;\r
-    while(i--)\r
-    {\r
-      int ch = context.get();\r
-      if (i < bytes)\r
-        data[INDEX(i)] = (unsigned char)ch;\r
-    }\r
-    // however, if the dumped size was different I don't know how to map the formats, so give an error\r
-    if (dumped_bytes != bytes)\r
-      throw stlplus::persistent_restore_failed(std::string("size mismatch"));\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // exported functions which simply call the low-level byte-dump and byte-restore routines above\r
-\r
-void stlplus::dump_float(stlplus::dump_context& context, const float& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  stlplus::dump_float(context, sizeof(float), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_float(restore_context& context, float& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  stlplus::restore_float(context, sizeof(float), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::dump_double(stlplus::dump_context& context, const double& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  stlplus::dump_float(context, sizeof(double), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_double(restore_context& context, double& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  stlplus::restore_float(context, sizeof(double), (unsigned char*)&data);\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/persistence/persistent_float.hpp b/src/stlplus/persistence/persistent_float.hpp
deleted file mode 100644 (file)
index 4a01e30..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_FLOAT\r
-#define STLPLUS_PERSISTENT_FLOAT\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of floating-point types\r
-\r
-//   Note: despite years and years of IEEE standardisation, not all\r
-//   architectures use IEEE-standard representations of floating-point numbers.\r
-//   Therefore a binary dump is not necessarily portable between platforms.\r
-//   Solving this is (currently) beyond the scope of the STLplus project.\r
-\r
-//   If you want to be strictly portable to all platforms, do not dump/restore float\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void dump_float(dump_context&, const float& data) throw(persistent_dump_failed);\r
-  void restore_float(restore_context&, float& data) throw(persistent_restore_failed);\r
-\r
-  void dump_double(dump_context&, const double& data) throw(persistent_dump_failed);\r
-  void restore_double(restore_context&, double& data) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_foursome.hpp b/src/stlplus/persistence/persistent_foursome.hpp
deleted file mode 100644 (file)
index b326a85..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_FOURSOME\r
-#define STLPLUS_PERSISTENT_FOURSOME\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL foursome\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "foursome.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename D1, typename D2, typename D3, typename D4>\r
-  void dump_foursome(dump_context&, const stlplus::foursome<T1,T2,T3,T4>& data, \r
-                     D1 dump_fn1, D2 dump_fn2, D3 dump_fn3, D4 dump_fn4)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename R1, typename R2, typename R3, typename R4>\r
-  void restore_foursome(restore_context&, stlplus::foursome<T1,T2,T3,T4>& data,\r
-                        R1 restore_fn1, R2 restore_fn2, R3 restore_fn3, R4 restore_fn4)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_foursome.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_foursome.tpp b/src/stlplus/persistence/persistent_foursome.tpp
deleted file mode 100644 (file)
index cfcf6ae..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename D1, typename D2, typename D3, typename D4>\r
-  void dump_foursome(dump_context& context, const foursome<T1,T2,T3,T4>& data, \r
-                     D1 dump_fn1, D2 dump_fn2, D3 dump_fn3, D4 dump_fn4)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_fn1(context,data.first);\r
-    dump_fn2(context,data.second);\r
-    dump_fn3(context,data.third);\r
-    dump_fn4(context,data.fourth);\r
-  }\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename R1, typename R2, typename R3, typename R4>\r
-  void restore_foursome(restore_context& context, foursome<T1,T2,T3,T4>& data,\r
-                        R1 restore_fn1, R2 restore_fn2, R3 restore_fn3, R4 restore_fn4)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    restore_fn1(context,data.first);\r
-    restore_fn2(context,data.second);\r
-    restore_fn3(context,data.third);\r
-    restore_fn4(context,data.fourth);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_hash.hpp b/src/stlplus/persistence/persistent_hash.hpp
deleted file mode 100644 (file)
index 623f285..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_HASH\r
-#define STLPLUS_PERSISTENT_HASH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence for STLplus hash\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "hash.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename H, typename E, typename DK, typename DT>\r
-  void dump_hash(dump_context&, const hash<K,T,H,E>& data, DK key_dump_fn, DT val_dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename K, typename T, typename H, typename E, typename RK, typename RT>\r
-  void restore_hash(restore_context&, hash<K,T,H,E>& data, RK key_restore_fn, RT val_restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_hash.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_hash.tpp b/src/stlplus/persistence/persistent_hash.tpp
deleted file mode 100644 (file)
index 9fe2dbc..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename K, typename T, typename H, typename E, typename DK, typename DT>\r
-  void dump_hash(dump_context& context, const hash<K,T,H,E>& data, DK key_fn, DT val_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (typename hash<K,T,H,E>::const_iterator i = data.begin(); i != data.end(); i++)\r
-    {\r
-      key_fn(context,i->first);\r
-      val_fn(context,i->second);\r
-    }\r
-  }\r
-\r
-  template<typename K, typename T, typename H, typename E, typename RK, typename RT>\r
-  void restore_hash(restore_context& context, hash<K,T,H,E>& data, RK key_fn, RT val_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.erase();\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    for (unsigned j = 0; j < size; j++)\r
-    {\r
-      K key;\r
-      key_fn(context,key);\r
-      val_fn(context,data[key]);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_inf.cpp b/src/stlplus/persistence/persistent_inf.cpp
deleted file mode 100644 (file)
index 29637c9..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// can be excluded to break the dependency on the portability library\r
-#ifndef NO_STLPLUS_INF\r
-\r
-#include "persistent_int.hpp"\r
-#include "persistent_string.hpp"\r
-#include "persistent_inf.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void stlplus::dump_inf(stlplus::dump_context& context, const stlplus::inf& data)\r
-  throw(stlplus::persistent_dump_failed)\r
-{\r
-  // don't support dumping of old versions\r
-  if (context.version() < 2)\r
-    throw stlplus::persistent_dump_failed(std::string("stlplus::inf::dump: wrong version"));\r
-  // just dump the string\r
-  stlplus::dump_string(context,data.get_bytes());\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void stlplus::restore_inf(stlplus::restore_context& context, stlplus::inf& data)\r
-  throw(stlplus::persistent_restore_failed)\r
-{\r
-  if (context.version() < 1)\r
-    throw stlplus::persistent_restore_failed(std::string("stlplus::inf::restore: wrong version"));\r
-  if (context.version() == 1)\r
-  {\r
-    // old-style restore relies on the word size being the same - 32-bits - on all platforms\r
-    // this can be restored on such machines but is not portable to 64-bit machines\r
-    std::string value;\r
-    unsigned bits = 0;\r
-    stlplus::restore_unsigned(context,bits);\r
-    unsigned words = (bits+7)/32;\r
-    // inf was dumped msB first\r
-    for (unsigned i = words; i--; )\r
-    {\r
-      // restore a word\r
-      unsigned word = 0;\r
-      stlplus::restore_unsigned(context,word);\r
-      // now extract the bytes\r
-      unsigned char* byte_ptr = (unsigned char*)(&word);\r
-      for (unsigned b = 4; b--; )\r
-        value.insert(value.begin(),byte_ptr[context.little_endian() ? b : 3 - b]);\r
-    }\r
-    data.set_bytes(value);\r
-  }\r
-  else\r
-  {\r
-    // new-style dump just uses the string persistence\r
-    std::string value;\r
-    stlplus::restore_string(context,value);\r
-    data.set_bytes(value);\r
-  }\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_inf.hpp b/src/stlplus/persistence/persistent_inf.hpp
deleted file mode 100644 (file)
index 2b456d9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_INF\r
-#define STLPLUS_PERSISTENT_INF\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//     Author:    Andy Rushton\r
-//     Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//     License:   BSD License, see ../docs/license.html\r
-  \r
-//     Persistence of stlplus infinite integer type - inf\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "inf.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void dump_inf(dump_context&, const inf& data) throw(persistent_dump_failed);\r
-  void restore_inf(restore_context&, inf& data) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_int.cpp b/src/stlplus/persistence/persistent_int.cpp
deleted file mode 100644 (file)
index 87d403a..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Macro for mapping either endian data onto little-endian addressing to make\r
-// my life easier in writing this code! I think better in little-endian mode\r
-// so the macro does nothing in that mode but maps little-endian onto\r
-// big-endian addressing in big-endian mode\r
-// TODO - make this compile-time configurable so it's more efficient\r
-\r
-#define INDEX(index) ((context.little_endian()) ? (index) : ((bytes) - (index) - 1))\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Integer types\r
-// format: {size}{byte}*size\r
-// size can be zero!\r
-//\r
-// A major problem is that integer types may be different sizes on different\r
-// machines or even with different compilers on the same machine (though I\r
-// haven't come across that yet). Neither the C nor the C++ standards specify\r
-// the size of integer types. Dumping an int on one machine might dump 16\r
-// bits. Restoring it on another machine might try to restore 32 bits. These\r
-// functions must therefore handle different type sizes. It does this by\r
-// writing the size to the file as well as the data, so the restore can\r
-// therefore know how many bytes to restore independent of the type size.\r
-//\r
-// In fact, the standard does not even specify the size of char (true! And\r
-// mind-numbingly stupid...). However, to be able to do anything at all, I've\r
-// had to assume that a char is 1 byte.\r
-\r
-static void dump_unsigned(stlplus::dump_context& context, unsigned bytes, unsigned char* data)\r
-  throw(stlplus::persistent_dump_failed)\r
-{\r
-  // first skip zero bytes - this may reduce the data to zero bytes long\r
-  unsigned i = bytes;\r
-  while(i >= 1 && data[INDEX(i-1)] == 0)\r
-    i--;\r
-  // put the remaining size\r
-  context.put((unsigned char)i);\r
-  // and put the bytes\r
-  while(i--)\r
-    context.put(data[INDEX(i)]);\r
-}\r
-\r
-static void dump_signed(stlplus::dump_context& context, unsigned bytes, unsigned char* data)\r
-  throw(stlplus::persistent_dump_failed)\r
-{\r
-  // first skip all-zero or all-one bytes but only if doing so does not change the sign\r
-  unsigned i = bytes;\r
-  if (data[INDEX(i-1)] < 128)\r
-  {\r
-    // positive number so discard leading zeros but only if the following byte is positive\r
-    while(i >= 2 && data[INDEX(i-1)] == 0 && data[INDEX(i-2)] < 128)\r
-      i--;\r
-  }\r
-  else\r
-  {\r
-    // negative number so discard leading ones but only if the following byte is negative\r
-    while(i >= 2 && data[INDEX(i-1)] == 255 && data[INDEX(i-2)] >= 128)\r
-      i--;\r
-  }\r
-  // put the remaining size\r
-  context.put((unsigned char)i);\r
-  // and put the bytes\r
-  while(i--)\r
-    context.put(data[INDEX(i)]);\r
-}\r
-\r
-static void restore_unsigned(stlplus::restore_context& context, unsigned bytes, unsigned char* data)\r
-  throw(stlplus::persistent_restore_failed)\r
-{\r
-  // get the dumped size from the file\r
-  unsigned dumped_bytes = (unsigned)context.get();\r
-  // zero fill any empty space\r
-  unsigned i = bytes;\r
-  for (; i > dumped_bytes; i--)\r
-    data[INDEX(i-1)] = 0;\r
-  // restore the dumped bytes but discard any that don't fit\r
-  while(i--)\r
-  {\r
-    int ch = context.get();\r
-    if (i < bytes)\r
-      data[INDEX(i)] = (unsigned char)ch;\r
-    else\r
-      throw stlplus::persistent_restore_failed(std::string("integer overflow"));\r
-  }\r
-}\r
-\r
-static void restore_signed(stlplus::restore_context& context, unsigned bytes, unsigned char* data)\r
-  throw(stlplus::persistent_restore_failed)\r
-{\r
-  // get the dumped size from the file\r
-  unsigned dumped_bytes = (unsigned)context.get();\r
-  // restore the dumped bytes but discard any that don't fit\r
-  unsigned i = dumped_bytes;\r
-  while(i--)\r
-  {\r
-    int ch = context.get();\r
-    if (i < bytes)\r
-      data[INDEX(i)] = (unsigned char)ch;\r
-    else\r
-      throw stlplus::persistent_restore_failed(std::string("integer overflow"));\r
-  }\r
-  // sign extend if the dumped integer was smaller\r
-  if (dumped_bytes < bytes)\r
-  {\r
-    if (data[INDEX(dumped_bytes-1)] < 128)\r
-    {\r
-      // positive so zero fill\r
-      for (i = dumped_bytes; i < bytes; i++)\r
-        data[INDEX(i)] = 0;\r
-    }\r
-    else\r
-    {\r
-      // negative so one fill\r
-      for (i = dumped_bytes; i < bytes; i++)\r
-        data[INDEX(i)] = 0xff;\r
-    }\r
-  }\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// exported functions\r
-\r
-// char is dumped and restored as an unsigned char because the signedness of char is not defined and can vary\r
-void stlplus::dump_char(stlplus::dump_context& context, const char& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  context.put((unsigned char)data);\r
-}\r
-\r
-void stlplus::restore_char(restore_context& context, char& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  data = (char)(unsigned char)context.get();\r
-}\r
-\r
-void stlplus::dump_signed_char(stlplus::dump_context& context, const signed char& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  context.put((unsigned char)data);\r
-}\r
-\r
-void stlplus::restore_signed_char(restore_context& context, signed char& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  data = (signed char)(unsigned char)context.get();\r
-}\r
-\r
-void stlplus::dump_unsigned_char(stlplus::dump_context& context, const unsigned char& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  context.put((unsigned char)data);\r
-}\r
-\r
-void stlplus::restore_unsigned_char(restore_context& context, unsigned char& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  data = (signed char)(unsigned char)context.get();\r
-}\r
-\r
-void stlplus::dump_short(stlplus::dump_context& context, const short& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  ::dump_signed(context, sizeof(short), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_short(restore_context& context, short& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  ::restore_signed(context, sizeof(short),(unsigned char*)&data);\r
-}\r
-\r
-void stlplus::dump_unsigned_short(stlplus::dump_context& context, const unsigned short& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  ::dump_unsigned(context, sizeof(unsigned short), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_unsigned_short(restore_context& context, unsigned short& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  ::restore_unsigned(context, sizeof(unsigned short),(unsigned char*)&data);\r
-}\r
-\r
-void stlplus::dump_int(stlplus::dump_context& context, const int& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  ::dump_signed(context, sizeof(int), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_int(restore_context& context, int& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  ::restore_signed(context, sizeof(int),(unsigned char*)&data);\r
-}\r
-\r
-void stlplus::dump_unsigned(stlplus::dump_context& context, const unsigned& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  ::dump_unsigned(context, sizeof(unsigned), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_unsigned(restore_context& context, unsigned& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  ::restore_unsigned(context, sizeof(unsigned),(unsigned char*)&data);\r
-}\r
-\r
-void stlplus::dump_long(stlplus::dump_context& context, const long& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  ::dump_signed(context, sizeof(long), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_long(restore_context& context, long& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  ::restore_signed(context, sizeof(long),(unsigned char*)&data);\r
-}\r
-\r
-void stlplus::dump_unsigned_long(stlplus::dump_context& context, const unsigned long& data) throw(stlplus::persistent_dump_failed)\r
-{\r
-  ::dump_unsigned(context, sizeof(unsigned long), (unsigned char*)&data);\r
-}\r
-\r
-void stlplus::restore_unsigned_long(restore_context& context, unsigned long& data) throw(stlplus::persistent_restore_failed)\r
-{\r
-  ::restore_unsigned(context, sizeof(unsigned long),(unsigned char*)&data);\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/persistence/persistent_int.hpp b/src/stlplus/persistence/persistent_int.hpp
deleted file mode 100644 (file)
index 404d1c5..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_INT\r
-#define STLPLUS_PERSISTENT_INT\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of basic integer types\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void dump_char(dump_context&, const char& data) throw(persistent_dump_failed);\r
-  void restore_char(restore_context&, char& data) throw(persistent_restore_failed);\r
-\r
-  void dump_signed_char(dump_context&, const signed char& data) throw(persistent_dump_failed);\r
-  void restore_signed_char(restore_context&, signed char& data) throw(persistent_restore_failed);\r
-\r
-  void dump_unsigned_char(dump_context&, const unsigned char& data) throw(persistent_dump_failed);\r
-  void restore_unsigned_char(restore_context&, unsigned char& data) throw(persistent_restore_failed);\r
-\r
-  void dump_short(dump_context&, const short& data) throw(persistent_dump_failed);\r
-  void restore_short(restore_context&, short& data) throw(persistent_restore_failed);\r
-\r
-  void dump_unsigned_short(dump_context&, const unsigned short& data) throw(persistent_dump_failed);\r
-  void restore_unsigned_short(restore_context&, unsigned short& data) throw(persistent_restore_failed);\r
-\r
-  void dump_int(dump_context&, const int& data) throw(persistent_dump_failed);\r
-  void restore_int(restore_context&, int& data) throw(persistent_restore_failed);\r
-\r
-  void dump_unsigned(dump_context&, const unsigned& data) throw(persistent_dump_failed);\r
-  void restore_unsigned(restore_context&, unsigned& data) throw(persistent_restore_failed);\r
-\r
-  void dump_long(dump_context&, const long& data) throw(persistent_dump_failed);\r
-  void restore_long(restore_context&, long& data) throw(persistent_restore_failed);\r
-\r
-  void dump_unsigned_long(dump_context&, const unsigned long& data) throw(persistent_dump_failed);\r
-  void restore_unsigned_long(restore_context&, unsigned long& data) throw(persistent_restore_failed);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_interface.hpp b/src/stlplus/persistence/persistent_interface.hpp
deleted file mode 100644 (file)
index 366954c..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_INTERFACE\r
-#define STLPLUS_PERSISTENT_INTERFACE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence for pointers to polymorphic classes using the interface approach.\r
-\r
-//   This works on a set of classes derived from a common superclass called\r
-//   persistent which is declared as an interface. Each subclass has a set of\r
-//   methods that enable clone/dump/restore operations. Each subclass must be\r
-//   registered with the persistence dump/restore context so that the system\r
-//   knows how to dump it.\r
-\r
-//   This approach is suited to classes that can be modified to add persistence\r
-//   methods. See persistent_callback for a non-invasive way of handling\r
-//   polymorphism.\r
-\r
-//   Objects are always dumped/restored as pointers to the superclass T.\r
-\r
-//   Multiple pointers to the same object are handled in the same way as for\r
-//   simple pointers\r
-\r
-//   Only classes registered with the context can be dumped and restored as\r
-//   polymorphic types - see dump_context::register_interface and\r
-//   restore_context::register_interface. Attempting to use any unrecognised class\r
-//   will throw an exception.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "persistent.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T>\r
-  void dump_interface(dump_context&, const T* const data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_interface(restore_context&, T*& data)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_interface.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_interface.tpp b/src/stlplus/persistence/persistent_interface.tpp
deleted file mode 100644 (file)
index a684aa3..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Polymorphous classes using the interface approach\r
-\r
-//   format: magic [ key data ]\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  void dump_interface(dump_context& context, const T* const data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    try\r
-    {\r
-      // register the address and get the magic key for it\r
-      std::pair<bool,unsigned> mapping = context.pointer_map(data);\r
-      dump_unsigned(context,mapping.second);\r
-      // if the address is null, then that is all that we need to do\r
-      // however, if it is non-null and this is the first sight of the address, dump the contents\r
-      if (data && !mapping.first)\r
-      {\r
-        // interface method\r
-        // the lookup just finds the magic key and the type has a dump method\r
-        // this will throw persistent_illegal_type if the type is not registered\r
-        unsigned key = context.lookup_interface(typeid(*data));\r
-        // dump the magic key for the type\r
-        dump_unsigned(context, key);\r
-        // now call the dump method defined by the interface\r
-        data->dump(context);\r
-      }\r
-    }\r
-    catch (const persistent_illegal_type& except)\r
-    {\r
-      // convert this to a simpler dump failed exception\r
-      throw persistent_dump_failed(except.what());\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  void restore_interface(restore_context& context, T*& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    try\r
-    {\r
-      // first delete any previous object pointed to since the restore creates the object of the right subclass\r
-      if (data)\r
-      {\r
-        delete data;\r
-        data = 0;\r
-      }\r
-      // get the magic key\r
-      unsigned magic = 0;\r
-      restore_unsigned(context,magic);\r
-      // now lookup the magic key to see if this pointer has already been restored\r
-      // null pointers are always flagged as already restored\r
-      std::pair<bool,void*> address = context.pointer_map(magic);\r
-      if (address.first)\r
-      {\r
-        // seen before, so simply map it to the existing address\r
-        data = (T*)address.second;\r
-      }\r
-      else\r
-      {\r
-        // now restore the magic key that denotes the particular subclass\r
-        unsigned key = 0;\r
-        restore_unsigned(context, key);\r
-        // interface approach\r
-        // first clone the sample object stored in the map - lookup_interface can throw persistent_illegal_type\r
-        data = (T*)(context.lookup_interface(key)->clone());\r
-        // add this pointer to the set of already seen objects\r
-        // do this before restoring the object so that self-referential structures restore correctly\r
-        context.pointer_add(magic,data);\r
-        // now restore the contents using the object's method\r
-        data->restore(context);\r
-      }\r
-    }\r
-    catch (const persistent_illegal_type& exception)\r
-    {\r
-      // convert this to a simpler dump failed exception\r
-      throw persistent_restore_failed(exception.what());\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_list.hpp b/src/stlplus/persistence/persistent_list.hpp
deleted file mode 100644 (file)
index b95d767..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_LIST\r
-#define STLPLUS_PERSISTENT_LIST\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL list\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <list>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename D>\r
-  void dump_list(dump_context&, const std::list<T>& data, D dump_fn) throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename R>\r
-  void restore_list(restore_context&, std::list<T>& data, R restore_fn) throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_list.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_list.tpp b/src/stlplus/persistence/persistent_list.tpp
deleted file mode 100644 (file)
index aaf696f..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename D>\r
-  void dump_list(dump_context& context, const std::list<T>& data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (typename std::list<T>::const_iterator i = data.begin(); i != data.end(); i++)\r
-      dump_fn(context,*i);\r
-  }\r
-\r
-  template<typename T, typename R>\r
-  void restore_list(restore_context& context, std::list<T>& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.clear();\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    for (unsigned i = 0; i < size; i++)\r
-    {\r
-      data.push_back(T());\r
-      restore_fn(context,data.back());\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_map.hpp b/src/stlplus/persistence/persistent_map.hpp
deleted file mode 100644 (file)
index 4f9449f..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_MAP\r
-#define STLPLUS_PERSISTENT_MAP\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence for STL map\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <map>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename P, typename DK, typename DT>\r
-  void dump_map(dump_context&, const std::map<K,T,P>& data, DK key_dump_fn, DT val_dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename K, typename T, typename P, typename RK, typename RT>\r
-  void restore_map(restore_context&, std::map<K,T,P>& data, RK key_restore_fn, RT val_restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_map.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_map.tpp b/src/stlplus/persistence/persistent_map.tpp
deleted file mode 100644 (file)
index b1af42c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename K, typename T, typename P, typename DK, typename DT>\r
-  void dump_map(dump_context& context, const std::map<K,T,P>& data, DK key_fn, DT val_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (typename std::map<K,T,P>::const_iterator i = data.begin(); i != data.end(); i++)\r
-    {\r
-      key_fn(context,i->first);\r
-      val_fn(context,i->second);\r
-    }\r
-  }\r
-\r
-  template<typename K, typename T, typename P, typename RK, typename RT>\r
-  void restore_map(restore_context& context, std::map<K,T,P>& data, RK key_fn, RT val_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.clear();\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    for (unsigned j = 0; j < size; j++)\r
-    {\r
-      K key;\r
-      key_fn(context,key);\r
-      val_fn(context,data[key]);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_matrix.hpp b/src/stlplus/persistence/persistent_matrix.hpp
deleted file mode 100644 (file)
index 2f727a2..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_MATRIX\r
-#define STLPLUS_PERSISTENT_MATRIX\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STLplus matrix\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "matrix.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename DT>\r
-  void dump_matrix(dump_context&, const matrix<T>& data, DT dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename RT>\r
-  void restore_matrix(restore_context&, matrix<T>& data, RT restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_matrix.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_matrix.tpp b/src/stlplus/persistence/persistent_matrix.tpp
deleted file mode 100644 (file)
index ac81f85..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename DT>\r
-  void dump_matrix(dump_context& context, const matrix<T>& data,\r
-                   DT dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    unsigned rows = data.rows();\r
-    unsigned cols = data.columns();\r
-    dump_unsigned(context, rows);\r
-    dump_unsigned(context, cols);\r
-    for (unsigned r = 0; r < rows; r++)\r
-      for (unsigned c = 0; c < cols; c++)\r
-        dump_fn(context, data(r,c));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename RT>\r
-  void restore_matrix(restore_context& context, matrix<T>& data,\r
-                      RT restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    unsigned rows = 0;\r
-    restore_unsigned(context, rows);\r
-    unsigned cols = 0;\r
-    restore_unsigned(context, cols);\r
-    data.resize(rows,cols);\r
-    for (unsigned r = 0; r < rows; r++)\r
-      for (unsigned c = 0; c < cols; c++)\r
-        restore_fn(context, data(r,c));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_multimap.hpp b/src/stlplus/persistence/persistent_multimap.hpp
deleted file mode 100644 (file)
index 0ad0716..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_MULTIMAP\r
-#define STLPLUS_PERSISTENT_MULTIMAP\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL multimap\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <map>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename P, typename DK, typename DT>\r
-  void dump_multimap(dump_context&, const std::multimap<K,T,P>& data, DK key_dump_fn, DT val_dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename K, typename T, typename P, typename RK, typename RT>\r
-  void restore_multimap(restore_context&, std::multimap<K,T,P>& data, RK key_restore_fn, RT val_restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_multimap.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_multimap.tpp b/src/stlplus/persistence/persistent_multimap.tpp
deleted file mode 100644 (file)
index 5f96a3d..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename K, typename T, typename P, typename DK, typename DT>\r
-  void dump_multimap(dump_context& context, const std::multimap<K,T,P>& data, DK key_fn, DT val_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (typename std::multimap<K,T,P>::const_iterator i = data.begin(); i != data.end(); i++)\r
-    {\r
-      key_fn(context,i->first);\r
-      val_fn(context,i->second);\r
-    }\r
-  }\r
-\r
-  template<typename K, typename T, typename P, typename RK, typename RT>\r
-  void restore_multimap(restore_context& context, std::multimap<K,T,P>& data, RK key_fn, RT val_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.clear();\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    for (unsigned j = 0; j < size; j++)\r
-    {\r
-      K key;\r
-      key_fn(context,key);\r
-      typename std::multimap<K,T,P>::iterator v = data.insert(std::pair<K,T>(key,T()));\r
-      val_fn(context,v->second);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_multiset.hpp b/src/stlplus/persistence/persistent_multiset.hpp
deleted file mode 100644 (file)
index d451a8e..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_MULTISET\r
-#define STLPLUS_PERSISTENT_MULTISET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL multiset\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <set>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename P, typename D>\r
-  void dump_multiset(dump_context&, const std::multiset<K,P>& data, D dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename K, typename P, typename R>\r
-  void restore_multiset(restore_context&, std::multiset<K,P>& data, R restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_multiset.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_multiset.tpp b/src/stlplus/persistence/persistent_multiset.tpp
deleted file mode 100644 (file)
index 0a31353..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename K, typename P, typename D>\r
-  void dump_multiset(dump_context& context, const std::multiset<K,P>& data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (typename std::multiset<K,P>::const_iterator i = data.begin(); i != data.end(); i++)\r
-      dump_fn(context,*i);\r
-  }\r
-\r
-  template<typename K, typename P, typename R>\r
-  void restore_multiset(restore_context& context, std::multiset<K,P>& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.clear();\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    typename std::multiset<K,P>::iterator i = data.begin();\r
-    for (unsigned j = 0; j < size; j++)\r
-    {\r
-      K key;\r
-      restore_fn(context,key);\r
-      // inserting using an iterator is O(n) rather than O(n*log(n))\r
-      i = data.insert(i, key);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_ntree.hpp b/src/stlplus/persistence/persistent_ntree.hpp
deleted file mode 100644 (file)
index 635da50..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_NTREE\r
-#define STLPLUS_PERSISTENT_NTREE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STLplus ntree\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "ntree.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // ntree\r
-\r
-  template<typename T, typename D>\r
-  void dump_ntree(dump_context&, const ntree<T>& data, D dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename R>\r
-  void restore_ntree(restore_context&, ntree<T>& data, R restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-  // iterator\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void dump_ntree_iterator(dump_context&, const ntree_iterator<T,TRef,TPtr>&)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void restore_ntree_iterator(restore_context&, ntree_iterator<T,TRef,TPtr>&)\r
-    throw(persistent_restore_failed);\r
-\r
-  // prefix iterator\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void dump_ntree_prefix_iterator(dump_context&, const ntree_prefix_iterator<T,TRef,TPtr>&)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void restore_ntree_prefix_iterator(restore_context&, ntree_prefix_iterator<T,TRef,TPtr>&)\r
-    throw(persistent_restore_failed);\r
-\r
-  // postfix iterator\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void dump_ntree_postfix_iterator(dump_context&, const ntree_postfix_iterator<T,TRef,TPtr>&)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void restore_ntree_postfix_iterator(restore_context&, ntree_postfix_iterator<T,TRef,TPtr>&)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_ntree.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_ntree.tpp b/src/stlplus/persistence/persistent_ntree.tpp
deleted file mode 100644 (file)
index d50ba17..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_bool.hpp"\r
-#include "persistent_int.hpp"\r
-#include "persistent_xref.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename D>\r
-  void dump_ntree_r(dump_context& context,\r
-                    const ntree<T>& tree, \r
-                    const TYPENAME ntree<T>::const_iterator& node,\r
-                    D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // the magic key of the ntree_node is dumped as well as the contents - this is used in iterator persistence\r
-    std::pair<bool,unsigned> node_mapping = context.pointer_map(node.node());\r
-    if (node_mapping.first) throw persistent_dump_failed("ntree: already dumped this node");\r
-    dump_unsigned(context,node_mapping.second);\r
-    // now dump the contents\r
-    dump_fn(context,*node);\r
-    // dump the number of children\r
-    unsigned children = tree.children(node);\r
-    dump_unsigned(context,children);\r
-    // recurse on the children\r
-    for (unsigned i = 0; i < children; i++)\r
-      dump_ntree_r<T,D>(context,tree,tree.child(node,i),dump_fn);\r
-  }\r
-\r
-  template<typename T, typename D>\r
-  void dump_ntree(dump_context& context,\r
-                  const ntree<T>& tree,\r
-                  D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // dump a magic key to the address of the tree for use in persistence of iterators\r
-    // and register it as a dumped address\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(&tree);\r
-    if (mapping.first) throw persistent_dump_failed("ntree: already dumped this tree");\r
-    dump_unsigned(context,mapping.second);\r
-    // now dump the tree contents - start with a flag to indicate whether the tree is empty\r
-    dump_bool(context, tree.empty());\r
-    // now recursively dump the contents\r
-    if (!tree.empty())\r
-      dump_ntree_r<T,D>(context,tree,tree.root(),dump_fn);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename R>\r
-  void restore_ntree_r(restore_context& context,\r
-                       ntree<T>& tree,\r
-                       const TYPENAME ntree<T>::iterator& node,\r
-                       R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    // restore the node magic key, check whether it has been used before and add it to the set of known addresses\r
-    unsigned node_magic = 0;\r
-    restore_unsigned(context,node_magic);\r
-    std::pair<bool,void*> node_mapping = context.pointer_map(node_magic);\r
-    if (node_mapping.first) throw persistent_restore_failed("ntree: restored this tree node already");\r
-    context.pointer_add(node_magic,node.node());\r
-    // now restore the node contents\r
-    restore_fn(context,*node);\r
-    // restore the number of children\r
-    unsigned children = 0;\r
-    restore_unsigned(context,children);\r
-    // recurse on each child\r
-    for (unsigned i = 0; i < children; i++)\r
-    {\r
-      typename ntree<T>::iterator child = tree.insert(node,i,T());\r
-      restore_ntree_r<T,R>(context,tree,child,restore_fn);\r
-    }\r
-  }\r
-\r
-  template<typename T, typename R>\r
-  void restore_ntree(restore_context& context,\r
-                     ntree<T>& tree,\r
-                     R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    tree.erase();\r
-    // restore the tree's magic key and map it onto the tree's address\r
-    // this is used in the persistence of iterators\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    context.pointer_add(magic,&tree);\r
-    // now restore the contents\r
-    bool empty = true;\r
-    restore_bool(context, empty);\r
-    if (!empty)\r
-    {\r
-      typename ntree<T>::iterator node = tree.insert(T());\r
-      restore_ntree_r<T,R>(context,tree,node,restore_fn);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void dump_ntree_iterator(dump_context& context,\r
-                           const ntree_iterator<T,TRef,TPtr>& data) \r
-    throw(persistent_dump_failed)\r
-  {\r
-    data.assert_valid();\r
-    dump_xref(context,data.owner());\r
-    dump_xref(context,data.node());\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void restore_ntree_iterator(restore_context& context,\r
-                              ntree_iterator<T,TRef,TPtr>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    const ntree<T>* owner = 0;\r
-    ntree_node<T>* node = 0;\r
-    restore_xref(context,owner);\r
-    restore_xref(context,node);\r
-    data = ntree_iterator<T,TRef,TPtr>(node->m_master);\r
-    data.assert_valid(owner);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void dump_ntree_prefix_iterator(dump_context& context,\r
-                                  const ntree_prefix_iterator<T,TRef,TPtr>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_ntree_iterator(context,data.iterator());\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void restore_ntree_prefix_iterator(restore_context& context,\r
-                                     ntree_prefix_iterator<T,TRef,TPtr>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    ntree_iterator<T,TRef,TPtr> iterator;\r
-    restore_ntree_iterator(context,iterator);\r
-    data = ntree_prefix_iterator<T,TRef,TPtr>(iterator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void dump_ntree_postfix_iterator(dump_context& context,\r
-                                   const ntree_postfix_iterator<T,TRef,TPtr>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_ntree_iterator(context,data.iterator());\r
-  }\r
-\r
-  template<typename T, typename TRef, typename TPtr>\r
-  void restore_ntree_postfix_iterator(restore_context& context,\r
-                                      ntree_postfix_iterator<T,TRef,TPtr>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    ntree_iterator<T,TRef,TPtr> iterator;\r
-    restore_ntree_iterator(context,iterator);\r
-    data = ntree_postfix_iterator<T,TRef,TPtr>(iterator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_pair.hpp b/src/stlplus/persistence/persistent_pair.hpp
deleted file mode 100644 (file)
index 7d23107..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_PAIR\r
-#define STLPLUS_PERSISTENT_PAIR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL pair\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <map>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename V1, typename V2, typename D1, typename D2>\r
-  void dump_pair(dump_context&, const std::pair<V1,V2>& data, D1 dump_fn1, D2 dump_fn2)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename V1, typename V2, typename R1, typename R2>\r
-  void restore_pair(restore_context&, std::pair<V1,V2>& data, R1 restore_fn1, R2 restore_fn2)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_pair.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_pair.tpp b/src/stlplus/persistence/persistent_pair.tpp
deleted file mode 100644 (file)
index aa118cf..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_pair.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename K, typename T, typename D1, typename D2>\r
-  void dump_pair(dump_context& context, const std::pair<K,T>& data, D1 dump_fn1, D2 dump_fn2)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_fn1(context,data.first);\r
-    dump_fn2(context,data.second);\r
-  }\r
-\r
-  template<typename K, typename T, typename R1, typename R2>\r
-  void restore_pair(restore_context& context, std::pair<K,T>& data, R1 restore_fn1, R2 restore_fn2)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    restore_fn1(context,data.first);\r
-    restore_fn2(context,data.second);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_pointer.hpp b/src/stlplus/persistence/persistent_pointer.hpp
deleted file mode 100644 (file)
index 02d0951..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_POINTER\r
-#define STLPLUS_PERSISTENT_POINTER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence for pointers to persistent objects\r
-\r
-//   Warning! The pointer must be a dynamically-allocated type, since the\r
-//   implementation uses new/delete\r
-\r
-//   Multiple pointers to the same object *will* be restored as multiple pointers\r
-//   to the same object. The object is dumped only the first time it is\r
-//   encountered along with a "magic key". Subsequent pointers to the same object\r
-//   cause only the magic key to be dumped. On restore, the object is only\r
-//   restored once and the magic keys are matched up so that the other pointers\r
-//   now point to the restored object.\r
-\r
-//   Supports null pointers too! If the data field to restore is null and the\r
-//   file format non-null, allocates a new T(). If the data field is non-null and\r
-//   the file format is null, deletes it and sets it null\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename D>\r
-  void dump_pointer(dump_context&, const T* const data, D dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename R>\r
-  void restore_pointer(restore_context&, T*& data, R restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_pointer.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_pointer.tpp b/src/stlplus/persistence/persistent_pointer.tpp
deleted file mode 100644 (file)
index c760b17..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   format: magic_key [ data ]\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename D>\r
-  void dump_pointer(dump_context& context, const T* const data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // register the address and get the magic key for it\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data);\r
-    dump_unsigned(context,mapping.second);\r
-    // if the address is null, then that is all that we need to do\r
-    // however, if it is non-null and this is the first sight of the address, dump the contents\r
-    // note that the address is mapped before it is dumped so that self-referential structures dump correctly\r
-    if (data && !mapping.first)\r
-      dump_fn(context,*data);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename R>\r
-  void restore_pointer(restore_context& context, T*& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    if (data)\r
-    {\r
-      delete data;\r
-      data = 0;\r
-    }\r
-    // get the magic key\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    // now lookup the magic key to see if this pointer has already been restored\r
-    // null pointers are always flagged as already restored\r
-    std::pair<bool,void*> address = context.pointer_map(magic);\r
-    if (address.first)\r
-    {\r
-      // seen before, so simply assign the old address\r
-      data = (T*)address.second;\r
-    }\r
-    else\r
-    {\r
-      // this pointer has never been seen before and is non-null\r
-      data = new T();\r
-      // add this pointer to the set of already seen objects\r
-      // do this before restoring the object so that self-referential structures restore correctly\r
-      context.pointer_add(magic,data);\r
-      // now restore it\r
-      restore_fn(context,*data);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_pointers.hpp b/src/stlplus/persistence/persistent_pointers.hpp
deleted file mode 100644 (file)
index 7e84759..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_POINTERS\r
-#define STLPLUS_PERSISTENT_POINTERS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of all pointer types\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistent_pointer.hpp"\r
-#include "persistent_xref.hpp"\r
-#include "persistent_callback.hpp"\r
-#include "persistent_interface.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_set.hpp b/src/stlplus/persistence/persistent_set.hpp
deleted file mode 100644 (file)
index a2f8c7a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_SET\r
-#define STLPLUS_PERSISTENT_SET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Set of persistence routines for the STL classes\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <set>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename P, typename D>\r
-  void dump_set(dump_context&, const std::set<K,P>& data, D dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename K, typename P, typename R>\r
-  void restore_set(restore_context&, std::set<K,P>& data, R restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_set.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_set.tpp b/src/stlplus/persistence/persistent_set.tpp
deleted file mode 100644 (file)
index 007d068..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename K, typename P, typename D>\r
-  void dump_set(dump_context& context, const std::set<K,P>& data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (typename std::set<K,P>::const_iterator i = data.begin(); i != data.end(); i++)\r
-      dump_fn(context,*i);\r
-  }\r
-\r
-  template<typename K, typename P, typename R>\r
-  void restore_set(restore_context& context, std::set<K,P>& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.clear();\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    typename std::set<K,P>::iterator i = data.begin();\r
-    for (unsigned j = 0; j < size; j++)\r
-    {\r
-      K key;\r
-      restore_fn(context,key);\r
-      // inserting using an iterator is O(n) rather than O(n*log(n))\r
-      i = data.insert(i, key);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_shortcuts.hpp b/src/stlplus/persistence/persistent_shortcuts.hpp
deleted file mode 100644 (file)
index beb54d0..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_SHORTCUTS\r
-#define STLPLUS_PERSISTENT_SHORTCUTS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Short-cut functions for dumping and restoring to common targets. These do\r
-//   the whole dump operation in a single function call.\r
-\r
-//   They take as their second template argument a dump or restore functor which\r
-//   is then called to perform the dump/restore operation.\r
-\r
-//   They use an installer callback function to install any polymorphic type\r
-//   handlers required prior to performing the dump/restore. If there are no\r
-//   polymorphic types used in the data structure, then the callback can be set\r
-//   to null (i.e. 0).\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // arbitrary IOStream device\r
-  // must be in binary mode\r
-\r
-  template<typename T, class D>\r
-  void dump_to_device(const T& source, std::ostream& result, D dump_fn, dump_context::installer installer)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, class R>\r
-  void restore_from_device(std::istream& source, T& result, R restore_fn, restore_context::installer installer)\r
-    throw(persistent_restore_failed);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // string IO device\r
-\r
-  template<typename T, class D>\r
-  void dump_to_string(const T& source, std::string& result, D dump_fn, dump_context::installer installer)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, class R>\r
-  void restore_from_string(const std::string& source, T& result, R restore_fn, restore_context::installer installer)\r
-    throw(persistent_restore_failed);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // file IO device\r
-\r
-  template<typename T, class D>\r
-  void dump_to_file(const T& source, const std::string& filename, D dump_fn, dump_context::installer installer)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, class R>\r
-  void restore_from_file(const std::string& filename, T& result, R restore_fn, restore_context::installer installer)\r
-    throw(persistent_restore_failed);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_shortcuts.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_shortcuts.tpp b/src/stlplus/persistence/persistent_shortcuts.tpp
deleted file mode 100644 (file)
index 9b5aac5..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include <sstream>\r
-#include <fstream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, class D>\r
-  void dump_to_device(const T& source, std::ostream& result, D dump_fn, \r
-                      dump_context::installer installer)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_context context(result);\r
-    context.register_all(installer);\r
-    dump_fn(context, source);\r
-  }\r
-\r
-  template<typename T, class R>\r
-  void restore_from_device(std::istream& source, T& result, R restore_fn,\r
-                           restore_context::installer installer)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    restore_context context(source);\r
-    context.register_all(installer);\r
-    restore_fn(context, result);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, class D>\r
-  void dump_to_string(const T& source, std::string& result, D dump_fn, \r
-                      dump_context::installer installer)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    std::ostringstream output(std::ios_base::out | std::ios_base::binary);\r
-    dump_to_device<T,D>(source, output, dump_fn, installer);\r
-    result = output.str();\r
-  }\r
-\r
-  template<typename T, class R>\r
-  void restore_from_string(const std::string& source, T& result, R restore_fn, \r
-                           restore_context::installer installer)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    std::istringstream input(source, std::ios_base::in | std::ios_base::binary);\r
-    restore_from_device<T,R>(input, result, restore_fn, installer);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, class D>\r
-  void dump_to_file(const T& source, const std::string& filename, D dump_fn,\r
-                    dump_context::installer installer)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    std::ofstream output(filename.c_str(), std::ios_base::out | std::ios_base::binary);\r
-    dump_to_device<T,D>(source, output, dump_fn, installer);\r
-  }\r
-\r
-  template<typename T, class R>\r
-  void restore_from_file(const std::string& filename, T& result, R restore_fn,\r
-                         restore_context::installer installer)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    std::ifstream input(filename.c_str(), std::ios_base::in | std::ios_base::binary);\r
-    restore_from_device<T,R>(input, result, restore_fn, installer);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_simple_ptr.hpp b/src/stlplus/persistence/persistent_simple_ptr.hpp
deleted file mode 100644 (file)
index ccf4260..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_SIMPLE_PTR\r
-#define STLPLUS_PERSISTENT_SIMPLE_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STLplus simple_ptr\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "simple_ptr.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // simple_ptr - uses dump/restore_pointer on the contents\r
-\r
-  template<typename T, typename DE>\r
-  void dump_simple_ptr(dump_context&, const simple_ptr<T>& data, DE dump_element)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename RE>\r
-  void restore_simple_ptr(restore_context&, simple_ptr<T>& data, RE restore_element)\r
-    throw(persistent_restore_failed);\r
-\r
-  // simple_ptr_clone using the polymorphic callback approach - uses dump/restore_callback on the contents\r
-\r
-  template<typename T>\r
-  void dump_simple_ptr_clone_callback(dump_context&, const simple_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_simple_ptr_clone_callback(restore_context&, simple_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed);\r
-\r
-  // simple_ptr_clone using the interface approach - uses dump/restore_interface on the contents\r
-\r
-  template<typename T>\r
-  void dump_simple_ptr_clone_interface(dump_context&, const simple_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_simple_ptr_clone_interface(restore_context&, simple_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed);\r
-\r
-  // simple_ptr_nocopy is not made persistent because if it is uncopyable, it must be undumpable\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_simple_ptr.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_simple_ptr.tpp b/src/stlplus/persistence/persistent_simple_ptr.tpp
deleted file mode 100644 (file)
index 36f88bd..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-#include "persistent_pointer.hpp"\r
-#include "persistent_callback.hpp"\r
-#include "persistent_interface.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename  T, typename DE>\r
-  void dump_simple_ptr(dump_context& context, const simple_ptr<T>& data,\r
-                      DE dump_element)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // Many smart pointers can point to the same object.\r
-    // I could have used the address of the object to differentiate, \r
-    // but that would not have differentiated between different null smart pointers\r
-    // so I use the address of the count to differentiate between different objects.\r
-    // get a magic key for the substructure - this also returns a flag saying whether its been seen before\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data._count());\r
-    // dump the magic key for the count\r
-    dump_unsigned(context,mapping.second);\r
-    // dump the contents always - this is because I need to rely on the pointer routines dumping a second magic key\r
-    // use the existing routines for ordinary pointers to dump the contents\r
-    dump_pointer(context,data._pointer(),dump_element);\r
-  }\r
-\r
-  template<typename T, typename RE>\r
-  void restore_simple_ptr(restore_context& context, simple_ptr<T>& data,\r
-                         RE restore_element)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    // get the old counter magic key\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    // lookup this magic number to see if we have seen this already\r
-    std::pair<bool,void*> mapping = context.pointer_map(magic);\r
-    if (mapping.first)\r
-    {\r
-      // this holder has already been restored\r
-      // now restore the object and rely on the pointer routines to return the existing object\r
-      T* value = 0;\r
-      restore_pointer(context,value,restore_element);\r
-      // dealias the existing holder and replace it with the seen-before holder to make this object an alias of it\r
-      data._make_alias(value, (unsigned*)mapping.second);\r
-    }\r
-    else\r
-    {\r
-      // this is the first contact with this holder\r
-      // make sure this smart pointer is unique to prevent side-effects\r
-      data.clear_unique();\r
-      // map the magic key onto this structure's holder\r
-      // do this before restoring the object so that self-referential structures restore correctly\r
-      context.pointer_add(magic,data._count());\r
-      // now restore the object\r
-      T* value = 0;\r
-      restore_pointer(context,value,restore_element);\r
-      // and add it to the pointer\r
-      data.set(value);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // simple_ptr_clone using callbacks\r
-\r
-  template<typename T>\r
-  void dump_simple_ptr_clone_callback(dump_context& context, const simple_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data._count());\r
-    dump_unsigned(context,mapping.second);\r
-    dump_callback(context,data._pointer());\r
-  }\r
-\r
-  template<typename T>\r
-  void restore_simple_ptr_clone_callback(restore_context& context, simple_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    std::pair<bool,void*> mapping = context.pointer_map(magic);\r
-    if (mapping.first)\r
-    {\r
-      T* value = 0;\r
-      restore_callback(context,value);\r
-      data._make_alias(value, (unsigned*)mapping.second);\r
-    }\r
-    else\r
-    {\r
-      data.clear_unique();\r
-      context.pointer_add(magic,data._count());\r
-      T* value = 0;\r
-      restore_callback(context,value);\r
-      data.set(value);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // simple_ptr_clone using interface\r
-\r
-  template<typename T>\r
-  void dump_simple_ptr_clone_interface(dump_context& context, const simple_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data._count());\r
-    dump_unsigned(context,mapping.second);\r
-    dump_interface(context,data._pointer());\r
-  }\r
-\r
-  template<typename T>\r
-  void restore_simple_ptr_clone_interface(restore_context& context, simple_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    std::pair<bool,void*> mapping = context.pointer_map(magic);\r
-    if (mapping.first)\r
-    {\r
-      T* value = 0;\r
-      restore_interface(context,value);\r
-      data._make_alias(value, (unsigned*)mapping.second);\r
-    }\r
-    else\r
-    {\r
-      data.clear_unique();\r
-      context.pointer_add(magic,data._count());\r
-      T* value = 0;\r
-      restore_interface(context,value);\r
-      data.set(value);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_smart_ptr.hpp b/src/stlplus/persistence/persistent_smart_ptr.hpp
deleted file mode 100644 (file)
index 5f37725..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_SMART_PTR\r
-#define STLPLUS_PERSISTENT_SMART_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STLplus smart_ptr\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "smart_ptr.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // smart_ptr - uses dump/restore_pointer on the contents\r
-\r
-  template<typename T, typename DE>\r
-  void dump_smart_ptr(dump_context&, const smart_ptr<T>& data, DE dump_element)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename RE>\r
-  void restore_smart_ptr(restore_context&, smart_ptr<T>& data, RE restore_element)\r
-    throw(persistent_restore_failed);\r
-\r
-  // smart_ptr_clone using the polymorphic callback approach - uses dump/restore_callback on the contents\r
-\r
-  template<typename T>\r
-  void dump_smart_ptr_clone_callback(dump_context&, const smart_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_smart_ptr_clone_callback(restore_context&, smart_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed);\r
-\r
-  // smart_ptr_clone using the interface approach - uses dump/restore_interface on the contents\r
-\r
-  template<typename T>\r
-  void dump_smart_ptr_clone_interface(dump_context&, const smart_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_smart_ptr_clone_interface(restore_context&, smart_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed);\r
-\r
-  // smart_ptr_nocopy is not made persistent because if it is uncopyable, it must be undumpable\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_smart_ptr.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_smart_ptr.tpp b/src/stlplus/persistence/persistent_smart_ptr.tpp
deleted file mode 100644 (file)
index 2ce5315..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-#include "persistent_pointer.hpp"\r
-#include "persistent_callback.hpp"\r
-#include "persistent_interface.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename  T, typename DE>\r
-  void dump_smart_ptr(dump_context& context, const smart_ptr<T>& data,\r
-                      DE dump_element)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // similar to the simple pointer routines, but use the address of the holder to tell which objects are aliases\r
-    // Many smart pointers can point to the same object.\r
-    // I could have used the address of the object to differentiate, \r
-    // but that would not have differentiated between different null smart pointers\r
-    // so I use the address of the substructure to differentiate between different objects.\r
-    // get a magic key for the substructure - this also returns a flag saying whether its been seen before\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data._handle());\r
-    // dump the magic key\r
-    dump_unsigned(context,mapping.second);\r
-    // dump the contents but only if this is the first time this object has been seen\r
-    // use the existing routines for ordinary pointers to dump the contents\r
-    if (!mapping.first)\r
-      dump_pointer(context,data.pointer(),dump_element);\r
-  }\r
-\r
-  template<typename T, typename RE>\r
-  void restore_smart_ptr(restore_context& context, smart_ptr<T>& data,\r
-                         RE restore_element)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    // get the old substructure magic key\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    // lookup this magic number to see if we have seen this already\r
-    std::pair<bool,void*> mapping = context.pointer_map(magic);\r
-    if (mapping.first)\r
-    {\r
-      // this holder has already been restored\r
-      // dealias the existing holder and replace it with the seen-before holder to make this object an alias of it\r
-      data._make_alias((smart_ptr_holder<T>*)mapping.second);\r
-    }\r
-    else\r
-    {\r
-      // this is the first contact with this holder\r
-      // make sure this smart pointer is unique to prevent side-effects\r
-      data.clear_unique();\r
-      // map the magic key onto this structure's holder\r
-      // do this before restoring the object so that self-referential structures restore correctly\r
-      context.pointer_add(magic,data._handle());\r
-      // now restore the object\r
-      T* value = 0;\r
-      restore_pointer(context,value,restore_element);\r
-      data.set(value);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr_clone using callbacks\r
-\r
-  template<typename T>\r
-  void dump_smart_ptr_clone_callback(dump_context& context, const smart_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // similar to the simple pointer routines, but use the address of the holder to tell which objects are aliases\r
-    // Many smart pointers can point to the same object.\r
-    // I could have used the address of the object to differentiate, \r
-    // but that would not have differentiated between different null smart pointers\r
-    // so I use the address of the substructure to differentiate between different objects.\r
-    // get a magic key for the substructure - this also returns a flag saying whether its been seen before\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data._handle());\r
-    // dump the magic key\r
-    dump_unsigned(context,mapping.second);\r
-    // dump the contents but only if this is the first time this object has been seen\r
-    // use the existing routines for ordinary pointers to dump the contents\r
-    if (!mapping.first)\r
-      dump_callback(context,data.pointer());\r
-  }\r
-\r
-  template<typename T>\r
-  void restore_smart_ptr_clone_callback(restore_context& context, smart_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    // get the old substructure magic key\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    // lookup this magic number to see if we have seen this already\r
-    std::pair<bool,void*> mapping = context.pointer_map(magic);\r
-    if (mapping.first)\r
-    {\r
-      // this holder has already been restored\r
-      // dealias the existing holder and replace it with the seen-before holder to make this object an alias of it\r
-      data._make_alias((smart_ptr_holder<T>*)mapping.second);\r
-    }\r
-    else\r
-    {\r
-      // this is the first contact with this holder\r
-      // make sure this smart pointer is unique to prevent side-effects\r
-      data.clear_unique();\r
-      // map the magic key onto this structure's holder\r
-      // do this before restoring the object so that self-referential structures restore correctly\r
-      context.pointer_add(magic,data._handle());\r
-      // now restore the object\r
-      T* value = 0;\r
-      restore_callback(context,value);\r
-      data.set(value);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // smart_ptr_clone using interface\r
-\r
-  template<typename T>\r
-  void dump_smart_ptr_clone_interface(dump_context& context, const smart_ptr_clone<T>& data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // similar to the simple pointer routines, but use the address of the holder to tell which objects are aliases\r
-    // Many smart pointers can point to the same object.\r
-    // I could have used the address of the object to differentiate, \r
-    // but that would not have differentiated between different null smart pointers\r
-    // so I use the address of the substructure to differentiate between different objects.\r
-    // get a magic key for the substructure - this also returns a flag saying whether its been seen before\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data._handle());\r
-    // dump the magic key\r
-    dump_unsigned(context,mapping.second);\r
-    // dump the contents but only if this is the first time this object has been seen\r
-    // use the existing routines for ordinary pointers to dump the contents\r
-    if (!mapping.first)\r
-      dump_interface(context,data.pointer());\r
-  }\r
-\r
-  template<typename T>\r
-  void restore_smart_ptr_clone_interface(restore_context& context, smart_ptr_clone<T>& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    // get the old substructure magic key\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    // lookup this magic number to see if we have seen this already\r
-    std::pair<bool,void*> mapping = context.pointer_map(magic);\r
-    if (mapping.first)\r
-    {\r
-      // this holder has already been restored\r
-      // dealias the existing holder and replace it with the seen-before holder to make this object an alias of it\r
-      data._make_alias((smart_ptr_holder<T>*)mapping.second);\r
-    }\r
-    else\r
-    {\r
-      // this is the first contact with this holder\r
-      // make sure this smart pointer is unique to prevent side-effects\r
-      data.clear_unique();\r
-      // map the magic key onto this structure's holder\r
-      // do this before restoring the object so that self-referential structures restore correctly\r
-      context.pointer_add(magic,data._handle());\r
-      // now restore the object\r
-      T* value = 0;\r
-      restore_interface(context,value);\r
-      data.set(value);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_stl.hpp b/src/stlplus/persistence/persistent_stl.hpp
deleted file mode 100644 (file)
index bc2f32b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_STL\r
-#define STLPLUS_PERSISTENT_STL\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Set of persistence routines for the STL classes\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "persistent_bitset.hpp"\r
-#include "persistent_complex.hpp"\r
-#include "persistent_deque.hpp"\r
-#include "persistent_list.hpp"\r
-#include "persistent_map.hpp"\r
-#include "persistent_multimap.hpp"\r
-#include "persistent_multiset.hpp"\r
-#include "persistent_pair.hpp"\r
-#include "persistent_set.hpp"\r
-#include "persistent_string.hpp"\r
-#include "persistent_vector.hpp"\r
-\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_stlplus.hpp b/src/stlplus/persistence/persistent_stlplus.hpp
deleted file mode 100644 (file)
index a3cb476..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_STLPLUS\r
-#define STLPLUS_PERSISTENT_STLPLUS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Set of persistence routines for the STLplus classes\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// can be excluded to break the dependency on the containers library\r
-#ifndef NO_STLPLUS_CONTAINERS\r
-#include "persistent_digraph.hpp"\r
-#include "persistent_foursome.hpp"\r
-#include "persistent_hash.hpp"\r
-#include "persistent_matrix.hpp"\r
-#include "persistent_ntree.hpp"\r
-#include "persistent_smart_ptr.hpp"\r
-#include "persistent_triple.hpp"\r
-#endif\r
-\r
-// can be excluded to break the dependency on the portability library\r
-#ifndef NO_STLPLUS_INF\r
-#include "persistent_inf.hpp"\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_string.cpp b/src/stlplus/persistence/persistent_string.cpp
deleted file mode 100644 (file)
index 80940d1..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_string.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-void stlplus::dump_string(stlplus::dump_context& context, const std::string& data)\r
-  throw(stlplus::persistent_dump_failed)\r
-{\r
-  stlplus::dump_basic_string(context, data, stlplus::dump_char);\r
-}\r
-\r
-void stlplus::restore_string(stlplus::restore_context& context, std::string& data)\r
-  throw(stlplus::persistent_restore_failed)\r
-{\r
-  stlplus::restore_basic_string(context, data, stlplus::restore_char);\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/persistence/persistent_string.hpp b/src/stlplus/persistence/persistent_string.hpp
deleted file mode 100644 (file)
index ff065c7..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_STRING\r
-#define STLPLUS_PERSISTENT_STRING\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence for STL strings\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // basic_string\r
-\r
-  template<typename charT, typename traits, typename allocator, typename D>\r
-  void dump_basic_string(dump_context&, const std::basic_string<charT,traits,allocator>& data, D dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename charT, typename traits, typename allocator, typename R>\r
-  void restore_basic_string(restore_context&, std::basic_string<charT,traits,allocator>& data, R restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-  // string\r
-\r
-  void dump_string(dump_context&, const std::string& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  void restore_string(restore_context&, std::string& data) \r
-    throw(persistent_restore_failed);\r
-\r
-\r
-  // Note: persistence of wstring not supported because it is too weakly defined and messy\r
-  //       decide on a byte-wide encoding of wide strings (e.g. UTF8) and use the string persistence on that\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_string.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_string.tpp b/src/stlplus/persistence/persistent_string.tpp
deleted file mode 100644 (file)
index c78f7e8..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // STL strings\r
-\r
-  template<typename charT, typename traits, typename allocator, typename D>\r
-  void dump_basic_string(dump_context& context, const std::basic_string<charT,traits,allocator>& data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    unsigned size = data.size();\r
-    dump_unsigned(context, size);\r
-    for (unsigned i = 0; i < size; i++)\r
-    {\r
-      charT ch = data[i];\r
-      dump_fn(context,ch);\r
-    }\r
-  }\r
-\r
-  template<typename charT, typename traits, typename allocator, typename R>\r
-  void restore_basic_string(restore_context& context, std::basic_string<charT,traits,allocator>& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    data.erase();\r
-    unsigned size = 0;\r
-    restore_unsigned(context, size);\r
-    for (unsigned i = 0; i < size; i++)\r
-    {\r
-      charT ch;\r
-      restore_fn(context,ch);\r
-      data += ch;\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_triple.hpp b/src/stlplus/persistence/persistent_triple.hpp
deleted file mode 100644 (file)
index d9e30d6..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_TRIPLE\r
-#define STLPLUS_PERSISTENT_TRIPLE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL triple\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include "triple.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename D1, typename D2, typename D3>\r
-  void dump_triple(dump_context&, const stlplus::triple<T1,T2,T3>& data, \r
-                   D1 dump_fn1, D2 dump_fn2, D3 dump_fn3)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T1, typename T2, typename T3, typename R1, typename R2, typename R3>\r
-  void restore_triple(restore_context&, stlplus::triple<T1,T2,T3>& data,\r
-                      R1 restore_fn1, R2 restore_fn2, R3 restore_fn3)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_triple.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_triple.tpp b/src/stlplus/persistence/persistent_triple.tpp
deleted file mode 100644 (file)
index 9c3c978..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T1, typename T2, typename T3, typename D1, typename D2, typename D3>\r
-  void dump_triple(dump_context& context, const triple<T1,T2,T3>& data, \r
-                   D1 dump_fn1, D2 dump_fn2, D3 dump_fn3)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_fn1(context,data.first);\r
-    dump_fn2(context,data.second);\r
-    dump_fn3(context,data.third);\r
-  }\r
-\r
-  template<typename T1, typename T2, typename T3, typename R1, typename R2, typename R3>\r
-  void restore_triple(restore_context& context, triple<T1,T2,T3>& data,\r
-                      R1 restore_fn1, R2 restore_fn2, R3 restore_fn3)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    restore_fn1(context,data.first);\r
-    restore_fn2(context,data.second);\r
-    restore_fn3(context,data.third);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_vector.cpp b/src/stlplus/persistence/persistent_vector.cpp
deleted file mode 100644 (file)
index b983d37..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_vector.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// specialisation for a vector of bool which has a different implementation to a vector of anything else\r
-\r
-void stlplus::dump_vector_bool(stlplus::dump_context& context, const std::vector<bool>& data)\r
-  throw(stlplus::persistent_dump_failed)\r
-{\r
-  stlplus::dump_unsigned(context,data.size());\r
-  unsigned size = data.size();\r
-  unsigned bytes = ((size + 7) / 8);\r
-  for (unsigned b = 0; b < bytes; b++)\r
-  {\r
-    unsigned char byte = 0;\r
-    unsigned char mask = 1;\r
-    for (unsigned e = 0; e < 8; e++)\r
-    {\r
-      unsigned i = b*8 + e;\r
-      if (i >= size) break;\r
-      if (data[i]) byte |= mask;\r
-      mask <<= 1;\r
-    }\r
-    context.put(byte);\r
-  }\r
-}\r
-\r
-void stlplus::restore_vector_bool(stlplus::restore_context& context, std::vector<bool>& data)\r
-  throw(stlplus::persistent_restore_failed)\r
-{\r
-  unsigned size = 0;\r
-  stlplus::restore_unsigned(context,size);\r
-  data.resize(size);\r
-  unsigned bytes = ((size + 7) / 8);\r
-  for (unsigned b = 0; b < bytes; b++)\r
-  {\r
-    unsigned char byte = context.get();\r
-    unsigned char mask = 1;\r
-    for (unsigned e = 0; e < 8; e++)\r
-    {\r
-      unsigned i = b*8 + e;\r
-      if (i >= size) break;\r
-      data[i] = ((byte & mask) != 0);\r
-      mask <<= 1;\r
-    }\r
-  }\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/persistence/persistent_vector.hpp b/src/stlplus/persistence/persistent_vector.hpp
deleted file mode 100644 (file)
index fd108aa..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_VECTOR\r
-#define STLPLUS_PERSISTENT_VECTOR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence of STL vector\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-#include <vector>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // vector\r
-\r
-  template<typename T, typename D>\r
-  void dump_vector(dump_context&, const std::vector<T>& data, D dump_fn)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T, typename R>\r
-  void restore_vector(restore_context&, std::vector<T>& data, R restore_fn)\r
-    throw(persistent_restore_failed);\r
-\r
-  // specialism for vector<bool>\r
-\r
-  void dump_vector_bool(dump_context&, const std::vector<bool>& data)\r
-    throw(persistent_dump_failed);\r
-\r
-  void restore_vector_bool(restore_context&, std::vector<bool>& data)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_vector.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_vector.tpp b/src/stlplus/persistence/persistent_vector.tpp
deleted file mode 100644 (file)
index 4ad69b6..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename D>\r
-  void dump_vector(dump_context& context, const std::vector<T>& data, D dump_fn)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    dump_unsigned(context,data.size());\r
-    for (unsigned i = 0; i < data.size(); i++)\r
-      dump_fn(context,data[i]);\r
-  }\r
-\r
-  template<typename T, typename R>\r
-  void restore_vector(restore_context& context, std::vector<T>& data, R restore_fn)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    unsigned size = 0;\r
-    restore_unsigned(context,size);\r
-    data.resize(size);\r
-    for (unsigned i = 0; i < size; i++)\r
-      restore_fn(context,data[i]);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/persistence/persistent_xref.hpp b/src/stlplus/persistence/persistent_xref.hpp
deleted file mode 100644 (file)
index c41e28d..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef STLPLUS_PERSISTENT_XREF\r
-#define STLPLUS_PERSISTENT_XREF\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Persistence for cross-references to persistent objects\r
-\r
-//   A cross-reference is a pointer to an object that has definitely been dumped\r
-//   already by one of dump_pointer, dump_interface or dump_callback, i.e. by\r
-//   one of the dump routines for pointers to objects.\r
-\r
-//   These are typically used in data structures as back-pointers or pointers\r
-//   between nodes.\r
-\r
-//   For example, you may have a tree with cross links. Dump the tree as the\r
-//   primary data structure first, then dump the cross links as cross-references\r
-//   afterwards. The whole tree must be dumped before any cross-references to\r
-//   ensure that all cross-references are known to the persistence system.\r
-\r
-//   These functions will throw an exception if the cross-reference points to\r
-//   something not dumped before.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistence_fixes.hpp"\r
-#include "persistent_contexts.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T>\r
-  void dump_xref(dump_context&, const T* const data)\r
-    throw(persistent_dump_failed);\r
-\r
-  template<typename T>\r
-  void restore_xref(restore_context&, T*& data)\r
-    throw(persistent_restore_failed);\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_xref.tpp"\r
-#endif\r
diff --git a/src/stlplus/persistence/persistent_xref.tpp b/src/stlplus/persistence/persistent_xref.tpp
deleted file mode 100644 (file)
index e12639d..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   format: magic_key [ data ]\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "persistent_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T>\r
-  void dump_xref(dump_context& context, const T* const data)\r
-    throw(persistent_dump_failed)\r
-  {\r
-    // register the address and get the magic key for it\r
-    std::pair<bool,unsigned> mapping = context.pointer_map(data);\r
-    // if this is the first view of this pointer, simply throw an exception\r
-    if (!mapping.first) throw persistent_dump_failed("tried to dump a cross-reference not seen before");\r
-    // otherwise, just dump the magic key\r
-    dump_unsigned(context,mapping.second);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////>\r
-\r
-  template<typename T>\r
-  void restore_xref(restore_context& context, T*& data)\r
-    throw(persistent_restore_failed)\r
-  {\r
-    // Note: I do not try to delete the old data because this is a cross-reference\r
-    // get the magic key\r
-    unsigned magic = 0;\r
-    restore_unsigned(context,magic);\r
-    // now lookup the magic key to see if this pointer has already been restored\r
-    // null pointers are always flagged as already restored\r
-    std::pair<bool,void*> address = context.pointer_map(magic);\r
-    // if this is the first view of this pointer, simply throw an exception\r
-    if (!address.first) throw persistent_restore_failed("tried to restore a cross-reference not seen before");\r
-    // seen before, so simply assign the old address\r
-    data = (T*)address.second;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
index 6a9cd6445ff3577e7d37b647ad773f50153923c5..e591a34cbd6105456b97e599c4d4d95dc278bcc5 100644 (file)
@@ -1,60 +1,60 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "build.hpp"\r
-#include "version.hpp"\r
-#include "dprintf.hpp"\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // report the platform-specific details of this build\r
-\r
-  std::string build(void)\r
-  {\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // work out the platform\r
-\r
-#ifdef _WIN32\r
-    std::string platform("Windows");\r
-#else\r
-    // at present there are no variations between different Unix platforms so\r
-    // they all map onto the generic Unix platform\r
-    std::string platform("Generic Unix");\r
-#endif\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // work out the compiler\r
-\r
-#if defined __GNUC__\r
-    std::string compiler(dformat("gcc v%s",__VERSION__));\r
-#elif defined _MSC_VER\r
-    std::string compiler(dformat("MSVC v%0.2f",((float)_MSC_VER)/100.0));\r
-#elif defined __BORLANDC__\r
-    std::string compiler(dformat("Borland v%d.%d",__BORLANDC__/256,__BORLANDC__/16%16));\r
-#else\r
-    std::string compiler("unknown compiler");\r
-#endif\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // work out the kind of build\r
-    // there are two variants - debug and release\r
-\r
-#ifndef NDEBUG\r
-    std::string variant("debug");\r
-#else\r
-    std::string variant("release");\r
-#endif\r
-\r
-    return std::string("STLplus v") + version() + ", " + platform + ", " + compiler + ", " + variant;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "build.hpp"
+#include "version.hpp"
+#include "dprintf.hpp"
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // report the platform-specific details of this build
+
+  std::string build(void)
+  {
+    ////////////////////////////////////////////////////////////////////////////////
+    // work out the platform
+
+#ifdef _WIN32
+    std::string platform("Windows");
+#else
+    // at present there are no variations between different Unix platforms so
+    // they all map onto the generic Unix platform
+    std::string platform("Generic Unix");
+#endif
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // work out the compiler
+
+#if defined __GNUC__
+    std::string compiler(dformat("gcc v%s",__VERSION__));
+#elif defined _MSC_VER
+    std::string compiler(dformat("MSVC v%0.2f",((float)_MSC_VER)/100.0));
+#elif defined __BORLANDC__
+    std::string compiler(dformat("Borland v%d.%d",__BORLANDC__/256,__BORLANDC__/16%16));
+#else
+    std::string compiler("unknown compiler");
+#endif
+
+    ////////////////////////////////////////////////////////////////////////////////
+    // work out the kind of build
+    // there are two variants - debug and release
+
+#ifndef NDEBUG
+    std::string variant("debug");
+#else
+    std::string variant("release");
+#endif
+
+    return std::string("STLplus v") + version() + ", " + platform + ", " + compiler + ", " + variant;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+} // end namespace stlplus
index b105f19b1827123c51432fffbebac6cf3ac37dff..a648beb2129fa6ad0f9f55bcd052220bb7a4f9d2 100644 (file)
@@ -1,34 +1,34 @@
-#ifndef STLPLUS_BUILD\r
-#define STLPLUS_BUILD\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Provides a printable representation of the build characteristics in the form:\r
-\r
-//     version, platform, compiler, variant\r
-\r
-//   Where\r
-//     version is the version of STLplus\r
-//     platform is the target operating system\r
-//     compiler is the compilation system and version that the function was compiled with\r
-//     variant is the kind of build - debug or release\r
-\r
-//   Example:\r
-//     STLplus version 3.0, Generic Unix, gcc v3.4, debug\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  std::string build(void);\r
-\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_BUILD
+#define STLPLUS_BUILD
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Provides a printable representation of the build characteristics in the form:
+
+//     version, platform, compiler, variant
+
+//   Where
+//     version is the version of STLplus
+//     platform is the target operating system
+//     compiler is the compilation system and version that the function was compiled with
+//     variant is the kind of build - debug or release
+
+//   Example:
+//     STLplus version 3.0, Generic Unix, gcc v3.4, debug
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  std::string build(void);
+
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif
index 562518eff9d86bdf0515067e1a229f813258be6c..d5b153489c086b4613863e1eafaba83c9648542f 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "debug.hpp"\r
-#include "dprintf.hpp"\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <stdio.h>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  static std::string format(const char* file, int line, const char* function, const char* message)\r
-  {\r
-    return dformat("%s:%d:%s: assertion failed: %s",\r
-                   (file ? file : ""),\r
-                   line,\r
-                   (function ? function : "") ,\r
-                   (message ? message : ""));\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  assert_failed::assert_failed(const char* file, int line, const char* function, const char* message)\r
-    throw() : \r
-    std::logic_error(format(file, line, function, message))\r
-  {\r
-  }\r
-\r
-  assert_failed::~assert_failed(void) throw()\r
-  {\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  static unsigned _debug_depth = 0;\r
-  static bool _debug_global = false;\r
-  static bool _debug_set = false;\r
-  static bool _debug_recurse = false;\r
-  static bool _debug_read = false;\r
-  static char* _debug_match = 0;\r
-  static const debug_trace* debug_last = 0;\r
-\r
-  void debug_global(const char* file, int line, const char* function, bool state)\r
-  {\r
-    _debug_global = state;\r
-    fprintf(stderr, "%s:%i:[%i]%s ", file, line, _debug_depth, function ? function : "");\r
-    fprintf(stderr, "debug global : %s\n", _debug_global ? "on" : "off");\r
-  }\r
-\r
-  void debug_assert_fail(const char* file, int line, const char* function, const char* test) \r
-    throw(assert_failed)\r
-  {\r
-    fprintf(stderr, "%s:%i:[%i]%s: assertion failed: %s\n", \r
-            file, line, _debug_depth, function ? function : "", test);\r
-    if (debug_last) debug_last->stackdump();\r
-    throw assert_failed(file, line, function, test);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  debug_trace::debug_trace(const char* f, int l, const char* fn) :\r
-    m_file(f), m_line(l), m_function(fn ? fn : ""), \r
-    m_depth(0), m_last(debug_last), m_dbg(false), m_old(false)\r
-  {\r
-    if (!_debug_read)\r
-    {\r
-      _debug_match = getenv("DEBUG");\r
-      _debug_recurse = getenv("DEBUG_LOCAL") == 0;\r
-      _debug_read = true;\r
-    }\r
-    m_dbg = _debug_set || (_debug_match && (!_debug_match[0] || (strcmp(_debug_match, m_file) == 0)));\r
-    m_old = _debug_set;\r
-    if (m_dbg && _debug_recurse)\r
-      _debug_set = true;\r
-    m_depth = ++_debug_depth;\r
-    debug_last = this;\r
-    if (debug()) report(std::string("entering ") + (m_function ? m_function : ""));\r
-  }\r
-\r
-  debug_trace::~debug_trace(void)\r
-  {\r
-    if (debug()) report("leaving");\r
-    --_debug_depth;\r
-    _debug_set = m_old;\r
-    debug_last = m_last;\r
-  }\r
-\r
-  const char* debug_trace::file(void) const\r
-  {\r
-    return m_file;\r
-  }\r
-\r
-  int debug_trace::line(void) const\r
-  {\r
-    return m_line;\r
-  }\r
-\r
-  bool debug_trace::debug(void) const\r
-  {\r
-    return m_dbg || _debug_global;\r
-  }\r
-\r
-  void debug_trace::debug_on(int l, bool recurse)\r
-  {\r
-    m_dbg = true;\r
-    m_old = _debug_set;\r
-    if (recurse)\r
-      _debug_set = true;\r
-    report(l, std::string("debug on") + (recurse ? " recursive" : ""));\r
-  }\r
-\r
-  void debug_trace::debug_off(int l)\r
-  {\r
-    if (debug()) report(l, std::string("debug off"));\r
-    m_dbg = false;\r
-    _debug_set = m_old;\r
-  }\r
-\r
-  void debug_trace::prefix(int l) const\r
-  {\r
-    fprintf(stderr, "%s:%i:[%i]%s ", m_file, l, m_depth, m_function ? m_function : "");\r
-  }\r
-\r
-  void debug_trace::do_report(int l, const std::string& message) const\r
-  {\r
-    prefix(l);\r
-    fprintf(stderr, "%s\n", message.c_str());\r
-    fflush(stderr);\r
-  }\r
-\r
-  void debug_trace::do_report(const std::string& message) const\r
-  {\r
-    do_report(m_line, message);\r
-  }\r
-\r
-  void debug_trace::report(int l, const std::string& message) const\r
-  {\r
-    do_report(l, message);\r
-  }\r
-\r
-  void debug_trace::report(const std::string& message) const\r
-  {\r
-    report(m_line, message);\r
-  }\r
-\r
-  void debug_trace::error(int l, const std::string& message) const\r
-  {\r
-    do_report(l, "ERROR: " + message);\r
-  }\r
-\r
-  void debug_trace::error(const std::string& message) const\r
-  {\r
-    error(m_line, message);\r
-  }\r
-\r
-  void debug_trace::stackdump(int l, const std::string& message) const\r
-  {\r
-    do_report(l, message);\r
-    stackdump();\r
-  }\r
-\r
-  void debug_trace::stackdump(const std::string& message) const\r
-  {\r
-    stackdump(m_line, message);\r
-  }\r
-\r
-  void debug_trace::stackdump(void) const\r
-  {\r
-    for (const debug_trace* item = this; item; item = item->m_last)\r
-      item->do_report("...called from here");\r
-  }\r
-\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "debug.hpp"
+#include "dprintf.hpp"
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  static std::string format(const char* file, int line, const char* function, const char* message)
+  {
+    return dformat("%s:%d:%s: assertion failed: %s",
+                   (file ? file : ""),
+                   line,
+                   (function ? function : "") ,
+                   (message ? message : ""));
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  assert_failed::assert_failed(const char* file, int line, const char* function, const char* message)
+    throw() : 
+    std::logic_error(format(file, line, function, message))
+  {
+  }
+
+  assert_failed::~assert_failed(void) throw()
+  {
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  static unsigned _debug_depth = 0;
+  static bool _debug_global = false;
+  static bool _debug_set = false;
+  static bool _debug_recurse = false;
+  static bool _debug_read = false;
+  static char* _debug_match = 0;
+  static const debug_trace* debug_last = 0;
+
+  void debug_global(const char* file, int line, const char* function, bool state)
+  {
+    _debug_global = state;
+    fprintf(stderr, "%s:%i:[%i]%s ", file, line, _debug_depth, function ? function : "");
+    fprintf(stderr, "debug global : %s\n", _debug_global ? "on" : "off");
+  }
+
+  void debug_assert_fail(const char* file, int line, const char* function, const char* test) 
+    throw(assert_failed)
+  {
+    fprintf(stderr, "%s:%i:[%i]%s: assertion failed: %s\n", 
+            file, line, _debug_depth, function ? function : "", test);
+    if (debug_last) debug_last->stackdump();
+    throw assert_failed(file, line, function, test);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  debug_trace::debug_trace(const char* f, int l, const char* fn) :
+    m_file(f), m_line(l), m_function(fn ? fn : ""), 
+    m_depth(0), m_last(debug_last), m_dbg(false), m_old(false)
+  {
+    if (!_debug_read)
+    {
+      _debug_match = getenv("DEBUG");
+      _debug_recurse = getenv("DEBUG_LOCAL") == 0;
+      _debug_read = true;
+    }
+    m_dbg = _debug_set || (_debug_match && (!_debug_match[0] || (strcmp(_debug_match, m_file) == 0)));
+    m_old = _debug_set;
+    if (m_dbg && _debug_recurse)
+      _debug_set = true;
+    m_depth = ++_debug_depth;
+    debug_last = this;
+    if (debug()) report(std::string("entering ") + (m_function ? m_function : ""));
+  }
+
+  debug_trace::~debug_trace(void)
+  {
+    if (debug()) report("leaving");
+    --_debug_depth;
+    _debug_set = m_old;
+    debug_last = m_last;
+  }
+
+  const char* debug_trace::file(void) const
+  {
+    return m_file;
+  }
+
+  int debug_trace::line(void) const
+  {
+    return m_line;
+  }
+
+  bool debug_trace::debug(void) const
+  {
+    return m_dbg || _debug_global;
+  }
+
+  void debug_trace::debug_on(int l, bool recurse)
+  {
+    m_dbg = true;
+    m_old = _debug_set;
+    if (recurse)
+      _debug_set = true;
+    report(l, std::string("debug on") + (recurse ? " recursive" : ""));
+  }
+
+  void debug_trace::debug_off(int l)
+  {
+    if (debug()) report(l, std::string("debug off"));
+    m_dbg = false;
+    _debug_set = m_old;
+  }
+
+  void debug_trace::prefix(int l) const
+  {
+    fprintf(stderr, "%s:%i:[%i]%s ", m_file, l, m_depth, m_function ? m_function : "");
+  }
+
+  void debug_trace::do_report(int l, const std::string& message) const
+  {
+    prefix(l);
+    fprintf(stderr, "%s\n", message.c_str());
+    fflush(stderr);
+  }
+
+  void debug_trace::do_report(const std::string& message) const
+  {
+    do_report(m_line, message);
+  }
+
+  void debug_trace::report(int l, const std::string& message) const
+  {
+    do_report(l, message);
+  }
+
+  void debug_trace::report(const std::string& message) const
+  {
+    report(m_line, message);
+  }
+
+  void debug_trace::error(int l, const std::string& message) const
+  {
+    do_report(l, "ERROR: " + message);
+  }
+
+  void debug_trace::error(const std::string& message) const
+  {
+    error(m_line, message);
+  }
+
+  void debug_trace::stackdump(int l, const std::string& message) const
+  {
+    do_report(l, message);
+    stackdump();
+  }
+
+  void debug_trace::stackdump(const std::string& message) const
+  {
+    stackdump(m_line, message);
+  }
+
+  void debug_trace::stackdump(void) const
+  {
+    for (const debug_trace* item = this; item; item = item->m_last)
+      item->do_report("...called from here");
+  }
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index a7aafd646ca9c7ae3453c07f5bdbdc7c62b555f8..981490b0acbc214549c3cc1c5152350c922f213a 100644 (file)
-#ifndef STLPLUS_DEBUG\r
-#define STLPLUS_DEBUG\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Set of simple debug utilities, all of which are switched off by the\r
-//   NDEBUG compiler directive\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "portability_fixes.hpp"\r
-#include <stdexcept>\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Problem with missing __FUNCTION__ macro\r
-////////////////////////////////////////////////////////////////////////////////\r
-// this macro is used in debugging but was missing in Visual Studio prior to version 7\r
-// it also has a different name in Borland\r
-\r
-#if defined(_MSC_VER) && (_MSC_VER < 1300)\r
-#define __FUNCTION__ 0\r
-#endif\r
-\r
-#ifdef __BORLANDC__\r
-#define __FUNCTION__ __FUNC__\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Exception thrown if an assertion fails\r
-\r
-namespace stlplus\r
-{\r
-\r
-  class assert_failed : public std::logic_error\r
-  {\r
-  public:\r
-    assert_failed(const char* file, int line, const char* function, const char* message) throw();\r
-    ~assert_failed(void) throw();\r
-  };\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // The macros used in debugging\r
-\r
-#ifndef NDEBUG\r
-\r
-#define DEBUG_TRACE stlplus::debug_trace stlplus_debug_trace(__FILE__,__LINE__,__FUNCTION__)\r
-#define IF_DEBUG(stmts) {if (stlplus_debug_trace.debug()){stlplus_debug_trace.prefix(__LINE__);stmts;}}\r
-#define DEBUG_REPORT(str) IF_DEBUG(stlplus_debug_trace.report(__LINE__,str))\r
-#define DEBUG_ERROR(str) stlplus_debug_trace.error(__LINE__,str)\r
-#define DEBUG_STACKDUMP(str) stlplus_debug_trace.stackdump(__LINE__,str)\r
-#define DEBUG_ON stlplus_debug_trace.debug_on(__LINE__,true)\r
-#define DEBUG_ON_LOCAL stlplus_debug_trace.debug_on(__LINE__,false)\r
-#define DEBUG_ON_GLOBAL stlplus::debug_global(__FILE__,__LINE__,__FUNCTION__,true)\r
-#define DEBUG_OFF_GLOBAL stlplus::debug_global(__FILE__,__LINE__,__FUNCTION__,false)\r
-#define DEBUG_OFF stlplus_debug_trace.debug_off(__LINE__)\r
-#define DEBUG_ASSERT(test) if (!(test))stlplus::debug_assert_fail(__FILE__,__LINE__,__FUNCTION__,#test)\r
-\r
-#else\r
-\r
-#define DEBUG_TRACE\r
-#define IF_DEBUG(stmts)\r
-#define DEBUG_REPORT(str)\r
-#define DEBUG_ERROR(str)\r
-#define DEBUG_STACKDUMP(str)\r
-#define DEBUG_ON\r
-#define DEBUG_ON_LOCAL\r
-#define DEBUG_ON_GLOBAL\r
-#define DEBUG_OFF_GLOBAL\r
-#define DEBUG_OFF\r
-#define DEBUG_ASSERT(test)\r
-\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// infrastructure - don't use directly\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void debug_global(const char* file, int line, const char* function, bool state = true);\r
-  void debug_assert_fail(const char* file, int line, const char* function, const char* test) throw(assert_failed);\r
-\r
-  class debug_trace\r
-  {\r
-  public:\r
-    debug_trace(const char* f, int l, const char* fn);\r
-    ~debug_trace(void);\r
-    const char* file(void) const;\r
-    int line(void) const;\r
-    bool debug(void) const;\r
-    void debug_on(int l, bool recurse);\r
-    void debug_off(int l);\r
-    void prefix(int l) const;\r
-    void report(int l, const std::string& message) const;\r
-    void report(const std::string& message) const;\r
-    void error(int l, const std::string& message) const;\r
-    void error(const std::string& message) const;\r
-    void stackdump(int l, const std::string& message) const;\r
-    void stackdump(const std::string& message) const;\r
-    void stackdump(void) const;\r
-\r
-  private:\r
-    const char* m_file;\r
-    int m_line;\r
-    const char* m_function;\r
-    unsigned m_depth;\r
-    const debug_trace* m_last;\r
-    bool m_dbg;\r
-    bool m_old;\r
-    void do_report(int l, const std::string& message) const;\r
-    void do_report(const std::string& message) const;\r
-\r
-    // make this class uncopyable\r
-    debug_trace(const debug_trace&);\r
-    debug_trace& operator = (const debug_trace&);\r
-  };\r
-\r
-} // end namespace stlplus\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_DEBUG
+#define STLPLUS_DEBUG
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Set of simple debug utilities, all of which are switched off by the
+//   NDEBUG compiler directive
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "portability_fixes.hpp"
+#include <stdexcept>
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+// Problem with missing __FUNCTION__ macro
+////////////////////////////////////////////////////////////////////////////////
+// this macro is used in debugging but was missing in Visual Studio prior to version 7
+// it also has a different name in Borland
+
+#if defined(_MSC_VER) && (_MSC_VER < 1300)
+#define __FUNCTION__ 0
+#endif
+
+#ifdef __BORLANDC__
+#define __FUNCTION__ __FUNC__
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Exception thrown if an assertion fails
+
+namespace stlplus
+{
+
+  class assert_failed : public std::logic_error
+  {
+  public:
+    assert_failed(const char* file, int line, const char* function, const char* message) throw();
+    ~assert_failed(void) throw();
+  };
+
+} // end namespace stlplus
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // The macros used in debugging
+
+#ifndef NDEBUG
+
+#define DEBUG_TRACE stlplus::debug_trace stlplus_debug_trace(__FILE__,__LINE__,__FUNCTION__)
+#define IF_DEBUG(stmts) {if (stlplus_debug_trace.debug()){stlplus_debug_trace.prefix(__LINE__);stmts;}}
+#define DEBUG_REPORT(str) IF_DEBUG(stlplus_debug_trace.report(__LINE__,str))
+#define DEBUG_ERROR(str) stlplus_debug_trace.error(__LINE__,str)
+#define DEBUG_STACKDUMP(str) stlplus_debug_trace.stackdump(__LINE__,str)
+#define DEBUG_ON stlplus_debug_trace.debug_on(__LINE__,true)
+#define DEBUG_ON_LOCAL stlplus_debug_trace.debug_on(__LINE__,false)
+#define DEBUG_ON_GLOBAL stlplus::debug_global(__FILE__,__LINE__,__FUNCTION__,true)
+#define DEBUG_OFF_GLOBAL stlplus::debug_global(__FILE__,__LINE__,__FUNCTION__,false)
+#define DEBUG_OFF stlplus_debug_trace.debug_off(__LINE__)
+#define DEBUG_ASSERT(test) if (!(test))stlplus::debug_assert_fail(__FILE__,__LINE__,__FUNCTION__,#test)
+
+#else
+
+#define DEBUG_TRACE
+#define IF_DEBUG(stmts)
+#define DEBUG_REPORT(str)
+#define DEBUG_ERROR(str)
+#define DEBUG_STACKDUMP(str)
+#define DEBUG_ON
+#define DEBUG_ON_LOCAL
+#define DEBUG_ON_GLOBAL
+#define DEBUG_OFF_GLOBAL
+#define DEBUG_OFF
+#define DEBUG_ASSERT(test)
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// infrastructure - don't use directly
+
+namespace stlplus
+{
+
+  void debug_global(const char* file, int line, const char* function, bool state = true);
+  void debug_assert_fail(const char* file, int line, const char* function, const char* test) throw(assert_failed);
+
+  class debug_trace
+  {
+  public:
+    debug_trace(const char* f, int l, const char* fn);
+    ~debug_trace(void);
+    const char* file(void) const;
+    int line(void) const;
+    bool debug(void) const;
+    void debug_on(int l, bool recurse);
+    void debug_off(int l);
+    void prefix(int l) const;
+    void report(int l, const std::string& message) const;
+    void report(const std::string& message) const;
+    void error(int l, const std::string& message) const;
+    void error(const std::string& message) const;
+    void stackdump(int l, const std::string& message) const;
+    void stackdump(const std::string& message) const;
+    void stackdump(void) const;
+
+  private:
+    const char* m_file;
+    int m_line;
+    const char* m_function;
+    unsigned m_depth;
+    const debug_trace* m_last;
+    bool m_dbg;
+    bool m_old;
+    void do_report(int l, const std::string& message) const;
+    void do_report(const std::string& message) const;
+
+    // make this class uncopyable
+    debug_trace(const debug_trace&);
+    debug_trace& operator = (const debug_trace&);
+  };
+
+} // end namespace stlplus
+
+  ////////////////////////////////////////////////////////////////////////////////
+#endif
index f03217ebb26be3013bda285dcfb888ed3090a473..b0e05c6b7097bd785c3a55c996bb0d383fba3dc0 100644 (file)
@@ -1,92 +1,92 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Notes:\r
-\r
-//   Feb 2007: Rewritten in terms of platform-specific fixes to the\r
-//   buffer-overflow problem. Using native functions for this has the added\r
-//   benefit of giving access to other features of the C-runtime such as Unicode\r
-//   support.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "dprintf.hpp"\r
-#include <stdio.h>\r
-#include <limits.h>\r
-#include <float.h>\r
-#include <ctype.h>\r
-#include <stdlib.h>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-  int vdprintf(std::string& formatted, const char* format, va_list args)\r
-  {\r
-#ifdef MSWINDOWS\r
-    int length = 0;\r
-    char* buffer = 0;\r
-    for(int buffer_length = 256; ; buffer_length*=2)\r
-    {\r
-      buffer = (char*)malloc(buffer_length);\r
-      if (!buffer) return -1;\r
-      length = _vsnprintf(buffer, buffer_length-1, format, args);\r
-      if (length >= 0)\r
-      {\r
-        buffer[length] = 0;\r
-        formatted += std::string(buffer);\r
-        free(buffer);\r
-        break;\r
-      }\r
-      free(buffer);\r
-    }\r
-    return length;\r
-#else\r
-    char* buffer = 0;\r
-    int length = vasprintf(&buffer, format, args);\r
-    if (!buffer) return -1;\r
-    if (length >= 0)\r
-      formatted += std::string(buffer);\r
-    free(buffer);\r
-    return length;\r
-#endif\r
-  }\r
-\r
-  int dprintf(std::string& formatted, const char* format, ...)\r
-  {\r
-    va_list args;\r
-    va_start(args, format);\r
-    int result = vdprintf(formatted, format, args);\r
-    va_end(args);\r
-    return result;\r
-  }\r
-\r
-  std::string vdformat(const char* format, va_list args) throw(std::invalid_argument)\r
-  {\r
-    std::string formatted;\r
-    int length = vdprintf(formatted, format, args);\r
-    if (length < 0) throw std::invalid_argument("dprintf");\r
-    return formatted;\r
-  }\r
-\r
-  std::string dformat(const char* format, ...) throw(std::invalid_argument)\r
-  {\r
-    std::string formatted;\r
-    va_list args;\r
-    va_start(args, format);\r
-    int length = vdprintf(formatted, format, args);\r
-    va_end(args);\r
-    if (length < 0) throw std::invalid_argument("dprintf");\r
-    return formatted;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Notes:
+
+//   Feb 2007: Rewritten in terms of platform-specific fixes to the
+//   buffer-overflow problem. Using native functions for this has the added
+//   benefit of giving access to other features of the C-runtime such as Unicode
+//   support.
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "dprintf.hpp"
+#include <stdio.h>
+#include <limits.h>
+#include <float.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+////////////////////////////////////////////////////////////////////////////////
+
+  int vdprintf(std::string& formatted, const char* format, va_list args)
+  {
+#ifdef MSWINDOWS
+    int length = 0;
+    char* buffer = 0;
+    for(int buffer_length = 256; ; buffer_length*=2)
+    {
+      buffer = (char*)malloc(buffer_length);
+      if (!buffer) return -1;
+      length = _vsnprintf(buffer, buffer_length-1, format, args);
+      if (length >= 0)
+      {
+        buffer[length] = 0;
+        formatted += std::string(buffer);
+        free(buffer);
+        break;
+      }
+      free(buffer);
+    }
+    return length;
+#else
+    char* buffer = 0;
+    int length = vasprintf(&buffer, format, args);
+    if (!buffer) return -1;
+    if (length >= 0)
+      formatted += std::string(buffer);
+    free(buffer);
+    return length;
+#endif
+  }
+
+  int dprintf(std::string& formatted, const char* format, ...)
+  {
+    va_list args;
+    va_start(args, format);
+    int result = vdprintf(formatted, format, args);
+    va_end(args);
+    return result;
+  }
+
+  std::string vdformat(const char* format, va_list args) throw(std::invalid_argument)
+  {
+    std::string formatted;
+    int length = vdprintf(formatted, format, args);
+    if (length < 0) throw std::invalid_argument("dprintf");
+    return formatted;
+  }
+
+  std::string dformat(const char* format, ...) throw(std::invalid_argument)
+  {
+    std::string formatted;
+    va_list args;
+    va_start(args, format);
+    int length = vdprintf(formatted, format, args);
+    va_end(args);
+    if (length < 0) throw std::invalid_argument("dprintf");
+    return formatted;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index f7de78b1bcdbb2439fd72d726854692d804a387f..360e5c10a6b0bc90c8cfbcdedc378eb0cbe31aaf 100644 (file)
-#ifndef STLPLUS_DPRINTF\r
-#define STLPLUS_DPRINTF\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Provides an sprintf-like function acting on STL strings. The 'd' in dprintf\r
-//   stands for "dynamic" in that the string is a dynamic string whereas a char*\r
-//   buffer would be static (in size that is, not static in C terms).\r
-\r
-//   The obvious solution to the problem of in-memory formatted output is to use\r
-//   sprintf(), but this is a potentially dangerous operation since it will quite\r
-//   happily charge off the end of the string it is printing to and thereby\r
-//   corrupt memory. This kind of buffer-overflow vulnerability is the source of\r
-//   most security failures exploited by virus-writers. It means that sprintf\r
-//   should *never* be used and should be made obsolete.\r
-\r
-//   In any case, using arbitrary-sized fixed-length buffers is not part of any\r
-//   quality-orientated design philosophy.\r
-\r
-//   Most operating systems now have a safe version of sprintf, but this is\r
-//   non-standard. The functions in this file are platform-independent interfaces\r
-//   to the underlying safe implementation.\r
-\r
-//   I would like to make this set of functions obsolete too, since I believe the\r
-//   C runtime should be deprecated in favour of C++ runtime which uses dynamic\r
-//   strings and can handle exceptions. However, there is as yet no C++\r
-//   equivalent functionality to some of the string-handling available through\r
-//   the printf-like functions, so it has to stay for now.\r
-\r
-//     int dprintf (std::string& buffer, const char* format, ...);\r
-\r
-//       Formats the message by appending to the std::string buffer according to\r
-//       the formatting codes in the format string. The return int is the number\r
-//       of characters generated by this call, i.e. the increase in the length of\r
-//       the std::string.\r
-\r
-//     int vdprintf (std::string& buffer, const char* format, va_list args);\r
-\r
-//       As above, but using a pre-initialised va_args argument list. Useful for\r
-//       nesting dprintf calls within variable argument functions.\r
-\r
-//     std::string dformat (const char* format, ...);\r
-\r
-//       Similar to dprintf() above, except the result is formatted into a new\r
-//       std::string which is returned by the function. Very useful for inline\r
-//       calls within an iostream expression.\r
-\r
-//       e.g.    cout << "Total: " << dformat("%6i",t) << endl;\r
-\r
-//     std::string vdformat (const char* format, va_list);\r
-  \r
-//       As above, but using a pre-initialised va_args argument list. Useful for nesting\r
-//       dformat calls within variable argument functions.\r
-\r
-//   The format string supports the following format codes as in the C runtime library:\r
-\r
-//     % [ flags ] [ field ] [ . precision ] [ modifier ] [ conversion ]\r
-\r
-//     flags:\r
-//       -    - left justified\r
-//       +    - print sign for +ve numbers\r
-//       ' '  - leading space where + sign would be\r
-//       0    - leading zeros to width of field\r
-//       #    - alternate format\r
-\r
-//     field:\r
-//       a numeric argument specifying the field width - default = 0\r
-//       * means take the next va_arg as the field width - if negative then left justify\r
-\r
-//     precision:\r
-//       a numeric argument the meaning of which depends on the conversion -\r
-//       - %s - max characters from a string - default = strlen()\r
-//       - %e, %f - decimal places to be displayed - default = 6\r
-//       - %g - significant digits to be displayed - default = 6\r
-//       - all integer conversions - minimum digits to display - default = 0\r
-//       * means take the next va_arg as the field width - if negative then left justify\r
-\r
-//     modifier:\r
-//       h    - short or unsigned short\r
-//       l    - long or unsigned long\r
-//       L    - long double\r
-\r
-//     conversions:\r
-//       d, i - short/int/long as decimal\r
-//       u    - short/int/long as unsigned decimal\r
-//       o    - short/int/long as unsigned octal - # adds leading 0\r
-//       x, X - short/int/long as unsigned hexadecimal - # adds leading 0x\r
-//       c    - char\r
-//       s    - char*\r
-//       f    - double/long double as fixed point\r
-//       e, E - double/long double as floating point\r
-//       g, G - double/long double as fixed point/floating point depending on value\r
-//       p    - void* as unsigned hexadecimal\r
-//       %    - literal %\r
-//       n    - int* as recipient of length of formatted string so far\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-#include <stdarg.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // format by appending to a string and return the increase in length\r
-  // if there is an error, return a negative number and leave the string unchanged\r
-  int dprintf (std::string& formatted, const char* format, ...);\r
-  int vdprintf (std::string& formatted, const char* format, va_list args);\r
-\r
-  // format into a new string and return the result\r
-  // if there is an error, throw an exception\r
-  std::string dformat (const char* format, ...) throw(std::invalid_argument);\r
-  std::string vdformat (const char* format, va_list) throw(std::invalid_argument);\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_DPRINTF
+#define STLPLUS_DPRINTF
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Provides an sprintf-like function acting on STL strings. The 'd' in dprintf
+//   stands for "dynamic" in that the string is a dynamic string whereas a char*
+//   buffer would be static (in size that is, not static in C terms).
+
+//   The obvious solution to the problem of in-memory formatted output is to use
+//   sprintf(), but this is a potentially dangerous operation since it will quite
+//   happily charge off the end of the string it is printing to and thereby
+//   corrupt memory. This kind of buffer-overflow vulnerability is the source of
+//   most security failures exploited by virus-writers. It means that sprintf
+//   should *never* be used and should be made obsolete.
+
+//   In any case, using arbitrary-sized fixed-length buffers is not part of any
+//   quality-orientated design philosophy.
+
+//   Most operating systems now have a safe version of sprintf, but this is
+//   non-standard. The functions in this file are platform-independent interfaces
+//   to the underlying safe implementation.
+
+//   I would like to make this set of functions obsolete too, since I believe the
+//   C runtime should be deprecated in favour of C++ runtime which uses dynamic
+//   strings and can handle exceptions. However, there is as yet no C++
+//   equivalent functionality to some of the string-handling available through
+//   the printf-like functions, so it has to stay for now.
+
+//     int dprintf (std::string& buffer, const char* format, ...);
+
+//       Formats the message by appending to the std::string buffer according to
+//       the formatting codes in the format string. The return int is the number
+//       of characters generated by this call, i.e. the increase in the length of
+//       the std::string.
+
+//     int vdprintf (std::string& buffer, const char* format, va_list args);
+
+//       As above, but using a pre-initialised va_args argument list. Useful for
+//       nesting dprintf calls within variable argument functions.
+
+//     std::string dformat (const char* format, ...);
+
+//       Similar to dprintf() above, except the result is formatted into a new
+//       std::string which is returned by the function. Very useful for inline
+//       calls within an iostream expression.
+
+//       e.g.    cout << "Total: " << dformat("%6i",t) << endl;
+
+//     std::string vdformat (const char* format, va_list);
+  
+//       As above, but using a pre-initialised va_args argument list. Useful for nesting
+//       dformat calls within variable argument functions.
+
+//   The format string supports the following format codes as in the C runtime library:
+
+//     % [ flags ] [ field ] [ . precision ] [ modifier ] [ conversion ]
+
+//     flags:
+//       -    - left justified
+//       +    - print sign for +ve numbers
+//       ' '  - leading space where + sign would be
+//       0    - leading zeros to width of field
+//       #    - alternate format
+
+//     field:
+//       a numeric argument specifying the field width - default = 0
+//       * means take the next va_arg as the field width - if negative then left justify
+
+//     precision:
+//       a numeric argument the meaning of which depends on the conversion -
+//       - %s - max characters from a string - default = strlen()
+//       - %e, %f - decimal places to be displayed - default = 6
+//       - %g - significant digits to be displayed - default = 6
+//       - all integer conversions - minimum digits to display - default = 0
+//       * means take the next va_arg as the field width - if negative then left justify
+
+//     modifier:
+//       h    - short or unsigned short
+//       l    - long or unsigned long
+//       L    - long double
+
+//     conversions:
+//       d, i - short/int/long as decimal
+//       u    - short/int/long as unsigned decimal
+//       o    - short/int/long as unsigned octal - # adds leading 0
+//       x, X - short/int/long as unsigned hexadecimal - # adds leading 0x
+//       c    - char
+//       s    - char*
+//       f    - double/long double as fixed point
+//       e, E - double/long double as floating point
+//       g, G - double/long double as fixed point/floating point depending on value
+//       p    - void* as unsigned hexadecimal
+//       %    - literal %
+//       n    - int* as recipient of length of formatted string so far
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+#include <stdexcept>
+#include <stdarg.h>
+
+namespace stlplus
+{
+
+  // format by appending to a string and return the increase in length
+  // if there is an error, return a negative number and leave the string unchanged
+  int dprintf (std::string& formatted, const char* format, ...);
+  int vdprintf (std::string& formatted, const char* format, va_list args);
+
+  // format into a new string and return the result
+  // if there is an error, throw an exception
+  std::string dformat (const char* format, ...) throw(std::invalid_argument);
+  std::string vdformat (const char* format, va_list) throw(std::invalid_argument);
+
+} // end namespace stlplus
+
+#endif
index cdd18489adf407660ada8c062909ae41fdc47a8f..4cd5741d9ad924cac329eb9d082cd902971d09c8 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "dynaload.hpp"\r
-\r
-#ifdef MSWINDOWS\r
-#include <windows.h>\r
-#else\r
-#include <dlfcn.h>\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef MSWINDOWS\r
-\r
-static std::string last_error(void)\r
-{\r
-  // get the last error code - if none, return the empty string\r
-  DWORD err = GetLastError();\r
-  if (err == 0) return std::string();\r
-  // get the system message for this error code\r
-  char* message;\r
-  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,\r
-                0,\r
-                err,\r
-                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
-                (LPTSTR)&message,\r
-                0,0);\r
-  std::string result = message;\r
-  LocalFree(message);\r
-  // the error message is for some perverse reason newline terminated - remove this\r
-  if (result[result.size()-1] == '\n')\r
-    result.erase(result.end()-1);\r
-  if (result[result.size()-1] == '\r')\r
-    result.erase(result.end()-1);\r
-  return result;\r
-}\r
-\r
-#else\r
-\r
-static std::string last_error(void)\r
-{\r
-  return std::string(dlerror());\r
-}\r
-\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // library management\r
-\r
-  // construct the object but do not load\r
-  dynaload::dynaload(void) : m_handle(0) \r
-  {\r
-  }\r
-\r
-  // construct and load\r
-  dynaload::dynaload(const std::string& library) : m_handle(0)\r
-  {\r
-    load(library);\r
-  }\r
-\r
-  // destroy and unload if loaded\r
-  dynaload::~dynaload(void)\r
-  {\r
-    unload();\r
-  }\r
-\r
-  // load the library - return success or fail\r
-  bool dynaload::load(const std::string& library)\r
-  {\r
-#ifdef MSWINDOWS\r
-    m_handle = (void*)LoadLibrary(library.c_str());\r
-#elif defined(CYGWIN)\r
-    m_handle = dlopen(library.c_str(),RTLD_NOW);\r
-#else\r
-    std::string full_library = std::string("lib") + library + std::string(".so");\r
-    m_handle = dlopen(full_library.c_str(),RTLD_NOW);\r
-#endif\r
-    if (!m_handle)\r
-    {\r
-      m_error = load_error;\r
-      m_text = last_error();\r
-    }\r
-    return loaded();\r
-  }\r
-\r
-  // unload the library if loaded\r
-  bool dynaload::unload(void)\r
-  {\r
-    if (!loaded()) return false;\r
-#ifdef MSWINDOWS\r
-    int status = FreeLibrary((HINSTANCE)m_handle) ? 0 : 1;\r
-#else\r
-    int status = dlclose(m_handle);\r
-#endif\r
-    if (status != 0)\r
-    {\r
-      m_error = unload_error;\r
-      m_text = last_error();\r
-    }\r
-    return status == 0;\r
-  }\r
-\r
-  // test whether the library is loaded\r
-  bool dynaload::loaded(void) const\r
-  {\r
-    return m_handle != 0;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // symbol management\r
-\r
-  // test whether a function is exported by the library\r
-  // does not set the error flag if fails\r
-  bool dynaload::present(const std::string& name)\r
-  {\r
-    if (!loaded()) return false;\r
-#ifdef MSWINDOWS\r
-    void* fn = (void*)GetProcAddress((HINSTANCE)m_handle,name.c_str());\r
-#else\r
-    void* fn = dlsym(m_handle,name.c_str());\r
-#endif\r
-    return fn != 0;\r
-  }\r
-\r
-  // get the function as a generic pointer\r
-  void* dynaload::symbol(const std::string& name)\r
-  {\r
-    if (!loaded()) return 0;\r
-#ifdef MSWINDOWS\r
-    void* fn = (void*)GetProcAddress((HINSTANCE)m_handle,name.c_str());\r
-#else\r
-    void* fn = dlsym(m_handle,name.c_str());\r
-#endif\r
-    if (!fn)\r
-    {\r
-      m_error = symbol_error;\r
-      m_text = last_error();\r
-    }\r
-    return fn;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // error management\r
-\r
-  // test whether there has been an error\r
-  bool dynaload::error(void) const\r
-  {\r
-    return m_error != no_error;\r
-  }\r
-\r
-  // clear an error once it has been handled (or ignored)\r
-  void dynaload::clear_error(void)\r
-  {\r
-    m_error = no_error;\r
-    m_text = std::string();\r
-  }\r
-\r
-  // get the type of the error as indicated by the enum error_t\r
-  dynaload::error_t dynaload::error_type(void) const\r
-  {\r
-    return m_error;\r
-  }\r
-\r
-  // get the text of the error as provided by the OS\r
-  std::string dynaload::error_text(void) const\r
-  {\r
-    return m_text;\r
-  }\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "dynaload.hpp"
+
+#ifdef MSWINDOWS
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef MSWINDOWS
+
+static std::string last_error(void)
+{
+  // get the last error code - if none, return the empty string
+  DWORD err = GetLastError();
+  if (err == 0) return std::string();
+  // get the system message for this error code
+  char* message;
+  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+                0,
+                err,
+                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                (LPTSTR)&message,
+                0,0);
+  std::string result = message;
+  LocalFree(message);
+  // the error message is for some perverse reason newline terminated - remove this
+  if (result[result.size()-1] == '\n')
+    result.erase(result.end()-1);
+  if (result[result.size()-1] == '\r')
+    result.erase(result.end()-1);
+  return result;
+}
+
+#else
+
+static std::string last_error(void)
+{
+  return std::string(dlerror());
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // library management
+
+  // construct the object but do not load
+  dynaload::dynaload(void) : m_handle(0) 
+  {
+  }
+
+  // construct and load
+  dynaload::dynaload(const std::string& library) : m_handle(0)
+  {
+    load(library);
+  }
+
+  // destroy and unload if loaded
+  dynaload::~dynaload(void)
+  {
+    unload();
+  }
+
+  // load the library - return success or fail
+  bool dynaload::load(const std::string& library)
+  {
+#ifdef MSWINDOWS
+    m_handle = (void*)LoadLibrary(library.c_str());
+#elif defined(CYGWIN)
+    m_handle = dlopen(library.c_str(),RTLD_NOW);
+#else
+    std::string full_library = std::string("lib") + library + std::string(".so");
+    m_handle = dlopen(full_library.c_str(),RTLD_NOW);
+#endif
+    if (!m_handle)
+    {
+      m_error = load_error;
+      m_text = last_error();
+    }
+    return loaded();
+  }
+
+  // unload the library if loaded
+  bool dynaload::unload(void)
+  {
+    if (!loaded()) return false;
+#ifdef MSWINDOWS
+    int status = FreeLibrary((HINSTANCE)m_handle) ? 0 : 1;
+#else
+    int status = dlclose(m_handle);
+#endif
+    if (status != 0)
+    {
+      m_error = unload_error;
+      m_text = last_error();
+    }
+    return status == 0;
+  }
+
+  // test whether the library is loaded
+  bool dynaload::loaded(void) const
+  {
+    return m_handle != 0;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////
+  // symbol management
+
+  // test whether a function is exported by the library
+  // does not set the error flag if fails
+  bool dynaload::present(const std::string& name)
+  {
+    if (!loaded()) return false;
+#ifdef MSWINDOWS
+    void* fn = (void*)GetProcAddress((HINSTANCE)m_handle,name.c_str());
+#else
+    void* fn = dlsym(m_handle,name.c_str());
+#endif
+    return fn != 0;
+  }
+
+  // get the function as a generic pointer
+  void* dynaload::symbol(const std::string& name)
+  {
+    if (!loaded()) return 0;
+#ifdef MSWINDOWS
+    void* fn = (void*)GetProcAddress((HINSTANCE)m_handle,name.c_str());
+#else
+    void* fn = dlsym(m_handle,name.c_str());
+#endif
+    if (!fn)
+    {
+      m_error = symbol_error;
+      m_text = last_error();
+    }
+    return fn;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////
+  // error management
+
+  // test whether there has been an error
+  bool dynaload::error(void) const
+  {
+    return m_error != no_error;
+  }
+
+  // clear an error once it has been handled (or ignored)
+  void dynaload::clear_error(void)
+  {
+    m_error = no_error;
+    m_text = std::string();
+  }
+
+  // get the type of the error as indicated by the enum error_t
+  dynaload::error_t dynaload::error_type(void) const
+  {
+    return m_error;
+  }
+
+  // get the text of the error as provided by the OS
+  std::string dynaload::error_text(void) const
+  {
+    return m_text;
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index dafaf243ee6dc66ae8cbc6e38c33671049fb8196..d35d324112497f6937255115f7902c0b3dbe52b8 100644 (file)
@@ -1,86 +1,86 @@
-#ifndef STLPLUS_DYNALOAD\r
-#define STLPLUS_DYNALOAD\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A portable interface to the dynamic loader - i.e. the system for loading\r
-//   dynamic libraries or shared libraries during the running of a program,\r
-//   rather than by linking\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // dynaload class manages a dynamic loadable library and unloads it on destruction\r
-\r
-  class dynaload\r
-  {\r
-  public:\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // library management\r
-\r
-    // construct the object but do not load\r
-    dynaload(void);\r
-\r
-    // construct and load\r
-    dynaload(const std::string& library);\r
-\r
-    // destroy and unload if loaded\r
-    ~dynaload(void);\r
-\r
-    // load the library - return success or fail\r
-    bool load(const std::string& library);\r
-\r
-    // unload the library if loaded\r
-    bool unload(void);\r
-\r
-    // test whether the library is loaded\r
-    bool loaded(void) const;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // symbol management\r
-\r
-    // test whether a function is exported by the library\r
-    bool present(const std::string& name);\r
-\r
-    // get the function as a generic pointer\r
-    void* symbol(const std::string& name);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error management\r
-\r
-    // enum values to indicate type of error\r
-    enum error_t {no_error, load_error, unload_error, symbol_error};\r
-\r
-    // test whether there has been an error\r
-    bool error(void) const;\r
-\r
-    // clear an error once it has been handled (or ignored)\r
-    void clear_error(void);\r
-\r
-    // get the type of the error as indicated by the enum error_t\r
-    error_t error_type(void) const;\r
-\r
-    // get the text of the error as provided by the OS\r
-    std::string error_text(void) const;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-\r
-  private:\r
-    void* m_handle;\r
-    error_t m_error;\r
-    std::string m_text;\r
-  };\r
-\r
-}\r
-\r
-#endif\r
+#ifndef STLPLUS_DYNALOAD
+#define STLPLUS_DYNALOAD
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A portable interface to the dynamic loader - i.e. the system for loading
+//   dynamic libraries or shared libraries during the running of a program,
+//   rather than by linking
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  //////////////////////////////////////////////////////////////////////////////
+  // dynaload class manages a dynamic loadable library and unloads it on destruction
+
+  class dynaload
+  {
+  public:
+
+    ////////////////////////////////////////////////////////////////////////////
+    // library management
+
+    // construct the object but do not load
+    dynaload(void);
+
+    // construct and load
+    dynaload(const std::string& library);
+
+    // destroy and unload if loaded
+    ~dynaload(void);
+
+    // load the library - return success or fail
+    bool load(const std::string& library);
+
+    // unload the library if loaded
+    bool unload(void);
+
+    // test whether the library is loaded
+    bool loaded(void) const;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // symbol management
+
+    // test whether a function is exported by the library
+    bool present(const std::string& name);
+
+    // get the function as a generic pointer
+    void* symbol(const std::string& name);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error management
+
+    // enum values to indicate type of error
+    enum error_t {no_error, load_error, unload_error, symbol_error};
+
+    // test whether there has been an error
+    bool error(void) const;
+
+    // clear an error once it has been handled (or ignored)
+    void clear_error(void);
+
+    // get the type of the error as indicated by the enum error_t
+    error_t error_type(void) const;
+
+    // get the text of the error as provided by the OS
+    std::string error_text(void) const;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+  private:
+    void* m_handle;
+    error_t m_error;
+    std::string m_text;
+  };
+
+}
+
+#endif
index 983d98483ac92d8285d8e44df41a008fe69524e2..cfca256232a3e7e6cb4e14fd76a0ece2b71a403b 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   This is a portable interface to the file system.\r
-\r
-//   The idea is that you write all file system access code using these functions,\r
-//   which are ported to all platforms that we are interested in. Therefore your\r
-//   code is inherently portable.\r
-\r
-//   Native Windows version: switched on by macro _WIN32 which is defined by VC++/Borland/Mingw compilers\r
-//   Unix/Gnu version:   default variant, no compiler directives are required but _WIN32 must be absent\r
-//   Cygwin/Gnu version: as Unix version but with additional support for Windows drive letters\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "file_system.hpp"\r
-#include "wildcard.hpp"\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include <time.h>\r
-#include <algorithm>\r
-#include <ctype.h>\r
-\r
-#ifdef MSWINDOWS\r
-#include <windows.h>\r
-#include <dos.h>\r
-#include <direct.h>\r
-#include <fcntl.h>\r
-#include <io.h>\r
-#include <sys/stat.h>\r
-#include <sys/types.h>\r
-#else\r
-#include <dirent.h>\r
-#include <fcntl.h>\r
-#include <sys/param.h>\r
-#include <unistd.h>\r
-#include <sys/stat.h>\r
-#include <sys/types.h>\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// definitions of separators\r
-\r
-#ifdef MSWINDOWS\r
-  static const char* separator_set = "\\/";\r
-  static const char preferred_separator = '\\';\r
-#else\r
-  static const char* separator_set = "/";\r
-  static const char preferred_separator = '/';\r
-#endif\r
-\r
-  static bool is_separator (char ch)\r
-  {\r
-    for (int i = 0; separator_set[i]; i++)\r
-    {\r
-      if (separator_set[i] == ch)\r
-        return true;\r
-    }\r
-    return false;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// implement string comparison of paths - Unix is case-sensitive, Windoze is case-insensitive\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  static std::string lowercase(const std::string& val)\r
-  {\r
-    std::string text = val;\r
-    for (unsigned i = 0; i < text.size(); i++)\r
-      text[i] = tolower(text[i]);\r
-    return text;\r
-  }\r
-\r
-#endif\r
-\r
-  bool path_compare(const std::string& l, const std::string& r)\r
-  {\r
-#ifdef MSWINDOWS\r
-    return lowercase(l) == lowercase(r);\r
-#else\r
-    return l == r;\r
-#endif\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Internal data structure used to hold the different parts of a filespec\r
-\r
-  class file_specification\r
-  {\r
-  private:\r
-    bool m_relative;                 // true = relative, false = absolute\r
-    std::string m_drive;             // drive - drive letter (e.g. "c:") or the path for an UNC (e.g. "\\somewhere")\r
-                                     //         empty if not known or on Unix\r
-    std::vector<std::string> m_path; // the subdirectory path to follow from the drive\r
-    std::string m_filename;          // the filename\r
-  public:\r
-    file_specification(void) : m_relative(false) {}\r
-    ~file_specification(void) {}\r
-\r
-    bool initialise_folder(const std::string& spec);\r
-    bool initialise_file(const std::string& spec);\r
-    bool simplify(void);\r
-    bool make_absolute(const std::string& root = folder_current_full());\r
-    bool make_absolute(const file_specification& root);\r
-    bool make_relative(const std::string& root = folder_current_full());\r
-    bool make_relative(const file_specification& root);\r
-    bool relative(void) const {return m_relative;}\r
-    bool absolute(void) const {return !relative();}\r
-    void set_relative(void) {m_relative = true;}\r
-    void set_absolute(void) {m_relative = false;}\r
-\r
-    const std::string& drive(void) const {return m_drive;}\r
-    std::string& drive(void) {return m_drive;}\r
-    void set_drive(const std::string& drive) {m_drive = drive;}\r
-\r
-    const std::vector<std::string>& path(void) const {return m_path;}\r
-    std::vector<std::string>& path(void) {return m_path;}\r
-    void set_path(const std::vector<std::string>& path) {m_path = path;}\r
-\r
-    void add_subpath(const std::string& subpath) {m_path.push_back(subpath);}\r
-    unsigned subpath_size(void) const {return m_path.size();}\r
-    const std::string& subpath_element(unsigned i) const {return m_path[i];}\r
-    void subpath_erase(unsigned i) {m_path.erase(m_path.begin()+i);}\r
-\r
-    const std::string& file(void) const {return m_filename;}\r
-    std::string& file(void) {return m_filename;}\r
-    void set_file(const std::string& file) {m_filename = file;}\r
-\r
-    std::string image(void) const;\r
-  };\r
-\r
-  bool file_specification::initialise_folder(const std::string& folder_spec)\r
-  {\r
-    std::string spec = folder_spec;\r
-    m_relative = true;\r
-    m_drive.erase();\r
-    m_path.clear();\r
-    m_filename.erase();\r
-    unsigned i = 0;\r
-#ifdef MSWINDOWS\r
-    // first split off the drive letter or UNC prefix on Windows\r
-    if (spec.size() >= 2 && isalpha(spec[0]) && spec[1] == ':')\r
-    {\r
-      // found a drive letter\r
-      i = 2;\r
-      m_drive = spec.substr(0, 2);\r
-      m_relative = false;\r
-      // if there is a drive but no path or a relative path, get the current\r
-      // path for this drive and prepend it to the path\r
-      if (i == spec.size() || !is_separator(spec[i]))\r
-      {\r
-        // getdcwd requires the drive number (1..26) not the letter (A..Z)\r
-        char path [MAX_PATH+1];\r
-        int drivenum = toupper(m_drive[0]) - 'A' + 1;\r
-        if (_getdcwd(drivenum, path, MAX_PATH+1))\r
-        {\r
-          // the path includes the drive so we have the drive info twice\r
-          // need to prepend this absolute path to the spec such that any remaining relative path is still retained\r
-          if (!is_separator(path[strlen(path)-1])) spec.insert(2, 1, preferred_separator);\r
-          spec.insert(2, path+2);\r
-        }\r
-        else\r
-        {\r
-          // non-existent drive - fill in just the root directory\r
-          spec.insert(2, 1, preferred_separator);\r
-        }\r
-      }\r
-    }\r
-    else if (spec.size() >= 2 && is_separator(spec[0]) && is_separator(spec[1]))\r
-    {\r
-      // found an UNC prefix\r
-      i = 2;\r
-      // find the end of the prefix by scanning for the next seperator or the end of the spec\r
-      while (i < spec.size() && !is_separator(spec[i])) i++;\r
-      m_drive = spec.substr(0, i);\r
-      m_relative = false;\r
-    }\r
-#endif\r
-#ifdef CYGWIN\r
-    // first split off the drive letter or UNC prefix on Windows - the Cygwin environment supports these too\r
-    if (spec.size() >= 2 && isalpha(spec[0]) && spec[1] == ':')\r
-    {\r
-      // found a drive letter\r
-      i = 2;\r
-      m_drive = spec.substr(0, 2);\r
-      m_relative = false;\r
-      // if there is a drive but no path or a relative path, get the current\r
-      // path for this drive and prepend it to the path\r
-      if (i == spec.size() || !is_separator(spec[i]))\r
-      {\r
-        // non-existent drive - fill in just the root directory\r
-        spec.insert(2, 1, preferred_separator);\r
-      }\r
-    }\r
-    else if (spec.size() >= 2 && is_separator(spec[0]) && is_separator(spec[1]))\r
-    {\r
-      // found an UNC prefix\r
-      i = 2;\r
-      // find the end of the prefix by scanning for the next seperator or the end of the spec\r
-      while (i < spec.size() && !is_separator(spec[i])) i++;\r
-      m_drive = spec.substr(0, i);\r
-      m_relative = false;\r
-    }\r
-#endif\r
-    // check whether the path is absolute or relative and discard the leading / if absolute\r
-    if (i < spec.size() && is_separator(spec[i]))\r
-    {\r
-      m_relative = false;\r
-      i++;\r
-#ifdef MSWINDOWS\r
-      // if there's no drive, fill it in on Windows since absolute paths must have a drive\r
-      if (m_drive.empty())\r
-      {\r
-        m_drive += (char)(_getdrive() - 1 + 'A');\r
-        m_drive += ':';\r
-      }\r
-#endif\r
-    }\r
-    // now extract the path elements - note that a trailing / is not significant since /a/b/c/ === /a/b/c\r
-    // also note that the leading / has been discarded - all paths are relative\r
-    // if absolute() is set, then paths are relative to the drive, else they are relative to the current path\r
-    unsigned start = i;\r
-    while(i <= spec.size())\r
-    {\r
-      if (i == spec.size())\r
-      {\r
-        // path element terminated by the end of the string\r
-        // discard this element if it is zero length because that represents the trailing /\r
-        if (i != start)\r
-          m_path.push_back(spec.substr(start, i-start));\r
-      }\r
-      else if (is_separator(spec[i]))\r
-      {\r
-        // path element terminated by a separator\r
-        m_path.push_back(spec.substr(start, i-start));\r
-        start = i+1;\r
-      }\r
-      i++;\r
-    }\r
-    // TODO - some error handling?\r
-    return true;\r
-  }\r
-\r
-  bool file_specification::initialise_file(const std::string& spec)\r
-  {\r
-    m_filename.erase();\r
-    // remove last element as the file and then treat the rest as a folder\r
-    unsigned i = spec.size();\r
-    while (--i)\r
-    {\r
-      if (is_separator(spec[i]))\r
-        break;\r
-#ifdef MSWINDOWS\r
-      // on windoze you can say a:fred.txt so the colon separates the path from the filename\r
-      else if (i == 1 && spec[i] == ':')\r
-        break;\r
-#endif\r
-    }\r
-    bool result = initialise_folder(spec.substr(0,i+1));\r
-    m_filename = spec.substr(i+1,spec.size()-i-1);\r
-    // TODO - some error handling?\r
-    return result;\r
-  }\r
-\r
-  bool file_specification::simplify(void)\r
-  {\r
-    // simplify the path by removing unnecessary . and .. entries - Note that zero-length entries are treated like .\r
-    for (unsigned i = 0; i < m_path.size(); )\r
-    {\r
-      if (m_path[i].empty() || m_path[i].compare(".") == 0)\r
-      {\r
-        // found . or null\r
-        // these both mean do nothing - so simply delete this element\r
-        m_path.erase(m_path.begin()+i);\r
-      }\r
-      else if (m_path[i].compare("..") == 0)\r
-      {\r
-        // found ..\r
-        if (i == 0 && !m_relative)\r
-        {\r
-          // up from the root does nothing so can be deleted\r
-          m_path.erase(m_path.begin()+i);\r
-          i++;\r
-        }\r
-        else if (i == 0 || m_path[i-1].compare("..") == 0)\r
-        {\r
-          // the first element of a relative path or the previous element is .. then keep it\r
-          i++;\r
-        }\r
-        else\r
-        {\r
-          // otherwise delete this element and the previous one\r
-          m_path.erase(m_path.begin()+i);\r
-          m_path.erase(m_path.begin()+i-1);\r
-          i--;\r
-        }\r
-      }\r
-      // keep all other elements\r
-      else\r
-        i++;\r
-    }\r
-    // TODO - error checking?\r
-    return true;\r
-  }\r
-\r
-  bool file_specification::make_absolute(const std::string& root)\r
-  {\r
-    // test whether already an absolute path in which case there's nothing to do\r
-    if (absolute()) return true;\r
-    // now simply call the other version of make_absolute\r
-    file_specification rootspec;\r
-    rootspec.initialise_folder(root);\r
-    return make_absolute(rootspec);\r
-  }\r
-\r
-  bool file_specification::make_absolute(const file_specification& rootspec)\r
-  {\r
-    // test whether already an absolute path in which case there's nothing to do\r
-    if (absolute()) return true;\r
-    // initialise the result with the root and make the root absolute\r
-    file_specification result = rootspec;\r
-    result.make_absolute();\r
-    // now append this's relative path and filename to the root's absolute path\r
-    for (unsigned i = 0; i < subpath_size(); i++)\r
-      result.add_subpath(subpath_element(i));\r
-    result.set_file(file());\r
-    // now the result is the absolute path, so transfer it to this\r
-    *this = result;\r
-    // and simplify to get rid of any unwanted .. or . elements\r
-    simplify();\r
-    return true;\r
-  }\r
-\r
-  bool file_specification::make_relative(const std::string& root)\r
-  {\r
-    // test whether already an relative path in which case there's nothing to do\r
-    if (relative()) return true;\r
-    // now simply call the other version of make_relative\r
-    file_specification rootspec;\r
-    rootspec.initialise_folder(root);\r
-    return make_relative(rootspec);\r
-  }\r
-\r
-  bool file_specification::make_relative(const file_specification& rootspec)\r
-  {\r
-    // test whether already an relative path in which case there's nothing to do\r
-    if (relative()) return true;\r
-    // initialise the result with the root and make the root absolute\r
-    file_specification absolute_root = rootspec;\r
-    absolute_root.make_absolute();\r
-    // now compare elements of the absolute root with elements of this to find the common path\r
-    // if the drives are different, no conversion can take place and the result must be absolute, else clear the drive\r
-    if (!path_compare(drive(), absolute_root.drive())) return true;\r
-    set_drive("");\r
-    // first remove leading elements that are identical to the corresponding element in root\r
-    unsigned i = 0;\r
-    while(subpath_size() > 0 && \r
-          i < absolute_root.subpath_size() && \r
-          path_compare(subpath_element(0), absolute_root.subpath_element(i)))\r
-    {\r
-      subpath_erase(0);\r
-      i++;\r
-    }\r
-    // now add a .. prefix for every element in root that is different from this\r
-    while (i < absolute_root.subpath_size())\r
-    {\r
-      m_path.insert(m_path.begin(), "..");\r
-      i++;\r
-    }\r
-    set_relative();\r
-    return true;\r
-  }\r
-\r
-  std::string file_specification::image(void) const\r
-  {\r
-    std::string result = m_drive;\r
-    if (absolute())\r
-      result += preferred_separator;\r
-    if (!m_path.empty())\r
-    {\r
-      for (unsigned i = 0; i < m_path.size(); i++)\r
-      {\r
-        if (i != 0) result += std::string(1,preferred_separator);\r
-        result += m_path[i];\r
-      }\r
-    }\r
-    else if (relative())\r
-      result += '.';\r
-    // add a trailing / to the last directory element\r
-    if (result.empty() || !is_separator(result[result.size()-1]))\r
-      result += preferred_separator;\r
-    if (!m_filename.empty())\r
-      result += m_filename;\r
-    return result;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// classifying functions\r
-\r
-#ifdef MSWINDOWS\r
-// file type tests are not defined for some reason on Windows despite them providing the stat() function!\r
-#define R_OK 4\r
-#define W_OK 2\r
-#endif\r
-\r
-  bool is_present (const std::string& thing)\r
-  {\r
-    // strip off any trailing separator because that will cause the stat function to fail\r
-    std::string path = thing;\r
-    if (!path.empty() && is_separator(path[path.size()-1]))\r
-      path.erase(path.size()-1,1);\r
-    // now test if this thing exists using the built-in stat function\r
-    struct stat buf;\r
-    return stat(path.c_str(), &buf) == 0;\r
-  }\r
-\r
-  bool is_folder (const std::string& thing)\r
-  {\r
-    // strip off any trailing separator because that will cause the stat function to fail\r
-    std::string path = thing;\r
-    if (!path.empty() && is_separator(path[path.size()-1]))\r
-      path.erase(path.size()-1,1);\r
-    // now test if this thing exists using the built-in stat function and if so, is it a folder\r
-    struct stat buf;\r
-    if (!(stat(path.c_str(), &buf) == 0)) {return false;}\r
-    return (buf.st_mode & S_IFDIR) != 0;\r
-  }\r
-\r
-  bool is_file (const std::string& thing)\r
-  {\r
-    // strip off any trailing separator because that will cause the stat function to fail\r
-    std::string path = thing;\r
-    if (!path.empty() && is_separator(path[path.size()-1]))\r
-      path.erase(path.size()-1,1);\r
-    // now test if this thing exists using the built-in stat function and if so, is it a file\r
-    struct stat buf;\r
-    if (!(stat(path.c_str(), &buf) == 0)) {return false;}\r
-    return (buf.st_mode & S_IFREG) != 0;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// file functions\r
-\r
-  bool file_exists (const std::string& filespec)\r
-  {\r
-    return is_file(filespec);\r
-  }\r
-\r
-  bool file_readable (const std::string& filespec)\r
-  {\r
-    // a file is readable if it exists and can be read\r
-    if (!file_exists(filespec)) return false;\r
-    return access(filespec.c_str(),R_OK)==0;\r
-  }\r
-\r
-  bool file_writable (const std::string& filespec)\r
-  {\r
-    // a file is writable if it exists as a file and is writable or if it doesn't exist but could be created and would be writable\r
-    if (is_present(filespec))\r
-    {\r
-      if (!is_file(filespec)) return false;\r
-      return access(filespec.c_str(),W_OK)==0;\r
-    }\r
-    std::string dir = folder_part(filespec);\r
-    if (dir.empty()) dir = ".";\r
-    return folder_writable(dir);\r
-  }\r
-\r
-  size_t file_size (const std::string& filespec)\r
-  {\r
-    struct stat buf;\r
-    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;\r
-    return buf.st_size;\r
-  }\r
-\r
-  bool file_delete (const std::string& filespec)\r
-  {\r
-    if (!is_file(filespec)) return false;\r
-    return remove(filespec.c_str())==0;\r
-  }\r
-\r
-  bool file_rename (const std::string& old_filespec, const std::string& new_filespec)\r
-  {\r
-    if (!is_file(old_filespec)) return false;\r
-    return rename(old_filespec.c_str(), new_filespec.c_str())==0;\r
-  }\r
-\r
-  bool file_copy (const std::string& old_filespec, const std::string& new_filespec)\r
-  {\r
-    if (!is_file(old_filespec)) return false;\r
-    // do an exact copy - to do this, use binary mode\r
-    bool result = true;\r
-    FILE* old_file = fopen(old_filespec.c_str(),"rb");\r
-    FILE* new_file = fopen(new_filespec.c_str(),"wb");\r
-    if (!old_file)\r
-      result = false;\r
-    else if (!new_file)\r
-      result = false;\r
-    else\r
-    {\r
-      for (int byte = getc(old_file); byte != EOF; byte = getc(old_file))\r
-        putc(byte,new_file);\r
-    }\r
-    if (old_file) fclose(old_file);\r
-    if (new_file) fclose(new_file);\r
-    return result;\r
-  }\r
-\r
-  bool file_move (const std::string& old_filespec, const std::string& new_filespec)\r
-  {\r
-    // try to move the file by renaming - if that fails then do a copy and delete the original\r
-    if (file_rename(old_filespec, new_filespec))\r
-      return true;\r
-    if (!file_copy(old_filespec, new_filespec))\r
-      return false;\r
-    // I'm not sure what to do if the delete fails - is that an error?\r
-    // I've made it an error and then delete the copy so that the original state is recovered\r
-    if (file_delete(old_filespec))\r
-      return true;\r
-    file_delete(new_filespec);\r
-    return false;\r
-  }\r
-\r
-  time_t file_created (const std::string& filespec)\r
-  {\r
-    struct stat buf;\r
-    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;\r
-    return buf.st_ctime;\r
-  }\r
-\r
-  time_t file_modified (const std::string& filespec)\r
-  {\r
-    struct stat buf;\r
-    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;\r
-    return buf.st_mtime;\r
-  }\r
-\r
-  time_t file_accessed (const std::string& filespec)\r
-  {\r
-    struct stat buf;\r
-    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;\r
-    return buf.st_atime;\r
-  }\r
-\r
-  std::string create_filespec (const std::string& directory, const std::string& filename)\r
-  {\r
-    std::string result = directory;\r
-    // if directory is empty then no directory part will be added\r
-    // add trailing slash if the directory was specified and does not have a trailing slash\r
-    if (!result.empty() && !is_separator(result[result.size()-1]))\r
-      result += preferred_separator;\r
-    // if filename is null or empty, nothing will be added so the path is then a directory path\r
-    result += filename;\r
-    return result;\r
-  }\r
-\r
-  std::string create_filespec (const std::string& directory, const std::string& basename, const std::string& extension)\r
-  {\r
-    return create_filespec(directory, create_filename(basename, extension));\r
-  }\r
-\r
-  std::string create_filename(const std::string& basename, const std::string& extension)\r
-  {\r
-    std::string name = basename;\r
-    // extension is optional - so the dot is also optional\r
-    if (!extension.empty())\r
-    {\r
-      if (extension[0] != '.') name += '.';\r
-      name += extension;\r
-    }\r
-    return name;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// folder functions\r
-\r
-  bool folder_create (const std::string& directory)\r
-  {\r
-#ifdef MSWINDOWS\r
-    return mkdir(directory.c_str()) == 0;\r
-#else\r
-    return mkdir(directory.c_str(), 0777) == 0;\r
-#endif\r
-  }\r
-\r
-  bool folder_exists (const std::string& directory)\r
-  {\r
-    return is_folder(directory);\r
-  }\r
-\r
-  bool folder_readable (const std::string& directory)\r
-  {\r
-    // a folder is readable if it exists and has read access\r
-    std::string dir = directory;\r
-    if (dir.empty()) dir = ".";\r
-    if (!folder_exists(dir)) return false;\r
-    return access(dir.c_str(),R_OK)==0;\r
-  }\r
-\r
-  bool folder_writable (const std::string& directory)\r
-  {\r
-    // a folder is writable if it exists and has write access\r
-    std::string dir = directory;\r
-    if (dir.empty()) dir = ".";\r
-    if (!folder_exists(dir)) return false;\r
-    return access(dir.c_str(),W_OK)==0;\r
-  }\r
-\r
-  bool folder_delete (const std::string& directory, bool recurse)\r
-  {\r
-    std::string dir = directory;\r
-    if (dir.empty()) dir = ".";\r
-    if (!folder_exists(dir)) return false;\r
-    bool result = true;\r
-    // depth-first traversal ensures that directory contents are deleted before trying to delete the directory itself\r
-    if (recurse)\r
-    {\r
-      std::vector<std::string> subdirectories = folder_subdirectories(dir);\r
-      for (std::vector<std::string>::size_type d = 0; d < subdirectories.size(); ++d)\r
-        if (!folder_delete(folder_down(dir,subdirectories[d]),true)) \r
-          result = false;\r
-      std::vector<std::string> files = folder_files(dir);\r
-      for (std::vector<std::string>::size_type f = 0; f < files.size(); ++f)\r
-        if (!file_delete(create_filespec(dir, files[f]))) \r
-          result = false;\r
-    }\r
-    if (rmdir(dir.c_str())!=0) result = false;\r
-    return result;\r
-  }\r
-\r
-  bool folder_rename (const std::string& old_directory, const std::string& new_directory)\r
-  {\r
-    if (!folder_exists(old_directory)) return false;\r
-    return rename(old_directory.c_str(), new_directory.c_str())==0;\r
-  }\r
-\r
-  bool folder_empty(const std::string& directory)\r
-  {\r
-    std::string dir = directory.empty() ? std::string(".") : directory;\r
-    bool result = true;\r
-#ifdef MSWINDOWS\r
-    std::string wildcard = create_filespec(dir, "*.*");\r
-    long handle = -1;\r
-    _finddata_t fileinfo;\r
-    for (bool OK = (handle = _findfirst((char*)wildcard.c_str(), &fileinfo)) != -1; OK; OK = (_findnext(handle, &fileinfo)==0))\r
-    {\r
-      std::string strentry = fileinfo.name;\r
-      if (strentry.compare(".")!=0 && strentry.compare("..")!=0)\r
-      {\r
-        result = false;\r
-        break;\r
-      }\r
-    }\r
-    _findclose(handle);\r
-#else\r
-    DIR* d = opendir(dir.c_str());\r
-    if (d)\r
-    {\r
-      for (dirent* entry = readdir(d); entry; entry = readdir(d))\r
-      {\r
-        std::string strentry = entry->d_name;\r
-        if (strentry.compare(".")!=0 && strentry.compare("..")!=0)\r
-        {\r
-          result = false;\r
-          break;\r
-        }\r
-      }\r
-      closedir(d);\r
-    }\r
-#endif\r
-    return result;\r
-  }\r
-\r
-  bool folder_set_current(const std::string& folder)\r
-  {\r
-    if (!folder_exists(folder))\r
-      return false;\r
-#ifdef MSWINDOWS\r
-    // Windose implementation - this returns non-zero for success\r
-    return (SetCurrentDirectoryA(folder.c_str()) != 0);\r
-#else\r
-    // Unix implementation - this returns zero for success\r
-    return (chdir(folder.c_str()) == 0);\r
-#endif\r
-  }\r
-\r
-  std::string folder_current (void)\r
-  {\r
-    return ".";\r
-  }\r
-\r
-  std::string folder_current_full(void)\r
-  {\r
-    // It's not clear from the documentation whether the buffer for a path should be one byte longer\r
-    // than the maximum path length to allow for the null termination, so I have made it so anyway\r
-#ifdef MSWINDOWS\r
-    char abspath [MAX_PATH+1];\r
-    return std::string(_fullpath(abspath, ".", MAX_PATH+1));\r
-#else\r
-    char pathname [MAXPATHLEN+1];\r
-    getcwd(pathname,MAXPATHLEN+1);\r
-    return std::string(pathname);\r
-#endif\r
-  }\r
-\r
-  std::string folder_down (const std::string& directory, const std::string& subdirectory)\r
-  {\r
-    file_specification spec;\r
-    spec.initialise_folder(directory);\r
-    spec.add_subpath(subdirectory);\r
-    return spec.image();\r
-  }\r
-\r
-  std::string folder_up (const std::string& directory, unsigned levels)\r
-  {\r
-    file_specification spec;\r
-    spec.initialise_folder(directory);\r
-    for (unsigned i = 0; i < levels; i++)\r
-      spec.add_subpath("..");\r
-    spec.simplify();\r
-    return spec.image();\r
-  }\r
-\r
-  std::vector<std::string> folder_subdirectories (const std::string& directory)\r
-  {\r
-    return folder_wildcard(directory, "*", true, false);\r
-  }\r
-\r
-  std::vector<std::string> folder_files (const std::string& directory)\r
-  {\r
-    return folder_wildcard(directory, "*", false, true);\r
-  }\r
-\r
-  std::vector<std::string> folder_all(const std::string& directory)\r
-  {\r
-    return folder_wildcard(directory, "*", true, true);\r
-  }\r
-\r
-  std::vector<std::string> folder_wildcard (const std::string& directory, const std::string& wild, bool subdirs, bool files)\r
-  {\r
-    std::string dir = directory.empty() ? std::string(".") : directory;\r
-    std::vector<std::string> results;\r
-#ifdef MSWINDOWS\r
-    std::string wildcard = create_filespec(dir, wild);\r
-    long handle = -1;\r
-    _finddata_t fileinfo;\r
-    for (bool OK = (handle = _findfirst((char*)wildcard.c_str(), &fileinfo)) != -1; OK; OK = (_findnext(handle, &fileinfo)==0))\r
-    {\r
-      std::string strentry = fileinfo.name;\r
-      if (strentry.compare(".")!=0 && strentry.compare("..")!=0)\r
-        if ((subdirs && (fileinfo.attrib & _A_SUBDIR)) || (files && !(fileinfo.attrib & _A_SUBDIR)))\r
-          results.push_back(strentry);\r
-    }\r
-    _findclose(handle);\r
-#else\r
-    DIR* d = opendir(dir.c_str());\r
-    if (d)\r
-    {\r
-      for (dirent* entry = readdir(d); entry; entry = readdir(d))\r
-      {\r
-        std::string strentry = entry->d_name;\r
-        if (strentry.compare(".")!=0 && strentry.compare("..")!=0)\r
-        {\r
-          std::string subpath = create_filespec(dir, strentry);\r
-          if (((subdirs && is_folder(subpath)) || (files && is_file(subpath))) && (wildcard(wild, strentry)))\r
-            results.push_back(strentry);\r
-        }\r
-      }\r
-      closedir(d);\r
-    }\r
-#endif\r
-    return results;\r
-  }\r
-\r
-  std::string folder_home (void)\r
-  {\r
-    if (getenv("HOME"))\r
-      return std::string(getenv("HOME"));\r
-#ifdef MSWINDOWS\r
-    if (getenv("HOMEDRIVE") || getenv("HOMEPATH"))\r
-      return std::string(getenv("HOMEDRIVE")) + std::string(getenv("HOMEPATH"));\r
-    return "C:\\";\r
-#else\r
-    if (getenv("USER"))\r
-      return folder_down("/home", std::string(getenv("USER")));\r
-    if (getenv("USERNAME"))\r
-      return folder_down("/home", std::string(getenv("USERNAME")));\r
-    return "";\r
-#endif\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// path functions convert between full and relative paths\r
-\r
-  bool is_full_path(const std::string& path)\r
-  {\r
-    file_specification spec;\r
-    spec.initialise_folder(path.empty() ? std::string(".") : path);\r
-    return spec.absolute();\r
-  }\r
-\r
-  bool is_relative_path(const std::string& path)\r
-  {\r
-    file_specification spec;\r
-    spec.initialise_folder(path.empty() ? std::string(".") : path);\r
-    return spec.relative();\r
-  }\r
-\r
-  static std::string full_path(const std::string& root, const std::string& path)\r
-  {\r
-    // convert path to a full path using root as the start point for relative paths\r
-    // decompose the path and test whether it is already an absolute path, in which case just return it\r
-    file_specification spec;\r
-    spec.initialise_folder(path.empty() ? std::string(".") : path);\r
-    if (spec.absolute()) return spec.image();\r
-    // okay, so the path is relative after all, so we need to combine it with the root path\r
-    // decompose the root path and check whether it is relative\r
-    file_specification rootspec;\r
-    rootspec.initialise_folder(root.empty() ? std::string(".") : root);\r
-    if (rootspec.relative())\r
-      rootspec.make_absolute();\r
-    // Now do the conversion of the path relative to the root\r
-    spec.make_absolute(rootspec);\r
-    return spec.image();\r
-  }\r
-\r
-  static std::string relative_path(const std::string& root, const std::string& path)\r
-  {\r
-    // convert path to a relative path, using the root path as its starting point\r
-    // first convert both paths to full paths relative to CWD\r
-    file_specification rootspec;\r
-    rootspec.initialise_folder(root.empty() ? std::string(".") : root);\r
-    if (rootspec.relative())\r
-      rootspec.make_absolute();\r
-    file_specification spec;\r
-    spec.initialise_folder(path.empty() ? std::string(".") : path);\r
-    if (spec.relative())\r
-      spec.make_absolute();\r
-    // now make path spec relative to the root spec\r
-    spec.make_relative(rootspec);\r
-    return spec.image();\r
-  }\r
-\r
-  std::string folder_to_path (const std::string& path, const std::string& directory)\r
-  {\r
-    return full_path(path, directory);\r
-  }\r
-\r
-  std::string filespec_to_path (const std::string& path, const std::string& spec)\r
-  {\r
-    return create_filespec(folder_to_path(path, folder_part(spec)),filename_part(spec));\r
-  }\r
-\r
-  std::string folder_to_path(const std::string& folder)\r
-  {\r
-    return folder_to_path(folder_current(), folder);\r
-  }\r
-\r
-  std::string filespec_to_path(const std::string& filespec)\r
-  {\r
-    return filespec_to_path(folder_current(), filespec);\r
-  }\r
-\r
-  std::string folder_to_relative_path(const std::string& root, const std::string& folder)\r
-  {\r
-    return relative_path(root, folder);\r
-  }\r
-\r
-  std::string filespec_to_relative_path(const std::string& root, const std::string& spec)\r
-  {\r
-    return create_filespec(folder_to_relative_path(root, folder_part(spec)),filename_part(spec));\r
-  }\r
-\r
-  std::string folder_to_relative_path(const std::string& folder)\r
-  {\r
-    return folder_to_relative_path(folder_current(), folder);\r
-  }\r
-\r
-  std::string filespec_to_relative_path(const std::string& filespec)\r
-  {\r
-    return filespec_to_relative_path(folder_current(), filespec);\r
-  }\r
-\r
-  std::string folder_append_separator(const std::string& folder)\r
-  {\r
-    std::string result = folder;\r
-    if (result.empty() || !is_separator(result[result.size()-1]))\r
-      result += preferred_separator;\r
-    return result;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string basename_part (const std::string& spec)\r
-  {\r
-    std::string fname = filename_part(spec);\r
-    // scan back through filename until a '.' is found and remove suffix\r
-    // the whole filename is the basename if there is no '.'\r
-    std::string::size_type i = fname.find_last_of('.');\r
-    // observe Unix convention that a dot at the start of a filename is part of the basename, not the extension\r
-    if (i != 0 && i != std::string::npos)\r
-      fname.erase(i, fname.size()-i);\r
-    return fname;\r
-  }\r
-\r
-  std::string filename_part (const std::string& spec)\r
-  {\r
-    // scan back through filename until a preferred_separator is found and remove prefix;\r
-    // if there is no preferred_separator then remove nothing, i.e. the whole filespec is filename\r
-    unsigned i = spec.size();\r
-    while (i--)\r
-    {\r
-      if (is_separator(spec[i]))\r
-        return spec.substr(i+1,spec.size()-i-1);\r
-    }\r
-    return spec;\r
-  }\r
-\r
-  std::string extension_part (const std::string& spec)\r
-  {\r
-    std::string fname = filename_part(spec);\r
-    // scan back through filename until a '.' is found and remove prefix;\r
-    std::string::size_type i = fname.find_last_of('.');\r
-    // observe Unix convention that a dot at the start of a filename is part of the name, not the extension;\r
-    if (i != 0 && i != std::string::npos)\r
-      fname.erase(0, i+1);\r
-    else\r
-      fname.erase();\r
-    return fname;\r
-  }\r
-\r
-  std::string folder_part (const std::string& spec)\r
-  {\r
-    // scan back through filename until a separator is found and remove prefix\r
-    // if there is no separator, remove the whole\r
-    unsigned i = spec.size();\r
-    while (i--)\r
-    {\r
-      if (is_separator(spec[i]))\r
-        return spec.substr(0,i);\r
-    }\r
-    return std::string();\r
-  }\r
-\r
-  std::vector<std::string> filespec_elements(const std::string& filespec)\r
-  {\r
-    file_specification spec;\r
-    spec.initialise_file(filespec);\r
-    std::vector<std::string> result = spec.path();\r
-    if (!spec.drive().empty()) result.insert(result.begin(),spec.drive());\r
-    if (!spec.file().empty()) result.push_back(spec.file());\r
-    return result;\r
-  }\r
-\r
-  std::vector<std::string> folder_elements(const std::string& folder)\r
-  {\r
-    file_specification spec;\r
-    spec.initialise_folder(folder);\r
-    std::vector<std::string> result = spec.path();\r
-    if (!spec.drive().empty()) result.insert(result.begin(),spec.drive());\r
-    return result;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// mimic the command lookup used by the shell\r
-\r
-// Windows looks at the following locations:\r
-// 1) application root\r
-// 2) current directory\r
-// 3) 32-bit system directory\r
-// 4) 16-bit system directory\r
-// 5) windows system directory\r
-// 6) %path%\r
-// currently only (2) and (6) has been implemented although many system folders are on the path anyway\r
-// also implement the implied .exe extension on commands with no path (see CreateProcess documentation)\r
-// TODO - PATHEXT handling to find non-exe executables\r
-\r
-  std::string path_lookup (const std::string& command)\r
-  {\r
-    std::string path = std::string(".") + PATH_SPLITTER + getenv("PATH");\r
-    return lookup(command, path);\r
-  }\r
-\r
-  std::string lookup (const std::string& command, const std::string& path, const std::string& splitter)\r
-  {\r
-    // first check whether the command is already a path and check whether it exists\r
-    if (!folder_part(command).empty())\r
-    {\r
-      if (file_exists(command))\r
-        return command;\r
-    }\r
-    else\r
-    {\r
-      // command is just a name - so do path lookup\r
-      // split the path into its elements\r
-      std::vector<std::string> paths;\r
-      if (!path.empty())\r
-      {\r
-        for(std::string::size_type offset = 0;;)\r
-        {\r
-          std::string::size_type found = path.find(splitter, offset);\r
-          if (found != std::string::npos)\r
-          {\r
-            paths.push_back(path.substr(offset, found-offset));\r
-            offset = found + splitter.size();\r
-          }\r
-          else\r
-          {\r
-            paths.push_back(path.substr(offset, path.size()-offset));\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      // now lookup each path to see if it its the matching one\r
-      for (unsigned i = 0; i < paths.size(); i++)\r
-      {\r
-        std::string spec = create_filespec(paths[i], command);\r
-        if (file_exists(spec))\r
-        {\r
-          return spec;\r
-        }\r
-      }\r
-    }\r
-#ifdef MSWINDOWS\r
-    // if there is no extension, try recursing on each possible extension\r
-    // TODO iterate through PATHEXT\r
-    if (extension_part(command).empty())\r
-      return lookup(create_filespec(folder_part(command), basename_part(command), "exe"), path, splitter);\r
-#endif\r
-    // if path lookup failed, return empty string to indicate error\r
-    return std::string();\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string install_path(const std::string& argv0)\r
-  {\r
-    std::string bin_directory = folder_part(argv0);\r
-    if (bin_directory.empty())\r
-    {\r
-      // do path lookup to find the executable path\r
-      bin_directory = folder_part(path_lookup(argv0));\r
-    }\r
-    return bin_directory;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   This is a portable interface to the file system.
+
+//   The idea is that you write all file system access code using these functions,
+//   which are ported to all platforms that we are interested in. Therefore your
+//   code is inherently portable.
+
+//   Native Windows version: switched on by macro _WIN32 which is defined by VC++/Borland/Mingw compilers
+//   Unix/Gnu version:   default variant, no compiler directives are required but _WIN32 must be absent
+//   Cygwin/Gnu version: as Unix version but with additional support for Windows drive letters
+
+////////////////////////////////////////////////////////////////////////////////
+#include "file_system.hpp"
+#include "wildcard.hpp"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <algorithm>
+#include <ctype.h>
+
+#ifdef MSWINDOWS
+#include <windows.h>
+#include <dos.h>
+#include <direct.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#else
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+////////////////////////////////////////////////////////////////////////////////
+// definitions of separators
+
+#ifdef MSWINDOWS
+  static const char* separator_set = "\\/";
+  static const char preferred_separator = '\\';
+#else
+  static const char* separator_set = "/";
+  static const char preferred_separator = '/';
+#endif
+
+  static bool is_separator (char ch)
+  {
+    for (int i = 0; separator_set[i]; i++)
+    {
+      if (separator_set[i] == ch)
+        return true;
+    }
+    return false;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// implement string comparison of paths - Unix is case-sensitive, Windoze is case-insensitive
+
+#ifdef MSWINDOWS
+
+  static std::string lowercase(const std::string& val)
+  {
+    std::string text = val;
+    for (unsigned i = 0; i < text.size(); i++)
+      text[i] = tolower(text[i]);
+    return text;
+  }
+
+#endif
+
+  bool path_compare(const std::string& l, const std::string& r)
+  {
+#ifdef MSWINDOWS
+    return lowercase(l) == lowercase(r);
+#else
+    return l == r;
+#endif
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// Internal data structure used to hold the different parts of a filespec
+
+  class file_specification
+  {
+  private:
+    bool m_relative;                 // true = relative, false = absolute
+    std::string m_drive;             // drive - drive letter (e.g. "c:") or the path for an UNC (e.g. "\\somewhere")
+                                     //         empty if not known or on Unix
+    std::vector<std::string> m_path; // the subdirectory path to follow from the drive
+    std::string m_filename;          // the filename
+  public:
+    file_specification(void) : m_relative(false) {}
+    ~file_specification(void) {}
+
+    bool initialise_folder(const std::string& spec);
+    bool initialise_file(const std::string& spec);
+    bool simplify(void);
+    bool make_absolute(const std::string& root = folder_current_full());
+    bool make_absolute(const file_specification& root);
+    bool make_relative(const std::string& root = folder_current_full());
+    bool make_relative(const file_specification& root);
+    bool relative(void) const {return m_relative;}
+    bool absolute(void) const {return !relative();}
+    void set_relative(void) {m_relative = true;}
+    void set_absolute(void) {m_relative = false;}
+
+    const std::string& drive(void) const {return m_drive;}
+    std::string& drive(void) {return m_drive;}
+    void set_drive(const std::string& drive) {m_drive = drive;}
+
+    const std::vector<std::string>& path(void) const {return m_path;}
+    std::vector<std::string>& path(void) {return m_path;}
+    void set_path(const std::vector<std::string>& path) {m_path = path;}
+
+    void add_subpath(const std::string& subpath) {m_path.push_back(subpath);}
+    unsigned subpath_size(void) const {return m_path.size();}
+    const std::string& subpath_element(unsigned i) const {return m_path[i];}
+    void subpath_erase(unsigned i) {m_path.erase(m_path.begin()+i);}
+
+    const std::string& file(void) const {return m_filename;}
+    std::string& file(void) {return m_filename;}
+    void set_file(const std::string& file) {m_filename = file;}
+
+    std::string image(void) const;
+  };
+
+  bool file_specification::initialise_folder(const std::string& folder_spec)
+  {
+    std::string spec = folder_spec;
+    m_relative = true;
+    m_drive.erase();
+    m_path.clear();
+    m_filename.erase();
+    unsigned i = 0;
+#ifdef MSWINDOWS
+    // first split off the drive letter or UNC prefix on Windows
+    if (spec.size() >= 2 && isalpha(spec[0]) && spec[1] == ':')
+    {
+      // found a drive letter
+      i = 2;
+      m_drive = spec.substr(0, 2);
+      m_relative = false;
+      // if there is a drive but no path or a relative path, get the current
+      // path for this drive and prepend it to the path
+      if (i == spec.size() || !is_separator(spec[i]))
+      {
+        // getdcwd requires the drive number (1..26) not the letter (A..Z)
+        char path [MAX_PATH+1];
+        int drivenum = toupper(m_drive[0]) - 'A' + 1;
+        if (_getdcwd(drivenum, path, MAX_PATH+1))
+        {
+          // the path includes the drive so we have the drive info twice
+          // need to prepend this absolute path to the spec such that any remaining relative path is still retained
+          if (!is_separator(path[strlen(path)-1])) spec.insert(2, 1, preferred_separator);
+          spec.insert(2, path+2);
+        }
+        else
+        {
+          // non-existent drive - fill in just the root directory
+          spec.insert(2, 1, preferred_separator);
+        }
+      }
+    }
+    else if (spec.size() >= 2 && is_separator(spec[0]) && is_separator(spec[1]))
+    {
+      // found an UNC prefix
+      i = 2;
+      // find the end of the prefix by scanning for the next seperator or the end of the spec
+      while (i < spec.size() && !is_separator(spec[i])) i++;
+      m_drive = spec.substr(0, i);
+      m_relative = false;
+    }
+#endif
+#ifdef CYGWIN
+    // first split off the drive letter or UNC prefix on Windows - the Cygwin environment supports these too
+    if (spec.size() >= 2 && isalpha(spec[0]) && spec[1] == ':')
+    {
+      // found a drive letter
+      i = 2;
+      m_drive = spec.substr(0, 2);
+      m_relative = false;
+      // if there is a drive but no path or a relative path, get the current
+      // path for this drive and prepend it to the path
+      if (i == spec.size() || !is_separator(spec[i]))
+      {
+        // non-existent drive - fill in just the root directory
+        spec.insert(2, 1, preferred_separator);
+      }
+    }
+    else if (spec.size() >= 2 && is_separator(spec[0]) && is_separator(spec[1]))
+    {
+      // found an UNC prefix
+      i = 2;
+      // find the end of the prefix by scanning for the next seperator or the end of the spec
+      while (i < spec.size() && !is_separator(spec[i])) i++;
+      m_drive = spec.substr(0, i);
+      m_relative = false;
+    }
+#endif
+    // check whether the path is absolute or relative and discard the leading / if absolute
+    if (i < spec.size() && is_separator(spec[i]))
+    {
+      m_relative = false;
+      i++;
+#ifdef MSWINDOWS
+      // if there's no drive, fill it in on Windows since absolute paths must have a drive
+      if (m_drive.empty())
+      {
+        m_drive += (char)(_getdrive() - 1 + 'A');
+        m_drive += ':';
+      }
+#endif
+    }
+    // now extract the path elements - note that a trailing / is not significant since /a/b/c/ === /a/b/c
+    // also note that the leading / has been discarded - all paths are relative
+    // if absolute() is set, then paths are relative to the drive, else they are relative to the current path
+    unsigned start = i;
+    while(i <= spec.size())
+    {
+      if (i == spec.size())
+      {
+        // path element terminated by the end of the string
+        // discard this element if it is zero length because that represents the trailing /
+        if (i != start)
+          m_path.push_back(spec.substr(start, i-start));
+      }
+      else if (is_separator(spec[i]))
+      {
+        // path element terminated by a separator
+        m_path.push_back(spec.substr(start, i-start));
+        start = i+1;
+      }
+      i++;
+    }
+    // TODO - some error handling?
+    return true;
+  }
+
+  bool file_specification::initialise_file(const std::string& spec)
+  {
+    m_filename.erase();
+    // remove last element as the file and then treat the rest as a folder
+    unsigned i = spec.size();
+    while (--i)
+    {
+      if (is_separator(spec[i]))
+        break;
+#ifdef MSWINDOWS
+      // on windoze you can say a:fred.txt so the colon separates the path from the filename
+      else if (i == 1 && spec[i] == ':')
+        break;
+#endif
+    }
+    bool result = initialise_folder(spec.substr(0,i+1));
+    m_filename = spec.substr(i+1,spec.size()-i-1);
+    // TODO - some error handling?
+    return result;
+  }
+
+  bool file_specification::simplify(void)
+  {
+    // simplify the path by removing unnecessary . and .. entries - Note that zero-length entries are treated like .
+    for (unsigned i = 0; i < m_path.size(); )
+    {
+      if (m_path[i].empty() || m_path[i].compare(".") == 0)
+      {
+        // found . or null
+        // these both mean do nothing - so simply delete this element
+        m_path.erase(m_path.begin()+i);
+      }
+      else if (m_path[i].compare("..") == 0)
+      {
+        // found ..
+        if (i == 0 && !m_relative)
+        {
+          // up from the root does nothing so can be deleted
+          m_path.erase(m_path.begin()+i);
+          i++;
+        }
+        else if (i == 0 || m_path[i-1].compare("..") == 0)
+        {
+          // the first element of a relative path or the previous element is .. then keep it
+          i++;
+        }
+        else
+        {
+          // otherwise delete this element and the previous one
+          m_path.erase(m_path.begin()+i);
+          m_path.erase(m_path.begin()+i-1);
+          i--;
+        }
+      }
+      // keep all other elements
+      else
+        i++;
+    }
+    // TODO - error checking?
+    return true;
+  }
+
+  bool file_specification::make_absolute(const std::string& root)
+  {
+    // test whether already an absolute path in which case there's nothing to do
+    if (absolute()) return true;
+    // now simply call the other version of make_absolute
+    file_specification rootspec;
+    rootspec.initialise_folder(root);
+    return make_absolute(rootspec);
+  }
+
+  bool file_specification::make_absolute(const file_specification& rootspec)
+  {
+    // test whether already an absolute path in which case there's nothing to do
+    if (absolute()) return true;
+    // initialise the result with the root and make the root absolute
+    file_specification result = rootspec;
+    result.make_absolute();
+    // now append this's relative path and filename to the root's absolute path
+    for (unsigned i = 0; i < subpath_size(); i++)
+      result.add_subpath(subpath_element(i));
+    result.set_file(file());
+    // now the result is the absolute path, so transfer it to this
+    *this = result;
+    // and simplify to get rid of any unwanted .. or . elements
+    simplify();
+    return true;
+  }
+
+  bool file_specification::make_relative(const std::string& root)
+  {
+    // test whether already an relative path in which case there's nothing to do
+    if (relative()) return true;
+    // now simply call the other version of make_relative
+    file_specification rootspec;
+    rootspec.initialise_folder(root);
+    return make_relative(rootspec);
+  }
+
+  bool file_specification::make_relative(const file_specification& rootspec)
+  {
+    // test whether already an relative path in which case there's nothing to do
+    if (relative()) return true;
+    // initialise the result with the root and make the root absolute
+    file_specification absolute_root = rootspec;
+    absolute_root.make_absolute();
+    // now compare elements of the absolute root with elements of this to find the common path
+    // if the drives are different, no conversion can take place and the result must be absolute, else clear the drive
+    if (!path_compare(drive(), absolute_root.drive())) return true;
+    set_drive("");
+    // first remove leading elements that are identical to the corresponding element in root
+    unsigned i = 0;
+    while(subpath_size() > 0 && 
+          i < absolute_root.subpath_size() && 
+          path_compare(subpath_element(0), absolute_root.subpath_element(i)))
+    {
+      subpath_erase(0);
+      i++;
+    }
+    // now add a .. prefix for every element in root that is different from this
+    while (i < absolute_root.subpath_size())
+    {
+      m_path.insert(m_path.begin(), "..");
+      i++;
+    }
+    set_relative();
+    return true;
+  }
+
+  std::string file_specification::image(void) const
+  {
+    std::string result = m_drive;
+    if (absolute())
+      result += preferred_separator;
+    if (!m_path.empty())
+    {
+      for (unsigned i = 0; i < m_path.size(); i++)
+      {
+        if (i != 0) result += std::string(1,preferred_separator);
+        result += m_path[i];
+      }
+    }
+    else if (relative())
+      result += '.';
+    // add a trailing / to the last directory element
+    if (result.empty() || !is_separator(result[result.size()-1]))
+      result += preferred_separator;
+    if (!m_filename.empty())
+      result += m_filename;
+    return result;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// classifying functions
+
+#ifdef MSWINDOWS
+// file type tests are not defined for some reason on Windows despite them providing the stat() function!
+#define R_OK 4
+#define W_OK 2
+#endif
+
+  bool is_present (const std::string& thing)
+  {
+    // strip off any trailing separator because that will cause the stat function to fail
+    std::string path = thing;
+    if (!path.empty() && is_separator(path[path.size()-1]))
+      path.erase(path.size()-1,1);
+    // now test if this thing exists using the built-in stat function
+    struct stat buf;
+    return stat(path.c_str(), &buf) == 0;
+  }
+
+  bool is_folder (const std::string& thing)
+  {
+    // strip off any trailing separator because that will cause the stat function to fail
+    std::string path = thing;
+    if (!path.empty() && is_separator(path[path.size()-1]))
+      path.erase(path.size()-1,1);
+    // now test if this thing exists using the built-in stat function and if so, is it a folder
+    struct stat buf;
+    if (!(stat(path.c_str(), &buf) == 0)) {return false;}
+    return (buf.st_mode & S_IFDIR) != 0;
+  }
+
+  bool is_file (const std::string& thing)
+  {
+    // strip off any trailing separator because that will cause the stat function to fail
+    std::string path = thing;
+    if (!path.empty() && is_separator(path[path.size()-1]))
+      path.erase(path.size()-1,1);
+    // now test if this thing exists using the built-in stat function and if so, is it a file
+    struct stat buf;
+    if (!(stat(path.c_str(), &buf) == 0)) {return false;}
+    return (buf.st_mode & S_IFREG) != 0;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// file functions
+
+  bool file_exists (const std::string& filespec)
+  {
+    return is_file(filespec);
+  }
+
+  bool file_readable (const std::string& filespec)
+  {
+    // a file is readable if it exists and can be read
+    if (!file_exists(filespec)) return false;
+    return access(filespec.c_str(),R_OK)==0;
+  }
+
+  bool file_writable (const std::string& filespec)
+  {
+    // a file is writable if it exists as a file and is writable or if it doesn't exist but could be created and would be writable
+    if (is_present(filespec))
+    {
+      if (!is_file(filespec)) return false;
+      return access(filespec.c_str(),W_OK)==0;
+    }
+    std::string dir = folder_part(filespec);
+    if (dir.empty()) dir = ".";
+    return folder_writable(dir);
+  }
+
+  size_t file_size (const std::string& filespec)
+  {
+    struct stat buf;
+    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;
+    return buf.st_size;
+  }
+
+  bool file_delete (const std::string& filespec)
+  {
+    if (!is_file(filespec)) return false;
+    return remove(filespec.c_str())==0;
+  }
+
+  bool file_rename (const std::string& old_filespec, const std::string& new_filespec)
+  {
+    if (!is_file(old_filespec)) return false;
+    return rename(old_filespec.c_str(), new_filespec.c_str())==0;
+  }
+
+  bool file_copy (const std::string& old_filespec, const std::string& new_filespec)
+  {
+    if (!is_file(old_filespec)) return false;
+    // do an exact copy - to do this, use binary mode
+    bool result = true;
+    FILE* old_file = fopen(old_filespec.c_str(),"rb");
+    FILE* new_file = fopen(new_filespec.c_str(),"wb");
+    if (!old_file)
+      result = false;
+    else if (!new_file)
+      result = false;
+    else
+    {
+      for (int byte = getc(old_file); byte != EOF; byte = getc(old_file))
+        putc(byte,new_file);
+    }
+    if (old_file) fclose(old_file);
+    if (new_file) fclose(new_file);
+    return result;
+  }
+
+  bool file_move (const std::string& old_filespec, const std::string& new_filespec)
+  {
+    // try to move the file by renaming - if that fails then do a copy and delete the original
+    if (file_rename(old_filespec, new_filespec))
+      return true;
+    if (!file_copy(old_filespec, new_filespec))
+      return false;
+    // I'm not sure what to do if the delete fails - is that an error?
+    // I've made it an error and then delete the copy so that the original state is recovered
+    if (file_delete(old_filespec))
+      return true;
+    file_delete(new_filespec);
+    return false;
+  }
+
+  time_t file_created (const std::string& filespec)
+  {
+    struct stat buf;
+    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;
+    return buf.st_ctime;
+  }
+
+  time_t file_modified (const std::string& filespec)
+  {
+    struct stat buf;
+    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;
+    return buf.st_mtime;
+  }
+
+  time_t file_accessed (const std::string& filespec)
+  {
+    struct stat buf;
+    if (!(stat(filespec.c_str(), &buf) == 0)) return 0;
+    return buf.st_atime;
+  }
+
+  std::string create_filespec (const std::string& directory, const std::string& filename)
+  {
+    std::string result = directory;
+    // if directory is empty then no directory part will be added
+    // add trailing slash if the directory was specified and does not have a trailing slash
+    if (!result.empty() && !is_separator(result[result.size()-1]))
+      result += preferred_separator;
+    // if filename is null or empty, nothing will be added so the path is then a directory path
+    result += filename;
+    return result;
+  }
+
+  std::string create_filespec (const std::string& directory, const std::string& basename, const std::string& extension)
+  {
+    return create_filespec(directory, create_filename(basename, extension));
+  }
+
+  std::string create_filename(const std::string& basename, const std::string& extension)
+  {
+    std::string name = basename;
+    // extension is optional - so the dot is also optional
+    if (!extension.empty())
+    {
+      if (extension[0] != '.') name += '.';
+      name += extension;
+    }
+    return name;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// folder functions
+
+  bool folder_create (const std::string& directory)
+  {
+#ifdef MSWINDOWS
+    return mkdir(directory.c_str()) == 0;
+#else
+    return mkdir(directory.c_str(), 0777) == 0;
+#endif
+  }
+
+  bool folder_exists (const std::string& directory)
+  {
+    return is_folder(directory);
+  }
+
+  bool folder_readable (const std::string& directory)
+  {
+    // a folder is readable if it exists and has read access
+    std::string dir = directory;
+    if (dir.empty()) dir = ".";
+    if (!folder_exists(dir)) return false;
+    return access(dir.c_str(),R_OK)==0;
+  }
+
+  bool folder_writable (const std::string& directory)
+  {
+    // a folder is writable if it exists and has write access
+    std::string dir = directory;
+    if (dir.empty()) dir = ".";
+    if (!folder_exists(dir)) return false;
+    return access(dir.c_str(),W_OK)==0;
+  }
+
+  bool folder_delete (const std::string& directory, bool recurse)
+  {
+    std::string dir = directory;
+    if (dir.empty()) dir = ".";
+    if (!folder_exists(dir)) return false;
+    bool result = true;
+    // depth-first traversal ensures that directory contents are deleted before trying to delete the directory itself
+    if (recurse)
+    {
+      std::vector<std::string> subdirectories = folder_subdirectories(dir);
+      for (std::vector<std::string>::size_type d = 0; d < subdirectories.size(); ++d)
+        if (!folder_delete(folder_down(dir,subdirectories[d]),true)) 
+          result = false;
+      std::vector<std::string> files = folder_files(dir);
+      for (std::vector<std::string>::size_type f = 0; f < files.size(); ++f)
+        if (!file_delete(create_filespec(dir, files[f]))) 
+          result = false;
+    }
+    if (rmdir(dir.c_str())!=0) result = false;
+    return result;
+  }
+
+  bool folder_rename (const std::string& old_directory, const std::string& new_directory)
+  {
+    if (!folder_exists(old_directory)) return false;
+    return rename(old_directory.c_str(), new_directory.c_str())==0;
+  }
+
+  bool folder_empty(const std::string& directory)
+  {
+    std::string dir = directory.empty() ? std::string(".") : directory;
+    bool result = true;
+#ifdef MSWINDOWS
+    std::string wildcard = create_filespec(dir, "*.*");
+    long handle = -1;
+    _finddata_t fileinfo;
+    for (bool OK = (handle = _findfirst((char*)wildcard.c_str(), &fileinfo)) != -1; OK; OK = (_findnext(handle, &fileinfo)==0))
+    {
+      std::string strentry = fileinfo.name;
+      if (strentry.compare(".")!=0 && strentry.compare("..")!=0)
+      {
+        result = false;
+        break;
+      }
+    }
+    _findclose(handle);
+#else
+    DIR* d = opendir(dir.c_str());
+    if (d)
+    {
+      for (dirent* entry = readdir(d); entry; entry = readdir(d))
+      {
+        std::string strentry = entry->d_name;
+        if (strentry.compare(".")!=0 && strentry.compare("..")!=0)
+        {
+          result = false;
+          break;
+        }
+      }
+      closedir(d);
+    }
+#endif
+    return result;
+  }
+
+  bool folder_set_current(const std::string& folder)
+  {
+    if (!folder_exists(folder))
+      return false;
+#ifdef MSWINDOWS
+    // Windose implementation - this returns non-zero for success
+    return (SetCurrentDirectoryA(folder.c_str()) != 0);
+#else
+    // Unix implementation - this returns zero for success
+    return (chdir(folder.c_str()) == 0);
+#endif
+  }
+
+  std::string folder_current (void)
+  {
+    return ".";
+  }
+
+  std::string folder_current_full(void)
+  {
+    // It's not clear from the documentation whether the buffer for a path should be one byte longer
+    // than the maximum path length to allow for the null termination, so I have made it so anyway
+#ifdef MSWINDOWS
+    char abspath [MAX_PATH+1];
+    return std::string(_fullpath(abspath, ".", MAX_PATH+1));
+#else
+    char pathname [MAXPATHLEN+1];
+    getcwd(pathname,MAXPATHLEN+1);
+    return std::string(pathname);
+#endif
+  }
+
+  std::string folder_down (const std::string& directory, const std::string& subdirectory)
+  {
+    file_specification spec;
+    spec.initialise_folder(directory);
+    spec.add_subpath(subdirectory);
+    return spec.image();
+  }
+
+  std::string folder_up (const std::string& directory, unsigned levels)
+  {
+    file_specification spec;
+    spec.initialise_folder(directory);
+    for (unsigned i = 0; i < levels; i++)
+      spec.add_subpath("..");
+    spec.simplify();
+    return spec.image();
+  }
+
+  std::vector<std::string> folder_subdirectories (const std::string& directory)
+  {
+    return folder_wildcard(directory, "*", true, false);
+  }
+
+  std::vector<std::string> folder_files (const std::string& directory)
+  {
+    return folder_wildcard(directory, "*", false, true);
+  }
+
+  std::vector<std::string> folder_all(const std::string& directory)
+  {
+    return folder_wildcard(directory, "*", true, true);
+  }
+
+  std::vector<std::string> folder_wildcard (const std::string& directory, const std::string& wild, bool subdirs, bool files)
+  {
+    std::string dir = directory.empty() ? std::string(".") : directory;
+    std::vector<std::string> results;
+#ifdef MSWINDOWS
+    std::string wildcard = create_filespec(dir, wild);
+    long handle = -1;
+    _finddata_t fileinfo;
+    for (bool OK = (handle = _findfirst((char*)wildcard.c_str(), &fileinfo)) != -1; OK; OK = (_findnext(handle, &fileinfo)==0))
+    {
+      std::string strentry = fileinfo.name;
+      if (strentry.compare(".")!=0 && strentry.compare("..")!=0)
+        if ((subdirs && (fileinfo.attrib & _A_SUBDIR)) || (files && !(fileinfo.attrib & _A_SUBDIR)))
+          results.push_back(strentry);
+    }
+    _findclose(handle);
+#else
+    DIR* d = opendir(dir.c_str());
+    if (d)
+    {
+      for (dirent* entry = readdir(d); entry; entry = readdir(d))
+      {
+        std::string strentry = entry->d_name;
+        if (strentry.compare(".")!=0 && strentry.compare("..")!=0)
+        {
+          std::string subpath = create_filespec(dir, strentry);
+          if (((subdirs && is_folder(subpath)) || (files && is_file(subpath))) && (wildcard(wild, strentry)))
+            results.push_back(strentry);
+        }
+      }
+      closedir(d);
+    }
+#endif
+    return results;
+  }
+
+  std::string folder_home (void)
+  {
+    if (getenv("HOME"))
+      return std::string(getenv("HOME"));
+#ifdef MSWINDOWS
+    if (getenv("HOMEDRIVE") || getenv("HOMEPATH"))
+      return std::string(getenv("HOMEDRIVE")) + std::string(getenv("HOMEPATH"));
+    return "C:\\";
+#else
+    if (getenv("USER"))
+      return folder_down("/home", std::string(getenv("USER")));
+    if (getenv("USERNAME"))
+      return folder_down("/home", std::string(getenv("USERNAME")));
+    return "";
+#endif
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// path functions convert between full and relative paths
+
+  bool is_full_path(const std::string& path)
+  {
+    file_specification spec;
+    spec.initialise_folder(path.empty() ? std::string(".") : path);
+    return spec.absolute();
+  }
+
+  bool is_relative_path(const std::string& path)
+  {
+    file_specification spec;
+    spec.initialise_folder(path.empty() ? std::string(".") : path);
+    return spec.relative();
+  }
+
+  static std::string full_path(const std::string& root, const std::string& path)
+  {
+    // convert path to a full path using root as the start point for relative paths
+    // decompose the path and test whether it is already an absolute path, in which case just return it
+    file_specification spec;
+    spec.initialise_folder(path.empty() ? std::string(".") : path);
+    if (spec.absolute()) return spec.image();
+    // okay, so the path is relative after all, so we need to combine it with the root path
+    // decompose the root path and check whether it is relative
+    file_specification rootspec;
+    rootspec.initialise_folder(root.empty() ? std::string(".") : root);
+    if (rootspec.relative())
+      rootspec.make_absolute();
+    // Now do the conversion of the path relative to the root
+    spec.make_absolute(rootspec);
+    return spec.image();
+  }
+
+  static std::string relative_path(const std::string& root, const std::string& path)
+  {
+    // convert path to a relative path, using the root path as its starting point
+    // first convert both paths to full paths relative to CWD
+    file_specification rootspec;
+    rootspec.initialise_folder(root.empty() ? std::string(".") : root);
+    if (rootspec.relative())
+      rootspec.make_absolute();
+    file_specification spec;
+    spec.initialise_folder(path.empty() ? std::string(".") : path);
+    if (spec.relative())
+      spec.make_absolute();
+    // now make path spec relative to the root spec
+    spec.make_relative(rootspec);
+    return spec.image();
+  }
+
+  std::string folder_to_path (const std::string& path, const std::string& directory)
+  {
+    return full_path(path, directory);
+  }
+
+  std::string filespec_to_path (const std::string& path, const std::string& spec)
+  {
+    return create_filespec(folder_to_path(path, folder_part(spec)),filename_part(spec));
+  }
+
+  std::string folder_to_path(const std::string& folder)
+  {
+    return folder_to_path(folder_current(), folder);
+  }
+
+  std::string filespec_to_path(const std::string& filespec)
+  {
+    return filespec_to_path(folder_current(), filespec);
+  }
+
+  std::string folder_to_relative_path(const std::string& root, const std::string& folder)
+  {
+    return relative_path(root, folder);
+  }
+
+  std::string filespec_to_relative_path(const std::string& root, const std::string& spec)
+  {
+    return create_filespec(folder_to_relative_path(root, folder_part(spec)),filename_part(spec));
+  }
+
+  std::string folder_to_relative_path(const std::string& folder)
+  {
+    return folder_to_relative_path(folder_current(), folder);
+  }
+
+  std::string filespec_to_relative_path(const std::string& filespec)
+  {
+    return filespec_to_relative_path(folder_current(), filespec);
+  }
+
+  std::string folder_append_separator(const std::string& folder)
+  {
+    std::string result = folder;
+    if (result.empty() || !is_separator(result[result.size()-1]))
+      result += preferred_separator;
+    return result;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  std::string basename_part (const std::string& spec)
+  {
+    std::string fname = filename_part(spec);
+    // scan back through filename until a '.' is found and remove suffix
+    // the whole filename is the basename if there is no '.'
+    std::string::size_type i = fname.find_last_of('.');
+    // observe Unix convention that a dot at the start of a filename is part of the basename, not the extension
+    if (i != 0 && i != std::string::npos)
+      fname.erase(i, fname.size()-i);
+    return fname;
+  }
+
+  std::string filename_part (const std::string& spec)
+  {
+    // scan back through filename until a preferred_separator is found and remove prefix;
+    // if there is no preferred_separator then remove nothing, i.e. the whole filespec is filename
+    unsigned i = spec.size();
+    while (i--)
+    {
+      if (is_separator(spec[i]))
+        return spec.substr(i+1,spec.size()-i-1);
+    }
+    return spec;
+  }
+
+  std::string extension_part (const std::string& spec)
+  {
+    std::string fname = filename_part(spec);
+    // scan back through filename until a '.' is found and remove prefix;
+    std::string::size_type i = fname.find_last_of('.');
+    // observe Unix convention that a dot at the start of a filename is part of the name, not the extension;
+    if (i != 0 && i != std::string::npos)
+      fname.erase(0, i+1);
+    else
+      fname.erase();
+    return fname;
+  }
+
+  std::string folder_part (const std::string& spec)
+  {
+    // scan back through filename until a separator is found and remove prefix
+    // if there is no separator, remove the whole
+    unsigned i = spec.size();
+    while (i--)
+    {
+      if (is_separator(spec[i]))
+        return spec.substr(0,i);
+    }
+    return std::string();
+  }
+
+  std::vector<std::string> filespec_elements(const std::string& filespec)
+  {
+    file_specification spec;
+    spec.initialise_file(filespec);
+    std::vector<std::string> result = spec.path();
+    if (!spec.drive().empty()) result.insert(result.begin(),spec.drive());
+    if (!spec.file().empty()) result.push_back(spec.file());
+    return result;
+  }
+
+  std::vector<std::string> folder_elements(const std::string& folder)
+  {
+    file_specification spec;
+    spec.initialise_folder(folder);
+    std::vector<std::string> result = spec.path();
+    if (!spec.drive().empty()) result.insert(result.begin(),spec.drive());
+    return result;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+// mimic the command lookup used by the shell
+
+// Windows looks at the following locations:
+// 1) application root
+// 2) current directory
+// 3) 32-bit system directory
+// 4) 16-bit system directory
+// 5) windows system directory
+// 6) %path%
+// currently only (2) and (6) has been implemented although many system folders are on the path anyway
+// also implement the implied .exe extension on commands with no path (see CreateProcess documentation)
+// TODO - PATHEXT handling to find non-exe executables
+
+  std::string path_lookup (const std::string& command)
+  {
+    std::string path = std::string(".") + PATH_SPLITTER + getenv("PATH");
+    return lookup(command, path);
+  }
+
+  std::string lookup (const std::string& command, const std::string& path, const std::string& splitter)
+  {
+    // first check whether the command is already a path and check whether it exists
+    if (!folder_part(command).empty())
+    {
+      if (file_exists(command))
+        return command;
+    }
+    else
+    {
+      // command is just a name - so do path lookup
+      // split the path into its elements
+      std::vector<std::string> paths;
+      if (!path.empty())
+      {
+        for(std::string::size_type offset = 0;;)
+        {
+          std::string::size_type found = path.find(splitter, offset);
+          if (found != std::string::npos)
+          {
+            paths.push_back(path.substr(offset, found-offset));
+            offset = found + splitter.size();
+          }
+          else
+          {
+            paths.push_back(path.substr(offset, path.size()-offset));
+            break;
+          }
+        }
+      }
+      // now lookup each path to see if it its the matching one
+      for (unsigned i = 0; i < paths.size(); i++)
+      {
+        std::string spec = create_filespec(paths[i], command);
+        if (file_exists(spec))
+        {
+          return spec;
+        }
+      }
+    }
+#ifdef MSWINDOWS
+    // if there is no extension, try recursing on each possible extension
+    // TODO iterate through PATHEXT
+    if (extension_part(command).empty())
+      return lookup(create_filespec(folder_part(command), basename_part(command), "exe"), path, splitter);
+#endif
+    // if path lookup failed, return empty string to indicate error
+    return std::string();
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+  std::string install_path(const std::string& argv0)
+  {
+    std::string bin_directory = folder_part(argv0);
+    if (bin_directory.empty())
+    {
+      // do path lookup to find the executable path
+      bin_directory = folder_part(path_lookup(argv0));
+    }
+    return bin_directory;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 374e86da2c9e8ba74d742fb5b7c2891cee756cf3..ce33ffeff1926cc647260a8e271a8274787e5141 100644 (file)
-#ifndef STLPLUS_FILE_SYSTEM\r
-#define STLPLUS_FILE_SYSTEM\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Simplified access to the File system\r
-\r
-//   All file system access and filename manipulation should be done\r
-//   with this package. Then it is only necessary to port this package\r
-//   to port all file handling.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-#include <vector>\r
-#include <time.h>\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // implement string comparison of paths - Unix is case-sensitive, Windows is case-insensitive\r
-\r
-  bool path_compare(const std::string& l, const std::string& r);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // classifying functions\r
-\r
-  // test for whether there's something (i.e. folder or file) with this name\r
-  bool is_present(const std::string& thing);\r
-  // test for whether there's something present and its a folder\r
-  bool is_folder(const std::string& thing);\r
-  // test for whether there's something present and its a file\r
-  bool is_file(const std::string& thing);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // file functions\r
-\r
-  // tests whether there's a file of this name\r
-  bool file_exists(const std::string& filespec);\r
-  // tests whether the file is readable - i.e. exists and has read mode set\r
-  bool file_readable(const std::string& filespec);\r
-  // tests whether file is writable - either it exists and is writable or doesn't exist but is in a writable folder\r
-  bool file_writable(const std::string& filespec);\r
-  // the size of the file in bytes - 0 if doesn't exist\r
-  size_t file_size(const std::string& filespec);\r
-  // delete the file - returns true if the delete succeeded\r
-  bool file_delete(const std::string& filespec);\r
-  // rename the file - returns true if the rename succeeded\r
-  bool file_rename (const std::string& old_filespec, const std::string& new_filespec);\r
-  // make an exact copy of the file - returns true if it succeeded\r
-  bool file_copy (const std::string& old_filespec, const std::string& new_filespec);\r
-  // move the file - tries to rename, if that fails, tries to copy - returns true if either of these succeeded\r
-  bool file_move (const std::string& old_filespec, const std::string& new_filespec);\r
-\r
-  // get the file's time stamps as a time_t - see the stlplus time.hpp package\r
-\r
-  // time the file was originally created\r
-  time_t file_created(const std::string& filespec);\r
-  // time the file was last modified\r
-  time_t file_modified(const std::string& filespec);\r
-  // time the file was accessed\r
-  time_t file_accessed(const std::string& filespec);\r
-\r
-  // platform-specific string handling to combine a directory and filename into a path\r
-\r
-  // combine a folder with a filename (basename.extension)\r
-  std::string create_filespec(const std::string& folder, const std::string& filename);\r
-  // combine a folder, a basename and an extension - extension does not need the .\r
-  std::string create_filespec(const std::string& folder, const std::string& basename, const std::string& extension);\r
-  // combine a basename and an extension - extension does not need the .\r
-  std::string create_filename(const std::string& basename, const std::string& extension);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // folder functions\r
-\r
-  // craete a folder - returns true if successful\r
-  bool folder_create(const std::string& folder);\r
-  // tests for whether the folder exists, i.e. there is something of that name and its a folder\r
-  bool folder_exists(const std::string& folder);\r
-  // test whether the folder contents are readable\r
-  bool folder_readable(const std::string& folder);\r
-  // tests whether the folder can be written to - for example to create a new file\r
-  bool folder_writable(const std::string& folder);\r
-  // delete the folder, optionally deleting the contents first - only succeeds if everything could be deleted\r
-  bool folder_delete(const std::string& folder, bool recurse = false);\r
-  // rename the folder - this probably only works within a disk/partition\r
-  bool folder_rename (const std::string& old_directory, const std::string& new_directory);\r
-  // test whether the folder is empty (of files)\r
-  bool folder_empty(const std::string& folder);\r
-\r
-  // set the current folder\r
-  bool folder_set_current(const std::string& folder);\r
-\r
-  // platform-specific string handling to retrieve some special locations\r
-  // these do not check whether the folder exists, they just process strings\r
-\r
-  // get the current folder\r
-  std::string folder_current(void);\r
-  // get the current folder as a full path\r
-  std::string folder_current_full(void);\r
-  // get the home folder - $HOME or %HOMEDRIVE%%HOMEPATH%\r
-  std::string folder_home(void);\r
-  // go down a level in the folder hierarchy\r
-  std::string folder_down(const std::string& folder, const std::string& subfolder);\r
-  // go up a level in the folder hierarchy\r
-  std::string folder_up(const std::string& folder, unsigned levels = 1);\r
-\r
-  // get folder contents\r
-\r
-  // the set of all subdirectories\r
-  std::vector<std::string> folder_subdirectories(const std::string& folder);\r
-  // the set of all files\r
-  std::vector<std::string> folder_files(const std::string& folder);\r
-  // the set of all folders and files\r
-  std::vector<std::string> folder_all(const std::string& folder);\r
-  // the set of all folder contents matching a wildcard string\r
-  // if folders is true, include folders; if files is true, include files\r
-  std::vector<std::string> folder_wildcard(const std::string& folder,\r
-                                           const std::string& wildcard,\r
-                                           bool folders = true,\r
-                                           bool files = true);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // path functions\r
-\r
-  // string manipulations of paths\r
-\r
-  // test whether a string represents a full path or a relative one\r
-  bool is_full_path(const std::string& path);\r
-  bool is_relative_path(const std::string& path);\r
-\r
-  // convert to a full path relative to the root path\r
-  std::string folder_to_path(const std::string& root, const std::string& folder);\r
-  std::string filespec_to_path(const std::string& root, const std::string& filespec);\r
-\r
-  // convert to a full path relative to the current working directory\r
-  std::string folder_to_path(const std::string& folder);\r
-  std::string filespec_to_path(const std::string& filespec);\r
-\r
-  // convert to a relative path relative to the root path\r
-  std::string folder_to_relative_path(const std::string& root, const std::string& folder);\r
-  std::string filespec_to_relative_path(const std::string& root, const std::string& filespec);\r
-\r
-  // convert to a relative path relative to the current working directory\r
-  std::string folder_to_relative_path(const std::string& folder);\r
-  std::string filespec_to_relative_path(const std::string& filespec);\r
-\r
-  // append a folder separator to the path to make it absolutely clear that it is a folder\r
-  std::string folder_append_separator(const std::string& folder);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // access functions split a filespec into its elements\r
-\r
-  // get the basename - that is, the name of the file without folder or extension parts\r
-  std::string basename_part(const std::string& filespec);\r
-  // get the filename - that is, the name of the file without folder part but with extension\r
-  std::string filename_part(const std::string& filespec);\r
-  // get the extension - that is the part of the filename after the . (and excluding the .)\r
-  std::string extension_part(const std::string& filespec);\r
-  // get the folder part - that is the filespec with the filename removed\r
-  std::string folder_part(const std::string& filespec);\r
-\r
-  // split a path into a vector of elements - i.e. split at the folder separator\r
-  std::vector<std::string> folder_elements(const std::string& folder);\r
-  std::vector<std::string> filespec_elements(const std::string& filespec);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Path lookup functions\r
-\r
-#ifdef MSWINDOWS\r
-#define PATH_SPLITTER ";"\r
-#else\r
-#define PATH_SPLITTER ":"\r
-#endif\r
-\r
-  // The lookup normally carried out by the shell to find a command in a\r
-  // directory in the PATH. Give this function the name of a command and it\r
-  // will return the full path. It returns an empty string on failure.\r
-  std::string path_lookup (const std::string& command);\r
-\r
-  // Generalised form of the above, takes a second argument\r
-  // - the list to search. This can be used to do other path lookups,\r
-  // such as LD_LIBRARY_PATH. The third argument specifies the splitter -\r
-  // the default value of PATH_SPLITTER is appropriate for environment variables.\r
-  std::string lookup (const std::string& file, const std::string& path, const std::string& splitter = PATH_SPLITTER);\r
-\r
-  // utility function for finding the folder that contains the current executable\r
-  // the argument is the argv[0] parameter passed to main\r
-  std::string install_path(const std::string& argv0);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_FILE_SYSTEM
+#define STLPLUS_FILE_SYSTEM
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Simplified access to the File system
+
+//   All file system access and filename manipulation should be done
+//   with this package. Then it is only necessary to port this package
+//   to port all file handling.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+#include <vector>
+#include <time.h>
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // implement string comparison of paths - Unix is case-sensitive, Windows is case-insensitive
+
+  bool path_compare(const std::string& l, const std::string& r);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // classifying functions
+
+  // test for whether there's something (i.e. folder or file) with this name
+  bool is_present(const std::string& thing);
+  // test for whether there's something present and its a folder
+  bool is_folder(const std::string& thing);
+  // test for whether there's something present and its a file
+  bool is_file(const std::string& thing);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // file functions
+
+  // tests whether there's a file of this name
+  bool file_exists(const std::string& filespec);
+  // tests whether the file is readable - i.e. exists and has read mode set
+  bool file_readable(const std::string& filespec);
+  // tests whether file is writable - either it exists and is writable or doesn't exist but is in a writable folder
+  bool file_writable(const std::string& filespec);
+  // the size of the file in bytes - 0 if doesn't exist
+  size_t file_size(const std::string& filespec);
+  // delete the file - returns true if the delete succeeded
+  bool file_delete(const std::string& filespec);
+  // rename the file - returns true if the rename succeeded
+  bool file_rename (const std::string& old_filespec, const std::string& new_filespec);
+  // make an exact copy of the file - returns true if it succeeded
+  bool file_copy (const std::string& old_filespec, const std::string& new_filespec);
+  // move the file - tries to rename, if that fails, tries to copy - returns true if either of these succeeded
+  bool file_move (const std::string& old_filespec, const std::string& new_filespec);
+
+  // get the file's time stamps as a time_t - see the stlplus time.hpp package
+
+  // time the file was originally created
+  time_t file_created(const std::string& filespec);
+  // time the file was last modified
+  time_t file_modified(const std::string& filespec);
+  // time the file was accessed
+  time_t file_accessed(const std::string& filespec);
+
+  // platform-specific string handling to combine a directory and filename into a path
+
+  // combine a folder with a filename (basename.extension)
+  std::string create_filespec(const std::string& folder, const std::string& filename);
+  // combine a folder, a basename and an extension - extension does not need the .
+  std::string create_filespec(const std::string& folder, const std::string& basename, const std::string& extension);
+  // combine a basename and an extension - extension does not need the .
+  std::string create_filename(const std::string& basename, const std::string& extension);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // folder functions
+
+  // craete a folder - returns true if successful
+  bool folder_create(const std::string& folder);
+  // tests for whether the folder exists, i.e. there is something of that name and its a folder
+  bool folder_exists(const std::string& folder);
+  // test whether the folder contents are readable
+  bool folder_readable(const std::string& folder);
+  // tests whether the folder can be written to - for example to create a new file
+  bool folder_writable(const std::string& folder);
+  // delete the folder, optionally deleting the contents first - only succeeds if everything could be deleted
+  bool folder_delete(const std::string& folder, bool recurse = false);
+  // rename the folder - this probably only works within a disk/partition
+  bool folder_rename (const std::string& old_directory, const std::string& new_directory);
+  // test whether the folder is empty (of files)
+  bool folder_empty(const std::string& folder);
+
+  // set the current folder
+  bool folder_set_current(const std::string& folder);
+
+  // platform-specific string handling to retrieve some special locations
+  // these do not check whether the folder exists, they just process strings
+
+  // get the current folder
+  std::string folder_current(void);
+  // get the current folder as a full path
+  std::string folder_current_full(void);
+  // get the home folder - $HOME or %HOMEDRIVE%%HOMEPATH%
+  std::string folder_home(void);
+  // go down a level in the folder hierarchy
+  std::string folder_down(const std::string& folder, const std::string& subfolder);
+  // go up a level in the folder hierarchy
+  std::string folder_up(const std::string& folder, unsigned levels = 1);
+
+  // get folder contents
+
+  // the set of all subdirectories
+  std::vector<std::string> folder_subdirectories(const std::string& folder);
+  // the set of all files
+  std::vector<std::string> folder_files(const std::string& folder);
+  // the set of all folders and files
+  std::vector<std::string> folder_all(const std::string& folder);
+  // the set of all folder contents matching a wildcard string
+  // if folders is true, include folders; if files is true, include files
+  std::vector<std::string> folder_wildcard(const std::string& folder,
+                                           const std::string& wildcard,
+                                           bool folders = true,
+                                           bool files = true);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // path functions
+
+  // string manipulations of paths
+
+  // test whether a string represents a full path or a relative one
+  bool is_full_path(const std::string& path);
+  bool is_relative_path(const std::string& path);
+
+  // convert to a full path relative to the root path
+  std::string folder_to_path(const std::string& root, const std::string& folder);
+  std::string filespec_to_path(const std::string& root, const std::string& filespec);
+
+  // convert to a full path relative to the current working directory
+  std::string folder_to_path(const std::string& folder);
+  std::string filespec_to_path(const std::string& filespec);
+
+  // convert to a relative path relative to the root path
+  std::string folder_to_relative_path(const std::string& root, const std::string& folder);
+  std::string filespec_to_relative_path(const std::string& root, const std::string& filespec);
+
+  // convert to a relative path relative to the current working directory
+  std::string folder_to_relative_path(const std::string& folder);
+  std::string filespec_to_relative_path(const std::string& filespec);
+
+  // append a folder separator to the path to make it absolutely clear that it is a folder
+  std::string folder_append_separator(const std::string& folder);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // access functions split a filespec into its elements
+
+  // get the basename - that is, the name of the file without folder or extension parts
+  std::string basename_part(const std::string& filespec);
+  // get the filename - that is, the name of the file without folder part but with extension
+  std::string filename_part(const std::string& filespec);
+  // get the extension - that is the part of the filename after the . (and excluding the .)
+  std::string extension_part(const std::string& filespec);
+  // get the folder part - that is the filespec with the filename removed
+  std::string folder_part(const std::string& filespec);
+
+  // split a path into a vector of elements - i.e. split at the folder separator
+  std::vector<std::string> folder_elements(const std::string& folder);
+  std::vector<std::string> filespec_elements(const std::string& filespec);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Path lookup functions
+
+#ifdef MSWINDOWS
+#define PATH_SPLITTER ";"
+#else
+#define PATH_SPLITTER ":"
+#endif
+
+  // The lookup normally carried out by the shell to find a command in a
+  // directory in the PATH. Give this function the name of a command and it
+  // will return the full path. It returns an empty string on failure.
+  std::string path_lookup (const std::string& command);
+
+  // Generalised form of the above, takes a second argument
+  // - the list to search. This can be used to do other path lookups,
+  // such as LD_LIBRARY_PATH. The third argument specifies the splitter -
+  // the default value of PATH_SPLITTER is appropriate for environment variables.
+  std::string lookup (const std::string& file, const std::string& path, const std::string& splitter = PATH_SPLITTER);
+
+  // utility function for finding the folder that contains the current executable
+  // the argument is the argv[0] parameter passed to main
+  std::string install_path(const std::string& argv0);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 80b047556783330867ef7dd05c514d7986ef1943..d70ab76453f40454f25043c39540ec2b6b3f15c6 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   The integer is represented as a sequence of bytes. They are stored such that\r
-//   element 0 is the lsB, which makes sense when seen as an integer offset but\r
-//   is counter-intuitive when you think that a string is usually read from left\r
-//   to right, 0 to size-1, in which case the lsB is on the *left*.\r
-\r
-//   This solution is compatible with 32-bit and 64-bit machines with either\r
-//   little-endian or big-endian representations of integers.\r
-\r
-//   Problem: I'm using std::string, which is an array of char. However, char is\r
-//   not well-defined - it could be signed or unsigned.\r
-\r
-//   In fact, there's no requirement for a char to even be one byte - it can be\r
-//   any size of one byte or more. However, it's just impossible to make any\r
-//   progress with that naffness (thanks to the C non-standardisation committee)\r
-//   and the practice is that char on every platform/compiler I've ever come\r
-//   across is that char = byte.\r
-\r
-//   The algorithms here use unsigned char to represent bit-patterns so I have to\r
-//   be careful to type-cast from char to unsigned char a lot. I use a typedef to\r
-//   make life easier.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "inf.hpp"\r
-#include <ctype.h>\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // choose a sensible C type for a byte\r
-\r
-  typedef unsigned char byte;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // local functions\r
-\r
-  // removes leading bytes that don't contribute to the value to create the minimum string representation\r
-  static void reduce_string(std::string& data)\r
-  {\r
-    while(data.size() > 1 && \r
-          ((byte(data[data.size()-1]) == byte(0) && byte(data[data.size()-2]) < byte(128)) ||\r
-           (byte(data[data.size()-1]) == byte(255) && byte(data[data.size()-2]) >= byte(128))))\r
-    {\r
-      data.erase(data.end()-1);\r
-    }\r
-  }\r
-\r
-  // generic implementations of type conversions from integer type to internal representation\r
-  // data: integer value for conversion\r
-  // result: internal representation\r
-\r
-  template <typename T>\r
-  static void convert_from_signed(const T& data, std::string& result)\r
-  {\r
-    result.erase();\r
-    bool lsb_first = little_endian();\r
-    byte* address = (byte*)&data;\r
-    for (size_t i = 0; i < sizeof(T); i++)\r
-    {\r
-      size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));\r
-      result.append(1,address[offset]);\r
-    }\r
-    reduce_string(result);\r
-  }\r
-\r
-  template <typename T>\r
-  static void convert_from_unsigned(const T& data, std::string& result)\r
-  {\r
-    result.erase();\r
-    bool lsb_first = little_endian();\r
-    byte* address = (byte*)&data;\r
-    for (size_t i = 0; i < sizeof(T); i++)\r
-    {\r
-      size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));\r
-      result.append(1,address[offset]);\r
-    }\r
-    // inf is signed - so there is a possible extra sign bit to add\r
-    result.append(1,std::string::value_type(0));\r
-    reduce_string(result);\r
-  }\r
-\r
-  // generic implementations of type conversions from internal representation to an integer type\r
-  // data : string representation of integer\r
-  // result: integer result of conversion\r
-  // return: flag indicating success - false = overflow\r
-\r
-  template <class T>\r
-  bool convert_to_signed(const std::string& data, T& result)\r
-  {\r
-    bool lsb_first = little_endian();\r
-    byte* address = (byte*)&result;\r
-    for (size_t i = 0; i < sizeof(T); i++)\r
-    {\r
-      size_t offset = lsb_first ? i : (sizeof(T) - i - 1);\r
-      if (i < data.size())\r
-        address[offset] = byte(data[i]);\r
-      else if (data.empty() || (byte(data[data.size()-1]) < byte(128)))\r
-        address[offset] = byte(0);\r
-      else\r
-        address[offset] = byte(255);\r
-    }\r
-    return data.size() <= sizeof(T);\r
-  }\r
-\r
-  template <class T>\r
-  bool convert_to_unsigned(const std::string& data, T& result)\r
-  {\r
-    bool lsb_first = little_endian();\r
-    byte* address = (byte*)&result;\r
-    for (size_t i = 0; i < sizeof(T); i++)\r
-    {\r
-      size_t offset = lsb_first ? i : (sizeof(T) - i - 1);\r
-      if (i < data.size())\r
-        address[offset] = byte(data[i]);\r
-      else\r
-        address[offset] = byte(0);\r
-    }\r
-    return data.size() <= sizeof(T);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Conversions to string\r
-\r
-  static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";\r
-  static int from_char [] = \r
-  {\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,\r
-    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
-    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
-    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
-    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
-  };\r
-\r
-  static void convert_to_string(const stlplus::inf& data, std::string& result, unsigned radix = 10)\r
-    throw(std::invalid_argument)\r
-  {\r
-    // only support the C-style radixes plus 0b for binary\r
-    if (radix != 2 && radix != 8 && radix != 10 && radix != 16)\r
-      throw std::invalid_argument("invalid radix value");\r
-    inf local_i = data;\r
-    // untangle all the options\r
-    bool binary = radix == 2;\r
-    bool octal = radix == 8;\r
-    bool hex = radix == 16;\r
-    // the C representations for binary, octal and hex use 2's-complement representation\r
-    // all other represenations use sign-magnitude\r
-    if (hex || octal || binary)\r
-    {\r
-      // bit-pattern representation\r
-      // this is the binary representation optionally shown in octal or hex\r
-      // first generate the binary by masking the bits\r
-      for (unsigned j = local_i.bits(); j--; )\r
-        result += (local_i.bit(j) ? '1' : '0');\r
-      // the result is now the full width of the type - e.g. int will give a 32-bit result\r
-      // now interpret this as either binary, octal or hex and add the prefix\r
-      if (binary)\r
-      {\r
-        // trim down to the smallest string that preserves the value\r
-        while (true)\r
-        {\r
-          // do not trim to less than 1 bit (sign only)\r
-          if (result.size() <= 1) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0b");\r
-      }\r
-      else if (octal)\r
-      {\r
-        // the result is currently binary\r
-        // trim down to the smallest string that preserves the value\r
-        while (true)\r
-        {\r
-          // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
-          if (result.size() <= 2) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier\r
-        while (result.size() % 3 != 0)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        // now convert to octal\r
-        std::string octal_result;\r
-        for (unsigned i = 0; i < result.size()/3; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*3] == '0')\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '0';\r
-              else\r
-                octal_result += '1';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '2';\r
-              else\r
-                octal_result += '3';\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '4';\r
-              else\r
-                octal_result += '5';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '6';\r
-              else\r
-                octal_result += '7';\r
-            }\r
-          }\r
-        }\r
-        result = octal_result;\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0");\r
-      }\r
-      else\r
-      {\r
-        // similar to octal\r
-        while (true)\r
-        {\r
-          // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
-          if (result.size() <= 2) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        // pad to a multiple of 4 characters\r
-        while (result.size() % 4 != 0)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        // now convert to hex\r
-        std::string hex_result;\r
-        for (unsigned i = 0; i < result.size()/4; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*4] == '0')\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '0';\r
-                else\r
-                  hex_result += '1';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '2';\r
-                else\r
-                  hex_result += '3';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '4';\r
-                else\r
-                  hex_result += '5';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '6';\r
-                else\r
-                  hex_result += '7';\r
-              }\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '8';\r
-                else\r
-                  hex_result += '9';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'a';\r
-                else\r
-                  hex_result += 'b';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'c';\r
-                else\r
-                  hex_result += 'd';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'e';\r
-                else\r
-                  hex_result += 'f';\r
-              }\r
-            }\r
-          }\r
-        }\r
-        result = hex_result;\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0x");\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // convert to sign-magnitude\r
-      // the representation is:\r
-      // [sign]magnitude\r
-      bool negative = local_i.negative();\r
-      local_i.abs();\r
-      // create a representation of the magnitude by successive division\r
-      inf inf_radix(radix);\r
-      do\r
-      {\r
-        std::pair<inf,inf> divided = local_i.divide(inf_radix);\r
-        unsigned remainder = divided.second.to_unsigned();\r
-        char digit = to_char[remainder];\r
-        result.insert((std::string::size_type)0, 1, digit);\r
-        local_i = divided.first;\r
-      }\r
-      while(!local_i.zero());\r
-      // add the prefixes\r
-      // add a sign only for negative values\r
-      if (negative)\r
-        result.insert((std::string::size_type)0, 1, '-');\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Conversions FROM string\r
-\r
-  void convert_from_string(const std::string& str, inf& result, unsigned radix = 10) throw(std::invalid_argument)\r
-  {\r
-    result = 0;\r
-    // only support the C-style radixes plus 0b for binary\r
-    // a radix of 0 means deduce the radix from the input - assume 10\r
-    if (radix != 0 && radix != 2 && radix != 8 && radix != 10 && radix != 16)\r
-      throw std::invalid_argument("invalid radix value");\r
-    unsigned i = 0;\r
-    // the radix passed as a parameter is just the default - it can be\r
-    // overridden by the C prefix\r
-    // Note: a leading zero is the C-style prefix for octal - I only make this\r
-    // override the default when the default radix is not specified\r
-    // first check for a C-style prefix\r
-    bool c_style = false;\r
-    if (i < str.size() && str[i] == '0')\r
-    {\r
-      // binary or hex\r
-      if (i+1 < str.size() && tolower(str[i+1]) == 'x')\r
-      {\r
-        c_style = true;\r
-        radix = 16;\r
-        i += 2;\r
-      }\r
-      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')\r
-      {\r
-        c_style = true;\r
-        radix = 2;\r
-        i += 2;\r
-      }\r
-      else if (radix == 0)\r
-      {\r
-        c_style = true;\r
-        radix = 8;\r
-        i += 1;\r
-      }\r
-    }\r
-    if (radix == 0)\r
-      radix = 10;\r
-    if (c_style)\r
-    {\r
-      // the C style formats are bit patterns not integer values - these need\r
-      // to be sign-extended to get the right value\r
-      std::string binary;\r
-      if (radix == 2)\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += '0';\r
-            break;\r
-          case '1':\r
-            binary += '1';\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid binary character in string " + str);\r
-          }\r
-        }\r
-      }\r
-      else if (radix == 8)\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += "000";\r
-            break;\r
-          case '1':\r
-            binary += "001";\r
-            break;\r
-          case '2':\r
-            binary += "010";\r
-            break;\r
-          case '3':\r
-            binary += "011";\r
-            break;\r
-          case '4':\r
-            binary += "100";\r
-            break;\r
-          case '5':\r
-            binary += "101";\r
-            break;\r
-          case '6':\r
-            binary += "110";\r
-            break;\r
-          case '7':\r
-            binary += "111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid octal character in string " + str);\r
-          }\r
-        }\r
-      }\r
-      else\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(tolower(str[j]))\r
-          {\r
-          case '0':\r
-            binary += "0000";\r
-            break;\r
-          case '1':\r
-            binary += "0001";\r
-            break;\r
-          case '2':\r
-            binary += "0010";\r
-            break;\r
-          case '3':\r
-            binary += "0011";\r
-            break;\r
-          case '4':\r
-            binary += "0100";\r
-            break;\r
-          case '5':\r
-            binary += "0101";\r
-            break;\r
-          case '6':\r
-            binary += "0110";\r
-            break;\r
-          case '7':\r
-            binary += "0111";\r
-            break;\r
-          case '8':\r
-            binary += "1000";\r
-            break;\r
-          case '9':\r
-            binary += "1001";\r
-            break;\r
-          case 'a':\r
-            binary += "1010";\r
-            break;\r
-          case 'b':\r
-            binary += "1011";\r
-            break;\r
-          case 'c':\r
-            binary += "1100";\r
-            break;\r
-          case 'd':\r
-            binary += "1101";\r
-            break;\r
-          case 'e':\r
-            binary += "1110";\r
-            break;\r
-          case 'f':\r
-            binary += "1111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid hex character in string " + str);\r
-          }\r
-        }\r
-      }\r
-      // now convert the value\r
-      result.resize(binary.size());\r
-      for (unsigned j = 0; j < binary.size(); j++)\r
-        result.preset(binary.size() - j - 1, binary[j] == '1');\r
-    }\r
-    else\r
-    {\r
-      // sign-magnitude representation\r
-      // now scan for a sign and find whether this is a negative number\r
-      bool negative = false;\r
-      if (i < str.size())\r
-      {\r
-        switch (str[i])\r
-        {\r
-        case '-':\r
-          negative = true;\r
-          i++;\r
-          break;\r
-        case '+':\r
-          i++;\r
-          break;\r
-        }\r
-      }\r
-      for (; i < str.size(); i++)\r
-      {\r
-        result *= inf(radix);\r
-        unsigned char ascii = (unsigned char)str[i];\r
-        int ch = from_char[ascii] ;\r
-        if (ch == -1)\r
-          throw std::invalid_argument("invalid decimal character in string " + str);\r
-        result += inf(ch);\r
-      }\r
-      if (negative)\r
-        result.negate();\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // constructors - mostly implemented in terms of the assignment operators\r
-\r
-  inf::inf(void)\r
-  {\r
-    // void constructor initialises to zero - represented as a single-byte value containing zero\r
-    m_data.append(1,std::string::value_type(0));\r
-  }\r
-\r
-  inf::inf(short r)\r
-  {\r
-    operator=(r);\r
-  }\r
-\r
-  inf::inf(unsigned short r)\r
-  {\r
-    operator=(r);\r
-  }\r
-\r
-  inf::inf(int r)\r
-  {\r
-    operator=(r);\r
-  }\r
-\r
-  inf::inf(unsigned r)\r
-  {\r
-    operator=(r);\r
-  }\r
-\r
-  inf::inf(long r)\r
-  {\r
-    operator=(r);\r
-  }\r
-\r
-  inf::inf(unsigned long r)\r
-  {\r
-    operator=(r);\r
-  }\r
-\r
-  inf::inf (const std::string& r) throw(std::invalid_argument)\r
-  {\r
-    operator=(r);\r
-  }\r
-\r
-  inf::inf(const inf& r)\r
-  {\r
-#ifdef __BORLANDC__\r
-    // work round bug in Borland compiler - copy constructor fails if string\r
-    // contains null characters, so do my own copy\r
-    for (unsigned i = 0; i < r.m_data.size(); i++)\r
-      m_data += r.m_data[i];\r
-#else\r
-    m_data = r.m_data;\r
-#endif\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  inf::~inf(void)\r
-  {\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // assignments convert from iteger types to internal representation\r
-\r
-  inf& inf::operator = (short r)\r
-  {\r
-    convert_from_signed(r, m_data);\r
-    return *this;\r
-  }\r
-\r
-  inf& inf::operator = (unsigned short r)\r
-  {\r
-    convert_from_unsigned(r, m_data);\r
-    return *this;\r
-  }\r
-\r
-  inf& inf::operator = (int r)\r
-  {\r
-    convert_from_signed(r, m_data);\r
-    return *this;\r
-  }\r
-\r
-  inf& inf::operator = (unsigned r)\r
-  {\r
-    convert_from_unsigned(r, m_data);\r
-    return *this;\r
-  }\r
-\r
-  inf& inf::operator = (long r)\r
-  {\r
-    convert_from_signed(r, m_data);\r
-    return *this;\r
-  }\r
-\r
-  inf& inf::operator = (unsigned long r)\r
-  {\r
-    convert_from_unsigned(r, m_data);\r
-    return *this;\r
-  }\r
-\r
-  inf& inf::operator = (const std::string& r) throw(std::invalid_argument)\r
-  {\r
-    convert_from_string(r, *this);\r
-    return *this;\r
-  }\r
-\r
-  inf& inf::operator = (const inf& r)\r
-  {\r
-    m_data = r.m_data;\r
-    return *this;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  short inf::to_short(bool truncate) const throw(std::overflow_error)\r
-  {\r
-    short result = 0;\r
-    if (!convert_to_signed(m_data, result))\r
-      if (!truncate)\r
-        throw std::overflow_error("stlplus::inf::to_short");\r
-    return result;\r
-  }\r
-\r
-  unsigned short inf::to_unsigned_short(bool truncate) const throw(std::overflow_error)\r
-  {\r
-    unsigned short result = 0;\r
-    if (!convert_to_unsigned(m_data, result))\r
-      if (!truncate)\r
-        throw std::overflow_error("stlplus::inf::to_unsigned_short");\r
-    return result;\r
-  }\r
-\r
-  int inf::to_int(bool truncate) const throw(std::overflow_error)\r
-  {\r
-    int result = 0;\r
-    if (!convert_to_signed(m_data, result))\r
-      if (!truncate)\r
-        throw std::overflow_error("stlplus::inf::to_int");\r
-    return result;\r
-  }\r
-\r
-  unsigned inf::to_unsigned(bool truncate) const throw(std::overflow_error)\r
-  {\r
-    unsigned result = 0;\r
-    if (!convert_to_unsigned(m_data, result))\r
-      if (!truncate)\r
-        throw std::overflow_error("stlplus::inf::to_unsigned");\r
-    return result;\r
-  }\r
-\r
-  long inf::to_long(bool truncate) const throw(std::overflow_error)\r
-  {\r
-    long result = 0;\r
-    if (!convert_to_signed(m_data, result))\r
-      if (!truncate)\r
-        throw std::overflow_error("stlplus::inf::to_long");\r
-    return result;\r
-  }\r
-\r
-  unsigned long inf::to_unsigned_long(bool truncate) const throw(std::overflow_error)\r
-  {\r
-    unsigned long result = 0;\r
-    if (!convert_to_unsigned(m_data, result))\r
-      if (!truncate)\r
-        throw std::overflow_error("stlplus::inf::to_unsigned_long");\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // resize the inf regardless of the data\r
-\r
-  void inf::resize(unsigned bits)\r
-  {\r
-    if (bits == 0) bits = 1;\r
-    unsigned bytes = (bits+7)/8;\r
-    byte extend = negative() ? byte(255) : byte (0);\r
-    while(bytes > m_data.size())\r
-      m_data.append(1,extend);\r
-  }\r
-\r
-  // reduce the bit count to the minimum needed to preserve the value\r
-\r
-  void inf::reduce(void)\r
-  {\r
-    reduce_string(m_data);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // the number of significant bits in the number\r
-\r
-  unsigned inf::bits (void) const\r
-  {\r
-    // The number of significant bits in the integer value - this is the number\r
-    // of indexable bits less any redundant sign bits at the msb\r
-    // This does not assume that the inf has been reduced to its minimum form\r
-    unsigned result = indexable_bits();\r
-    bool sign = bit(result-1);\r
-    while (result > 1 && (sign == bit(result-2)))\r
-      result--;\r
-    return result;\r
-  }\r
-\r
-  unsigned inf::size(void) const\r
-  {\r
-    return bits();\r
-  }\r
-\r
-  unsigned inf::indexable_bits (void) const\r
-  {\r
-    return 8 * unsigned(m_data.size());\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // bitwise operations\r
-\r
-  bool inf::bit (unsigned index) const throw(std::out_of_range)\r
-  {\r
-    if (index >= indexable_bits())\r
-      throw std::out_of_range(std::string("stlplus::inf::bit"));\r
-    // first split the offset into byte offset and bit offset\r
-    unsigned byte_offset = index/8;\r
-    unsigned bit_offset = index%8;\r
-    return (byte(m_data[byte_offset]) & (byte(1) << bit_offset)) != 0;\r
-  }\r
-\r
-  bool inf::operator [] (unsigned index) const throw(std::out_of_range)\r
-  {\r
-    return bit(index);\r
-  }\r
-\r
-  void inf::set (unsigned index)  throw(std::out_of_range)\r
-  {\r
-    if (index >= indexable_bits())\r
-      throw std::out_of_range(std::string("stlplus::inf::set"));\r
-    // first split the offset into byte offset and bit offset\r
-    unsigned byte_offset = index/8;\r
-    unsigned bit_offset = index%8;\r
-    m_data[byte_offset] |= (byte(1) << bit_offset);\r
-  }\r
-\r
-  void inf::clear (unsigned index)  throw(std::out_of_range)\r
-  {\r
-    if (index >= indexable_bits())\r
-      throw std::out_of_range(std::string("stlplus::inf::clear"));\r
-    // first split the offset into byte offset and bit offset\r
-    unsigned byte_offset = index/8;\r
-    unsigned bit_offset = index%8;\r
-    m_data[byte_offset] &= (~(byte(1) << bit_offset));\r
-  }\r
-\r
-  void inf::preset (unsigned index, bool value)  throw(std::out_of_range)\r
-  {\r
-    if (value)\r
-      set(index);\r
-    else\r
-      clear(index);\r
-  }\r
-\r
-  inf inf::slice(unsigned low, unsigned high) const throw(std::out_of_range)\r
-  {\r
-    if (low >= indexable_bits())\r
-      throw std::out_of_range(std::string("stlplus::inf::slice: low index"));\r
-    if (high >= indexable_bits())\r
-      throw std::out_of_range(std::string("stlplus::inf::slice: high index"));\r
-    inf result;\r
-    if (high >= low)\r
-    {\r
-      // create a result the right size and filled with sign bits\r
-      std::string::size_type result_size = (high-low+1+7)/8;\r
-      result.m_data.erase();\r
-      byte extend = bit(high) ? byte(255) : byte (0);\r
-      while (result.m_data.size() < result_size)\r
-        result.m_data.append(1,extend);\r
-      // now set the relevant bits\r
-      for (unsigned i = low; i <= high; i++)\r
-        result.preset(i-low, bit(i));\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // testing operations\r
-\r
-  bool inf::negative (void) const\r
-  {\r
-    return bit(indexable_bits()-1);\r
-  }\r
-\r
-  bool inf::natural (void) const\r
-  {\r
-    return !negative();\r
-  }\r
-\r
-  bool inf::positive (void) const\r
-  {\r
-    return natural() && !zero();\r
-  }\r
-\r
-  bool inf::zero (void) const\r
-  {\r
-    for (std::string::size_type i = 0; i < m_data.size(); i++)\r
-      if (m_data[i] != 0)\r
-        return false;\r
-    return true;\r
-  }\r
-\r
-  bool inf::non_zero (void) const\r
-  {\r
-    return !zero();\r
-  }\r
-\r
-  bool inf::operator ! (void) const\r
-  {\r
-    return zero();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // comparison operators\r
-\r
-  bool inf::operator == (const inf& r) const\r
-  {\r
-    // Two infs are equal if they are numerically equal, even if they are\r
-    // different sizes (i.e. they could be non-reduced values).\r
-    // This makes life a little more complicated than if I could assume that values were reduced.\r
-    byte l_extend = negative() ? byte(255) : byte (0);\r
-    byte r_extend = r.negative() ? byte(255) : byte (0);\r
-    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());\r
-    for (std::string::size_type i = bytes; i--; )\r
-    {\r
-      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);\r
-      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);\r
-      if (l_byte != r_byte)\r
-        return false;\r
-    }\r
-    return true;\r
-  }\r
-\r
-  bool inf::operator != (const inf& r) const\r
-  {\r
-    return !operator==(r);\r
-  }\r
-\r
-  bool inf::operator < (const inf& r) const\r
-  {\r
-    // This could be implemented in terms of subtraction. However, it can be\r
-    // simplified since there is no need to calculate the accurate difference,\r
-    // just the direction of the difference. I compare from msB down and as\r
-    // soon as a byte difference is found, that defines the ordering. The\r
-    // problem is that in 2's-complement, all negative values are greater than\r
-    // all natural values if you just do a straight unsigned comparison. I\r
-    // handle this by doing a preliminary test for different signs.\r
-\r
-    // For example, a 3-bit signed type has the coding:\r
-    // 000 = 0\r
-    // ...\r
-    // 011 = 3\r
-    // 100 = -4\r
-    // ...\r
-    // 111 = -1\r
-\r
-    // So, for natural values, the ordering of the integer values is the\r
-    // ordering of the bit patterns. Similarly, for negative values, the\r
-    // ordering of the integer values is the ordering of the bit patterns\r
-    // However, the bit patterns for the negative values are *greater than*\r
-    // the natural values. This is a side-effect of the naffness of\r
-    // 2's-complement representation\r
-\r
-    // first handle the case of comparing two values with different signs\r
-    bool l_sign = negative();\r
-    bool r_sign = r.negative();\r
-    if (l_sign != r_sign)\r
-    {\r
-      // one argument must be negative and the other natural\r
-      // the left is less if it is the negative one\r
-      return l_sign;\r
-    }\r
-    // the arguments are the same sign\r
-    // so the ordering is a simple unsigned byte-by-byte comparison\r
-    // However, this is complicated by the possibility that the values could be different lengths\r
-    byte l_extend = l_sign ? byte(255) : byte (0);\r
-    byte r_extend = r_sign ? byte(255) : byte (0);\r
-    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());\r
-    for (std::string::size_type i = bytes; i--; )\r
-    {\r
-      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);\r
-      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);\r
-      if (l_byte != r_byte)\r
-        return l_byte < r_byte;\r
-    }\r
-    // if I get here, the two are equal, so that is not less-than\r
-    return false;\r
-  }\r
-\r
-  bool inf::operator <= (const inf& r) const\r
-  {\r
-    return !(r < *this);\r
-  }\r
-\r
-  bool inf::operator > (const inf& r) const\r
-  {\r
-    return r < *this;\r
-  }\r
-\r
-  bool inf::operator >= (const inf& r) const\r
-  {\r
-    return !(*this < r);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // logical operators\r
-\r
-  inf& inf::invert (void)\r
-  {\r
-    for (std::string::size_type i = 0; i < m_data.size(); i++)\r
-      m_data[i] = ~m_data[i];\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator ~ (void) const\r
-  {\r
-    inf result(*this);\r
-    result.invert();\r
-    return result;\r
-  }\r
-\r
-  inf& inf::operator &= (const inf& r)\r
-  {\r
-    // bitwise AND is extended to the length of the largest argument\r
-    byte l_extend = negative() ? byte(255) : byte (0);\r
-    byte r_extend = r.negative() ? byte(255) : byte (0);\r
-    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());\r
-    for (std::string::size_type i = 0; i < bytes; i++)\r
-    {\r
-      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);\r
-      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);\r
-      byte result = l_byte & r_byte;\r
-      if (i < m_data.size())\r
-        m_data[i] = result;\r
-      else\r
-        m_data.append(1,result);\r
-    }\r
-    // now reduce the result\r
-    reduce();\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator & (const inf& r) const\r
-  {\r
-    inf result(*this);\r
-    result &= r;\r
-    return result;\r
-  }\r
-\r
-  inf& inf::operator |= (const inf& r)\r
-  {\r
-    // bitwise OR is extended to the length of the largest argument\r
-    byte l_extend = negative() ? byte(255) : byte (0);\r
-    byte r_extend = r.negative() ? byte(255) : byte (0);\r
-    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());\r
-    for (std::string::size_type i = 0; i < bytes; i++)\r
-    {\r
-      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);\r
-      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);\r
-      byte result = l_byte | r_byte;\r
-      if (i < m_data.size())\r
-        m_data[i] = result;\r
-      else\r
-        m_data.append(1,result);\r
-    }\r
-    // now reduce the result\r
-    reduce();\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator | (const inf& r) const\r
-  {\r
-    inf result(*this);\r
-    result |= r;\r
-    return result;\r
-  }\r
-\r
-  inf& inf::operator ^= (const inf& r)\r
-  {\r
-    // bitwise XOR is extended to the length of the largest argument\r
-    byte l_extend = negative() ? byte(255) : byte (0);\r
-    byte r_extend = r.negative() ? byte(255) : byte (0);\r
-    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());\r
-    for (std::string::size_type i = 0; i < bytes; i++)\r
-    {\r
-      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);\r
-      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);\r
-      byte result = l_byte ^ r_byte;\r
-      if (i < m_data.size())\r
-        m_data[i] = result;\r
-      else\r
-        m_data.append(1,result);\r
-    }\r
-    // now reduce the result\r
-    reduce();\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator ^ (const inf& r) const\r
-  {\r
-    inf result(*this);\r
-    result ^= r;\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // shift operators all preserve the value by increasing the word size\r
-\r
-  inf& inf::operator <<= (unsigned shift)\r
-  {\r
-    // left shift is a shift towards the msb, with 0s being shifted in at the lsb\r
-    // split this into a byte shift followed by a bit shift\r
-\r
-    // first expand the value to be big enough for the result\r
-    std::string::size_type new_size = (indexable_bits() + shift + 7) / 8;\r
-    byte extend = negative() ? byte(255) : byte (0);\r
-    while (m_data.size() < new_size)\r
-      m_data.append(1,extend);\r
-    // now do the byte shift\r
-    unsigned byte_shift = shift/8;\r
-    if (byte_shift > 0)\r
-    {\r
-      for (std::string::size_type b = new_size; b--; )\r
-        m_data[b] = (b >= byte_shift) ? m_data[b-byte_shift] : byte(0);\r
-    }\r
-    // and finally the bit shift\r
-    unsigned bit_shift = shift%8;\r
-    if (bit_shift > 0)\r
-    {\r
-      for (std::string::size_type b = new_size; b--; )\r
-      {\r
-        byte current = byte(m_data[b]);\r
-        byte previous = b > 0 ? m_data[b-1] : byte(0);\r
-        m_data[b] = (current << bit_shift) | (previous >> (8 - bit_shift));\r
-      }\r
-    }\r
-    // now reduce the result\r
-    reduce();\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator << (unsigned shift) const\r
-  {\r
-    inf result(*this);\r
-    result <<= shift;\r
-    return result;\r
-  }\r
-\r
-  inf& inf::operator >>= (unsigned shift)\r
-  {\r
-    // right shift is a shift towards the lsb, with sign bits being shifted in at the msb\r
-    // split this into a byte shift followed by a bit shift\r
-\r
-    // a byte of sign bits\r
-    byte extend = negative() ? byte(255) : byte (0);\r
-    // do the byte shift\r
-    unsigned byte_shift = shift/8;\r
-    if (byte_shift > 0)\r
-    {\r
-      for (std::string::size_type b = 0; b < m_data.size(); b++)\r
-        m_data[b] = (b + byte_shift < m_data.size()) ? m_data[b+byte_shift] : extend;\r
-    }\r
-    // and finally the bit shift\r
-    unsigned bit_shift = shift%8;\r
-    if (bit_shift > 0)\r
-    {\r
-      for (std::string::size_type b = 0; b < m_data.size(); b++)\r
-      {\r
-        byte current = byte(m_data[b]);\r
-        byte next = ((b+1) < m_data.size()) ? m_data[b+1] : extend;\r
-        byte shifted = (current >> bit_shift) | (next << (8 - bit_shift));\r
-        m_data[b] = shifted;\r
-      }\r
-    }\r
-    // now reduce the result\r
-    reduce();\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator >> (unsigned shift) const\r
-  {\r
-    inf result(*this);\r
-    result >>= shift;\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // negation operators\r
-\r
-  inf& inf::negate (void)\r
-  {\r
-    // do 2's-complement negation\r
-    // equivalent to inversion plus one\r
-    invert();\r
-    operator += (inf(1));\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator - (void) const\r
-  {\r
-    inf result(*this);\r
-    result.negate();\r
-    return result;\r
-  }\r
-\r
-  inf& inf::abs(void)\r
-  {\r
-    if (negative()) negate();\r
-    return *this;\r
-  }\r
-\r
-  inf abs(const inf& i)\r
-  {\r
-    inf result = i;\r
-    result.abs();\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // addition operators\r
-\r
-  inf& inf::operator += (const inf& r)\r
-  {\r
-    // do 2's-complement addition\r
-    // Note that the addition can give a result that is larger than either argument\r
-    byte carry = 0;\r
-    std::string::size_type max_size = maximum(m_data.size(),r.m_data.size());\r
-    byte l_extend = negative() ? byte(255) : byte (0);\r
-    byte r_extend = r.negative() ? byte(255) : byte (0);\r
-    for (std::string::size_type i = 0; i < max_size; i++)\r
-    {\r
-      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);\r
-      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);\r
-      // calculate the addition in a type that is bigger than a byte in order to catch the carry-out\r
-      unsigned short result = ((unsigned short)(l_byte)) + ((unsigned short)(r_byte)) + carry;\r
-      // now truncate the result to get the lsB\r
-      if (i < m_data.size())\r
-        m_data[i] = byte(result);\r
-      else\r
-        m_data.append(1,byte(result));\r
-      // and capture the carry out by grabbing the second byte of the result\r
-      carry = byte(result >> 8);\r
-    }\r
-    // if the result overflowed or underflowed, add an extra byte to catch it\r
-    unsigned short result = ((unsigned short)(l_extend)) + ((unsigned short)(r_extend)) + carry;\r
-    if (byte(result) != (negative() ? byte(255) : byte(0)))\r
-      m_data.append(1,byte(result));\r
-    // now reduce the result\r
-    reduce();\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator + (const inf& r) const\r
-  {\r
-    inf result(*this);\r
-    result += r;\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // subtraction operators\r
-\r
-  inf& inf::operator -= (const inf& r)\r
-  {\r
-    // subtraction is defined in terms of negation and addition\r
-    inf negated = -r;\r
-    operator += (negated);\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator - (const inf& r) const\r
-  {\r
-    inf result(*this);\r
-    result -= r;\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // multiplication operators\r
-\r
-  inf& inf::operator *= (const inf& r)\r
-  {\r
-    // 2's complement multiplication\r
-    // one day I'll do a more efficient version than this based on the underlying representation\r
-    inf left(*this);\r
-    inf right = r;\r
-    // make the right value natural but preserve its sign for later\r
-    bool right_negative = right.negative();\r
-    right.abs();\r
-    // implemented as a series of conditional additions\r
-    operator = (0);\r
-    //  left.resize(right.bits() + left.bits() - 1);\r
-    left <<= right.bits()-1;\r
-    for (unsigned i = right.bits(); i--; )\r
-    {\r
-      if (right[i]) \r
-        operator += (left);\r
-      left >>= 1;\r
-    }\r
-    if (right_negative)\r
-      negate();\r
-    // now reduce the result\r
-    reduce();\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator * (const inf& r) const\r
-  {\r
-    inf result(*this);\r
-    result *= r;\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // division and remainder operators\r
-\r
-  std::pair<inf,inf> inf::divide(const inf& right) const throw(divide_by_zero)\r
-  {\r
-    if (right.zero())\r
-      throw divide_by_zero("stlplus::inf::divide");\r
-    inf numerator(*this);\r
-    inf denominator = right;\r
-    // make the numerator natural but preserve the sign for later\r
-    bool numerator_negative = numerator.negative();\r
-    numerator.abs();\r
-    // same with the denominator\r
-    bool denominator_negative = denominator.negative();\r
-    denominator.abs();\r
-    // the quotient and remainder will form the result\r
-    // start with the quotiont zero and the remainder equal to the whole of the\r
-    // numerator, then do trial subtraction from this\r
-    inf quotient;\r
-    inf remainder = numerator;\r
-    // there's nothing more to do if the numerator is smaller than the denominator\r
-    // but otherwise do the division\r
-    if (numerator.bits() >= denominator.bits())\r
-    {\r
-      // make the quotient big enough to take the result\r
-      quotient.resize(numerator.bits());\r
-      // start with the numerator shifted to the far left\r
-      unsigned shift = numerator.bits() - denominator.bits();\r
-      denominator <<= shift;\r
-      // do the division by repeated subtraction, \r
-      for (unsigned i = shift+1; i--; )\r
-      {\r
-        if (remainder >= denominator)\r
-        {\r
-          remainder -= denominator;\r
-          quotient.set(i);\r
-        }\r
-        denominator >>= 1;\r
-      }\r
-    }\r
-    // now adjust the signs \r
-    // x/(-y) == (-x)/y == -(x/y)\r
-    if (numerator_negative != denominator_negative)\r
-      quotient.negate();\r
-    quotient.reduce();\r
-    // x%(-y) == x%y and (-x)%y == -(x%y)\r
-    if (numerator_negative)\r
-      remainder.negate();\r
-    remainder.reduce();\r
-    return std::pair<inf,inf>(quotient,remainder);\r
-  }\r
-\r
-  inf& inf::operator /= (const inf& r) throw(divide_by_zero)\r
-  {\r
-    std::pair<inf,inf> result = divide(r);\r
-    operator=(result.first);\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator / (const inf& r) const throw(divide_by_zero)\r
-  {\r
-    std::pair<inf,inf> result = divide(r);\r
-    return result.first;\r
-  }\r
-\r
-  inf& inf::operator %= (const inf& r) throw(divide_by_zero)\r
-  {\r
-    std::pair<inf,inf> result = divide(r);\r
-    operator=(result.second);\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator % (const inf& r) const throw(divide_by_zero)\r
-  {\r
-    std::pair<inf,inf> result = divide(r);\r
-    return result.second;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // prefix (void) and postfix (int) operators\r
-\r
-  inf& inf::operator ++ (void)\r
-  {\r
-    operator += (inf(1));\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator ++ (int)\r
-  {\r
-    inf old(*this);\r
-    operator += (inf(1));\r
-    return old;\r
-  }\r
-\r
-  inf& inf::operator -- (void)\r
-  {\r
-    operator -= (inf(1));\r
-    return *this;\r
-  }\r
-\r
-  inf inf::operator -- (int)\r
-  {\r
-    inf old(*this);\r
-    operator -= (inf(1));\r
-    return old;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // string representation and I/O routines\r
-\r
-  std::string inf::to_string(unsigned radix) const\r
-    throw(std::invalid_argument)\r
-  {\r
-    std::string result;\r
-    convert_to_string(*this, result, radix);\r
-    return result;\r
-  }\r
-\r
-  inf& inf::from_string(const std::string& value, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    convert_from_string(value, *this, radix);\r
-    return *this;\r
-  }\r
-\r
-  std::ostream& operator << (std::ostream& str, const inf& i)\r
-  {\r
-    try\r
-    {\r
-      // get radix\r
-      unsigned radix = 10;\r
-      if (str.flags() & std::ios_base::oct)\r
-        radix = 8;\r
-      if (str.flags() & std::ios_base::hex)\r
-        radix = 16;\r
-      // the field width is handled by iostream, so I don't need to handle it as well\r
-      // generate the string representation then print it\r
-      str << i.to_string(radix);\r
-    }\r
-    catch(const std::invalid_argument)\r
-    {\r
-      str.setstate(std::ios_base::badbit);\r
-    }\r
-    return str;\r
-  }\r
-\r
-  std::istream& operator >> (std::istream& str, inf& i)\r
-  {\r
-    try\r
-    {\r
-      // get radix\r
-      unsigned radix = 10;\r
-      if (str.flags() & std::ios_base::oct)\r
-        radix = 8;\r
-      if (str.flags() & std::ios_base::hex)\r
-        radix = 16;\r
-      // now get the string image of the value\r
-      std::string image;\r
-      str >> image;\r
-      // and convert to inf\r
-      i.from_string(image, radix);\r
-    }\r
-    catch(const std::invalid_argument)\r
-    {\r
-      str.setstate(std::ios_base::badbit);\r
-    }\r
-    return str;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // diagnostic dump\r
-  // just convert to hex\r
-\r
-  std::string inf::image_debug(void) const\r
-  {\r
-    // create this dump in the human-readable form, i.e. msB to the left\r
-    std::string result = "0x";\r
-    for (std::string::size_type i = m_data.size(); i--; )\r
-    {\r
-      byte current = m_data[i];\r
-      byte msB = (current & byte(0xf0)) >> 4;\r
-      result += to_char[msB];\r
-      byte lsB = (current & byte(0x0f));\r
-      result += to_char[lsB];\r
-    }\r
-    return result;\r
-  }\r
-\r
-  const std::string& inf::get_bytes(void) const\r
-  {\r
-    return m_data;\r
-  }\r
-\r
-  void inf::set_bytes(const std::string& data)\r
-  {\r
-    m_data = data;\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   The integer is represented as a sequence of bytes. They are stored such that
+//   element 0 is the lsB, which makes sense when seen as an integer offset but
+//   is counter-intuitive when you think that a string is usually read from left
+//   to right, 0 to size-1, in which case the lsB is on the *left*.
+
+//   This solution is compatible with 32-bit and 64-bit machines with either
+//   little-endian or big-endian representations of integers.
+
+//   Problem: I'm using std::string, which is an array of char. However, char is
+//   not well-defined - it could be signed or unsigned.
+
+//   In fact, there's no requirement for a char to even be one byte - it can be
+//   any size of one byte or more. However, it's just impossible to make any
+//   progress with that naffness (thanks to the C non-standardisation committee)
+//   and the practice is that char on every platform/compiler I've ever come
+//   across is that char = byte.
+
+//   The algorithms here use unsigned char to represent bit-patterns so I have to
+//   be careful to type-cast from char to unsigned char a lot. I use a typedef to
+//   make life easier.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "inf.hpp"
+#include <ctype.h>
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // choose a sensible C type for a byte
+
+  typedef unsigned char byte;
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // local functions
+
+  // removes leading bytes that don't contribute to the value to create the minimum string representation
+  static void reduce_string(std::string& data)
+  {
+    while(data.size() > 1 && 
+          ((byte(data[data.size()-1]) == byte(0) && byte(data[data.size()-2]) < byte(128)) ||
+           (byte(data[data.size()-1]) == byte(255) && byte(data[data.size()-2]) >= byte(128))))
+    {
+      data.erase(data.end()-1);
+    }
+  }
+
+  // generic implementations of type conversions from integer type to internal representation
+  // data: integer value for conversion
+  // result: internal representation
+
+  template <typename T>
+  static void convert_from_signed(const T& data, std::string& result)
+  {
+    result.erase();
+    bool lsb_first = little_endian();
+    byte* address = (byte*)&data;
+    for (size_t i = 0; i < sizeof(T); i++)
+    {
+      size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));
+      result.append(1,address[offset]);
+    }
+    reduce_string(result);
+  }
+
+  template <typename T>
+  static void convert_from_unsigned(const T& data, std::string& result)
+  {
+    result.erase();
+    bool lsb_first = little_endian();
+    byte* address = (byte*)&data;
+    for (size_t i = 0; i < sizeof(T); i++)
+    {
+      size_t offset = (lsb_first ? i : (sizeof(T) - i - 1));
+      result.append(1,address[offset]);
+    }
+    // inf is signed - so there is a possible extra sign bit to add
+    result.append(1,std::string::value_type(0));
+    reduce_string(result);
+  }
+
+  // generic implementations of type conversions from internal representation to an integer type
+  // data : string representation of integer
+  // result: integer result of conversion
+  // return: flag indicating success - false = overflow
+
+  template <class T>
+  bool convert_to_signed(const std::string& data, T& result)
+  {
+    bool lsb_first = little_endian();
+    byte* address = (byte*)&result;
+    for (size_t i = 0; i < sizeof(T); i++)
+    {
+      size_t offset = lsb_first ? i : (sizeof(T) - i - 1);
+      if (i < data.size())
+        address[offset] = byte(data[i]);
+      else if (data.empty() || (byte(data[data.size()-1]) < byte(128)))
+        address[offset] = byte(0);
+      else
+        address[offset] = byte(255);
+    }
+    return data.size() <= sizeof(T);
+  }
+
+  template <class T>
+  bool convert_to_unsigned(const std::string& data, T& result)
+  {
+    bool lsb_first = little_endian();
+    byte* address = (byte*)&result;
+    for (size_t i = 0; i < sizeof(T); i++)
+    {
+      size_t offset = lsb_first ? i : (sizeof(T) - i - 1);
+      if (i < data.size())
+        address[offset] = byte(data[i]);
+      else
+        address[offset] = byte(0);
+    }
+    return data.size() <= sizeof(T);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Conversions to string
+
+  static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";
+  static int from_char [] = 
+  {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+  };
+
+  static void convert_to_string(const stlplus::inf& data, std::string& result, unsigned radix = 10)
+    throw(std::invalid_argument)
+  {
+    // only support the C-style radixes plus 0b for binary
+    if (radix != 2 && radix != 8 && radix != 10 && radix != 16)
+      throw std::invalid_argument("invalid radix value");
+    inf local_i = data;
+    // untangle all the options
+    bool binary = radix == 2;
+    bool octal = radix == 8;
+    bool hex = radix == 16;
+    // the C representations for binary, octal and hex use 2's-complement representation
+    // all other represenations use sign-magnitude
+    if (hex || octal || binary)
+    {
+      // bit-pattern representation
+      // this is the binary representation optionally shown in octal or hex
+      // first generate the binary by masking the bits
+      for (unsigned j = local_i.bits(); j--; )
+        result += (local_i.bit(j) ? '1' : '0');
+      // the result is now the full width of the type - e.g. int will give a 32-bit result
+      // now interpret this as either binary, octal or hex and add the prefix
+      if (binary)
+      {
+        // trim down to the smallest string that preserves the value
+        while (true)
+        {
+          // do not trim to less than 1 bit (sign only)
+          if (result.size() <= 1) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        // add the prefix
+        result.insert((std::string::size_type)0, "0b");
+      }
+      else if (octal)
+      {
+        // the result is currently binary
+        // trim down to the smallest string that preserves the value
+        while (true)
+        {
+          // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+          if (result.size() <= 2) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
+        while (result.size() % 3 != 0)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        // now convert to octal
+        std::string octal_result;
+        for (unsigned i = 0; i < result.size()/3; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*3] == '0')
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '0';
+              else
+                octal_result += '1';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '2';
+              else
+                octal_result += '3';
+            }
+          }
+          else
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '4';
+              else
+                octal_result += '5';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '6';
+              else
+                octal_result += '7';
+            }
+          }
+        }
+        result = octal_result;
+        // add the prefix
+        result.insert((std::string::size_type)0, "0");
+      }
+      else
+      {
+        // similar to octal
+        while (true)
+        {
+          // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+          if (result.size() <= 2) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        // pad to a multiple of 4 characters
+        while (result.size() % 4 != 0)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        // now convert to hex
+        std::string hex_result;
+        for (unsigned i = 0; i < result.size()/4; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*4] == '0')
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '0';
+                else
+                  hex_result += '1';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '2';
+                else
+                  hex_result += '3';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '4';
+                else
+                  hex_result += '5';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '6';
+                else
+                  hex_result += '7';
+              }
+            }
+          }
+          else
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '8';
+                else
+                  hex_result += '9';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'a';
+                else
+                  hex_result += 'b';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'c';
+                else
+                  hex_result += 'd';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'e';
+                else
+                  hex_result += 'f';
+              }
+            }
+          }
+        }
+        result = hex_result;
+        // add the prefix
+        result.insert((std::string::size_type)0, "0x");
+      }
+    }
+    else
+    {
+      // convert to sign-magnitude
+      // the representation is:
+      // [sign]magnitude
+      bool negative = local_i.negative();
+      local_i.abs();
+      // create a representation of the magnitude by successive division
+      inf inf_radix(radix);
+      do
+      {
+        std::pair<inf,inf> divided = local_i.divide(inf_radix);
+        unsigned remainder = divided.second.to_unsigned();
+        char digit = to_char[remainder];
+        result.insert((std::string::size_type)0, 1, digit);
+        local_i = divided.first;
+      }
+      while(!local_i.zero());
+      // add the prefixes
+      // add a sign only for negative values
+      if (negative)
+        result.insert((std::string::size_type)0, 1, '-');
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Conversions FROM string
+
+  void convert_from_string(const std::string& str, inf& result, unsigned radix = 10) throw(std::invalid_argument)
+  {
+    result = 0;
+    // only support the C-style radixes plus 0b for binary
+    // a radix of 0 means deduce the radix from the input - assume 10
+    if (radix != 0 && radix != 2 && radix != 8 && radix != 10 && radix != 16)
+      throw std::invalid_argument("invalid radix value");
+    unsigned i = 0;
+    // the radix passed as a parameter is just the default - it can be
+    // overridden by the C prefix
+    // Note: a leading zero is the C-style prefix for octal - I only make this
+    // override the default when the default radix is not specified
+    // first check for a C-style prefix
+    bool c_style = false;
+    if (i < str.size() && str[i] == '0')
+    {
+      // binary or hex
+      if (i+1 < str.size() && tolower(str[i+1]) == 'x')
+      {
+        c_style = true;
+        radix = 16;
+        i += 2;
+      }
+      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')
+      {
+        c_style = true;
+        radix = 2;
+        i += 2;
+      }
+      else if (radix == 0)
+      {
+        c_style = true;
+        radix = 8;
+        i += 1;
+      }
+    }
+    if (radix == 0)
+      radix = 10;
+    if (c_style)
+    {
+      // the C style formats are bit patterns not integer values - these need
+      // to be sign-extended to get the right value
+      std::string binary;
+      if (radix == 2)
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += '0';
+            break;
+          case '1':
+            binary += '1';
+            break;
+          default:
+            throw std::invalid_argument("invalid binary character in string " + str);
+          }
+        }
+      }
+      else if (radix == 8)
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += "000";
+            break;
+          case '1':
+            binary += "001";
+            break;
+          case '2':
+            binary += "010";
+            break;
+          case '3':
+            binary += "011";
+            break;
+          case '4':
+            binary += "100";
+            break;
+          case '5':
+            binary += "101";
+            break;
+          case '6':
+            binary += "110";
+            break;
+          case '7':
+            binary += "111";
+            break;
+          default:
+            throw std::invalid_argument("invalid octal character in string " + str);
+          }
+        }
+      }
+      else
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(tolower(str[j]))
+          {
+          case '0':
+            binary += "0000";
+            break;
+          case '1':
+            binary += "0001";
+            break;
+          case '2':
+            binary += "0010";
+            break;
+          case '3':
+            binary += "0011";
+            break;
+          case '4':
+            binary += "0100";
+            break;
+          case '5':
+            binary += "0101";
+            break;
+          case '6':
+            binary += "0110";
+            break;
+          case '7':
+            binary += "0111";
+            break;
+          case '8':
+            binary += "1000";
+            break;
+          case '9':
+            binary += "1001";
+            break;
+          case 'a':
+            binary += "1010";
+            break;
+          case 'b':
+            binary += "1011";
+            break;
+          case 'c':
+            binary += "1100";
+            break;
+          case 'd':
+            binary += "1101";
+            break;
+          case 'e':
+            binary += "1110";
+            break;
+          case 'f':
+            binary += "1111";
+            break;
+          default:
+            throw std::invalid_argument("invalid hex character in string " + str);
+          }
+        }
+      }
+      // now convert the value
+      result.resize(binary.size());
+      for (unsigned j = 0; j < binary.size(); j++)
+        result.preset(binary.size() - j - 1, binary[j] == '1');
+    }
+    else
+    {
+      // sign-magnitude representation
+      // now scan for a sign and find whether this is a negative number
+      bool negative = false;
+      if (i < str.size())
+      {
+        switch (str[i])
+        {
+        case '-':
+          negative = true;
+          i++;
+          break;
+        case '+':
+          i++;
+          break;
+        }
+      }
+      for (; i < str.size(); i++)
+      {
+        result *= inf(radix);
+        unsigned char ascii = (unsigned char)str[i];
+        int ch = from_char[ascii] ;
+        if (ch == -1)
+          throw std::invalid_argument("invalid decimal character in string " + str);
+        result += inf(ch);
+      }
+      if (negative)
+        result.negate();
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // constructors - mostly implemented in terms of the assignment operators
+
+  inf::inf(void)
+  {
+    // void constructor initialises to zero - represented as a single-byte value containing zero
+    m_data.append(1,std::string::value_type(0));
+  }
+
+  inf::inf(short r)
+  {
+    operator=(r);
+  }
+
+  inf::inf(unsigned short r)
+  {
+    operator=(r);
+  }
+
+  inf::inf(int r)
+  {
+    operator=(r);
+  }
+
+  inf::inf(unsigned r)
+  {
+    operator=(r);
+  }
+
+  inf::inf(long r)
+  {
+    operator=(r);
+  }
+
+  inf::inf(unsigned long r)
+  {
+    operator=(r);
+  }
+
+  inf::inf (const std::string& r) throw(std::invalid_argument)
+  {
+    operator=(r);
+  }
+
+  inf::inf(const inf& r)
+  {
+#ifdef __BORLANDC__
+    // work round bug in Borland compiler - copy constructor fails if string
+    // contains null characters, so do my own copy
+    for (unsigned i = 0; i < r.m_data.size(); i++)
+      m_data += r.m_data[i];
+#else
+    m_data = r.m_data;
+#endif
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  inf::~inf(void)
+  {
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // assignments convert from iteger types to internal representation
+
+  inf& inf::operator = (short r)
+  {
+    convert_from_signed(r, m_data);
+    return *this;
+  }
+
+  inf& inf::operator = (unsigned short r)
+  {
+    convert_from_unsigned(r, m_data);
+    return *this;
+  }
+
+  inf& inf::operator = (int r)
+  {
+    convert_from_signed(r, m_data);
+    return *this;
+  }
+
+  inf& inf::operator = (unsigned r)
+  {
+    convert_from_unsigned(r, m_data);
+    return *this;
+  }
+
+  inf& inf::operator = (long r)
+  {
+    convert_from_signed(r, m_data);
+    return *this;
+  }
+
+  inf& inf::operator = (unsigned long r)
+  {
+    convert_from_unsigned(r, m_data);
+    return *this;
+  }
+
+  inf& inf::operator = (const std::string& r) throw(std::invalid_argument)
+  {
+    convert_from_string(r, *this);
+    return *this;
+  }
+
+  inf& inf::operator = (const inf& r)
+  {
+    m_data = r.m_data;
+    return *this;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  short inf::to_short(bool truncate) const throw(std::overflow_error)
+  {
+    short result = 0;
+    if (!convert_to_signed(m_data, result))
+      if (!truncate)
+        throw std::overflow_error("stlplus::inf::to_short");
+    return result;
+  }
+
+  unsigned short inf::to_unsigned_short(bool truncate) const throw(std::overflow_error)
+  {
+    unsigned short result = 0;
+    if (!convert_to_unsigned(m_data, result))
+      if (!truncate)
+        throw std::overflow_error("stlplus::inf::to_unsigned_short");
+    return result;
+  }
+
+  int inf::to_int(bool truncate) const throw(std::overflow_error)
+  {
+    int result = 0;
+    if (!convert_to_signed(m_data, result))
+      if (!truncate)
+        throw std::overflow_error("stlplus::inf::to_int");
+    return result;
+  }
+
+  unsigned inf::to_unsigned(bool truncate) const throw(std::overflow_error)
+  {
+    unsigned result = 0;
+    if (!convert_to_unsigned(m_data, result))
+      if (!truncate)
+        throw std::overflow_error("stlplus::inf::to_unsigned");
+    return result;
+  }
+
+  long inf::to_long(bool truncate) const throw(std::overflow_error)
+  {
+    long result = 0;
+    if (!convert_to_signed(m_data, result))
+      if (!truncate)
+        throw std::overflow_error("stlplus::inf::to_long");
+    return result;
+  }
+
+  unsigned long inf::to_unsigned_long(bool truncate) const throw(std::overflow_error)
+  {
+    unsigned long result = 0;
+    if (!convert_to_unsigned(m_data, result))
+      if (!truncate)
+        throw std::overflow_error("stlplus::inf::to_unsigned_long");
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // resize the inf regardless of the data
+
+  void inf::resize(unsigned bits)
+  {
+    if (bits == 0) bits = 1;
+    unsigned bytes = (bits+7)/8;
+    byte extend = negative() ? byte(255) : byte (0);
+    while(bytes > m_data.size())
+      m_data.append(1,extend);
+  }
+
+  // reduce the bit count to the minimum needed to preserve the value
+
+  void inf::reduce(void)
+  {
+    reduce_string(m_data);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // the number of significant bits in the number
+
+  unsigned inf::bits (void) const
+  {
+    // The number of significant bits in the integer value - this is the number
+    // of indexable bits less any redundant sign bits at the msb
+    // This does not assume that the inf has been reduced to its minimum form
+    unsigned result = indexable_bits();
+    bool sign = bit(result-1);
+    while (result > 1 && (sign == bit(result-2)))
+      result--;
+    return result;
+  }
+
+  unsigned inf::size(void) const
+  {
+    return bits();
+  }
+
+  unsigned inf::indexable_bits (void) const
+  {
+    return 8 * unsigned(m_data.size());
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // bitwise operations
+
+  bool inf::bit (unsigned index) const throw(std::out_of_range)
+  {
+    if (index >= indexable_bits())
+      throw std::out_of_range(std::string("stlplus::inf::bit"));
+    // first split the offset into byte offset and bit offset
+    unsigned byte_offset = index/8;
+    unsigned bit_offset = index%8;
+    return (byte(m_data[byte_offset]) & (byte(1) << bit_offset)) != 0;
+  }
+
+  bool inf::operator [] (unsigned index) const throw(std::out_of_range)
+  {
+    return bit(index);
+  }
+
+  void inf::set (unsigned index)  throw(std::out_of_range)
+  {
+    if (index >= indexable_bits())
+      throw std::out_of_range(std::string("stlplus::inf::set"));
+    // first split the offset into byte offset and bit offset
+    unsigned byte_offset = index/8;
+    unsigned bit_offset = index%8;
+    m_data[byte_offset] |= (byte(1) << bit_offset);
+  }
+
+  void inf::clear (unsigned index)  throw(std::out_of_range)
+  {
+    if (index >= indexable_bits())
+      throw std::out_of_range(std::string("stlplus::inf::clear"));
+    // first split the offset into byte offset and bit offset
+    unsigned byte_offset = index/8;
+    unsigned bit_offset = index%8;
+    m_data[byte_offset] &= (~(byte(1) << bit_offset));
+  }
+
+  void inf::preset (unsigned index, bool value)  throw(std::out_of_range)
+  {
+    if (value)
+      set(index);
+    else
+      clear(index);
+  }
+
+  inf inf::slice(unsigned low, unsigned high) const throw(std::out_of_range)
+  {
+    if (low >= indexable_bits())
+      throw std::out_of_range(std::string("stlplus::inf::slice: low index"));
+    if (high >= indexable_bits())
+      throw std::out_of_range(std::string("stlplus::inf::slice: high index"));
+    inf result;
+    if (high >= low)
+    {
+      // create a result the right size and filled with sign bits
+      std::string::size_type result_size = (high-low+1+7)/8;
+      result.m_data.erase();
+      byte extend = bit(high) ? byte(255) : byte (0);
+      while (result.m_data.size() < result_size)
+        result.m_data.append(1,extend);
+      // now set the relevant bits
+      for (unsigned i = low; i <= high; i++)
+        result.preset(i-low, bit(i));
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // testing operations
+
+  bool inf::negative (void) const
+  {
+    return bit(indexable_bits()-1);
+  }
+
+  bool inf::natural (void) const
+  {
+    return !negative();
+  }
+
+  bool inf::positive (void) const
+  {
+    return natural() && !zero();
+  }
+
+  bool inf::zero (void) const
+  {
+    for (std::string::size_type i = 0; i < m_data.size(); i++)
+      if (m_data[i] != 0)
+        return false;
+    return true;
+  }
+
+  bool inf::non_zero (void) const
+  {
+    return !zero();
+  }
+
+  bool inf::operator ! (void) const
+  {
+    return zero();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // comparison operators
+
+  bool inf::operator == (const inf& r) const
+  {
+    // Two infs are equal if they are numerically equal, even if they are
+    // different sizes (i.e. they could be non-reduced values).
+    // This makes life a little more complicated than if I could assume that values were reduced.
+    byte l_extend = negative() ? byte(255) : byte (0);
+    byte r_extend = r.negative() ? byte(255) : byte (0);
+    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+    for (std::string::size_type i = bytes; i--; )
+    {
+      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+      if (l_byte != r_byte)
+        return false;
+    }
+    return true;
+  }
+
+  bool inf::operator != (const inf& r) const
+  {
+    return !operator==(r);
+  }
+
+  bool inf::operator < (const inf& r) const
+  {
+    // This could be implemented in terms of subtraction. However, it can be
+    // simplified since there is no need to calculate the accurate difference,
+    // just the direction of the difference. I compare from msB down and as
+    // soon as a byte difference is found, that defines the ordering. The
+    // problem is that in 2's-complement, all negative values are greater than
+    // all natural values if you just do a straight unsigned comparison. I
+    // handle this by doing a preliminary test for different signs.
+
+    // For example, a 3-bit signed type has the coding:
+    // 000 = 0
+    // ...
+    // 011 = 3
+    // 100 = -4
+    // ...
+    // 111 = -1
+
+    // So, for natural values, the ordering of the integer values is the
+    // ordering of the bit patterns. Similarly, for negative values, the
+    // ordering of the integer values is the ordering of the bit patterns
+    // However, the bit patterns for the negative values are *greater than*
+    // the natural values. This is a side-effect of the naffness of
+    // 2's-complement representation
+
+    // first handle the case of comparing two values with different signs
+    bool l_sign = negative();
+    bool r_sign = r.negative();
+    if (l_sign != r_sign)
+    {
+      // one argument must be negative and the other natural
+      // the left is less if it is the negative one
+      return l_sign;
+    }
+    // the arguments are the same sign
+    // so the ordering is a simple unsigned byte-by-byte comparison
+    // However, this is complicated by the possibility that the values could be different lengths
+    byte l_extend = l_sign ? byte(255) : byte (0);
+    byte r_extend = r_sign ? byte(255) : byte (0);
+    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+    for (std::string::size_type i = bytes; i--; )
+    {
+      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+      if (l_byte != r_byte)
+        return l_byte < r_byte;
+    }
+    // if I get here, the two are equal, so that is not less-than
+    return false;
+  }
+
+  bool inf::operator <= (const inf& r) const
+  {
+    return !(r < *this);
+  }
+
+  bool inf::operator > (const inf& r) const
+  {
+    return r < *this;
+  }
+
+  bool inf::operator >= (const inf& r) const
+  {
+    return !(*this < r);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // logical operators
+
+  inf& inf::invert (void)
+  {
+    for (std::string::size_type i = 0; i < m_data.size(); i++)
+      m_data[i] = ~m_data[i];
+    return *this;
+  }
+
+  inf inf::operator ~ (void) const
+  {
+    inf result(*this);
+    result.invert();
+    return result;
+  }
+
+  inf& inf::operator &= (const inf& r)
+  {
+    // bitwise AND is extended to the length of the largest argument
+    byte l_extend = negative() ? byte(255) : byte (0);
+    byte r_extend = r.negative() ? byte(255) : byte (0);
+    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+    for (std::string::size_type i = 0; i < bytes; i++)
+    {
+      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+      byte result = l_byte & r_byte;
+      if (i < m_data.size())
+        m_data[i] = result;
+      else
+        m_data.append(1,result);
+    }
+    // now reduce the result
+    reduce();
+    return *this;
+  }
+
+  inf inf::operator & (const inf& r) const
+  {
+    inf result(*this);
+    result &= r;
+    return result;
+  }
+
+  inf& inf::operator |= (const inf& r)
+  {
+    // bitwise OR is extended to the length of the largest argument
+    byte l_extend = negative() ? byte(255) : byte (0);
+    byte r_extend = r.negative() ? byte(255) : byte (0);
+    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+    for (std::string::size_type i = 0; i < bytes; i++)
+    {
+      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+      byte result = l_byte | r_byte;
+      if (i < m_data.size())
+        m_data[i] = result;
+      else
+        m_data.append(1,result);
+    }
+    // now reduce the result
+    reduce();
+    return *this;
+  }
+
+  inf inf::operator | (const inf& r) const
+  {
+    inf result(*this);
+    result |= r;
+    return result;
+  }
+
+  inf& inf::operator ^= (const inf& r)
+  {
+    // bitwise XOR is extended to the length of the largest argument
+    byte l_extend = negative() ? byte(255) : byte (0);
+    byte r_extend = r.negative() ? byte(255) : byte (0);
+    std::string::size_type bytes = maximum(m_data.size(),r.m_data.size());
+    for (std::string::size_type i = 0; i < bytes; i++)
+    {
+      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+      byte result = l_byte ^ r_byte;
+      if (i < m_data.size())
+        m_data[i] = result;
+      else
+        m_data.append(1,result);
+    }
+    // now reduce the result
+    reduce();
+    return *this;
+  }
+
+  inf inf::operator ^ (const inf& r) const
+  {
+    inf result(*this);
+    result ^= r;
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // shift operators all preserve the value by increasing the word size
+
+  inf& inf::operator <<= (unsigned shift)
+  {
+    // left shift is a shift towards the msb, with 0s being shifted in at the lsb
+    // split this into a byte shift followed by a bit shift
+
+    // first expand the value to be big enough for the result
+    std::string::size_type new_size = (indexable_bits() + shift + 7) / 8;
+    byte extend = negative() ? byte(255) : byte (0);
+    while (m_data.size() < new_size)
+      m_data.append(1,extend);
+    // now do the byte shift
+    unsigned byte_shift = shift/8;
+    if (byte_shift > 0)
+    {
+      for (std::string::size_type b = new_size; b--; )
+        m_data[b] = (b >= byte_shift) ? m_data[b-byte_shift] : byte(0);
+    }
+    // and finally the bit shift
+    unsigned bit_shift = shift%8;
+    if (bit_shift > 0)
+    {
+      for (std::string::size_type b = new_size; b--; )
+      {
+        byte current = byte(m_data[b]);
+        byte previous = b > 0 ? m_data[b-1] : byte(0);
+        m_data[b] = (current << bit_shift) | (previous >> (8 - bit_shift));
+      }
+    }
+    // now reduce the result
+    reduce();
+    return *this;
+  }
+
+  inf inf::operator << (unsigned shift) const
+  {
+    inf result(*this);
+    result <<= shift;
+    return result;
+  }
+
+  inf& inf::operator >>= (unsigned shift)
+  {
+    // right shift is a shift towards the lsb, with sign bits being shifted in at the msb
+    // split this into a byte shift followed by a bit shift
+
+    // a byte of sign bits
+    byte extend = negative() ? byte(255) : byte (0);
+    // do the byte shift
+    unsigned byte_shift = shift/8;
+    if (byte_shift > 0)
+    {
+      for (std::string::size_type b = 0; b < m_data.size(); b++)
+        m_data[b] = (b + byte_shift < m_data.size()) ? m_data[b+byte_shift] : extend;
+    }
+    // and finally the bit shift
+    unsigned bit_shift = shift%8;
+    if (bit_shift > 0)
+    {
+      for (std::string::size_type b = 0; b < m_data.size(); b++)
+      {
+        byte current = byte(m_data[b]);
+        byte next = ((b+1) < m_data.size()) ? m_data[b+1] : extend;
+        byte shifted = (current >> bit_shift) | (next << (8 - bit_shift));
+        m_data[b] = shifted;
+      }
+    }
+    // now reduce the result
+    reduce();
+    return *this;
+  }
+
+  inf inf::operator >> (unsigned shift) const
+  {
+    inf result(*this);
+    result >>= shift;
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // negation operators
+
+  inf& inf::negate (void)
+  {
+    // do 2's-complement negation
+    // equivalent to inversion plus one
+    invert();
+    operator += (inf(1));
+    return *this;
+  }
+
+  inf inf::operator - (void) const
+  {
+    inf result(*this);
+    result.negate();
+    return result;
+  }
+
+  inf& inf::abs(void)
+  {
+    if (negative()) negate();
+    return *this;
+  }
+
+  inf abs(const inf& i)
+  {
+    inf result = i;
+    result.abs();
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // addition operators
+
+  inf& inf::operator += (const inf& r)
+  {
+    // do 2's-complement addition
+    // Note that the addition can give a result that is larger than either argument
+    byte carry = 0;
+    std::string::size_type max_size = maximum(m_data.size(),r.m_data.size());
+    byte l_extend = negative() ? byte(255) : byte (0);
+    byte r_extend = r.negative() ? byte(255) : byte (0);
+    for (std::string::size_type i = 0; i < max_size; i++)
+    {
+      byte l_byte = (i < m_data.size() ? byte(m_data[i]) : l_extend);
+      byte r_byte = (i < r.m_data.size() ? byte(r.m_data[i]) : r_extend);
+      // calculate the addition in a type that is bigger than a byte in order to catch the carry-out
+      unsigned short result = ((unsigned short)(l_byte)) + ((unsigned short)(r_byte)) + carry;
+      // now truncate the result to get the lsB
+      if (i < m_data.size())
+        m_data[i] = byte(result);
+      else
+        m_data.append(1,byte(result));
+      // and capture the carry out by grabbing the second byte of the result
+      carry = byte(result >> 8);
+    }
+    // if the result overflowed or underflowed, add an extra byte to catch it
+    unsigned short result = ((unsigned short)(l_extend)) + ((unsigned short)(r_extend)) + carry;
+    if (byte(result) != (negative() ? byte(255) : byte(0)))
+      m_data.append(1,byte(result));
+    // now reduce the result
+    reduce();
+    return *this;
+  }
+
+  inf inf::operator + (const inf& r) const
+  {
+    inf result(*this);
+    result += r;
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // subtraction operators
+
+  inf& inf::operator -= (const inf& r)
+  {
+    // subtraction is defined in terms of negation and addition
+    inf negated = -r;
+    operator += (negated);
+    return *this;
+  }
+
+  inf inf::operator - (const inf& r) const
+  {
+    inf result(*this);
+    result -= r;
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // multiplication operators
+
+  inf& inf::operator *= (const inf& r)
+  {
+    // 2's complement multiplication
+    // one day I'll do a more efficient version than this based on the underlying representation
+    inf left(*this);
+    inf right = r;
+    // make the right value natural but preserve its sign for later
+    bool right_negative = right.negative();
+    right.abs();
+    // implemented as a series of conditional additions
+    operator = (0);
+    //  left.resize(right.bits() + left.bits() - 1);
+    left <<= right.bits()-1;
+    for (unsigned i = right.bits(); i--; )
+    {
+      if (right[i]) 
+        operator += (left);
+      left >>= 1;
+    }
+    if (right_negative)
+      negate();
+    // now reduce the result
+    reduce();
+    return *this;
+  }
+
+  inf inf::operator * (const inf& r) const
+  {
+    inf result(*this);
+    result *= r;
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // division and remainder operators
+
+  std::pair<inf,inf> inf::divide(const inf& right) const throw(divide_by_zero)
+  {
+    if (right.zero())
+      throw divide_by_zero("stlplus::inf::divide");
+    inf numerator(*this);
+    inf denominator = right;
+    // make the numerator natural but preserve the sign for later
+    bool numerator_negative = numerator.negative();
+    numerator.abs();
+    // same with the denominator
+    bool denominator_negative = denominator.negative();
+    denominator.abs();
+    // the quotient and remainder will form the result
+    // start with the quotiont zero and the remainder equal to the whole of the
+    // numerator, then do trial subtraction from this
+    inf quotient;
+    inf remainder = numerator;
+    // there's nothing more to do if the numerator is smaller than the denominator
+    // but otherwise do the division
+    if (numerator.bits() >= denominator.bits())
+    {
+      // make the quotient big enough to take the result
+      quotient.resize(numerator.bits());
+      // start with the numerator shifted to the far left
+      unsigned shift = numerator.bits() - denominator.bits();
+      denominator <<= shift;
+      // do the division by repeated subtraction, 
+      for (unsigned i = shift+1; i--; )
+      {
+        if (remainder >= denominator)
+        {
+          remainder -= denominator;
+          quotient.set(i);
+        }
+        denominator >>= 1;
+      }
+    }
+    // now adjust the signs 
+    // x/(-y) == (-x)/y == -(x/y)
+    if (numerator_negative != denominator_negative)
+      quotient.negate();
+    quotient.reduce();
+    // x%(-y) == x%y and (-x)%y == -(x%y)
+    if (numerator_negative)
+      remainder.negate();
+    remainder.reduce();
+    return std::pair<inf,inf>(quotient,remainder);
+  }
+
+  inf& inf::operator /= (const inf& r) throw(divide_by_zero)
+  {
+    std::pair<inf,inf> result = divide(r);
+    operator=(result.first);
+    return *this;
+  }
+
+  inf inf::operator / (const inf& r) const throw(divide_by_zero)
+  {
+    std::pair<inf,inf> result = divide(r);
+    return result.first;
+  }
+
+  inf& inf::operator %= (const inf& r) throw(divide_by_zero)
+  {
+    std::pair<inf,inf> result = divide(r);
+    operator=(result.second);
+    return *this;
+  }
+
+  inf inf::operator % (const inf& r) const throw(divide_by_zero)
+  {
+    std::pair<inf,inf> result = divide(r);
+    return result.second;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // prefix (void) and postfix (int) operators
+
+  inf& inf::operator ++ (void)
+  {
+    operator += (inf(1));
+    return *this;
+  }
+
+  inf inf::operator ++ (int)
+  {
+    inf old(*this);
+    operator += (inf(1));
+    return old;
+  }
+
+  inf& inf::operator -- (void)
+  {
+    operator -= (inf(1));
+    return *this;
+  }
+
+  inf inf::operator -- (int)
+  {
+    inf old(*this);
+    operator -= (inf(1));
+    return old;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // string representation and I/O routines
+
+  std::string inf::to_string(unsigned radix) const
+    throw(std::invalid_argument)
+  {
+    std::string result;
+    convert_to_string(*this, result, radix);
+    return result;
+  }
+
+  inf& inf::from_string(const std::string& value, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    convert_from_string(value, *this, radix);
+    return *this;
+  }
+
+  std::ostream& operator << (std::ostream& str, const inf& i)
+  {
+    try
+    {
+      // get radix
+      unsigned radix = 10;
+      if (str.flags() & std::ios_base::oct)
+        radix = 8;
+      if (str.flags() & std::ios_base::hex)
+        radix = 16;
+      // the field width is handled by iostream, so I don't need to handle it as well
+      // generate the string representation then print it
+      str << i.to_string(radix);
+    }
+    catch(const std::invalid_argument)
+    {
+      str.setstate(std::ios_base::badbit);
+    }
+    return str;
+  }
+
+  std::istream& operator >> (std::istream& str, inf& i)
+  {
+    try
+    {
+      // get radix
+      unsigned radix = 10;
+      if (str.flags() & std::ios_base::oct)
+        radix = 8;
+      if (str.flags() & std::ios_base::hex)
+        radix = 16;
+      // now get the string image of the value
+      std::string image;
+      str >> image;
+      // and convert to inf
+      i.from_string(image, radix);
+    }
+    catch(const std::invalid_argument)
+    {
+      str.setstate(std::ios_base::badbit);
+    }
+    return str;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // diagnostic dump
+  // just convert to hex
+
+  std::string inf::image_debug(void) const
+  {
+    // create this dump in the human-readable form, i.e. msB to the left
+    std::string result = "0x";
+    for (std::string::size_type i = m_data.size(); i--; )
+    {
+      byte current = m_data[i];
+      byte msB = (current & byte(0xf0)) >> 4;
+      result += to_char[msB];
+      byte lsB = (current & byte(0x0f));
+      result += to_char[lsB];
+    }
+    return result;
+  }
+
+  const std::string& inf::get_bytes(void) const
+  {
+    return m_data;
+  }
+
+  void inf::set_bytes(const std::string& data)
+  {
+    m_data = data;
+  }
+
+} // end namespace stlplus
index f28541af6bf9ce7083ffb4f7b26aeb9c8f807321..c20acd4c7109be19f57d90d8f3f4b849dc6015f7 100644 (file)
-#ifndef STLPLUS_INF\r
-#define STLPLUS_INF\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   An infinite-precision integer class. This allows calculations on large\r
-//   integers to be performed without overflow.\r
-\r
-//   this class can throw the following exceptions:\r
-//     std::out_of_range\r
-//     std::overflow_error\r
-//     std::invalid_argument\r
-//     stlplus::divide_by_zero    // why doesn't std have this?\r
-//   all of these are derivations of the baseclass:\r
-//     std::logic_error\r
-//   So you can catch all of them by catching the baseclass\r
-\r
-//   Warning: inf was never intended to be fast, it is just for programs which\r
-//   need a bit of infinite-precision integer arithmetic. For high-performance\r
-//   processing, use the Gnu Multi-Precision (GMP) library. The inf type is just\r
-//   easier to integrate and is already ported to all platforms and compilers\r
-//   that STLplus is ported to.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include "portability_exceptions.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class inf\r
-  {\r
-  public:\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // constructors and assignments initialise the inf\r
-\r
-    // the void constructor initialises to zero, the others initialise to the\r
-    // value of the C integer type or the text value contained in the string\r
-\r
-    inf(void);\r
-    explicit inf(short);\r
-    explicit inf(unsigned short);\r
-    explicit inf(int);\r
-    explicit inf(unsigned);\r
-    explicit inf(long);\r
-    explicit inf(unsigned long);\r
-    explicit inf(const std::string&) throw(std::invalid_argument);\r
-    inf(const inf&);\r
-\r
-    ~inf(void);\r
-\r
-    // assignments with equivalent behaviour to the constructors\r
-\r
-    inf& operator = (short);\r
-    inf& operator = (unsigned short);\r
-    inf& operator = (int);\r
-    inf& operator = (unsigned);\r
-    inf& operator = (long);\r
-    inf& operator = (unsigned long);\r
-    inf& operator = (const std::string&) throw(std::invalid_argument);\r
-    inf& operator = (const inf&);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // conversions back to the C types\r
-    // truncate: controls the behaviour when the value is too long for the result\r
-    //           true: truncate the value\r
-    //           false: throw an exception\r
-\r
-    short to_short(bool truncate = true) const throw(std::overflow_error);\r
-    unsigned short to_unsigned_short(bool truncate = true) const throw(std::overflow_error);\r
-\r
-    int to_int(bool truncate = true) const throw(std::overflow_error);\r
-    unsigned to_unsigned(bool truncate = true) const throw(std::overflow_error);\r
-\r
-    long to_long(bool truncate = true) const throw(std::overflow_error);\r
-    unsigned long to_unsigned_long(bool truncate = true) const throw(std::overflow_error);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // bitwise manipulation\r
-\r
-    void resize(unsigned bits);\r
-    void reduce(void);\r
-\r
-    // the number of significant bits in the value\r
-    unsigned bits (void) const;\r
-    unsigned size (void) const;\r
-\r
-    // the number of bits that can be accessed by the bit() method (=bits() rounded up to the next byte)\r
-    unsigned indexable_bits(void) const;\r
-\r
-    bool bit (unsigned index) const throw(std::out_of_range);\r
-    bool operator [] (unsigned index) const throw(std::out_of_range);\r
-\r
-    void set (unsigned index) throw(std::out_of_range);\r
-    void clear (unsigned index) throw(std::out_of_range);\r
-    void preset (unsigned index, bool value) throw(std::out_of_range);\r
-\r
-    inf slice(unsigned low, unsigned high) const throw(std::out_of_range);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // tests for common values or ranges\r
-\r
-    bool negative (void) const;\r
-    bool natural (void) const;\r
-    bool positive (void) const;\r
-    bool zero (void) const;\r
-    bool non_zero (void) const;\r
-\r
-    // tests used in if(i) and if(!i)\r
-//  operator bool (void) const;\r
-    bool operator ! (void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // comparisons\r
-\r
-    bool operator == (const inf&) const;\r
-    bool operator != (const inf&) const;\r
-    bool operator < (const inf&) const;\r
-    bool operator <= (const inf&) const;\r
-    bool operator > (const inf&) const;\r
-    bool operator >= (const inf&) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // bitwise logic operations\r
-\r
-    inf& invert (void);\r
-    inf operator ~ (void) const;\r
-\r
-    inf& operator &= (const inf&);\r
-    inf operator & (const inf&) const;\r
-\r
-    inf& operator |= (const inf&);\r
-    inf operator | (const inf&) const;\r
-\r
-    inf& operator ^= (const inf&);\r
-    inf operator ^ (const inf&) const;\r
-\r
-    inf& operator <<= (unsigned shift);\r
-    inf operator << (unsigned shift) const;\r
-\r
-    inf& operator >>= (unsigned shift);\r
-    inf operator >> (unsigned shift) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // arithmetic operations\r
-\r
-    inf& negate (void);\r
-    inf operator - (void) const;\r
-\r
-    inf& abs(void);\r
-    friend inf abs(const inf&);\r
-\r
-    inf& operator += (const inf&);\r
-    inf operator + (const inf&) const;\r
-\r
-    inf& operator -= (const inf&);\r
-    inf operator - (const inf&) const;\r
-\r
-    inf& operator *= (const inf&);\r
-    inf operator * (const inf&) const;\r
-\r
-    inf& operator /= (const inf&) throw(divide_by_zero);\r
-    inf operator / (const inf&) const throw(divide_by_zero);\r
-\r
-    inf& operator %= (const inf&) throw(divide_by_zero);\r
-    inf operator % (const inf&) const throw(divide_by_zero);\r
-\r
-    // combined division operator - returns the result pair(quotient,remainder) in one go\r
-    std::pair<inf,inf> divide(const inf&) const throw(divide_by_zero);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // pre- and post- increment and decrement\r
-\r
-    inf& operator ++ (void);\r
-    inf operator ++ (int);\r
-    inf& operator -- (void);\r
-    inf operator -- (int);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // string representation and I/O\r
-\r
-    std::string image_debug(void) const;\r
-\r
-    // conversion to a string representation\r
-    // radix must be 10, 2, 8 or 16\r
-    std::string to_string(unsigned radix = 10) const\r
-      throw(std::invalid_argument);\r
-\r
-    // conversion from a string\r
-    // radix == 0 - radix is deduced from the input - assumed 10 unless number is prefixed by 0b, 0 or 0x\r
-    // however, you can specify the radix to be 10, 2, 8 or 16 to force that interpretation\r
-    inf& from_string(const std::string&, unsigned radix = 0)\r
-      throw(std::invalid_argument);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-  private:\r
-    std::string m_data;\r
-  public:\r
-    const std::string& get_bytes(void) const;\r
-    void set_bytes(const std::string&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // redefine friends for gcc v4.1\r
-\r
-  inf abs(const inf&);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::ostream& operator << (std::ostream&, const inf&);\r
-  std::istream& operator >> (std::istream&, inf&);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_INF
+#define STLPLUS_INF
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   An infinite-precision integer class. This allows calculations on large
+//   integers to be performed without overflow.
+
+//   this class can throw the following exceptions:
+//     std::out_of_range
+//     std::overflow_error
+//     std::invalid_argument
+//     stlplus::divide_by_zero    // why doesn't std have this?
+//   all of these are derivations of the baseclass:
+//     std::logic_error
+//   So you can catch all of them by catching the baseclass
+
+//   Warning: inf was never intended to be fast, it is just for programs which
+//   need a bit of infinite-precision integer arithmetic. For high-performance
+//   processing, use the Gnu Multi-Precision (GMP) library. The inf type is just
+//   easier to integrate and is already ported to all platforms and compilers
+//   that STLplus is ported to.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include "portability_exceptions.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+////////////////////////////////////////////////////////////////////////////////
+
+  class inf
+  {
+  public:
+
+    //////////////////////////////////////////////////////////////////////////////
+    // constructors and assignments initialise the inf
+
+    // the void constructor initialises to zero, the others initialise to the
+    // value of the C integer type or the text value contained in the string
+
+    inf(void);
+    explicit inf(short);
+    explicit inf(unsigned short);
+    explicit inf(int);
+    explicit inf(unsigned);
+    explicit inf(long);
+    explicit inf(unsigned long);
+    explicit inf(const std::string&) throw(std::invalid_argument);
+    inf(const inf&);
+
+    ~inf(void);
+
+    // assignments with equivalent behaviour to the constructors
+
+    inf& operator = (short);
+    inf& operator = (unsigned short);
+    inf& operator = (int);
+    inf& operator = (unsigned);
+    inf& operator = (long);
+    inf& operator = (unsigned long);
+    inf& operator = (const std::string&) throw(std::invalid_argument);
+    inf& operator = (const inf&);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // conversions back to the C types
+    // truncate: controls the behaviour when the value is too long for the result
+    //           true: truncate the value
+    //           false: throw an exception
+
+    short to_short(bool truncate = true) const throw(std::overflow_error);
+    unsigned short to_unsigned_short(bool truncate = true) const throw(std::overflow_error);
+
+    int to_int(bool truncate = true) const throw(std::overflow_error);
+    unsigned to_unsigned(bool truncate = true) const throw(std::overflow_error);
+
+    long to_long(bool truncate = true) const throw(std::overflow_error);
+    unsigned long to_unsigned_long(bool truncate = true) const throw(std::overflow_error);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // bitwise manipulation
+
+    void resize(unsigned bits);
+    void reduce(void);
+
+    // the number of significant bits in the value
+    unsigned bits (void) const;
+    unsigned size (void) const;
+
+    // the number of bits that can be accessed by the bit() method (=bits() rounded up to the next byte)
+    unsigned indexable_bits(void) const;
+
+    bool bit (unsigned index) const throw(std::out_of_range);
+    bool operator [] (unsigned index) const throw(std::out_of_range);
+
+    void set (unsigned index) throw(std::out_of_range);
+    void clear (unsigned index) throw(std::out_of_range);
+    void preset (unsigned index, bool value) throw(std::out_of_range);
+
+    inf slice(unsigned low, unsigned high) const throw(std::out_of_range);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // tests for common values or ranges
+
+    bool negative (void) const;
+    bool natural (void) const;
+    bool positive (void) const;
+    bool zero (void) const;
+    bool non_zero (void) const;
+
+    // tests used in if(i) and if(!i)
+//  operator bool (void) const;
+    bool operator ! (void) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // comparisons
+
+    bool operator == (const inf&) const;
+    bool operator != (const inf&) const;
+    bool operator < (const inf&) const;
+    bool operator <= (const inf&) const;
+    bool operator > (const inf&) const;
+    bool operator >= (const inf&) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // bitwise logic operations
+
+    inf& invert (void);
+    inf operator ~ (void) const;
+
+    inf& operator &= (const inf&);
+    inf operator & (const inf&) const;
+
+    inf& operator |= (const inf&);
+    inf operator | (const inf&) const;
+
+    inf& operator ^= (const inf&);
+    inf operator ^ (const inf&) const;
+
+    inf& operator <<= (unsigned shift);
+    inf operator << (unsigned shift) const;
+
+    inf& operator >>= (unsigned shift);
+    inf operator >> (unsigned shift) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // arithmetic operations
+
+    inf& negate (void);
+    inf operator - (void) const;
+
+    inf& abs(void);
+    friend inf abs(const inf&);
+
+    inf& operator += (const inf&);
+    inf operator + (const inf&) const;
+
+    inf& operator -= (const inf&);
+    inf operator - (const inf&) const;
+
+    inf& operator *= (const inf&);
+    inf operator * (const inf&) const;
+
+    inf& operator /= (const inf&) throw(divide_by_zero);
+    inf operator / (const inf&) const throw(divide_by_zero);
+
+    inf& operator %= (const inf&) throw(divide_by_zero);
+    inf operator % (const inf&) const throw(divide_by_zero);
+
+    // combined division operator - returns the result pair(quotient,remainder) in one go
+    std::pair<inf,inf> divide(const inf&) const throw(divide_by_zero);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // pre- and post- increment and decrement
+
+    inf& operator ++ (void);
+    inf operator ++ (int);
+    inf& operator -- (void);
+    inf operator -- (int);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // string representation and I/O
+
+    std::string image_debug(void) const;
+
+    // conversion to a string representation
+    // radix must be 10, 2, 8 or 16
+    std::string to_string(unsigned radix = 10) const
+      throw(std::invalid_argument);
+
+    // conversion from a string
+    // radix == 0 - radix is deduced from the input - assumed 10 unless number is prefixed by 0b, 0 or 0x
+    // however, you can specify the radix to be 10, 2, 8 or 16 to force that interpretation
+    inf& from_string(const std::string&, unsigned radix = 0)
+      throw(std::invalid_argument);
+
+    //////////////////////////////////////////////////////////////////////////////
+  private:
+    std::string m_data;
+  public:
+    const std::string& get_bytes(void) const;
+    void set_bytes(const std::string&);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // redefine friends for gcc v4.1
+
+  inf abs(const inf&);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::ostream& operator << (std::ostream&, const inf&);
+  std::istream& operator >> (std::istream&, inf&);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 6dc1fada2bb40ccb29e5b4baa9a7da6d6f96b169..0db880ee3752848ec75660a0455baf8df94ce20f 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Author:    Andy Rushton\r
-// Copyright: (c) Southampton University 1999-2004\r
-//            (c) Andy Rushton           2004-2009\r
-// License:   BSD License, see ../docs/license.html\r
-\r
-// Contains all the platform-specific socket handling used by the TCP and UDP classes\r
-\r
-// TODO - any conversion required to support IPv6\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "ip_sockets.hpp"\r
-#include "dprintf.hpp"\r
-#include <string.h>\r
-\r
-#ifdef MSWINDOWS\r
-// Windoze-specific includes\r
-#include <winsock2.h>\r
-#define ERRNO WSAGetLastError()\r
-#define HERRNO WSAGetLastError()\r
-#define IOCTL ioctlsocket\r
-#define CLOSE closesocket\r
-#define SHUT_RDWR SD_BOTH\r
-#define EINPROGRESS WSAEINPROGRESS\r
-#define EWOULDBLOCK WSAEWOULDBLOCK\r
-#define ECONNRESET WSAECONNRESET\r
-#define SOCKLEN_T int\r
-#else\r
-// Generic Unix includes\r
-// fix for older versions of Darwin?\r
-#define _BSD_SOCKLEN_T_ int\r
-#include <sys/types.h>\r
-#include <sys/socket.h>\r
-#include <sys/ioctl.h>\r
-#include <sys/time.h>\r
-#include <netinet/in.h>\r
-#include <errno.h>\r
-#include <netdb.h>\r
-#include <unistd.h>\r
-#define INVALID_SOCKET -1\r
-#define ERRNO errno\r
-#define HERRNO h_errno\r
-#define SOCKET int\r
-#define SOCKET_ERROR -1\r
-#define IOCTL ::ioctl\r
-#define CLOSE ::close\r
-#define SOCKLEN_T socklen_t\r
-#ifdef SOLARIS\r
-// Sun put some definitions in a different place\r
-#include <sys/filio.h>\r
-#endif\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Utilities\r
-\r
-  // get an operating-system error message given an error code\r
-  static std::string error_string(int error)\r
-  {\r
-    std::string result = "error " + dformat("%d",error);\r
-#ifdef MSWINDOWS\r
-    char* message = 0;\r
-    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,\r
-                  0,\r
-                  error,\r
-                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // "User default language"\r
-                  (LPTSTR)&message,\r
-                  0,0);\r
-    if (message) \r
-    {\r
-      result = message;\r
-      LocalFree(message);\r
-    }\r
-    // the error message is for some perverse reason newline terminated - remove this\r
-    if (result[result.size()-1] == '\n')\r
-      result.erase(result.end()-1);\r
-    if (result[result.size()-1] == '\r')\r
-      result.erase(result.end()-1);\r
-#else\r
-    char* message = strerror(error);\r
-    if (message && message[0])\r
-      result = message;\r
-#endif\r
-    return result;\r
-  }\r
-\r
-  // convert address:port into a sockaddr\r
-  static void convert_address(unsigned long address, unsigned short port, sockaddr& sa)\r
-  {\r
-    sa.sa_family = AF_INET;\r
-    unsigned short network_port = htons(port);\r
-    memcpy(&sa.sa_data[0], &network_port, sizeof(network_port));\r
-    unsigned long network_address = htonl(address);\r
-    memcpy(&sa.sa_data[2], &network_address, sizeof(network_address));\r
-  }\r
-\r
-//   // convert host:port into a sockaddr\r
-//   static void convert_host(hostent& host, unsigned short port, sockaddr& sa)\r
-//   {\r
-//     sa.sa_family = host.h_addrtype;\r
-//     unsigned short network_port = htons(port);\r
-//     memcpy(&sa.sa_data[0], &network_port, sizeof(network_port));\r
-//     memcpy(&sa.sa_data[2], host.h_addr, host.h_length);\r
-//   }\r
-\r
-  // convert sockaddr to address:port\r
-  static void convert_sockaddr(const sockaddr& sa, unsigned long& address, unsigned short& port)\r
-  {\r
-    unsigned short network_port = 0;\r
-    memcpy(&network_port, &sa.sa_data[0], sizeof(network_port));\r
-    port = ntohs(network_port);\r
-    unsigned long network_address = 0;\r
-    memcpy(&network_address, &sa.sa_data[2], sizeof(network_address));\r
-    address = ntohl(network_address);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Initialisation\r
-  // Windows requires that Winsock is initialised before use and closed after\r
-  // These routines initialise once on first use and close on the destruction of the last object using it\r
-  // on non-windows platforms, I still increment/decrement the sockets count variable for diagnostic purposes\r
-\r
-  static int sockets_count = 0;\r
-\r
-  static int sockets_init(void)\r
-  {\r
-    int error = 0;\r
-    if (sockets_count++ == 0)\r
-    {\r
-#ifdef MSWINDOWS\r
-      WSAData winsock_info;\r
-      // request Winsock 2.0 or higher\r
-      error = WSAStartup(MAKEWORD(2,0),&winsock_info);\r
-#endif\r
-    }\r
-    return error;\r
-  }\r
-\r
-  static int sockets_close(void)\r
-  {\r
-    int error = 0;\r
-    if (--sockets_count == 0)\r
-    {\r
-#ifdef MSWINDOWS\r
-      if (WSACleanup() == SOCKET_ERROR)\r
-        error = ERRNO;\r
-#endif\r
-    }\r
-    return error;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Socket Implementation - common code to manipulate a TCP socket\r
-\r
-  class IP_socket_internals\r
-  {\r
-  private:\r
-    IP_socket_type m_type;\r
-    SOCKET m_socket;\r
-    unsigned long m_remote_address;\r
-    unsigned short m_remote_port;\r
-    mutable int m_error;\r
-    mutable std::string m_message;\r
-    unsigned m_count;\r
-\r
-    // disable copying of the internals\r
-    IP_socket_internals(const IP_socket_internals&);\r
-    IP_socket_internals& operator=(const IP_socket_internals&);\r
-\r
-  public:\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // PIMPL alias counting \r
-\r
-    void increment(void)\r
-      {\r
-        ++m_count;\r
-      }\r
-\r
-    bool decrement(void)\r
-      {\r
-        --m_count;\r
-        return m_count == 0;\r
-      }\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // constructors/destructors\r
-\r
-    // construct an invalid socket\r
-    IP_socket_internals(void) : m_type(undefined_socket_type), m_socket(INVALID_SOCKET), m_error(0), m_count(1)\r
-      {\r
-        set_error(sockets_init());\r
-      }\r
-\r
-    // close on destroy\r
-    ~IP_socket_internals(void)\r
-      {\r
-        close();\r
-        set_error(sockets_close());\r
-      }\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // initialisation, connection\r
-\r
-    bool initialised(void) const\r
-      {\r
-        return m_socket != INVALID_SOCKET;\r
-      }\r
-\r
-    // attach this object to a pre-opened socket\r
-    bool set(SOCKET socket, unsigned long remote_address, unsigned short remote_port)\r
-      {\r
-        if (initialised()) close();\r
-        clear_error();\r
-        m_socket = socket;\r
-        m_remote_address = remote_address;\r
-        m_remote_port = remote_port;\r
-        return true;\r
-      }\r
-\r
-    // create a raw socket attached to this object\r
-    bool initialise(IP_socket_type type)\r
-      {\r
-        if (initialised()) close();\r
-        clear_error();\r
-        if ((type != TCP) && (type != UDP))\r
-        {\r
-          set_error(-1, "Illegal socket type");\r
-          return false;\r
-        }\r
-        // create an anonymous socket\r
-        m_socket = ::socket(AF_INET, ((type == TCP) ? SOCK_STREAM : SOCK_DGRAM), 0);\r
-        if (m_socket == INVALID_SOCKET)\r
-        {\r
-          set_error(ERRNO);\r
-          close();\r
-          return false;\r
-        }\r
-        // record the type on success only\r
-        m_type = type;\r
-        // set the socket into non-blocking mode\r
-        unsigned long nonblocking = 1;\r
-        if (IOCTL(m_socket, FIONBIO, &nonblocking) == SOCKET_ERROR)\r
-        {\r
-          set_error(ERRNO);\r
-          return false;\r
-        }\r
-        return true;\r
-      }\r
-    \r
-    // function for performing IP lookup (i.e. gethostbyname)\r
-    // could be standalone but making it a member means that it can use the socket's error handler\r
-    // - remote_address: IP name or number\r
-    // - returns the IP address as a number - zero if there's an error\r
-    unsigned long ip_lookup(const std::string& remote_address)\r
-      {\r
-        unsigned long result = 0;\r
-        // Lookup the IP address to convert it into a host record\r
-        // this DOES lookup IP address names as well (not according to MS help !!)\r
-        // TODO - convert this to use ::getaddrinfo - ::gethostbyname is deprecated\r
-        hostent* host_info = ::gethostbyname(remote_address.c_str());\r
-        if (!host_info)\r
-        {\r
-          set_error(HERRNO);\r
-          return 0;\r
-        }\r
-        // extract the address from the host info\r
-        unsigned long network_address = 0;\r
-        memcpy(&network_address, host_info->h_addr, host_info->h_length);\r
-        result = ntohl(network_address);\r
-        return result;\r
-      }\r
-\r
-    // tests whether a socket is ready for communication\r
-    bool select(bool readable, bool writeable, unsigned wait)\r
-      {\r
-        if (!initialised()) return false;\r
-        // set up the readable set\r
-        fd_set readable_set;\r
-        fd_set* readable_set_ptr = 0;\r
-        if (readable)\r
-        {\r
-          FD_ZERO(&readable_set);\r
-          FD_SET(m_socket,&readable_set);\r
-          readable_set_ptr = &readable_set;\r
-        }\r
-        // set up the writeable set\r
-        fd_set writeable_set;\r
-        fd_set* writeable_set_ptr = 0;\r
-        if (writeable)\r
-        {\r
-          FD_ZERO(&writeable_set);\r
-          FD_SET(m_socket,&writeable_set);\r
-          writeable_set_ptr = &writeable_set;\r
-        }\r
-        // TODO - check the error set and lookup the error?\r
-        fd_set* error_set_ptr = 0;\r
-        // set up the timout value\r
-        // Note: a null pointer implements a blocking select\r
-        //       a pointer to a zero value implements a zero-wait poll\r
-        //       a pointer to a positive value implements a poll with a timeout\r
-        // I currently only implement polling with timeout which may be zero  - no blocking\r
-        timeval timeout;\r
-        timeval* timeout_ptr = 0;\r
-        timeout.tv_sec = wait/1000000;\r
-        timeout.tv_usec = wait%1000000;\r
-        timeout_ptr = &timeout;\r
-        // now test the socket\r
-        int select_result = ::select(m_socket+1, readable_set_ptr, writeable_set_ptr, error_set_ptr, timeout_ptr);\r
-        switch(select_result)\r
-        {\r
-        case SOCKET_ERROR:\r
-          // select failed with an error - trap the error\r
-          set_error(ERRNO);\r
-          return false;\r
-        case 0:\r
-          // timeout exceeded without a connection appearing\r
-          return false;\r
-        default:\r
-          // at least one connection is pending\r
-          // TODO - do we need to do the extra socket options checking on Posix?\r
-          // TODO - does this connect in any way to the error_set above?\r
-          return true;\r
-        }\r
-      }\r
-\r
-    // bind the socket to a port so that it can receive from specific address\r
-    bool bind(unsigned long remote_address, unsigned short local_port)\r
-      {\r
-        if (!initialised()) return false;\r
-        // name the socket and bind it to a port - this is a requirement for a server\r
-        sockaddr server;\r
-        convert_address(INADDR_ANY, local_port, server);\r
-        if (::bind(m_socket, &server, sizeof(server)) == SOCKET_ERROR)\r
-        {\r
-          set_error(ERRNO);\r
-          close();\r
-          return false;\r
-        }\r
-        return true;\r
-      }\r
-    \r
-    // bind the socket to a port so that it can receive from any address\r
-    bool bind_any(unsigned short local_port)\r
-      {\r
-        return bind(INADDR_ANY, local_port);\r
-      }\r
-\r
-    // set this socket up to be a listening port\r
-    // must have been bound to a local port already\r
-    // - length of backlog queue to manage - may be zero\r
-    // - returns success status\r
-    bool listen(unsigned short queue)\r
-      {\r
-        if (!initialised()) return false;\r
-        // set the port to listen for incoming connections\r
-        if (::listen(m_socket, (int)queue) == SOCKET_ERROR)\r
-        {\r
-          set_error(ERRNO);\r
-          close();\r
-          return false;\r
-        }\r
-        return true;\r
-      }\r
-\r
-    // test whether there's an incoming connection on the socket\r
-    // only applicable if it has been set up as a listening port\r
-    bool accept_ready(unsigned wait)\r
-      {\r
-        // the test for a connection being ready is the same as the test for whether the socket is readable\r
-        // see documentation for select\r
-        return select(true, false, wait);\r
-      }\r
-\r
-    // accept a connection on the socket\r
-    // only applicable if it has been set up as a listening port\r
-    // - returns socket filled in with the accepted connection's details - or with the error fields set\r
-    IP_socket accept(void)\r
-      {\r
-        if (!initialised()) return IP_socket();\r
-        IP_socket result;\r
-        // accept the connection, at the same time getting the address of the connecting client\r
-        sockaddr saddress;\r
-        SOCKLEN_T saddress_length = sizeof(saddress);\r
-        SOCKET socket = ::accept(m_socket, &saddress, &saddress_length);\r
-        if (socket == INVALID_SOCKET)\r
-        {\r
-          // only set the result socket with an error\r
-          result.m_impl->set_error(ERRNO);\r
-          return result;\r
-        }\r
-        // extract the contents of the address\r
-        unsigned long remote_address = 0;\r
-        unsigned short remote_port = 0;\r
-        convert_sockaddr(saddress, remote_address, remote_port);\r
-        result.m_impl->set(socket, remote_address, remote_port);\r
-        return result;\r
-      }\r
-\r
-    // client connect to a server\r
-    // - remote_address: IP number of remote address to connect to\r
-    // - remote_port: port to connect to\r
-    bool connect(unsigned long remote_address, unsigned short remote_port)\r
-      {\r
-        if (!initialised()) return false;\r
-        // fill in the connection data structure\r
-        sockaddr connect_data;\r
-        convert_address(remote_address, remote_port, connect_data);\r
-        // connect binds the socket to a local address\r
-        // if connectionless it simply sets the default remote address\r
-        // if connectioned it makes the connection\r
-        if (::connect(m_socket, &connect_data, sizeof(connect_data)) == SOCKET_ERROR)\r
-        {\r
-          // the socket is non-blocking, so connect will almost certainly fail with EINPROGRESS which is not an error\r
-          // only catch real errors\r
-          int error = ERRNO;\r
-          if (error != EINPROGRESS && error != EWOULDBLOCK)\r
-          {\r
-            set_error(error);\r
-            return false;\r
-          }\r
-        }\r
-        // extract the remote connection details for local storage\r
-        convert_sockaddr(connect_data, m_remote_address, m_remote_port);\r
-        return true;\r
-      }\r
-\r
-    // test whether a socket is connected and ready to communicate\r
-    bool connected(unsigned wait)\r
-      {\r
-        if (!initialised()) return false;\r
-        // Linux and Windows docs say test with select for whether socket is\r
-        // writable. However, a problem has been reported with Linux whereby\r
-        // the OS will report a socket as writable when it isn't\r
-        // first use the select method\r
-        if (!select(false, true, wait))\r
-          return false;\r
-#ifdef MSWINDOWS\r
-        // Windows needs no further processing - select method works\r
-        return true;\r
-#else\r
-        // Posix version needs further checking using the socket options\r
-        // DJDM: socket has returned EINPROGRESS on the first attempt at connection\r
-        // it has also returned that it can be written to\r
-        // we must now ask it if it has actually connected - using getsockopt\r
-        int error = 0;\r
-        socklen_t serror = sizeof(int);\r
-        if (::getsockopt(m_socket, SOL_SOCKET, SO_ERROR, &error, &serror)==0)\r
-          // handle the error value - one of them means that the socket has connected\r
-          if (!error || error == EISCONN)\r
-            return true;\r
-        return false;\r
-#endif\r
-      }\r
-\r
-    bool close(void)\r
-      {\r
-        bool result = true;\r
-        if (initialised())\r
-        {\r
-          if (shutdown(m_socket,SHUT_RDWR) == SOCKET_ERROR)\r
-          {\r
-            set_error(ERRNO);\r
-            result = false;\r
-          }\r
-          if (CLOSE(m_socket) == SOCKET_ERROR)\r
-          {\r
-            set_error(ERRNO);\r
-            result = false;\r
-          }\r
-        }\r
-        m_socket = INVALID_SOCKET;\r
-        m_remote_address = 0;\r
-        m_remote_port = 0;\r
-        return result;\r
-      }\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // sending/receiving\r
-\r
-    bool send_ready(unsigned wait)\r
-      {\r
-        // determines whether the socket is ready to send by testing whether it is writable\r
-        return select(false, true, wait);\r
-      }\r
-\r
-    bool send (std::string& data)\r
-      {\r
-        if (!initialised()) return false;\r
-        // send the data - this will never block but may not send all the data\r
-        int bytes = ::send(m_socket, data.c_str(), data.size(), 0);\r
-        if (bytes == SOCKET_ERROR)\r
-        {\r
-          set_error(ERRNO);\r
-          return false;\r
-        }\r
-        // remove the sent bytes from the data buffer so that the buffer represents the data still to be sent\r
-        data.erase(0,bytes);\r
-        return true;\r
-      }\r
-\r
-    bool send_packet(std::string& data, unsigned long address = 0, unsigned short port = 0)\r
-      {\r
-        if (!initialised()) return false;\r
-        // if no address specified, rely on the socket having been connected (can I test this?)\r
-        // so use the standard send, otherwise use the sendto function\r
-        int bytes = 0;\r
-        if (!address)\r
-        {\r
-          bytes = ::send(m_socket, data.c_str(), data.size(), 0);\r
-        }\r
-        else\r
-        {\r
-          sockaddr saddress;\r
-          convert_address(address, port, saddress);\r
-          bytes = ::sendto(m_socket, data.c_str(), data.size(), 0, &saddress, sizeof(saddress));\r
-        }\r
-        if (bytes == SOCKET_ERROR)\r
-        {\r
-          set_error(ERRNO);\r
-          return false;\r
-        }\r
-        // remove the sent bytes from the data buffer so that the buffer represents the data still to be sent\r
-        data.erase(0,bytes);\r
-        return true;\r
-      }\r
-\r
-    bool receive_ready(unsigned wait)\r
-      {\r
-        // determines whether the socket is ready to receive by testing whether it is readable\r
-        return select(true, false, wait);\r
-      }\r
-\r
-    bool receive (std::string& data)\r
-      {\r
-        if (!initialised()) return false;\r
-        // determine how much data is available to read\r
-        unsigned long bytes = 0;\r
-        if (IOCTL(m_socket, FIONREAD, &bytes) == SOCKET_ERROR)\r
-        {\r
-          set_error(ERRNO);\r
-          return false;\r
-        }\r
-        // get the data up to the amount claimed to be present - this is non-blocking\r
-        char* buffer = new char[bytes+1];\r
-        int read = ::recv(m_socket, buffer, bytes, 0);\r
-        if (read == SOCKET_ERROR)\r
-        {\r
-          delete[] buffer;\r
-          set_error(ERRNO);\r
-          close();\r
-          return false;\r
-        }\r
-        if (read == 0)\r
-        {\r
-          // TODO - check whether this is an appropriate conditon to close the socket\r
-          close();\r
-        }\r
-        else\r
-        {\r
-          // this is binary data so copy the bytes including nulls\r
-          data.append(buffer,read);\r
-        }\r
-        delete[] buffer;\r
-        return true;\r
-      }\r
-\r
-    bool receive_packet(std::string& data, unsigned long& address, unsigned short& port)\r
-      {\r
-        if (!initialised()) return false;\r
-        // determine how much data is available to read\r
-        unsigned long bytes = 0;\r
-        if (IOCTL(m_socket, FIONREAD, &bytes) == SOCKET_ERROR)\r
-        {\r
-          set_error(ERRNO);\r
-          return false;\r
-        }\r
-        // get the data up to the amount claimed to be present - this is non-blocking\r
-        // also get the sender's details\r
-        char* buffer = new char[bytes+1];\r
-        sockaddr saddress;\r
-        SOCKLEN_T saddress_length = sizeof(saddress);\r
-        int read = ::recvfrom(m_socket, buffer, bytes, 0, &saddress, &saddress_length);\r
-        if (read == SOCKET_ERROR)\r
-        {\r
-          // UDP connection reset means that a previous sent failed to deliver cos the address was unknown\r
-          // this is NOT an error with the sending server socket, which IS still usable\r
-          int error = ERRNO;\r
-          if (error != ECONNRESET)\r
-          {\r
-            delete[] buffer;\r
-            set_error(error);\r
-            close();\r
-            return false;\r
-          }\r
-        }\r
-        // this is binary data so copy the bytes including nulls\r
-        data.append(buffer,read);\r
-        // also retrieve the sender's details\r
-        convert_sockaddr(saddress, address, port);\r
-        delete[] buffer;\r
-        return true;\r
-      }\r
-\r
-    bool receive_packet(std::string& data)\r
-      {\r
-        // call the above and then discard the address details\r
-        unsigned long address = 0;\r
-        unsigned short port = 0;\r
-        return receive_packet(data, address, port);\r
-      }\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // informational\r
-\r
-    IP_socket_type type(void) const\r
-      {\r
-        return m_type;\r
-      }\r
-\r
-    unsigned short local_port(void) const\r
-      {\r
-        if (!initialised()) return 0;\r
-        sockaddr saddress;\r
-        SOCKLEN_T saddress_length = sizeof(saddress);\r
-        if (::getsockname(m_socket, &saddress, &saddress_length) != 0)\r
-        {\r
-          set_error(ERRNO);\r
-          return 0;\r
-        }\r
-        unsigned long address = 0;\r
-        unsigned short port = 0;\r
-        convert_sockaddr(saddress, address, port);\r
-        return port;\r
-      }\r
-\r
-    unsigned long remote_address(void) const\r
-      {\r
-        return m_remote_address;\r
-      }\r
-\r
-    unsigned short remote_port(void) const\r
-      {\r
-        return m_remote_port;\r
-      }\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error handling\r
-\r
-    void set_error (int error, const char* message = 0) const\r
-      {\r
-        if (error != 0)\r
-        {\r
-          m_error = error;\r
-          if (message && (message[0] != 0))\r
-            m_message = message;\r
-          else\r
-            m_message = error_string(error);\r
-        }\r
-      }\r
-\r
-    int error(void) const\r
-      {\r
-        return m_error;\r
-      }\r
-\r
-    void clear_error (void) const\r
-      {\r
-        m_error = 0;\r
-        m_message.erase();\r
-      }\r
-\r
-    std::string message(void) const\r
-      {\r
-        return m_message;\r
-      }\r
-\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Socket - common code to manipulate a socket\r
-\r
-  // create an uninitialised socket\r
-  IP_socket::IP_socket(void) : m_impl(new IP_socket_internals)\r
-  {\r
-  }\r
-\r
-  // create an initialised socket\r
-  // - type: create either a TCP or UDP socket - if neither, creates an uninitialised socket\r
-  IP_socket::IP_socket(IP_socket_type type) : m_impl(new IP_socket_internals)\r
-  {\r
-    initialise(type);\r
-  }\r
-\r
-  // destroy the socket, closing it if open\r
-  IP_socket::~IP_socket(void)\r
-  {\r
-    if (m_impl->decrement())\r
-      delete m_impl;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // copying is implemented as aliasing\r
-\r
-  IP_socket::IP_socket(const IP_socket& right) : m_impl(0)\r
-  {\r
-    // make this an alias of right\r
-    m_impl = right.m_impl;\r
-    m_impl->increment();\r
-  }\r
-\r
-  IP_socket& IP_socket::operator=(const IP_socket& right)\r
-  {\r
-    // make self-copy safe\r
-    if (m_impl == right.m_impl) return *this;\r
-    // first dealias the existing implementation\r
-    if (m_impl->decrement())\r
-      delete m_impl;\r
-    // now make this an alias of right\r
-    m_impl = right.m_impl;\r
-    m_impl->increment();\r
-    return *this;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // initialisation, connection\r
-\r
-  // initialise the socket\r
-  // - type: create either a TCP or UDP socket\r
-  // - returns success status\r
-  bool IP_socket::initialise(IP_socket_type type)\r
-  {\r
-    return m_impl->initialise(type);\r
-  }\r
-\r
-  // test whether this is an initialised socket\r
-  // - returns whether this is initialised\r
-  bool IP_socket::initialised(void) const\r
-  {\r
-    return m_impl->initialised();\r
-  }\r
-\r
-  // close, i.e. disconnect the socket\r
-  // - returns a success flag\r
-  bool IP_socket::close(void)\r
-  {\r
-    return m_impl->close();\r
-  }\r
-\r
-  // function for performing IP lookup (i.e. gethostbyname)\r
-  // could be standalone but making it a member means that it can use the socket's error handler\r
-  // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-  // - returns the IP address as a long integer - zero if there's an error\r
-  unsigned long IP_socket::ip_lookup(const std::string& remote_address)\r
-  {\r
-    return m_impl->ip_lookup(remote_address);\r
-  }\r
-\r
-  // test whether a socket is ready to communicate\r
-  // - readable: test whether socket is ready to read\r
-  // - writeable: test whether a socket is ready to write\r
-  // - timeout: if socket is not ready, time to wait before giving up - in micro-seconds - 0 means don't wait\r
-  // returns false if not ready or error - use error() method to tell - true if ready\r
-  bool IP_socket::select(bool readable, bool writeable, unsigned timeout)\r
-  {\r
-    return m_impl->select(readable, writeable, timeout);\r
-  }\r
-\r
-  // bind the socket to a port so that it can receive from specific address - typically used by a client\r
-  // - remote_address: IP number of remote server to send/receive to/from\r
-  // - local_port: port on local machine to bind to the address\r
-  // - returns success flag\r
-  bool IP_socket::bind(unsigned long remote_address, unsigned short local_port)\r
-  {\r
-    return m_impl->bind(remote_address, local_port);\r
-  }\r
-\r
-  // bind the socket to a port so that it can receive from any address - typically used by a server\r
-  // - local_port: port on local machine to bind to the address\r
-  // - returns success flag\r
-  bool IP_socket::bind_any(unsigned short local_port)\r
-  {\r
-    return m_impl->bind_any(local_port);\r
-  }\r
-\r
-  // initialise a socket and set this socket up to be a listening port\r
-  // - queue: length of backlog queue to manage - may be zero\r
-  // - returns success status\r
-  bool IP_socket::listen(unsigned short queue)\r
-  {\r
-    return m_impl->listen(queue);\r
-  }\r
-\r
-  // test for a connection on the object's socket - only applicable if it has been set up as a listening port\r
-  // - returns true if a connection is ready to be accepted\r
-  bool IP_socket::accept_ready(unsigned timeout) const\r
-  {\r
-    return m_impl->accept_ready(timeout);\r
-  }\r
-\r
-  // accept a connection on the object's socket - only applicable if it has been set up as a listening port\r
-  // - returns the connection as a new socket\r
-  IP_socket IP_socket::accept(void)\r
-  {\r
-    return m_impl->accept();\r
-  }\r
-\r
-  // client connect to a server\r
-  // - address: IP number already lookup up with ip_lookup\r
-  // - port: port to connect to\r
-  // - returns a success flag\r
-  bool IP_socket::connect(unsigned long address, unsigned short port)\r
-  {\r
-    return m_impl->connect(address, port);\r
-  }\r
-\r
-  // test whether a socket is connected and ready to communicate, returns on successful connect or timeout\r
-  // - timeout: how long to wait in microseconds if not connected yet\r
-  // - returns success flag\r
-  bool IP_socket::connected(unsigned timeout)\r
-  {\r
-    return m_impl->connected(timeout);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // sending/receiving\r
-\r
-  // test whether a socket is connected and ready to send data, returns if ready or on timeout\r
-  // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-  // - returns status\r
-  bool IP_socket::send_ready(unsigned timeout)\r
-  {\r
-    return m_impl->send_ready(timeout);\r
-  }\r
-\r
-  // send data through the socket - if the data is long only part of it may\r
-  // be sent. The sent part is removed from the data, so the same string can\r
-  // be sent again and again until it is empty.\r
-  // - data: string containing data to be sent - any data successfully sent is removed\r
-  // - returns success flag\r
-  bool IP_socket::send (std::string& data)\r
-  {\r
-    return m_impl->send(data);\r
-  }\r
-\r
-  // send data through a connectionless (UDP) socket\r
-  // the data will be sent as a single packet\r
-  // - packet: string containing data to be sent - any data successfully sent is removed\r
-  // - remote_address: address of the remote host to send to - optional if the socket has been connected to remote\r
-  // - remote_port: port of the remote host to send to - optional if the socket has been connected to remote\r
-  // - returns success flag\r
-  bool IP_socket::send_packet(std::string& packet, unsigned long remote_address, unsigned short remote_port)\r
-  {\r
-    return m_impl->send_packet(packet, remote_address, remote_port);\r
-  }\r
-\r
-  // send data through a connectionless (UDP) socket\r
-  // the data will be sent as a single packet\r
-  // only works if the socket has been connected to remote\r
-  // - packet: string containing data to be sent - any data successfully sent is removed\r
-  // - returns success flag\r
-  bool IP_socket::send_packet(std::string& packet)\r
-  {\r
-    return m_impl->send_packet(packet);\r
-  }\r
-\r
-  // test whether a socket is connected and ready to receive data, returns if ready or on timeout\r
-  // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-  // - returns status\r
-  bool IP_socket::receive_ready(unsigned timeout)\r
-  {\r
-    return m_impl->receive_ready(timeout);\r
-  }\r
-\r
-  // receive data through a connection-based (TCP) socket\r
-  // if the data is long only part of it may be received. The received data\r
-  // is appended to the string, building it up in stages, so the same string\r
-  // can be received again and again until all information has been\r
-  // received.\r
-  // - data: string receiving data from socket - any data successfully received is appended\r
-  // - returns success flag\r
-  bool IP_socket::receive (std::string& data)\r
-  {\r
-    return m_impl->receive(data);\r
-  }\r
-\r
-  // receive data through a connectionless (UDP) socket\r
-  // - packet: string receiving data from socket - any data successfully received is appended\r
-  // - remote_address: returns the address of the remote host received from\r
-  // - remote_port: returns the port of the remote host received from\r
-  // - returns success flag\r
-  bool IP_socket::receive_packet(std::string& packet, unsigned long& remote_address, unsigned short& remote_port)\r
-  {\r
-    return m_impl->receive_packet(packet, remote_address, remote_port);\r
-  }\r
-\r
-  // variant of above which does not give back the address and port of the sender\r
-  // receive data through a connectionless (UDP) socket\r
-  // - packet: string receiving data from socket - any data successfully received is appended\r
-  // - returns success flag\r
-  bool IP_socket::receive_packet(std::string& packet)\r
-  {\r
-    return m_impl->receive_packet(packet);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // informational\r
-\r
-  IP_socket_type IP_socket::type(void) const\r
-  {\r
-    return m_impl->type();\r
-  }\r
-\r
-  unsigned short IP_socket::local_port(void) const\r
-  {\r
-    return m_impl->local_port();\r
-  }\r
-\r
-  unsigned long IP_socket::remote_address(void) const\r
-  {\r
-    return m_impl->remote_address();\r
-  }\r
-\r
-  unsigned short IP_socket::remote_port(void) const\r
-  {\r
-    return m_impl->remote_port();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // error handling\r
-\r
-  void IP_socket::set_error (int error, const std::string& message) const\r
-  {\r
-    m_impl->set_error(error, message.c_str());\r
-  }\r
-\r
-  void IP_socket::clear_error (void) const\r
-  {\r
-    m_impl->clear_error();\r
-  }\r
-\r
-  int IP_socket::error(void) const\r
-  {\r
-    return m_impl->error();\r
-  }\r
-\r
-  std::string IP_socket::message(void) const\r
-  {\r
-    return m_impl->message();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+// Author:    Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+//            (c) Andy Rushton           2004-2009
+// License:   BSD License, see ../docs/license.html
+
+// Contains all the platform-specific socket handling used by the TCP and UDP classes
+
+// TODO - any conversion required to support IPv6
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "ip_sockets.hpp"
+#include "dprintf.hpp"
+#include <string.h>
+
+#ifdef MSWINDOWS
+// Windoze-specific includes
+#include <winsock2.h>
+#define ERRNO WSAGetLastError()
+#define HERRNO WSAGetLastError()
+#define IOCTL ioctlsocket
+#define CLOSE closesocket
+#define SHUT_RDWR SD_BOTH
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define ECONNRESET WSAECONNRESET
+#define SOCKLEN_T int
+#else
+// Generic Unix includes
+// fix for older versions of Darwin?
+#define _BSD_SOCKLEN_T_ int
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#define INVALID_SOCKET -1
+#define ERRNO errno
+#define HERRNO h_errno
+#define SOCKET int
+#define SOCKET_ERROR -1
+#define IOCTL ::ioctl
+#define CLOSE ::close
+#define SOCKLEN_T socklen_t
+#ifdef SOLARIS
+// Sun put some definitions in a different place
+#include <sys/filio.h>
+#endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Utilities
+
+  // get an operating-system error message given an error code
+  static std::string error_string(int error)
+  {
+    std::string result = "error " + dformat("%d",error);
+#ifdef MSWINDOWS
+    char* message = 0;
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+                  0,
+                  error,
+                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // "User default language"
+                  (LPTSTR)&message,
+                  0,0);
+    if (message) 
+    {
+      result = message;
+      LocalFree(message);
+    }
+    // the error message is for some perverse reason newline terminated - remove this
+    if (result[result.size()-1] == '\n')
+      result.erase(result.end()-1);
+    if (result[result.size()-1] == '\r')
+      result.erase(result.end()-1);
+#else
+    char* message = strerror(error);
+    if (message && message[0])
+      result = message;
+#endif
+    return result;
+  }
+
+  // convert address:port into a sockaddr
+  static void convert_address(unsigned long address, unsigned short port, sockaddr& sa)
+  {
+    sa.sa_family = AF_INET;
+    unsigned short network_port = htons(port);
+    memcpy(&sa.sa_data[0], &network_port, sizeof(network_port));
+    unsigned long network_address = htonl(address);
+    memcpy(&sa.sa_data[2], &network_address, sizeof(network_address));
+  }
+
+//   // convert host:port into a sockaddr
+//   static void convert_host(hostent& host, unsigned short port, sockaddr& sa)
+//   {
+//     sa.sa_family = host.h_addrtype;
+//     unsigned short network_port = htons(port);
+//     memcpy(&sa.sa_data[0], &network_port, sizeof(network_port));
+//     memcpy(&sa.sa_data[2], host.h_addr, host.h_length);
+//   }
+
+  // convert sockaddr to address:port
+  static void convert_sockaddr(const sockaddr& sa, unsigned long& address, unsigned short& port)
+  {
+    unsigned short network_port = 0;
+    memcpy(&network_port, &sa.sa_data[0], sizeof(network_port));
+    port = ntohs(network_port);
+    unsigned long network_address = 0;
+    memcpy(&network_address, &sa.sa_data[2], sizeof(network_address));
+    address = ntohl(network_address);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Initialisation
+  // Windows requires that Winsock is initialised before use and closed after
+  // These routines initialise once on first use and close on the destruction of the last object using it
+  // on non-windows platforms, I still increment/decrement the sockets count variable for diagnostic purposes
+
+  static int sockets_count = 0;
+
+  static int sockets_init(void)
+  {
+    int error = 0;
+    if (sockets_count++ == 0)
+    {
+#ifdef MSWINDOWS
+      WSAData winsock_info;
+      // request Winsock 2.0 or higher
+      error = WSAStartup(MAKEWORD(2,0),&winsock_info);
+#endif
+    }
+    return error;
+  }
+
+  static int sockets_close(void)
+  {
+    int error = 0;
+    if (--sockets_count == 0)
+    {
+#ifdef MSWINDOWS
+      if (WSACleanup() == SOCKET_ERROR)
+        error = ERRNO;
+#endif
+    }
+    return error;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Socket Implementation - common code to manipulate a TCP socket
+
+  class IP_socket_internals
+  {
+  private:
+    IP_socket_type m_type;
+    SOCKET m_socket;
+    unsigned long m_remote_address;
+    unsigned short m_remote_port;
+    mutable int m_error;
+    mutable std::string m_message;
+    unsigned m_count;
+
+    // disable copying of the internals
+    IP_socket_internals(const IP_socket_internals&);
+    IP_socket_internals& operator=(const IP_socket_internals&);
+
+  public:
+
+    ////////////////////////////////////////////////////////////////////////////
+    // PIMPL alias counting 
+
+    void increment(void)
+      {
+        ++m_count;
+      }
+
+    bool decrement(void)
+      {
+        --m_count;
+        return m_count == 0;
+      }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // constructors/destructors
+
+    // construct an invalid socket
+    IP_socket_internals(void) : m_type(undefined_socket_type), m_socket(INVALID_SOCKET), m_error(0), m_count(1)
+      {
+        set_error(sockets_init());
+      }
+
+    // close on destroy
+    ~IP_socket_internals(void)
+      {
+        close();
+        set_error(sockets_close());
+      }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // initialisation, connection
+
+    bool initialised(void) const
+      {
+        return m_socket != INVALID_SOCKET;
+      }
+
+    // attach this object to a pre-opened socket
+    bool set(SOCKET socket, unsigned long remote_address, unsigned short remote_port)
+      {
+        if (initialised()) close();
+        clear_error();
+        m_socket = socket;
+        m_remote_address = remote_address;
+        m_remote_port = remote_port;
+        return true;
+      }
+
+    // create a raw socket attached to this object
+    bool initialise(IP_socket_type type)
+      {
+        if (initialised()) close();
+        clear_error();
+        if ((type != TCP) && (type != UDP))
+        {
+          set_error(-1, "Illegal socket type");
+          return false;
+        }
+        // create an anonymous socket
+        m_socket = ::socket(AF_INET, ((type == TCP) ? SOCK_STREAM : SOCK_DGRAM), 0);
+        if (m_socket == INVALID_SOCKET)
+        {
+          set_error(ERRNO);
+          close();
+          return false;
+        }
+        // record the type on success only
+        m_type = type;
+        // set the socket into non-blocking mode
+        unsigned long nonblocking = 1;
+        if (IOCTL(m_socket, FIONBIO, &nonblocking) == SOCKET_ERROR)
+        {
+          set_error(ERRNO);
+          return false;
+        }
+        return true;
+      }
+    
+    // function for performing IP lookup (i.e. gethostbyname)
+    // could be standalone but making it a member means that it can use the socket's error handler
+    // - remote_address: IP name or number
+    // - returns the IP address as a number - zero if there's an error
+    unsigned long ip_lookup(const std::string& remote_address)
+      {
+        unsigned long result = 0;
+        // Lookup the IP address to convert it into a host record
+        // this DOES lookup IP address names as well (not according to MS help !!)
+        // TODO - convert this to use ::getaddrinfo - ::gethostbyname is deprecated
+        hostent* host_info = ::gethostbyname(remote_address.c_str());
+        if (!host_info)
+        {
+          set_error(HERRNO);
+          return 0;
+        }
+        // extract the address from the host info
+        unsigned long network_address = 0;
+        memcpy(&network_address, host_info->h_addr, host_info->h_length);
+        result = ntohl(network_address);
+        return result;
+      }
+
+    // tests whether a socket is ready for communication
+    bool select(bool readable, bool writeable, unsigned wait)
+      {
+        if (!initialised()) return false;
+        // set up the readable set
+        fd_set readable_set;
+        fd_set* readable_set_ptr = 0;
+        if (readable)
+        {
+          FD_ZERO(&readable_set);
+          FD_SET(m_socket,&readable_set);
+          readable_set_ptr = &readable_set;
+        }
+        // set up the writeable set
+        fd_set writeable_set;
+        fd_set* writeable_set_ptr = 0;
+        if (writeable)
+        {
+          FD_ZERO(&writeable_set);
+          FD_SET(m_socket,&writeable_set);
+          writeable_set_ptr = &writeable_set;
+        }
+        // TODO - check the error set and lookup the error?
+        fd_set* error_set_ptr = 0;
+        // set up the timout value
+        // Note: a null pointer implements a blocking select
+        //       a pointer to a zero value implements a zero-wait poll
+        //       a pointer to a positive value implements a poll with a timeout
+        // I currently only implement polling with timeout which may be zero  - no blocking
+        timeval timeout;
+        timeval* timeout_ptr = 0;
+        timeout.tv_sec = wait/1000000;
+        timeout.tv_usec = wait%1000000;
+        timeout_ptr = &timeout;
+        // now test the socket
+        int select_result = ::select(m_socket+1, readable_set_ptr, writeable_set_ptr, error_set_ptr, timeout_ptr);
+        switch(select_result)
+        {
+        case SOCKET_ERROR:
+          // select failed with an error - trap the error
+          set_error(ERRNO);
+          return false;
+        case 0:
+          // timeout exceeded without a connection appearing
+          return false;
+        default:
+          // at least one connection is pending
+          // TODO - do we need to do the extra socket options checking on Posix?
+          // TODO - does this connect in any way to the error_set above?
+          return true;
+        }
+      }
+
+    // bind the socket to a port so that it can receive from specific address
+    bool bind(unsigned long remote_address, unsigned short local_port)
+      {
+        if (!initialised()) return false;
+        // name the socket and bind it to a port - this is a requirement for a server
+        sockaddr server;
+        convert_address(INADDR_ANY, local_port, server);
+        if (::bind(m_socket, &server, sizeof(server)) == SOCKET_ERROR)
+        {
+          set_error(ERRNO);
+          close();
+          return false;
+        }
+        return true;
+      }
+    
+    // bind the socket to a port so that it can receive from any address
+    bool bind_any(unsigned short local_port)
+      {
+        return bind(INADDR_ANY, local_port);
+      }
+
+    // set this socket up to be a listening port
+    // must have been bound to a local port already
+    // - length of backlog queue to manage - may be zero
+    // - returns success status
+    bool listen(unsigned short queue)
+      {
+        if (!initialised()) return false;
+        // set the port to listen for incoming connections
+        if (::listen(m_socket, (int)queue) == SOCKET_ERROR)
+        {
+          set_error(ERRNO);
+          close();
+          return false;
+        }
+        return true;
+      }
+
+    // test whether there's an incoming connection on the socket
+    // only applicable if it has been set up as a listening port
+    bool accept_ready(unsigned wait)
+      {
+        // the test for a connection being ready is the same as the test for whether the socket is readable
+        // see documentation for select
+        return select(true, false, wait);
+      }
+
+    // accept a connection on the socket
+    // only applicable if it has been set up as a listening port
+    // - returns socket filled in with the accepted connection's details - or with the error fields set
+    IP_socket accept(void)
+      {
+        if (!initialised()) return IP_socket();
+        IP_socket result;
+        // accept the connection, at the same time getting the address of the connecting client
+        sockaddr saddress;
+        SOCKLEN_T saddress_length = sizeof(saddress);
+        SOCKET socket = ::accept(m_socket, &saddress, &saddress_length);
+        if (socket == INVALID_SOCKET)
+        {
+          // only set the result socket with an error
+          result.m_impl->set_error(ERRNO);
+          return result;
+        }
+        // extract the contents of the address
+        unsigned long remote_address = 0;
+        unsigned short remote_port = 0;
+        convert_sockaddr(saddress, remote_address, remote_port);
+        result.m_impl->set(socket, remote_address, remote_port);
+        return result;
+      }
+
+    // client connect to a server
+    // - remote_address: IP number of remote address to connect to
+    // - remote_port: port to connect to
+    bool connect(unsigned long remote_address, unsigned short remote_port)
+      {
+        if (!initialised()) return false;
+        // fill in the connection data structure
+        sockaddr connect_data;
+        convert_address(remote_address, remote_port, connect_data);
+        // connect binds the socket to a local address
+        // if connectionless it simply sets the default remote address
+        // if connectioned it makes the connection
+        if (::connect(m_socket, &connect_data, sizeof(connect_data)) == SOCKET_ERROR)
+        {
+          // the socket is non-blocking, so connect will almost certainly fail with EINPROGRESS which is not an error
+          // only catch real errors
+          int error = ERRNO;
+          if (error != EINPROGRESS && error != EWOULDBLOCK)
+          {
+            set_error(error);
+            return false;
+          }
+        }
+        // extract the remote connection details for local storage
+        convert_sockaddr(connect_data, m_remote_address, m_remote_port);
+        return true;
+      }
+
+    // test whether a socket is connected and ready to communicate
+    bool connected(unsigned wait)
+      {
+        if (!initialised()) return false;
+        // Linux and Windows docs say test with select for whether socket is
+        // writable. However, a problem has been reported with Linux whereby
+        // the OS will report a socket as writable when it isn't
+        // first use the select method
+        if (!select(false, true, wait))
+          return false;
+#ifdef MSWINDOWS
+        // Windows needs no further processing - select method works
+        return true;
+#else
+        // Posix version needs further checking using the socket options
+        // DJDM: socket has returned EINPROGRESS on the first attempt at connection
+        // it has also returned that it can be written to
+        // we must now ask it if it has actually connected - using getsockopt
+        int error = 0;
+        socklen_t serror = sizeof(int);
+        if (::getsockopt(m_socket, SOL_SOCKET, SO_ERROR, &error, &serror)==0)
+          // handle the error value - one of them means that the socket has connected
+          if (!error || error == EISCONN)
+            return true;
+        return false;
+#endif
+      }
+
+    bool close(void)
+      {
+        bool result = true;
+        if (initialised())
+        {
+          if (shutdown(m_socket,SHUT_RDWR) == SOCKET_ERROR)
+          {
+            set_error(ERRNO);
+            result = false;
+          }
+          if (CLOSE(m_socket) == SOCKET_ERROR)
+          {
+            set_error(ERRNO);
+            result = false;
+          }
+        }
+        m_socket = INVALID_SOCKET;
+        m_remote_address = 0;
+        m_remote_port = 0;
+        return result;
+      }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // sending/receiving
+
+    bool send_ready(unsigned wait)
+      {
+        // determines whether the socket is ready to send by testing whether it is writable
+        return select(false, true, wait);
+      }
+
+    bool send (std::string& data)
+      {
+        if (!initialised()) return false;
+        // send the data - this will never block but may not send all the data
+        int bytes = ::send(m_socket, data.c_str(), data.size(), 0);
+        if (bytes == SOCKET_ERROR)
+        {
+          set_error(ERRNO);
+          return false;
+        }
+        // remove the sent bytes from the data buffer so that the buffer represents the data still to be sent
+        data.erase(0,bytes);
+        return true;
+      }
+
+    bool send_packet(std::string& data, unsigned long address = 0, unsigned short port = 0)
+      {
+        if (!initialised()) return false;
+        // if no address specified, rely on the socket having been connected (can I test this?)
+        // so use the standard send, otherwise use the sendto function
+        int bytes = 0;
+        if (!address)
+        {
+          bytes = ::send(m_socket, data.c_str(), data.size(), 0);
+        }
+        else
+        {
+          sockaddr saddress;
+          convert_address(address, port, saddress);
+          bytes = ::sendto(m_socket, data.c_str(), data.size(), 0, &saddress, sizeof(saddress));
+        }
+        if (bytes == SOCKET_ERROR)
+        {
+          set_error(ERRNO);
+          return false;
+        }
+        // remove the sent bytes from the data buffer so that the buffer represents the data still to be sent
+        data.erase(0,bytes);
+        return true;
+      }
+
+    bool receive_ready(unsigned wait)
+      {
+        // determines whether the socket is ready to receive by testing whether it is readable
+        return select(true, false, wait);
+      }
+
+    bool receive (std::string& data)
+      {
+        if (!initialised()) return false;
+        // determine how much data is available to read
+        unsigned long bytes = 0;
+        if (IOCTL(m_socket, FIONREAD, &bytes) == SOCKET_ERROR)
+        {
+          set_error(ERRNO);
+          return false;
+        }
+        // get the data up to the amount claimed to be present - this is non-blocking
+        char* buffer = new char[bytes+1];
+        int read = ::recv(m_socket, buffer, bytes, 0);
+        if (read == SOCKET_ERROR)
+        {
+          delete[] buffer;
+          set_error(ERRNO);
+          close();
+          return false;
+        }
+        if (read == 0)
+        {
+          // TODO - check whether this is an appropriate conditon to close the socket
+          close();
+        }
+        else
+        {
+          // this is binary data so copy the bytes including nulls
+          data.append(buffer,read);
+        }
+        delete[] buffer;
+        return true;
+      }
+
+    bool receive_packet(std::string& data, unsigned long& address, unsigned short& port)
+      {
+        if (!initialised()) return false;
+        // determine how much data is available to read
+        unsigned long bytes = 0;
+        if (IOCTL(m_socket, FIONREAD, &bytes) == SOCKET_ERROR)
+        {
+          set_error(ERRNO);
+          return false;
+        }
+        // get the data up to the amount claimed to be present - this is non-blocking
+        // also get the sender's details
+        char* buffer = new char[bytes+1];
+        sockaddr saddress;
+        SOCKLEN_T saddress_length = sizeof(saddress);
+        int read = ::recvfrom(m_socket, buffer, bytes, 0, &saddress, &saddress_length);
+        if (read == SOCKET_ERROR)
+        {
+          // UDP connection reset means that a previous sent failed to deliver cos the address was unknown
+          // this is NOT an error with the sending server socket, which IS still usable
+          int error = ERRNO;
+          if (error != ECONNRESET)
+          {
+            delete[] buffer;
+            set_error(error);
+            close();
+            return false;
+          }
+        }
+        // this is binary data so copy the bytes including nulls
+        data.append(buffer,read);
+        // also retrieve the sender's details
+        convert_sockaddr(saddress, address, port);
+        delete[] buffer;
+        return true;
+      }
+
+    bool receive_packet(std::string& data)
+      {
+        // call the above and then discard the address details
+        unsigned long address = 0;
+        unsigned short port = 0;
+        return receive_packet(data, address, port);
+      }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // informational
+
+    IP_socket_type type(void) const
+      {
+        return m_type;
+      }
+
+    unsigned short local_port(void) const
+      {
+        if (!initialised()) return 0;
+        sockaddr saddress;
+        SOCKLEN_T saddress_length = sizeof(saddress);
+        if (::getsockname(m_socket, &saddress, &saddress_length) != 0)
+        {
+          set_error(ERRNO);
+          return 0;
+        }
+        unsigned long address = 0;
+        unsigned short port = 0;
+        convert_sockaddr(saddress, address, port);
+        return port;
+      }
+
+    unsigned long remote_address(void) const
+      {
+        return m_remote_address;
+      }
+
+    unsigned short remote_port(void) const
+      {
+        return m_remote_port;
+      }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error handling
+
+    void set_error (int error, const char* message = 0) const
+      {
+        if (error != 0)
+        {
+          m_error = error;
+          if (message && (message[0] != 0))
+            m_message = message;
+          else
+            m_message = error_string(error);
+        }
+      }
+
+    int error(void) const
+      {
+        return m_error;
+      }
+
+    void clear_error (void) const
+      {
+        m_error = 0;
+        m_message.erase();
+      }
+
+    std::string message(void) const
+      {
+        return m_message;
+      }
+
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Socket - common code to manipulate a socket
+
+  // create an uninitialised socket
+  IP_socket::IP_socket(void) : m_impl(new IP_socket_internals)
+  {
+  }
+
+  // create an initialised socket
+  // - type: create either a TCP or UDP socket - if neither, creates an uninitialised socket
+  IP_socket::IP_socket(IP_socket_type type) : m_impl(new IP_socket_internals)
+  {
+    initialise(type);
+  }
+
+  // destroy the socket, closing it if open
+  IP_socket::~IP_socket(void)
+  {
+    if (m_impl->decrement())
+      delete m_impl;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////
+  // copying is implemented as aliasing
+
+  IP_socket::IP_socket(const IP_socket& right) : m_impl(0)
+  {
+    // make this an alias of right
+    m_impl = right.m_impl;
+    m_impl->increment();
+  }
+
+  IP_socket& IP_socket::operator=(const IP_socket& right)
+  {
+    // make self-copy safe
+    if (m_impl == right.m_impl) return *this;
+    // first dealias the existing implementation
+    if (m_impl->decrement())
+      delete m_impl;
+    // now make this an alias of right
+    m_impl = right.m_impl;
+    m_impl->increment();
+    return *this;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////
+  // initialisation, connection
+
+  // initialise the socket
+  // - type: create either a TCP or UDP socket
+  // - returns success status
+  bool IP_socket::initialise(IP_socket_type type)
+  {
+    return m_impl->initialise(type);
+  }
+
+  // test whether this is an initialised socket
+  // - returns whether this is initialised
+  bool IP_socket::initialised(void) const
+  {
+    return m_impl->initialised();
+  }
+
+  // close, i.e. disconnect the socket
+  // - returns a success flag
+  bool IP_socket::close(void)
+  {
+    return m_impl->close();
+  }
+
+  // function for performing IP lookup (i.e. gethostbyname)
+  // could be standalone but making it a member means that it can use the socket's error handler
+  // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+  // - returns the IP address as a long integer - zero if there's an error
+  unsigned long IP_socket::ip_lookup(const std::string& remote_address)
+  {
+    return m_impl->ip_lookup(remote_address);
+  }
+
+  // test whether a socket is ready to communicate
+  // - readable: test whether socket is ready to read
+  // - writeable: test whether a socket is ready to write
+  // - timeout: if socket is not ready, time to wait before giving up - in micro-seconds - 0 means don't wait
+  // returns false if not ready or error - use error() method to tell - true if ready
+  bool IP_socket::select(bool readable, bool writeable, unsigned timeout)
+  {
+    return m_impl->select(readable, writeable, timeout);
+  }
+
+  // bind the socket to a port so that it can receive from specific address - typically used by a client
+  // - remote_address: IP number of remote server to send/receive to/from
+  // - local_port: port on local machine to bind to the address
+  // - returns success flag
+  bool IP_socket::bind(unsigned long remote_address, unsigned short local_port)
+  {
+    return m_impl->bind(remote_address, local_port);
+  }
+
+  // bind the socket to a port so that it can receive from any address - typically used by a server
+  // - local_port: port on local machine to bind to the address
+  // - returns success flag
+  bool IP_socket::bind_any(unsigned short local_port)
+  {
+    return m_impl->bind_any(local_port);
+  }
+
+  // initialise a socket and set this socket up to be a listening port
+  // - queue: length of backlog queue to manage - may be zero
+  // - returns success status
+  bool IP_socket::listen(unsigned short queue)
+  {
+    return m_impl->listen(queue);
+  }
+
+  // test for a connection on the object's socket - only applicable if it has been set up as a listening port
+  // - returns true if a connection is ready to be accepted
+  bool IP_socket::accept_ready(unsigned timeout) const
+  {
+    return m_impl->accept_ready(timeout);
+  }
+
+  // accept a connection on the object's socket - only applicable if it has been set up as a listening port
+  // - returns the connection as a new socket
+  IP_socket IP_socket::accept(void)
+  {
+    return m_impl->accept();
+  }
+
+  // client connect to a server
+  // - address: IP number already lookup up with ip_lookup
+  // - port: port to connect to
+  // - returns a success flag
+  bool IP_socket::connect(unsigned long address, unsigned short port)
+  {
+    return m_impl->connect(address, port);
+  }
+
+  // test whether a socket is connected and ready to communicate, returns on successful connect or timeout
+  // - timeout: how long to wait in microseconds if not connected yet
+  // - returns success flag
+  bool IP_socket::connected(unsigned timeout)
+  {
+    return m_impl->connected(timeout);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////
+  // sending/receiving
+
+  // test whether a socket is connected and ready to send data, returns if ready or on timeout
+  // - timeout: how long to wait in microseconds if not connected yet (blocking)
+  // - returns status
+  bool IP_socket::send_ready(unsigned timeout)
+  {
+    return m_impl->send_ready(timeout);
+  }
+
+  // send data through the socket - if the data is long only part of it may
+  // be sent. The sent part is removed from the data, so the same string can
+  // be sent again and again until it is empty.
+  // - data: string containing data to be sent - any data successfully sent is removed
+  // - returns success flag
+  bool IP_socket::send (std::string& data)
+  {
+    return m_impl->send(data);
+  }
+
+  // send data through a connectionless (UDP) socket
+  // the data will be sent as a single packet
+  // - packet: string containing data to be sent - any data successfully sent is removed
+  // - remote_address: address of the remote host to send to - optional if the socket has been connected to remote
+  // - remote_port: port of the remote host to send to - optional if the socket has been connected to remote
+  // - returns success flag
+  bool IP_socket::send_packet(std::string& packet, unsigned long remote_address, unsigned short remote_port)
+  {
+    return m_impl->send_packet(packet, remote_address, remote_port);
+  }
+
+  // send data through a connectionless (UDP) socket
+  // the data will be sent as a single packet
+  // only works if the socket has been connected to remote
+  // - packet: string containing data to be sent - any data successfully sent is removed
+  // - returns success flag
+  bool IP_socket::send_packet(std::string& packet)
+  {
+    return m_impl->send_packet(packet);
+  }
+
+  // test whether a socket is connected and ready to receive data, returns if ready or on timeout
+  // - timeout: how long to wait in microseconds if not connected yet (blocking)
+  // - returns status
+  bool IP_socket::receive_ready(unsigned timeout)
+  {
+    return m_impl->receive_ready(timeout);
+  }
+
+  // receive data through a connection-based (TCP) socket
+  // if the data is long only part of it may be received. The received data
+  // is appended to the string, building it up in stages, so the same string
+  // can be received again and again until all information has been
+  // received.
+  // - data: string receiving data from socket - any data successfully received is appended
+  // - returns success flag
+  bool IP_socket::receive (std::string& data)
+  {
+    return m_impl->receive(data);
+  }
+
+  // receive data through a connectionless (UDP) socket
+  // - packet: string receiving data from socket - any data successfully received is appended
+  // - remote_address: returns the address of the remote host received from
+  // - remote_port: returns the port of the remote host received from
+  // - returns success flag
+  bool IP_socket::receive_packet(std::string& packet, unsigned long& remote_address, unsigned short& remote_port)
+  {
+    return m_impl->receive_packet(packet, remote_address, remote_port);
+  }
+
+  // variant of above which does not give back the address and port of the sender
+  // receive data through a connectionless (UDP) socket
+  // - packet: string receiving data from socket - any data successfully received is appended
+  // - returns success flag
+  bool IP_socket::receive_packet(std::string& packet)
+  {
+    return m_impl->receive_packet(packet);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////
+  // informational
+
+  IP_socket_type IP_socket::type(void) const
+  {
+    return m_impl->type();
+  }
+
+  unsigned short IP_socket::local_port(void) const
+  {
+    return m_impl->local_port();
+  }
+
+  unsigned long IP_socket::remote_address(void) const
+  {
+    return m_impl->remote_address();
+  }
+
+  unsigned short IP_socket::remote_port(void) const
+  {
+    return m_impl->remote_port();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////
+  // error handling
+
+  void IP_socket::set_error (int error, const std::string& message) const
+  {
+    m_impl->set_error(error, message.c_str());
+  }
+
+  void IP_socket::clear_error (void) const
+  {
+    m_impl->clear_error();
+  }
+
+  int IP_socket::error(void) const
+  {
+    return m_impl->error();
+  }
+
+  std::string IP_socket::message(void) const
+  {
+    return m_impl->message();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index ac86ebcb1446ee179fb2cc96511e07b760122d48..f0bd314546041dd1ae50e78315a455762e603858 100644 (file)
-#ifndef STLPLUS_IP_SOCKET\r
-#define STLPLUS_IP_SOCKET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Author:    Andy Rushton\r
-// Copyright: (c) Southampton University 1999-2004\r
-//            (c) Andy Rushton           2004-2009\r
-// License:   BSD License, see ../docs/license.html\r
-\r
-// A platform-independent (Unix and Windows anyway) interface to Internet-Protocol sockets\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // internals\r
-  // use a PIMPL interface to hide the platform-specifics in the implementation\r
-\r
-  class IP_socket_internals;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////\r
-  // Types of socket supported\r
-\r
-  enum IP_socket_type {undefined_socket_type = -1, TCP = 0, UDP = 1};\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // Socket class\r
-\r
-  class IP_socket\r
-  {\r
-  public:\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // constructors/destructors\r
-\r
-    // create an uninitialised socket\r
-    IP_socket(void);\r
-\r
-    // create an initialised socket\r
-    // - type: create either a TCP or UDP socket\r
-    IP_socket(IP_socket_type type);\r
-\r
-    // destroy the socket, closing it if open\r
-    ~IP_socket(void);\r
-\r
-    // copying is implemented as aliasing\r
-    IP_socket(const IP_socket&);\r
-    IP_socket& operator=(const IP_socket&);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // initialisation\r
-\r
-    // initialise the socket\r
-    // - type: create either a TCP or UDP socket\r
-    // - returns success status\r
-    bool initialise(IP_socket_type type);\r
-\r
-    // test whether this is an initialised socket\r
-    // - returns whether this is initialised\r
-    bool initialised(void) const;\r
-\r
-    // close, i.e. disconnect the socket\r
-    // - returns a success flag\r
-    bool close(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // Socket configuration\r
-\r
-    // function for performing IP lookup (i.e. gethostbyname)\r
-    // could be standalone but making it a member means that it can use the socket's error handler\r
-    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again\r
-    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-    // - returns the IP address as a long integer - zero if there's an error\r
-    unsigned long ip_lookup(const std::string& remote_address);\r
-\r
-    // test whether a socket is ready to communicate\r
-    // - readable: test whether socket is ready to read\r
-    // - writeable: test whether a socket is ready to write\r
-    // - timeout: if socket is not ready, time to wait before giving up - in micro-seconds - 0 means don't wait\r
-    // returns false if not ready or error - use error() method to tell - true if ready\r
-    bool select(bool readable, bool writeable, unsigned timeout = 0);\r
-\r
-    // bind the socket to a port so that it can receive from specific address - typically used by a client\r
-    // - remote_address: IP number of remote server to send/receive to/from\r
-    // - local_port: port on local machine to bind to the address\r
-    // - returns success flag\r
-    bool bind(unsigned long remote_address, unsigned short local_port);\r
-\r
-    // bind the socket to a port so that it can receive from any address - typically used by a server\r
-    // - local_port: port on local machine to bind to the address\r
-    // - returns success flag\r
-    bool bind_any(unsigned short local_port);\r
-\r
-    // set this socket up to be a listening port\r
-    // socket must be bound to a port already\r
-    // - queue: length of backlog queue to manage - may be zero meaning no queue\r
-    // - returns success status\r
-    bool listen(unsigned short queue = 0);\r
-\r
-    // test for a connection on the socket\r
-    // only applicable if it has been set up as a listening port\r
-    // - timeout: how long to wait in microseconds if not connected yet\r
-    // - returns true if a connection is ready to be accepted\r
-    bool accept_ready(unsigned timeout = 0) const;\r
-\r
-    // accept a connection on the socket\r
-    // only applicable if it has been set up as a listening port\r
-    // - returns the connection as a new socket\r
-    IP_socket accept(void);\r
-\r
-    // create a connection - usually used by a client\r
-    // TCP: client connect to a remote server\r
-    // UDP: setup remote address and port for sends\r
-    // - remote_address: IP number already looked up using ip_lookup\r
-    // - remote_port: port to connect to\r
-    // - returns a success flag\r
-    bool connect(unsigned long remote_address, unsigned short remote_port);\r
-\r
-    // test whether a socket is connected and ready to communicate, returns on successful connect or timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet\r
-    // - returns true if connected and ready to communicate, false if not ready or error\r
-    bool connected(unsigned timeout = 0);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // sending/receiving\r
-\r
-    // test whether a socket is connected and ready to send data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    bool send_ready(unsigned timeout = 0);\r
-\r
-    // send data through a connection-based (TCP) socket\r
-    // if the data is long only part of it may be sent. The sent part is\r
-    // removed from the data, so the same string can be sent again and again\r
-    // until it is empty.\r
-    // - data: string containing data to be sent - any data successfully sent is removed\r
-    // - returns success flag\r
-    bool send(std::string& data);\r
-\r
-    // send data through a connectionless (UDP) socket\r
-    // the data will be sent as a single packet\r
-    // - packet: string containing data to be sent - any data successfully sent is removed\r
-    // - remote_address: address of the remote host to send to - optional if the socket has been connected to remote\r
-    // - remote_port: port of the remote host to send to - optional if the socket has been connected to remote\r
-    // - returns success flag\r
-    bool send_packet(std::string& packet, unsigned long remote_address, unsigned short remote_port);\r
-\r
-    // send data through a connectionless (UDP) socket\r
-    // the data will be sent as a single packet\r
-    // only works if the socket has been connected to remote\r
-    // - packet: string containing data to be sent - any data successfully sent is removed\r
-    // - returns success flag\r
-    bool send_packet(std::string& packet);\r
-\r
-    // test whether a socket is connected and ready to receive data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    bool receive_ready(unsigned wait = 0);\r
-\r
-    // receive data through a connection-based (TCP) socket\r
-    // if the data is long only part of it may be received. The received data\r
-    // is appended to the string, building it up in stages, so the same string\r
-    // can be received again and again until all information has been\r
-    // received.\r
-    // - data: string receiving data from socket - any data successfully received is appended\r
-    // - returns success flag\r
-    bool receive(std::string& data);\r
-\r
-    // receive data through a connectionless (UDP) socket\r
-    // - packet: string receiving data from socket - any data successfully received is appended\r
-    // - remote_address: returns the address of the remote host received from\r
-    // - remote_port: returns the port of the remote host received from\r
-    // - returns success flag\r
-    bool receive_packet(std::string& packet, unsigned long& remote_address, unsigned short& remote_port);\r
-\r
-    // variant of above which does not give back the address and port of the sender\r
-    // receive data through a connectionless (UDP) socket\r
-    // - packet: string receiving data from socket - any data successfully received is appended\r
-    // - returns success flag\r
-    bool receive_packet(std::string& packet);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // informational\r
-\r
-    // gets the type of socket\r
-    // - returns undefined_socket_type, TCP or UDP\r
-    IP_socket_type type(void) const;\r
-\r
-    // the local port number of the connection\r
-    // returns the port number, 0 if not bound to a port\r
-    unsigned short local_port(void) const;\r
-\r
-    // the remote address of the connection\r
-    // returns the address, 0 if not connected\r
-    unsigned long remote_address(void) const;\r
-\r
-    // the remote port number of the connection\r
-    // returns the port number, 0 if not connected to a port\r
-    unsigned short remote_port(void) const;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error handling\r
-    // errors are set internally\r
-    // an error code of 0 is the test for no error, don't rely on the message being an empty string\r
-    // an error code != 0 means an error, then there will be a message explaining the error\r
-\r
-    // indicate an error - mostly used internally, you can set your own errors - use a negative code\r
-    void set_error (int error, const std::string& message) const;\r
-\r
-    // if an error is set it stays set - so you must clear it before further operations\r
-    void clear_error (void) const;\r
-\r
-    // get the error code of the last error\r
-    int error(void) const;\r
-\r
-    // get the explanatory message of the last error\r
-    std::string message(void) const;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-\r
-  private:\r
-    friend class IP_socket_internals;\r
-    IP_socket_internals* m_impl;\r
-  };\r
-\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_IP_SOCKET
+#define STLPLUS_IP_SOCKET
+////////////////////////////////////////////////////////////////////////////////
+
+// Author:    Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+//            (c) Andy Rushton           2004-2009
+// License:   BSD License, see ../docs/license.html
+
+// A platform-independent (Unix and Windows anyway) interface to Internet-Protocol sockets
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  //////////////////////////////////////////////////////////////////////////////
+  // internals
+  // use a PIMPL interface to hide the platform-specifics in the implementation
+
+  class IP_socket_internals;
+
+  ////////////////////////////////////////////////////////////////////////////
+  // Types of socket supported
+
+  enum IP_socket_type {undefined_socket_type = -1, TCP = 0, UDP = 1};
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Socket class
+
+  class IP_socket
+  {
+  public:
+
+    ////////////////////////////////////////////////////////////////////////////
+    // constructors/destructors
+
+    // create an uninitialised socket
+    IP_socket(void);
+
+    // create an initialised socket
+    // - type: create either a TCP or UDP socket
+    IP_socket(IP_socket_type type);
+
+    // destroy the socket, closing it if open
+    ~IP_socket(void);
+
+    // copying is implemented as aliasing
+    IP_socket(const IP_socket&);
+    IP_socket& operator=(const IP_socket&);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // initialisation
+
+    // initialise the socket
+    // - type: create either a TCP or UDP socket
+    // - returns success status
+    bool initialise(IP_socket_type type);
+
+    // test whether this is an initialised socket
+    // - returns whether this is initialised
+    bool initialised(void) const;
+
+    // close, i.e. disconnect the socket
+    // - returns a success flag
+    bool close(void);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // Socket configuration
+
+    // function for performing IP lookup (i.e. gethostbyname)
+    // could be standalone but making it a member means that it can use the socket's error handler
+    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again
+    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+    // - returns the IP address as a long integer - zero if there's an error
+    unsigned long ip_lookup(const std::string& remote_address);
+
+    // test whether a socket is ready to communicate
+    // - readable: test whether socket is ready to read
+    // - writeable: test whether a socket is ready to write
+    // - timeout: if socket is not ready, time to wait before giving up - in micro-seconds - 0 means don't wait
+    // returns false if not ready or error - use error() method to tell - true if ready
+    bool select(bool readable, bool writeable, unsigned timeout = 0);
+
+    // bind the socket to a port so that it can receive from specific address - typically used by a client
+    // - remote_address: IP number of remote server to send/receive to/from
+    // - local_port: port on local machine to bind to the address
+    // - returns success flag
+    bool bind(unsigned long remote_address, unsigned short local_port);
+
+    // bind the socket to a port so that it can receive from any address - typically used by a server
+    // - local_port: port on local machine to bind to the address
+    // - returns success flag
+    bool bind_any(unsigned short local_port);
+
+    // set this socket up to be a listening port
+    // socket must be bound to a port already
+    // - queue: length of backlog queue to manage - may be zero meaning no queue
+    // - returns success status
+    bool listen(unsigned short queue = 0);
+
+    // test for a connection on the socket
+    // only applicable if it has been set up as a listening port
+    // - timeout: how long to wait in microseconds if not connected yet
+    // - returns true if a connection is ready to be accepted
+    bool accept_ready(unsigned timeout = 0) const;
+
+    // accept a connection on the socket
+    // only applicable if it has been set up as a listening port
+    // - returns the connection as a new socket
+    IP_socket accept(void);
+
+    // create a connection - usually used by a client
+    // TCP: client connect to a remote server
+    // UDP: setup remote address and port for sends
+    // - remote_address: IP number already looked up using ip_lookup
+    // - remote_port: port to connect to
+    // - returns a success flag
+    bool connect(unsigned long remote_address, unsigned short remote_port);
+
+    // test whether a socket is connected and ready to communicate, returns on successful connect or timeout
+    // - timeout: how long to wait in microseconds if not connected yet
+    // - returns true if connected and ready to communicate, false if not ready or error
+    bool connected(unsigned timeout = 0);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // sending/receiving
+
+    // test whether a socket is connected and ready to send data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    bool send_ready(unsigned timeout = 0);
+
+    // send data through a connection-based (TCP) socket
+    // if the data is long only part of it may be sent. The sent part is
+    // removed from the data, so the same string can be sent again and again
+    // until it is empty.
+    // - data: string containing data to be sent - any data successfully sent is removed
+    // - returns success flag
+    bool send(std::string& data);
+
+    // send data through a connectionless (UDP) socket
+    // the data will be sent as a single packet
+    // - packet: string containing data to be sent - any data successfully sent is removed
+    // - remote_address: address of the remote host to send to - optional if the socket has been connected to remote
+    // - remote_port: port of the remote host to send to - optional if the socket has been connected to remote
+    // - returns success flag
+    bool send_packet(std::string& packet, unsigned long remote_address, unsigned short remote_port);
+
+    // send data through a connectionless (UDP) socket
+    // the data will be sent as a single packet
+    // only works if the socket has been connected to remote
+    // - packet: string containing data to be sent - any data successfully sent is removed
+    // - returns success flag
+    bool send_packet(std::string& packet);
+
+    // test whether a socket is connected and ready to receive data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    bool receive_ready(unsigned wait = 0);
+
+    // receive data through a connection-based (TCP) socket
+    // if the data is long only part of it may be received. The received data
+    // is appended to the string, building it up in stages, so the same string
+    // can be received again and again until all information has been
+    // received.
+    // - data: string receiving data from socket - any data successfully received is appended
+    // - returns success flag
+    bool receive(std::string& data);
+
+    // receive data through a connectionless (UDP) socket
+    // - packet: string receiving data from socket - any data successfully received is appended
+    // - remote_address: returns the address of the remote host received from
+    // - remote_port: returns the port of the remote host received from
+    // - returns success flag
+    bool receive_packet(std::string& packet, unsigned long& remote_address, unsigned short& remote_port);
+
+    // variant of above which does not give back the address and port of the sender
+    // receive data through a connectionless (UDP) socket
+    // - packet: string receiving data from socket - any data successfully received is appended
+    // - returns success flag
+    bool receive_packet(std::string& packet);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // informational
+
+    // gets the type of socket
+    // - returns undefined_socket_type, TCP or UDP
+    IP_socket_type type(void) const;
+
+    // the local port number of the connection
+    // returns the port number, 0 if not bound to a port
+    unsigned short local_port(void) const;
+
+    // the remote address of the connection
+    // returns the address, 0 if not connected
+    unsigned long remote_address(void) const;
+
+    // the remote port number of the connection
+    // returns the port number, 0 if not connected to a port
+    unsigned short remote_port(void) const;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error handling
+    // errors are set internally
+    // an error code of 0 is the test for no error, don't rely on the message being an empty string
+    // an error code != 0 means an error, then there will be a message explaining the error
+
+    // indicate an error - mostly used internally, you can set your own errors - use a negative code
+    void set_error (int error, const std::string& message) const;
+
+    // if an error is set it stays set - so you must clear it before further operations
+    void clear_error (void) const;
+
+    // get the error code of the last error
+    int error(void) const;
+
+    // get the explanatory message of the last error
+    std::string message(void) const;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+  private:
+    friend class IP_socket_internals;
+    IP_socket_internals* m_impl;
+  };
+
+
+} // end namespace stlplus
+
+#endif
index 942c18225cf5b1443fc41d83657b908fa78f8cea..92ec10aa535c9f7ba583c25c1dab969906fec601 100644 (file)
@@ -1,28 +1,28 @@
-#ifndef STLPLUS_PORTABILITY\r
-#define STLPLUS_PORTABILITY\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Allows all the STLplus portability packages to be included in one go\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "build.hpp"\r
-#include "debug.hpp"\r
-#include "dprintf.hpp"\r
-#include "dynaload.hpp"\r
-#include "file_system.hpp"\r
-#include "inf.hpp"\r
-#include "subprocesses.hpp"\r
-#include "tcp_sockets.hpp"\r
-#include "udp_sockets.hpp"\r
-#include "time.hpp"\r
-#include "version.hpp"\r
-#include "wildcard.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_PORTABILITY
+#define STLPLUS_PORTABILITY
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Allows all the STLplus portability packages to be included in one go
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "build.hpp"
+#include "debug.hpp"
+#include "dprintf.hpp"
+#include "dynaload.hpp"
+#include "file_system.hpp"
+#include "inf.hpp"
+#include "subprocesses.hpp"
+#include "tcp_sockets.hpp"
+#include "udp_sockets.hpp"
+#include "time.hpp"
+#include "version.hpp"
+#include "wildcard.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
index c66b7bf98fe6945aab43d69923c262c65674ad63..e47e6a08902619748ecc398891137108938e1c93 100644 (file)
@@ -1,33 +1,33 @@
-#ifndef STLPLUS_PORTABILITY_EXCEPTIONS\r
-#define STLPLUS_PORTABILITY_EXCEPTIONS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Adds missing arithmetic exceptions used in this library but missing from std\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // thrown by division when the divisor is zero\r
-  // This is a subclass of std::logic_error so can be caught by a generic catch clause for the superclass\r
-\r
-  class divide_by_zero : public std::logic_error {\r
-  public:\r
-    divide_by_zero (const std::string& what_arg): std::logic_error (what_arg) { }\r
-  };\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_PORTABILITY_EXCEPTIONS
+#define STLPLUS_PORTABILITY_EXCEPTIONS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Adds missing arithmetic exceptions used in this library but missing from std
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // thrown by division when the divisor is zero
+  // This is a subclass of std::logic_error so can be caught by a generic catch clause for the superclass
+
+  class divide_by_zero : public std::logic_error {
+  public:
+    divide_by_zero (const std::string& what_arg): std::logic_error (what_arg) { }
+  };
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index e26ee28684678f9592e4ab8be7f8d04da5166813..5b49e0c82002d5b0ba915d54247bc1a91d602dc4 100644 (file)
@@ -1,39 +1,39 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-\r
-#ifdef MSWINDOWS\r
-#include "windows.h"\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// problems with missing functions\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef MSWINDOWS\r
-unsigned sleep(unsigned seconds)\r
-{\r
-  Sleep(1000*seconds);\r
-  // should return remaining time if interrupted - however Windoze Sleep cannot be interrupted\r
-  return 0;\r
-}\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Function for establishing endian-ness\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-bool stlplus::little_endian(void)\r
-{\r
-  int sample = 1;\r
-  char* sample_bytes = (char*)&sample;\r
-  return sample_bytes[0] != 0;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+
+#ifdef MSWINDOWS
+#include "windows.h"
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// problems with missing functions
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef MSWINDOWS
+unsigned sleep(unsigned seconds)
+{
+  Sleep(1000*seconds);
+  // should return remaining time if interrupted - however Windoze Sleep cannot be interrupted
+  return 0;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Function for establishing endian-ness
+////////////////////////////////////////////////////////////////////////////////
+
+bool stlplus::little_endian(void)
+{
+  int sample = 1;
+  char* sample_bytes = (char*)&sample;
+  return sample_bytes[0] != 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
index b6a030c5f6264be49f615c3871f9f6181f98169c..26c426a5a56120a27b7800c1076285a06129f3ee 100644 (file)
-#ifndef STLPLUS_PORTABILITY_FIXES\r
-#define STLPLUS_PORTABILITY_FIXES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Contains work arounds for OS or Compiler specific problems to try to make\r
-//   them look more alike\r
-\r
-//   It is strongly recommended that this header be included as the first\r
-//   #include in every source file\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Problem with MicroSoft defining two different macros to identify Windows\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#if defined(_WIN32) || defined(_WIN32_WCE)\r
-#define MSWINDOWS\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Problems with unnecessary or unfixable compiler warnings\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef _MSC_VER\r
-// Microsoft Visual Studio\r
-// shut up the following irritating warnings\r
-//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)\r
-//   4305 - VC6, identifier type was converted to a smaller type\r
-//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)\r
-//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it\r
-//   4290 - VC6, C++ exception specification ignored\r
-//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)\r
-//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program\r
-//   4996 - VC8, 'xxxx' was declared deprecated\r
-#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4675 4996)\r
-#endif\r
-\r
-#ifdef __BORLANDC__\r
-// Borland\r
-// Shut up the following irritating warnings\r
-//   8026 - Functions with exception specifications are not expanded inline\r
-//   8027 - Functions with xxx are not expanded inline\r
-#pragma warn -8026\r
-#pragma warn -8027\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Problems with redefinition of min/max in various different versions of library headers\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// The Windows headers define macros called max/min which conflict with the templates std::max and std::min.\r
-// So, to avoid conflicts, MS removed the std::max/min rather than fixing the problem!\r
-// From Visual Studio .NET (SV7, compiler version 13.00) the STL templates have been added correctly.\r
-// For MFC compatibility, only undef min and max in non-MFC programs - some bits of MFC\r
-// use macro min/max in headers. \r
-\r
-// I've created extra template function definitions minimum/maximum that avoid all the problems above\r
-\r
-namespace stlplus\r
-{\r
-  template<typename T> const T& maximum(const T& l, const T& r) {return l > r ? l : r;}\r
-  template<typename T> const T& minimum(const T& l, const T& r) {return l < r ? l : r;}\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Problems with differences between namespaces\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Note: not sure of the relevance of this - maybe deprecated?\r
-// problem in gcc pre-v3 where the sub-namespaces in std aren't present\r
-// this mean that the statement "using namespace std::rel_ops" created an error because the namespace didn't exist\r
-\r
-// I've done a fix here that creates an empty namespace for this case, but I\r
-// do *not* try to move the contents of std::rel_ops into namespace std\r
-// This fix only works if you use "using namespace std::rel_ops" to bring in the template relational operators (e.g. != defined i.t.o. ==)\r
-\r
-#ifdef __GNUC__\r
-namespace std\r
-{\r
-  namespace rel_ops\r
-  {\r
-  }\r
-}\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// problems with missing functions\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef MSWINDOWS\r
-unsigned sleep(unsigned seconds);\r
-#else\r
-#include <unistd.h>\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Function for establishing endian-ness\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Different machine architectures store data using different byte orders.\r
-// This is referred to as Big- and Little-Endian Byte Ordering. \r
-//\r
-// The issue is: where does a pointer to an integer type actually point?\r
-//\r
-// In both conventions, the address points to the left of the word but:\r
-// Big-Endian - The most significant byte is on the left end of a word\r
-// Little-Endian - The least significant byte is on the left end of a word\r
-//\r
-// Bytes are addressed left to right, so in big-endian order byte 0 is the\r
-// msB, whereas in little-endian order byte 0 is the lsB. For example,\r
-// Intel-based machines store data in little-endian byte order so byte 0 is\r
-// the lsB.\r
-//\r
-// This function establishes byte order at run-time\r
-\r
-namespace stlplus\r
-{\r
-  bool little_endian(void);\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_PORTABILITY_FIXES
+#define STLPLUS_PORTABILITY_FIXES
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Contains work arounds for OS or Compiler specific problems to try to make
+//   them look more alike
+
+//   It is strongly recommended that this header be included as the first
+//   #include in every source file
+
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Problem with MicroSoft defining two different macros to identify Windows
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#define MSWINDOWS
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Problems with unnecessary or unfixable compiler warnings
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+// Microsoft Visual Studio
+// shut up the following irritating warnings
+//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)
+//   4305 - VC6, identifier type was converted to a smaller type
+//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)
+//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it
+//   4290 - VC6, C++ exception specification ignored
+//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)
+//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program
+//   4996 - VC8, 'xxxx' was declared deprecated
+#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4675 4996)
+#endif
+
+#ifdef __BORLANDC__
+// Borland
+// Shut up the following irritating warnings
+//   8026 - Functions with exception specifications are not expanded inline
+//   8027 - Functions with xxx are not expanded inline
+#pragma warn -8026
+#pragma warn -8027
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Problems with redefinition of min/max in various different versions of library headers
+////////////////////////////////////////////////////////////////////////////////
+
+// The Windows headers define macros called max/min which conflict with the templates std::max and std::min.
+// So, to avoid conflicts, MS removed the std::max/min rather than fixing the problem!
+// From Visual Studio .NET (SV7, compiler version 13.00) the STL templates have been added correctly.
+// For MFC compatibility, only undef min and max in non-MFC programs - some bits of MFC
+// use macro min/max in headers. 
+
+// I've created extra template function definitions minimum/maximum that avoid all the problems above
+
+namespace stlplus
+{
+  template<typename T> const T& maximum(const T& l, const T& r) {return l > r ? l : r;}
+  template<typename T> const T& minimum(const T& l, const T& r) {return l < r ? l : r;}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Problems with differences between namespaces
+////////////////////////////////////////////////////////////////////////////////
+
+// Note: not sure of the relevance of this - maybe deprecated?
+// problem in gcc pre-v3 where the sub-namespaces in std aren't present
+// this mean that the statement "using namespace std::rel_ops" created an error because the namespace didn't exist
+
+// I've done a fix here that creates an empty namespace for this case, but I
+// do *not* try to move the contents of std::rel_ops into namespace std
+// This fix only works if you use "using namespace std::rel_ops" to bring in the template relational operators (e.g. != defined i.t.o. ==)
+
+#ifdef __GNUC__
+namespace std
+{
+  namespace rel_ops
+  {
+  }
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// problems with missing functions
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef MSWINDOWS
+unsigned sleep(unsigned seconds);
+#else
+#include <unistd.h>
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Function for establishing endian-ness
+////////////////////////////////////////////////////////////////////////////////
+// Different machine architectures store data using different byte orders.
+// This is referred to as Big- and Little-Endian Byte Ordering. 
+//
+// The issue is: where does a pointer to an integer type actually point?
+//
+// In both conventions, the address points to the left of the word but:
+// Big-Endian - The most significant byte is on the left end of a word
+// Little-Endian - The least significant byte is on the left end of a word
+//
+// Bytes are addressed left to right, so in big-endian order byte 0 is the
+// msB, whereas in little-endian order byte 0 is the lsB. For example,
+// Intel-based machines store data in little-endian byte order so byte 0 is
+// the lsB.
+//
+// This function establishes byte order at run-time
+
+namespace stlplus
+{
+  bool little_endian(void);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
index a8139c238468b8ff6665234fd56ce25d6eedcfeb..0c7d76f1de89f3399b7eefd9d8a4616baa4d5d4f 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Bug fix by Alistair Low: kill on Windows now kills grandchild processes as\r
-// well as the child process. This is done using jobs - which has to be\r
-// enabled by stating that the version of Windows is at least 5.0\r
-#if defined(_WIN32) || defined(_WIN32_WCE)\r
-#define _WIN32_WINNT 0x0500\r
-#endif\r
-\r
-#include "subprocesses.hpp"\r
-#include "file_system.hpp"\r
-#include "dprintf.hpp"\r
-#include <ctype.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-\r
-#ifdef MSWINDOWS\r
-#else\r
-#include <signal.h>\r
-#include <errno.h>\r
-#include <sys/wait.h>\r
-#include <unistd.h>\r
-#include <fcntl.h>\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // argument-vector related stuff\r
-\r
-  static void skip_white (const std::string& command, unsigned& i)\r
-  {\r
-    while(i < command.size() && isspace(command[i]))\r
-      i++;\r
-  }\r
-\r
-  // get_argument is the main function for breaking a string down into separate command arguments\r
-  // it mimics the way shells break down a command into an argv[] and unescapes the escaped characters on the way\r
-\r
-  static std::string get_argument (const std::string& command, unsigned& i)\r
-  {\r
-    std::string result;\r
-#ifdef MSWINDOWS\r
-\r
-  // as far as I know, there is only double-quoting and no escape character in DOS\r
-  // so, how do you include a double-quote in an argument???\r
-\r
-    bool dquote = false;\r
-    for ( ; i < command.size(); i++)\r
-    {\r
-      char ch = command[i];\r
-      if (!dquote && isspace(ch)) break;\r
-      if (dquote)\r
-      {\r
-        if (ch == '\"')\r
-          dquote = false;\r
-        else\r
-          result += ch;\r
-      }\r
-      else if (ch == '\"')\r
-        dquote = true;\r
-      else\r
-        result += ch;\r
-    }\r
-#else\r
-    bool squote = false;\r
-    bool dquote = false;\r
-    bool escaped = false;\r
-    for ( ; i < command.size(); i++)\r
-    {\r
-      char ch = command[i];\r
-      if (!squote && !dquote && !escaped && isspace(ch)) break;\r
-      if (escaped)\r
-      {\r
-        result += ch;\r
-        escaped = false;\r
-      }\r
-      else if (squote)\r
-      {\r
-        if (ch == '\'')\r
-          squote = false;\r
-        else\r
-          result += ch;\r
-      }\r
-      else if (ch == '\\')\r
-        escaped = true;\r
-      else if (dquote)\r
-      {\r
-        if (ch == '\"')\r
-          dquote = false;\r
-        else\r
-          result += ch;\r
-      }\r
-      else if (ch == '\'')\r
-        squote = true;\r
-      else if (ch == '\"')\r
-        dquote = true;\r
-      else\r
-        result += ch;\r
-    }\r
-#endif\r
-\r
-    return result;\r
-  }\r
-\r
-\r
-  // this function performs the reverse of the above on a single argument\r
-  // it escapes special characters and quotes the argument if necessary ready for shell interpretation\r
-\r
-  static std::string make_argument (const std::string& arg)\r
-  {\r
-    std::string result;\r
-    bool needs_quotes = false;\r
-\r
-    for (unsigned i = 0; i < arg.size(); i++)\r
-    {\r
-      switch (arg[i])\r
-      {\r
-        // set of characters requiring escapes\r
-#ifdef MSWINDOWS\r
-#else\r
-      case '\\': case '\'': case '\"': case '`': case '(': case ')': \r
-      case '&': case '|': case '<': case '>': case '*': case '?': case '!':\r
-        result += '\\';\r
-        result += arg[i];\r
-        break;\r
-#endif\r
-        // set of whitespace characters that force quoting\r
-      case ' ':\r
-        result += arg[i];\r
-        needs_quotes = true;\r
-        break;\r
-      default:\r
-        result += arg[i];\r
-        break;\r
-      }\r
-    }\r
-\r
-    if (needs_quotes)\r
-    {\r
-      result.insert(result.begin(), '"');\r
-      result += '"';\r
-    }\r
-    return result;\r
-  }\r
-\r
-  static char* copy_string (const char* str)\r
-  {\r
-    char* result = new char[strlen(str)+1];\r
-    strcpy(result,str);\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  arg_vector::arg_vector (void)\r
-  {\r
-    m_argv = 0;\r
-  }\r
-\r
-  arg_vector::arg_vector (const arg_vector& a)\r
-  {\r
-    m_argv = 0;\r
-    *this = a;\r
-  }\r
-\r
-  arg_vector::arg_vector (char** a)\r
-  {\r
-    m_argv = 0;\r
-    *this = a;\r
-  }\r
-\r
-  arg_vector::arg_vector (const std::string& command)\r
-  {\r
-    m_argv = 0;\r
-    *this = command;\r
-  }\r
-\r
-  arg_vector::arg_vector (const char* command)\r
-  {\r
-    m_argv = 0;\r
-    *this = command;\r
-  }\r
-\r
-  arg_vector::~arg_vector (void)\r
-  {\r
-    clear();\r
-  }\r
-\r
-  arg_vector& arg_vector::operator = (const arg_vector& a)\r
-  {\r
-    return *this = a.m_argv;\r
-  }\r
-\r
-  arg_vector& arg_vector::operator = (char** argv)\r
-  {\r
-    clear();\r
-    for (unsigned i = 0; argv[i]; i++)\r
-      operator += (argv[i]);\r
-    return *this;\r
-  }\r
-\r
-  arg_vector& arg_vector::operator = (const std::string& command)\r
-  {\r
-    clear();\r
-    for (unsigned i = 0; i < command.size(); )\r
-    {\r
-      std::string argument = get_argument(command, i);\r
-      operator += (argument);\r
-      skip_white(command, i);\r
-    }\r
-    return *this;\r
-  }\r
-\r
-  arg_vector& arg_vector::operator = (const char* command)\r
-  {\r
-    return operator = (std::string(command));\r
-  }\r
-\r
-  arg_vector& arg_vector::operator += (const std::string& str)\r
-  {\r
-    insert(size(), str);\r
-    return *this;\r
-  }\r
-\r
-  arg_vector& arg_vector::operator -= (const std::string& str)\r
-  {\r
-    insert(0, str);\r
-    return *this;\r
-  }\r
-\r
-  void arg_vector::insert (unsigned index, const std::string& str) throw(std::out_of_range)\r
-  {\r
-    if (index > size()) throw std::out_of_range("arg_vector::insert");\r
-    // copy up to but not including index, then add the new argument, then copy the rest\r
-    char** new_argv = new char*[size()+2];\r
-    unsigned i = 0;\r
-    for ( ; i < index; i++)\r
-      new_argv[i] = copy_string(m_argv[i]);\r
-    new_argv[index] = copy_string(str.c_str());\r
-    for ( ; i < size(); i++)\r
-      new_argv[i+1] = copy_string(m_argv[i]);\r
-    new_argv[i+1] = 0;\r
-    clear();\r
-    m_argv = new_argv;\r
-  }\r
-\r
-  void arg_vector::clear (unsigned index) throw(std::out_of_range)\r
-  {\r
-    if (index >= size()) throw std::out_of_range("arg_vector::clear");\r
-    // copy up to index, skip it, then copy the rest\r
-    char** new_argv = new char*[size()];\r
-    unsigned i = 0;\r
-    for ( ; i < index; i++)\r
-      new_argv[i] = copy_string(m_argv[i]);\r
-    i++;\r
-    for ( ; i < size(); i++)\r
-      new_argv[i-1] = copy_string(m_argv[i]);\r
-    new_argv[i-1] = 0;\r
-    clear();\r
-    m_argv = new_argv;\r
-  }\r
-\r
-  void arg_vector::clear(void)\r
-  {\r
-    if (m_argv)\r
-    {\r
-      for (unsigned i = 0; m_argv[i]; i++)\r
-        delete[] m_argv[i];\r
-      delete[] m_argv;\r
-      m_argv = 0;\r
-    }\r
-  }\r
-\r
-  unsigned arg_vector::size (void) const\r
-  {\r
-    unsigned i = 0;\r
-    if (m_argv)\r
-      while (m_argv[i])\r
-        i++;\r
-    return i;\r
-  }\r
-\r
-  arg_vector::operator char** (void) const\r
-  {\r
-    return m_argv;\r
-  }\r
-\r
-  char** arg_vector::argv (void) const\r
-  {\r
-    return m_argv;\r
-  }\r
-\r
-  char* arg_vector::operator [] (unsigned index) const throw(std::out_of_range)\r
-  {\r
-    if (index >= size()) throw std::out_of_range("arg_vector::operator[]");\r
-    return m_argv[index];\r
-  }\r
-\r
-  char* arg_vector::argv0 (void) const throw(std::out_of_range)\r
-  {\r
-    return operator [] (0);\r
-  }\r
-\r
-  std::string arg_vector::image (void) const\r
-  {\r
-    std::string result;\r
-    for (unsigned i = 0; i < size(); i++)\r
-    {\r
-      if (i) result += ' ';\r
-      result += make_argument(m_argv[i]);\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // environment-vector\r
-\r
-  // Windoze environment is a single string containing null-terminated\r
-  // name=value strings and the whole terminated by a null\r
-\r
-  // Unix environment is a null-terminated vector of pointers to null-terminated strings\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // platform specifics\r
-\r
-#ifdef MSWINDOWS\r
-  // Windows utilities\r
-\r
-  // Windows environment variables are case-insensitive and I do comparisons by converting to lowercase\r
-  static std::string lowercase(const std::string& val)\r
-  {\r
-    std::string text = val;\r
-    for (unsigned i = 0; i < text.size(); i++)\r
-      text[i] = tolower(text[i]);\r
-    return text;\r
-  }\r
-\r
-  static unsigned envp_size(const char* envp)\r
-  {\r
-    unsigned size = 0;\r
-    while (envp[size] || (size > 0 && envp[size-1])) size++;\r
-    size++;\r
-    return size;\r
-  }\r
-\r
-  static void envp_extract(std::string& name, std::string& value, const char* envp, unsigned& envi)\r
-  {\r
-    name.erase();\r
-    value.erase();\r
-    if (!envp[envi]) return;\r
-    // some special variables start with '=' so ensure at least one character in the name\r
-    name += envp[envi++];\r
-    while(envp[envi] != '=')\r
-      name += envp[envi++];\r
-    envi++;\r
-    while(envp[envi])\r
-      value += envp[envi++];\r
-    envi++;\r
-  }\r
-\r
-  static void envp_append(const std::string& name, const std::string& value, char* envp, unsigned& envi)\r
-  {\r
-    for (unsigned i = 0; i < name.size(); i++)\r
-      envp[envi++] = name[i];\r
-    envp[envi++] = '=';\r
-    for (unsigned j = 0; j < value.size(); j++)\r
-      envp[envi++] = value[j];\r
-    envp[envi++] = '\0';\r
-    envp[envi] = '\0';\r
-  }\r
-\r
-  static char* envp_copy(const char* envp)\r
-  {\r
-    unsigned size = envp_size(envp);\r
-    char* result = new char[size];\r
-    result[0] = '\0';\r
-    unsigned i = 0;\r
-    unsigned j = 0;\r
-    while(envp[i])\r
-    {\r
-      std::string name;\r
-      std::string value;\r
-      envp_extract(name, value, envp, i);\r
-      envp_append(name, value, result, j);\r
-    }\r
-    return result;\r
-  }\r
-\r
-  static void envp_clear(char*& envp)\r
-  {\r
-    if (envp)\r
-    {\r
-      delete[] envp;\r
-      envp = 0;\r
-    }\r
-  }\r
-\r
-  static bool envp_equal(const std::string& left, const std::string& right)\r
-  {\r
-    return lowercase(left) == lowercase(right);\r
-  }\r
-\r
-  static bool envp_less(const std::string& left, const std::string& right)\r
-  {\r
-    return lowercase(left) < lowercase(right);\r
-  }\r
-\r
-#else\r
-  // Unix utilities\r
-\r
-  extern char** environ;\r
-\r
-  static unsigned envp_size(char* const* envp)\r
-  {\r
-    unsigned size = 0;\r
-    while(envp[size]) size++;\r
-    size++;\r
-    return size;\r
-  }\r
-\r
-  static void envp_extract(std::string& name, std::string& value, char* const* envp, unsigned& envi)\r
-  {\r
-    name = "";\r
-    value = "";\r
-    if (!envp[envi]) return;\r
-    unsigned i = 0;\r
-    while(envp[envi][i] != '=')\r
-      name += envp[envi][i++];\r
-    i++;\r
-    while(envp[envi][i])\r
-      value += envp[envi][i++];\r
-    envi++;\r
-  }\r
-\r
-  static void envp_append(const std::string& name, const std::string& value, char** envp, unsigned& envi)\r
-  {\r
-    std::string entry = name + "=" + value;\r
-    envp[envi] = copy_string(entry.c_str());\r
-    envi++;\r
-    envp[envi] = 0;\r
-  }\r
-\r
-  static char** envp_copy(char* const* envp)\r
-  {\r
-    unsigned size = envp_size(envp);\r
-    char** result = new char*[size];\r
-    unsigned i = 0;\r
-    unsigned j = 0;\r
-    while(envp[i])\r
-    {\r
-      std::string name;\r
-      std::string value;\r
-      envp_extract(name, value, envp, i);\r
-      envp_append(name, value, result, j);\r
-    }\r
-    return result;\r
-  }\r
-\r
-  static void envp_clear(char**& envp)\r
-  {\r
-    if (envp)\r
-    {\r
-      for (unsigned i = 0; envp[i]; i++)\r
-        delete[] envp[i];\r
-      delete[] envp;\r
-      envp = 0;\r
-    }\r
-  }\r
-\r
-  static bool envp_equal(const std::string& left, const std::string& right)\r
-  {\r
-    return left == right;\r
-  }\r
-\r
-  static bool envp_less(const std::string& left, const std::string& right)\r
-  {\r
-    return left < right;\r
-  }\r
-\r
-#endif\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  env_vector::env_vector(void)\r
-  {\r
-#ifdef MSWINDOWS\r
-    char* env = (char*)GetEnvironmentStringsA();\r
-    m_env = envp_copy(env);\r
-    FreeEnvironmentStringsA(env);\r
-#else\r
-    m_env = envp_copy(::environ);\r
-#endif\r
-  }\r
-\r
-  env_vector::env_vector (const env_vector& a)\r
-  {\r
-    m_env = 0;\r
-    *this = a;\r
-  }\r
-\r
-  env_vector::~env_vector (void)\r
-  {\r
-    clear();\r
-  }\r
-\r
-  env_vector& env_vector::operator = (const env_vector& a)\r
-  {\r
-    clear();\r
-    m_env = envp_copy(a.m_env);\r
-    return *this;\r
-  }\r
-\r
-  void env_vector::clear(void)\r
-  {\r
-    envp_clear(m_env);\r
-  }\r
-\r
-  void env_vector::add(const std::string& name, const std::string& value)\r
-  {\r
-    // the trick is to add the value in alphabetic order\r
-    // this is done by copying the existing environment string to a new\r
-    // string, inserting the new value when a name greater than it is found\r
-    unsigned size = envp_size(m_env);\r
-#ifdef MSWINDOWS\r
-    unsigned new_size = size + name.size() + value.size() + 2;\r
-    char* new_v = new char[new_size];\r
-    new_v[0] = '\0';\r
-#else\r
-    unsigned new_size = size + 1;\r
-    char** new_v = new char*[new_size];\r
-    new_v[0] = 0;\r
-#endif\r
-    // now extract each name=value pair and check the ordering\r
-    bool added = false;\r
-    unsigned i = 0;\r
-    unsigned j = 0;\r
-    while(m_env[i])\r
-    {\r
-      std::string current_name;\r
-      std::string current_value;\r
-      envp_extract(current_name, current_value, m_env, i);\r
-      if (envp_equal(name,current_name))\r
-      {\r
-        // replace an existing value\r
-        envp_append(name, value, new_v, j);\r
-      }\r
-      else if (!added && envp_less(name,current_name))\r
-      {\r
-        // add the new value first, then the existing one\r
-        envp_append(name, value, new_v, j);\r
-        envp_append(current_name, current_value, new_v, j);\r
-        added = true;\r
-      }\r
-      else\r
-      {\r
-        // just add the existing value\r
-        envp_append(current_name, current_value, new_v, j);\r
-      }\r
-    }\r
-    if (!added)\r
-      envp_append(name, value, new_v, j);\r
-    envp_clear(m_env);\r
-    m_env = new_v;\r
-  }\r
-\r
-\r
-  bool env_vector::remove (const std::string& name)\r
-  {\r
-    bool result = false;\r
-    // this is done by copying the existing environment string to a new string, but excluding the specified name\r
-    unsigned size = envp_size(m_env);\r
-#ifdef MSWINDOWS\r
-    char* new_v = new char[size];\r
-    new_v[0] = '\0';\r
-#else\r
-    char** new_v = new char*[size];\r
-    new_v[0] = 0;\r
-#endif\r
-    unsigned i = 0;\r
-    unsigned j = 0;\r
-    while(m_env[i])\r
-    {\r
-      std::string current_name;\r
-      std::string current_value;\r
-      envp_extract(current_name, current_value, m_env, i);\r
-      if (envp_equal(name,current_name))\r
-        result = true;\r
-      else\r
-        envp_append(current_name, current_value, new_v, j);\r
-    }\r
-    envp_clear(m_env);\r
-    m_env = new_v;\r
-    return result;\r
-  }\r
-\r
-  std::string env_vector::operator [] (const std::string& name) const\r
-  {\r
-    return get(name);\r
-  }\r
-\r
-  std::string env_vector::get (const std::string& name) const\r
-  {\r
-    unsigned i = 0;\r
-    while(m_env[i])\r
-    {\r
-      std::string current_name;\r
-      std::string current_value;\r
-      envp_extract(current_name, current_value, m_env, i);\r
-      if (envp_equal(name,current_name))\r
-        return current_value;\r
-    }\r
-    return std::string();\r
-  }\r
-\r
-  unsigned env_vector::size (void) const\r
-  {\r
-    unsigned i = 0;\r
-#ifdef MSWINDOWS\r
-    unsigned offset = 0;\r
-    while(m_env[offset])\r
-    {\r
-      std::string current_name;\r
-      std::string current_value;\r
-      envp_extract(current_name, current_value, m_env, offset);\r
-      i++;\r
-    }\r
-#else\r
-    while(m_env[i])\r
-      i++;\r
-#endif\r
-\r
-    return i;\r
-  }\r
-\r
-  std::pair<std::string,std::string> env_vector::operator [] (unsigned index) const throw(std::out_of_range)\r
-  {\r
-    return get(index);\r
-  }\r
-\r
-  std::pair<std::string,std::string> env_vector::get (unsigned index) const throw(std::out_of_range)\r
-  {\r
-    if (index >= size()) throw std::out_of_range("arg_vector::get");\r
-    unsigned j = 0;\r
-    for (unsigned i = 0; i < index; i++)\r
-    {\r
-      std::string current_name;\r
-      std::string current_value;\r
-      envp_extract(current_name, current_value, m_env, j);\r
-    }\r
-    std::string name;\r
-    std::string value;\r
-    envp_extract(name, value, m_env, j);\r
-    return std::make_pair(name,value);\r
-  }\r
-\r
-  ENVIRON_TYPE env_vector::envp (void) const\r
-  {\r
-    return m_env;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Synchronous subprocess\r
-  // Win32 implementation mostly cribbed from MSDN examples and then made (much) more readable\r
-  // Unix implementation mostly from man pages and bitter experience\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  subprocess::subprocess(void)\r
-  {\r
-    m_pid.hProcess = 0;\r
-    m_job = 0;\r
-    m_child_in = 0;\r
-    m_child_out = 0;\r
-    m_child_err = 0;\r
-    m_err = 0;\r
-    m_status = 0;\r
-  }\r
-\r
-#else\r
-\r
-  subprocess::subprocess(void)\r
-  {\r
-    m_pid = -1;\r
-    m_child_in = -1;\r
-    m_child_out = -1;\r
-    m_child_err = -1;\r
-    m_err = 0;\r
-    m_status = 0;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  subprocess::~subprocess(void)\r
-  {\r
-    if (m_pid.hProcess != 0)\r
-    {\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      kill();\r
-      WaitForSingleObject(m_pid.hProcess, INFINITE);\r
-      CloseHandle(m_pid.hThread);\r
-      CloseHandle(m_pid.hProcess);\r
-      CloseHandle(m_job);\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  subprocess::~subprocess(void)\r
-  {\r
-    if (m_pid != -1)\r
-    {\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      kill();\r
-      for (;;)\r
-      {\r
-        int wait_status = 0;\r
-        int wait_ret_val = waitpid(m_pid, &wait_status, 0);\r
-        if (wait_ret_val != -1 || errno != EINTR) break;\r
-      }\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-  void subprocess::add_variable(const std::string& name, const std::string& value)\r
-  {\r
-    m_env.add(name, value);\r
-  }\r
-\r
-  bool subprocess::remove_variable(const std::string& name)\r
-  {\r
-    return m_env.remove(name);\r
-  }\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  bool subprocess::spawn(const std::string& path, const arg_vector& argv,\r
-                         bool connect_stdin, bool connect_stdout, bool connect_stderr)\r
-  {\r
-    bool result = true;\r
-    // first create the pipes to be used to connect to the child stdin/out/err\r
-    // If no pipes requested, then connect to the parent stdin/out/err\r
-    // for some reason you have to create a pipe handle, then duplicate it\r
-    // This is not well explained in MSDN but seems to work\r
-    PIPE_TYPE parent_stdin = 0;\r
-    if (!connect_stdin)\r
-      parent_stdin = GetStdHandle(STD_INPUT_HANDLE);\r
-    else\r
-    {\r
-      PIPE_TYPE tmp = 0;\r
-      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};\r
-      CreatePipe(&parent_stdin, &tmp, &inherit_handles, 0);\r
-      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_in, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);\r
-    }\r
-\r
-    PIPE_TYPE parent_stdout = 0;\r
-    if (!connect_stdout)\r
-      parent_stdout = GetStdHandle(STD_OUTPUT_HANDLE);\r
-    else\r
-    {\r
-      PIPE_TYPE tmp = 0;\r
-      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};\r
-      CreatePipe(&tmp, &parent_stdout, &inherit_handles, 0);\r
-      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_out, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);\r
-    }\r
-\r
-    PIPE_TYPE parent_stderr = 0;\r
-    if (!connect_stderr)\r
-      parent_stderr = GetStdHandle(STD_ERROR_HANDLE);\r
-    else\r
-    {\r
-      PIPE_TYPE tmp = 0;\r
-      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};\r
-      CreatePipe(&tmp, &parent_stderr, &inherit_handles, 0);\r
-      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_err, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);\r
-    }\r
-\r
-    // Now create the subprocess\r
-    // The horrible trick of creating a console window and hiding it seems to be required for the pipes to work\r
-    // Note that the child will inherit a copy of the pipe handles\r
-    STARTUPINFOA startup = {sizeof(STARTUPINFO),0,0,0,0,0,0,0,0,0,0,\r
-                            STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW,SW_HIDE,0,0,\r
-                            parent_stdin,parent_stdout,parent_stderr};\r
-    bool created = CreateProcessA(path.c_str(),(char*)argv.image().c_str(),0,0,TRUE,CREATE_SUSPENDED,m_env.envp(),0,&startup,&m_pid) != 0;\r
-    // close the parent copy of the pipe handles so that the pipes will be closed when the child releases them\r
-    if (connect_stdin) CloseHandle(parent_stdin);\r
-    if (connect_stdout) CloseHandle(parent_stdout);\r
-    if (connect_stderr) CloseHandle(parent_stderr);\r
-    if (!created)\r
-    {\r
-      m_err = GetLastError();\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      result = false;\r
-    }\r
-    else\r
-    {\r
-      m_job = CreateJobObject(NULL, NULL);\r
-      AssignProcessToJobObject(m_job, m_pid.hProcess);\r
-      ResumeThread(m_pid.hThread);\r
-\r
-      // The child process is now running so call the user's callback\r
-      // The convention is that the callback can return false, in which case this will kill the child (if its still running)\r
-      if (!callback())\r
-      {\r
-        result = false;\r
-        kill();\r
-      }\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      // wait for the child to finish\r
-      // TODO - kill the child if a timeout happens\r
-      WaitForSingleObject(m_pid.hProcess, INFINITE);\r
-      DWORD exit_status = 0;\r
-      if (!GetExitCodeProcess(m_pid.hProcess, &exit_status))\r
-      {\r
-        m_err = GetLastError();\r
-        result = false;\r
-      }\r
-      else if (exit_status != 0)\r
-        result = false;\r
-      m_status = (int)exit_status;\r
-      CloseHandle(m_pid.hThread);\r
-      CloseHandle(m_pid.hProcess);\r
-      CloseHandle(m_job);\r
-    }\r
-    m_pid.hProcess = 0;\r
-    return result;\r
-  }\r
-\r
-#else\r
-\r
-  bool subprocess::spawn(const std::string& path, const arg_vector& argv,\r
-                         bool connect_stdin, bool connect_stdout, bool connect_stderr)\r
-  {\r
-    bool result = true;\r
-    // first create the pipes to be used to connect to the child stdin/out/err\r
-\r
-    int stdin_pipe [2] = {-1, -1};\r
-    if (connect_stdin)\r
-      pipe(stdin_pipe);\r
-\r
-    int stdout_pipe [2] = {-1, -1};\r
-    if (connect_stdout)\r
-      pipe(stdout_pipe);\r
-\r
-    int stderr_pipe [2] = {-1, -1};\r
-    if (connect_stderr)\r
-      pipe(stderr_pipe);\r
-\r
-    // now create the subprocess\r
-    // In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec\r
-    m_pid = ::fork();\r
-    switch(m_pid)\r
-    {\r
-    case -1:   // failed to fork\r
-      m_err = errno;\r
-      if (connect_stdin)\r
-      {\r
-        ::close(stdin_pipe[0]);\r
-        ::close(stdin_pipe[1]);\r
-      }\r
-      if (connect_stdout)\r
-      {\r
-        ::close(stdout_pipe[0]);\r
-        ::close(stdout_pipe[1]);\r
-      }\r
-      if (connect_stderr)\r
-      {\r
-        ::close(stderr_pipe[0]);\r
-        ::close(stderr_pipe[1]);\r
-      }\r
-      result = false;\r
-      break;\r
-    case 0:  // in child;\r
-    {\r
-      // for each pipe, close the end of the duplicated pipe that is being used by the parent\r
-      // and connect the child's end of the pipe to the appropriate standard I/O device\r
-      if (connect_stdin)\r
-      {\r
-        ::close(stdin_pipe[1]);\r
-        dup2(stdin_pipe[0],STDIN_FILENO);\r
-      }\r
-      if (connect_stdout)\r
-      {\r
-        ::close(stdout_pipe[0]);\r
-        dup2(stdout_pipe[1],STDOUT_FILENO);\r
-      }\r
-      if (connect_stderr)\r
-      {\r
-        ::close(stderr_pipe[0]);\r
-        dup2(stderr_pipe[1],STDERR_FILENO);\r
-      }\r
-      execve(path.c_str(), argv.argv(), m_env.envp());\r
-      // will only ever get here if the exec() failed completely - *must* now exit the child process\r
-      // by using errno, the parent has some chance of diagnosing the cause of the problem\r
-      exit(errno);\r
-    }\r
-    break;\r
-    default:  // in parent\r
-    {\r
-      // for each pipe, close the end of the duplicated pipe that is being used by the child\r
-      // and connect the parent's end of the pipe to the class members so that they are visible to the parent() callback\r
-      if (connect_stdin)\r
-      {\r
-        ::close(stdin_pipe[0]);\r
-        m_child_in = stdin_pipe[1];\r
-      }\r
-      if (connect_stdout)\r
-      {\r
-        ::close(stdout_pipe[1]);\r
-        m_child_out = stdout_pipe[0];\r
-      }\r
-      if (connect_stderr)\r
-      {\r
-        ::close(stderr_pipe[1]);\r
-        m_child_err = stderr_pipe[0];\r
-      }\r
-      // call the user's callback\r
-      if (!callback())\r
-      {\r
-        result = false;\r
-        kill();\r
-      }\r
-      // close the pipes and wait for the child to finish\r
-      // wait exits on a signal which may be the child signalling its exit or may be an interrupt\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      int wait_status = 0;\r
-      for (;;)\r
-      {\r
-        int wait_ret_val = waitpid(m_pid, &wait_status, 0);\r
-        if (wait_ret_val != -1 || errno != EINTR) break;\r
-      }\r
-      // establish whether an error occurred\r
-      if (WIFSIGNALED(wait_status))\r
-      {\r
-        // set_error(errno);\r
-        m_status = WTERMSIG(wait_status);\r
-        result = false;\r
-      }\r
-      else if (WIFEXITED(wait_status))\r
-      {\r
-        m_status = WEXITSTATUS(wait_status);\r
-        if (m_status != 0)\r
-          result = false;\r
-      }\r
-      m_pid = -1;\r
-    }\r
-    break;\r
-    }\r
-    return result;\r
-  }\r
-\r
-#endif\r
-\r
-  bool subprocess::spawn(const std::string& command_line,\r
-                                  bool connect_stdin, bool connect_stdout, bool connect_stderr)\r
-  {\r
-    arg_vector arguments = command_line;\r
-    if (arguments.size() == 0) return false;\r
-    std::string path = path_lookup(arguments.argv0());\r
-    if (path.empty()) return false;\r
-    return spawn(path, arguments, connect_stdin, connect_stdout, connect_stderr);\r
-  }\r
-\r
-  bool subprocess::callback(void)\r
-  {\r
-    return true;\r
-  }\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  bool subprocess::kill (void)\r
-  {\r
-    if (!m_pid.hProcess) return false;\r
-    close_stdin();\r
-    close_stdout();\r
-    close_stderr();\r
-    if (!TerminateJobObject(m_job, (UINT)-1))\r
-    {\r
-      m_err = GetLastError();\r
-      return false;\r
-    }\r
-    return true;\r
-  }\r
-\r
-#else\r
-\r
-  bool subprocess::kill (void)\r
-  {\r
-    if (m_pid == -1) return false;\r
-    close_stdin();\r
-    close_stdout();\r
-    close_stderr();\r
-    if (::kill(m_pid, SIGINT) == -1)\r
-    {\r
-      m_err = errno;\r
-      return false;\r
-    }\r
-    return true;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  int subprocess::write_stdin (std::string& buffer)\r
-  {\r
-    if (m_child_in == 0) return -1;\r
-    // do a blocking write of the whole buffer\r
-    DWORD bytes = 0;\r
-    if (!WriteFile(m_child_in, buffer.c_str(), (DWORD)buffer.size(), &bytes, 0))\r
-    {\r
-      m_err = GetLastError();\r
-      close_stdin();\r
-      return -1;\r
-    }\r
-    // now discard that part of the buffer that was written\r
-    if (bytes > 0)\r
-      buffer.erase(0, bytes);\r
-    return bytes;\r
-  }\r
-\r
-#else\r
-\r
-  int subprocess::write_stdin (std::string& buffer)\r
-  {\r
-    if (m_child_in == -1) return -1;\r
-    // do a blocking write of the whole buffer\r
-    int bytes = write(m_child_in, buffer.c_str(), buffer.size());\r
-    if (bytes == -1)\r
-    {\r
-      m_err = errno;\r
-      close_stdin();\r
-      return -1;\r
-    }\r
-    // now discard that part of the buffer that was written\r
-    if (bytes > 0)\r
-      buffer.erase(0, bytes);\r
-    return bytes;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  int subprocess::read_stdout (std::string& buffer)\r
-  {\r
-    if (m_child_out == 0) return -1;\r
-    DWORD bytes = 0;\r
-    DWORD buffer_size = 256;\r
-    char* tmp = new char[buffer_size];\r
-    if (!ReadFile(m_child_out, tmp, buffer_size, &bytes, 0))\r
-    {\r
-      if (GetLastError() != ERROR_BROKEN_PIPE)\r
-        m_err = GetLastError();\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return (int)bytes;\r
-  }\r
-\r
-#else\r
-\r
-  int subprocess::read_stdout (std::string& buffer)\r
-  {\r
-    if (m_child_out == -1) return -1;\r
-    int buffer_size = 256;\r
-    char* tmp = new char[buffer_size];\r
-    int bytes = read(m_child_out, tmp, buffer_size);\r
-    if (bytes == -1)\r
-    {\r
-      m_err = errno;\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return bytes;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  int subprocess::read_stderr(std::string& buffer)\r
-  {\r
-    if (m_child_err == 0) return -1;\r
-    DWORD bytes = 0;\r
-    DWORD buffer_size = 256;\r
-    char* tmp = new char[buffer_size];\r
-    if (!ReadFile(m_child_err, tmp, buffer_size, &bytes, 0))\r
-    {\r
-      if (GetLastError() != ERROR_BROKEN_PIPE)\r
-        m_err = GetLastError();\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return (int)bytes;\r
-  }\r
-\r
-#else\r
-\r
-  int subprocess::read_stderr (std::string& buffer)\r
-  {\r
-    if (m_child_err == -1) return -1;\r
-    int buffer_size = 256;\r
-    char* tmp = new char[buffer_size];\r
-    int bytes = read(m_child_err, tmp, buffer_size);\r
-    if (bytes == -1)\r
-    {\r
-      m_err = errno;\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return bytes;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  void subprocess::close_stdin (void)\r
-  {\r
-    if (m_child_in)\r
-    {\r
-      CloseHandle(m_child_in);\r
-      m_child_in = 0;\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  void subprocess::close_stdin (void)\r
-  {\r
-    if (m_child_in != -1)\r
-    {\r
-      ::close(m_child_in);\r
-      m_child_in = -1;\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  void subprocess::close_stdout (void)\r
-  {\r
-    if (m_child_out)\r
-    {\r
-      CloseHandle(m_child_out);\r
-      m_child_out = 0;\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  void subprocess::close_stdout (void)\r
-  {\r
-    if (m_child_out != -1)\r
-    {\r
-      ::close(m_child_out);\r
-      m_child_out = -1;\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  void subprocess::close_stderr (void)\r
-  {\r
-    if (m_child_err)\r
-    {\r
-      CloseHandle(m_child_err);\r
-      m_child_err = 0;\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  void subprocess::close_stderr (void)\r
-  {\r
-    if (m_child_err != -1)\r
-    {\r
-      ::close(m_child_err);\r
-      m_child_err = -1;\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-  bool subprocess::error(void) const\r
-  {\r
-    return m_err != 0;\r
-  }\r
-\r
-  int subprocess::error_number(void) const\r
-  {\r
-    return m_err;\r
-  }\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  std::string subprocess::error_text(void) const\r
-  {\r
-    if (m_err == 0) return std::string();\r
-    char* message;\r
-    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,\r
-                  0,\r
-                  m_err,\r
-                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
-                  (LPTSTR)&message,\r
-                  0,0);\r
-    std::string result = message;\r
-    LocalFree(message);\r
-    // the error message is for some perverse reason newline terminated - remove this\r
-    if (result[result.size()-1] == '\n')\r
-      result.erase(result.end()-1);\r
-    if (result[result.size()-1] == '\r')\r
-      result.erase(result.end()-1);\r
-    return result;\r
-  }\r
-\r
-#else\r
-\r
-  std::string subprocess::error_text(void) const\r
-  {\r
-    if (m_err == 0) return std::string();\r
-    char* text = strerror(m_err);\r
-    if (text) return std::string(text);\r
-    return "error number " + dformat("%d",m_err);\r
-  }\r
-\r
-#endif\r
-\r
-  int subprocess::exit_status(void) const\r
-  {\r
-    return m_status;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // backtick subprocess and operations\r
-\r
-  backtick_subprocess::backtick_subprocess(void) : subprocess()\r
-  {\r
-  }\r
-\r
-  bool backtick_subprocess::callback(void)\r
-  {\r
-    for (;;)\r
-    {\r
-      std::string buffer;\r
-      int read_size = read_stdout(buffer);\r
-      if (read_size < 0) break;\r
-      m_text += buffer;\r
-    }\r
-    return !error();\r
-  }\r
-\r
-  bool backtick_subprocess::spawn(const std::string& path, const arg_vector& argv)\r
-  {\r
-    return subprocess::spawn(path, argv, false, true, false);\r
-  }\r
-\r
-  bool backtick_subprocess::spawn(const std::string& command_line)\r
-  {\r
-    return subprocess::spawn(command_line, false, true, false);\r
-  }\r
-\r
-  std::vector<std::string> backtick_subprocess::text(void) const\r
-  {\r
-    std::vector<std::string> result;\r
-    // convert the raw text into a vector of strings, each corresponding to a line\r
-    // in the process, strip out platform-specific line-endings\r
-    for (unsigned i = 0; i < m_text.size(); i++)\r
-    {\r
-      // handle any kind of line-ending - Dos, Unix or MacOS\r
-      switch(m_text[i])\r
-      {\r
-      case '\xd': // carriage-return - optionally followed by linefeed\r
-      {\r
-        // discard optional following linefeed\r
-        if ((i+1 < m_text.size()) && (m_text[i+1] == '\xa'))\r
-          i++;\r
-        // add a new line to the end of the vector\r
-        result.push_back(std::string());\r
-        break;\r
-      }\r
-      case '\xa': // linefeed\r
-      {\r
-        // add a new line to the end of the vector\r
-        result.push_back(std::string());\r
-        break;\r
-      }\r
-      default:\r
-      {\r
-        result.back() += m_text[i];\r
-        break;\r
-      }\r
-      }\r
-    }\r
-    // tidy up - if the last line ended with a newline, the vector will end with an empty string - discard this\r
-    if ((result.size()) > 0 && result.back().empty())\r
-      result.erase(result.end()-1);\r
-    return result;\r
-  }\r
-\r
-  std::vector<std::string> backtick(const std::string& path, const arg_vector& argv)\r
-  {\r
-    backtick_subprocess sub;\r
-    sub.spawn(path, argv);\r
-    return sub.text();\r
-  }\r
-\r
-  std::vector<std::string> backtick(const std::string& command_line)\r
-  {\r
-    backtick_subprocess sub;\r
-    sub.spawn(command_line);\r
-    return sub.text();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Asynchronous subprocess\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  async_subprocess::async_subprocess(void)\r
-  {\r
-    m_pid.hProcess = 0;\r
-    m_job = 0;\r
-    m_child_in = 0;\r
-    m_child_out = 0;\r
-    m_child_err = 0;\r
-    m_err = 0;\r
-    m_status = 0;\r
-  }\r
-\r
-#else\r
-\r
-  async_subprocess::async_subprocess(void)\r
-  {\r
-    m_pid = -1;\r
-    m_child_in = -1;\r
-    m_child_out = -1;\r
-    m_child_err = -1;\r
-    m_err = 0;\r
-    m_status = 0;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  async_subprocess::~async_subprocess(void)\r
-  {\r
-    if (m_pid.hProcess != 0)\r
-    {\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      kill();\r
-      WaitForSingleObject(m_pid.hProcess, INFINITE);\r
-      CloseHandle(m_pid.hThread);\r
-      CloseHandle(m_pid.hProcess);\r
-      CloseHandle(m_job);\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  async_subprocess::~async_subprocess(void)\r
-  {\r
-    if (m_pid != -1)\r
-    {\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      kill();\r
-      for (;;)\r
-      {\r
-        int wait_status = 0;\r
-        int wait_ret_val = waitpid(m_pid, &wait_status, 0);\r
-        if (wait_ret_val != -1 || errno != EINTR) break;\r
-      }\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-  void async_subprocess::set_error(int e)\r
-  {\r
-    m_err = e;\r
-  }\r
-\r
-  void async_subprocess::add_variable(const std::string& name, const std::string& value)\r
-  {\r
-    m_env.add(name, value);\r
-  }\r
-\r
-  bool async_subprocess::remove_variable(const std::string& name)\r
-  {\r
-    return m_env.remove(name);\r
-  }\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  bool async_subprocess::spawn(const std::string& path, const arg_vector& argv,\r
-                                        bool connect_stdin, bool connect_stdout, bool connect_stderr)\r
-  {\r
-    bool result = true;\r
-    // first create the pipes to be used to connect to the child stdin/out/err\r
-    // If no pipes requested, then connect to the parent stdin/out/err\r
-    // for some reason you have to create a pipe handle, then duplicate it\r
-    // This is not well explained in MSDN but seems to work\r
-    PIPE_TYPE parent_stdin = 0;\r
-    if (!connect_stdin)\r
-      parent_stdin = GetStdHandle(STD_INPUT_HANDLE);\r
-    else\r
-    {\r
-      PIPE_TYPE tmp = 0;\r
-      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};\r
-      CreatePipe(&parent_stdin, &tmp, &inherit_handles, 0);\r
-      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_in, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);\r
-    }\r
-\r
-    PIPE_TYPE parent_stdout = 0;\r
-    if (!connect_stdout)\r
-      parent_stdout = GetStdHandle(STD_OUTPUT_HANDLE);\r
-    else\r
-    {\r
-      PIPE_TYPE tmp = 0;\r
-      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};\r
-      CreatePipe(&tmp, &parent_stdout, &inherit_handles, 0);\r
-      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_out, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);\r
-    }\r
-\r
-    PIPE_TYPE parent_stderr = 0;\r
-    if (!connect_stderr)\r
-      parent_stderr = GetStdHandle(STD_ERROR_HANDLE);\r
-    else\r
-    {\r
-      PIPE_TYPE tmp = 0;\r
-      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};\r
-      CreatePipe(&tmp, &parent_stderr, &inherit_handles, 0);\r
-      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_err, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);\r
-    }\r
-\r
-    // Now create the subprocess\r
-    // The horrible trick of creating a console window and hiding it seems to be required for the pipes to work\r
-    // Note that the child will inherit a copy of the pipe handles\r
-    STARTUPINFOA startup = {sizeof(STARTUPINFO),0,0,0,0,0,0,0,0,0,0,\r
-                            STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW,SW_HIDE,0,0,\r
-                            parent_stdin,parent_stdout,parent_stderr};\r
-    bool created = CreateProcessA(path.c_str(),(char*)argv.image().c_str(),0,0,TRUE,CREATE_SUSPENDED,m_env.envp(),0,&startup,&m_pid) != 0;\r
-    // close the parent copy of the pipe handles so that the pipes will be closed when the child releases them\r
-    if (connect_stdin) CloseHandle(parent_stdin);\r
-    if (connect_stdout) CloseHandle(parent_stdout);\r
-    if (connect_stderr) CloseHandle(parent_stderr);\r
-    if (!created)\r
-    {\r
-      set_error(GetLastError());\r
-      close_stdin();\r
-      close_stdout();\r
-      close_stderr();\r
-      result = false;\r
-    }\r
-    else\r
-    {\r
-      m_job = CreateJobObject(NULL, NULL);\r
-      AssignProcessToJobObject(m_job, m_pid.hProcess);\r
-      ResumeThread(m_pid.hThread);\r
-    }\r
-    return result;\r
-  }\r
-\r
-#else\r
-\r
-  bool async_subprocess::spawn(const std::string& path, const arg_vector& argv,\r
-                               bool connect_stdin, bool connect_stdout, bool connect_stderr)\r
-  {\r
-    bool result = true;\r
-    // first create the pipes to be used to connect to the child stdin/out/err\r
-\r
-    int stdin_pipe [2] = {-1, -1};\r
-    if (connect_stdin)\r
-      pipe(stdin_pipe);\r
-\r
-    int stdout_pipe [2] = {-1, -1};\r
-    if (connect_stdout)\r
-      pipe(stdout_pipe);\r
-\r
-    int stderr_pipe [2] = {-1, -1};\r
-    if (connect_stderr)\r
-      pipe(stderr_pipe);\r
-\r
-    // now create the subprocess\r
-    // In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec\r
-    m_pid = ::fork();\r
-    switch(m_pid)\r
-    {\r
-    case -1:   // failed to fork\r
-      set_error(errno);\r
-      if (connect_stdin)\r
-      {\r
-        ::close(stdin_pipe[0]);\r
-        ::close(stdin_pipe[1]);\r
-      }\r
-      if (connect_stdout)\r
-      {\r
-        ::close(stdout_pipe[0]);\r
-        ::close(stdout_pipe[1]);\r
-      }\r
-      if (connect_stderr)\r
-      {\r
-        ::close(stderr_pipe[0]);\r
-        ::close(stderr_pipe[1]);\r
-      }\r
-      result = false;\r
-      break;\r
-    case 0:  // in child;\r
-    {\r
-      // for each pipe, close the end of the duplicated pipe that is being used by the parent\r
-      // and connect the child's end of the pipe to the appropriate standard I/O device\r
-      if (connect_stdin)\r
-      {\r
-        ::close(stdin_pipe[1]);\r
-        dup2(stdin_pipe[0],STDIN_FILENO);\r
-      }\r
-      if (connect_stdout)\r
-      {\r
-        ::close(stdout_pipe[0]);\r
-        dup2(stdout_pipe[1],STDOUT_FILENO);\r
-      }\r
-      if (connect_stderr)\r
-      {\r
-        ::close(stderr_pipe[0]);\r
-        dup2(stderr_pipe[1],STDERR_FILENO);\r
-      }\r
-      execve(path.c_str(), argv.argv(), m_env.envp());\r
-      // will only ever get here if the exec() failed completely - *must* now exit the child process\r
-      // by using errno, the parent has some chance of diagnosing the cause of the problem\r
-      exit(errno);\r
-    }\r
-    break;\r
-    default:  // in parent\r
-    {\r
-      // for each pipe, close the end of the duplicated pipe that is being used by the child\r
-      // and connect the parent's end of the pipe to the class members so that they are visible to the parent() callback\r
-      if (connect_stdin)\r
-      {\r
-        ::close(stdin_pipe[0]);\r
-        m_child_in = stdin_pipe[1];\r
-        if (fcntl(m_child_in, F_SETFL, O_NONBLOCK) == -1)\r
-        {\r
-          set_error(errno);\r
-          result = false;\r
-        }\r
-      }\r
-      if (connect_stdout)\r
-      {\r
-        ::close(stdout_pipe[1]);\r
-        m_child_out = stdout_pipe[0];\r
-        if (fcntl(m_child_out, F_SETFL, O_NONBLOCK) == -1)\r
-        {\r
-          set_error(errno);\r
-          result = false;\r
-        }\r
-      }\r
-      if (connect_stderr)\r
-      {\r
-        ::close(stderr_pipe[1]);\r
-        m_child_err = stderr_pipe[0];\r
-        if (fcntl(m_child_err, F_SETFL, O_NONBLOCK) == -1)\r
-        {\r
-          set_error(errno);\r
-          result = false;\r
-        }\r
-      }\r
-    }\r
-    break;\r
-    }\r
-    return result;\r
-  }\r
-\r
-#endif\r
-\r
-  bool async_subprocess::spawn(const std::string& command_line,\r
-                               bool connect_stdin, bool connect_stdout, bool connect_stderr)\r
-  {\r
-    arg_vector arguments = command_line;\r
-    if (arguments.size() == 0) return false;\r
-    std::string path = path_lookup(arguments.argv0());\r
-    if (path.empty()) return false;\r
-    return spawn(path, arguments, connect_stdin, connect_stdout, connect_stderr);\r
-  }\r
-\r
-  bool async_subprocess::callback(void)\r
-  {\r
-    return true;\r
-  }\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  bool async_subprocess::tick(void)\r
-  {\r
-    bool result = true;\r
-    if (!callback())\r
-      kill();\r
-    DWORD exit_status = 0;\r
-    if (!GetExitCodeProcess(m_pid.hProcess, &exit_status))\r
-    {\r
-      set_error(GetLastError());\r
-      result = false;\r
-    }\r
-    else if (exit_status != STILL_ACTIVE)\r
-    {\r
-      CloseHandle(m_pid.hThread);\r
-      CloseHandle(m_pid.hProcess);\r
-      CloseHandle(m_job);\r
-      m_pid.hProcess = 0;\r
-      result = false;\r
-    }\r
-    m_status = (int)exit_status;\r
-    return result;\r
-  }\r
-\r
-#else\r
-\r
-  bool async_subprocess::tick(void)\r
-  {\r
-    bool result = true;\r
-    if (!callback())\r
-      kill();\r
-    int wait_status = 0;\r
-    int wait_ret_val = waitpid(m_pid, &wait_status, WNOHANG);\r
-    if (wait_ret_val == -1 && errno != EINTR)\r
-    {\r
-      set_error(errno);\r
-      result = false;\r
-    }\r
-    else if (wait_ret_val != 0)\r
-    {\r
-      // the only states that indicate a terminated child are WIFSIGNALLED and WIFEXITED\r
-      if (WIFSIGNALED(wait_status))\r
-      {\r
-        // set_error(errno);\r
-        m_status = WTERMSIG(wait_status);\r
-        result = false;\r
-      }\r
-      else if (WIFEXITED(wait_status))\r
-      {\r
-        // child has exited\r
-        m_status = WEXITSTATUS(wait_status);\r
-        result = false;\r
-      }\r
-    }\r
-    if (!result)\r
-      m_pid = -1;\r
-    return result;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  bool async_subprocess::kill(void)\r
-  {\r
-    if (!m_pid.hProcess) return false;\r
-    close_stdin();\r
-    close_stdout();\r
-    close_stderr();\r
-    if (!TerminateJobObject(m_job, (UINT)-1))\r
-    {\r
-      set_error(GetLastError());\r
-      return false;\r
-    }\r
-    return true;\r
-  }\r
-\r
-#else\r
-\r
-  bool async_subprocess::kill(void)\r
-  {\r
-    if (m_pid == -1) return false;\r
-    close_stdin();\r
-    close_stdout();\r
-    close_stderr();\r
-    if (::kill(m_pid, SIGINT) == -1)\r
-    {\r
-      set_error(errno);\r
-      return false;\r
-    }\r
-    return true;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  int async_subprocess::write_stdin (std::string& buffer)\r
-  {\r
-    if (m_child_in == 0) return -1;\r
-    // there doesn't seem to be a way of doing non-blocking writes under Windoze\r
-    DWORD bytes = 0;\r
-    if (!WriteFile(m_child_in, buffer.c_str(), (DWORD)buffer.size(), &bytes, 0))\r
-    {\r
-      set_error(GetLastError());\r
-      close_stdin();\r
-      return -1;\r
-    }\r
-    // now discard that part of the buffer that was written\r
-    if (bytes > 0)\r
-      buffer.erase(0, bytes);\r
-    return (int)bytes;\r
-  }\r
-\r
-#else\r
-\r
-  int async_subprocess::write_stdin (std::string& buffer)\r
-  {\r
-    if (m_child_in == -1) return -1;\r
-    // relies on the pipe being non-blocking\r
-    // This does block under Windoze\r
-    int bytes = write(m_child_in, buffer.c_str(), buffer.size());\r
-    if (bytes == -1 && errno == EAGAIN)\r
-    {\r
-      // not ready\r
-      return 0;\r
-    }\r
-    if (bytes == -1)\r
-    {\r
-      // error on write - close the pipe and give up\r
-      set_error(errno);\r
-      close_stdin();\r
-      return -1;\r
-    }\r
-    // successful write\r
-    // now discard that part of the buffer that was written\r
-    if (bytes > 0)\r
-      buffer.erase(0, bytes);\r
-    return bytes;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  int async_subprocess::read_stdout (std::string& buffer)\r
-  {\r
-    if (m_child_out == 0) return -1;\r
-    // peek at the buffer to see how much data there is in the first place\r
-    DWORD buffer_size = 0;\r
-    if (!PeekNamedPipe(m_child_out, 0, 0, 0, &buffer_size, 0))\r
-    {\r
-      if (GetLastError() != ERROR_BROKEN_PIPE)\r
-        set_error(GetLastError());\r
-      close_stdout();\r
-      return -1;\r
-    }\r
-    if (buffer_size == 0) return 0;\r
-    DWORD bytes = 0;\r
-    char* tmp = new char[buffer_size];\r
-    if (!ReadFile(m_child_out, tmp, buffer_size, &bytes, 0))\r
-    {\r
-      set_error(GetLastError());\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return (int)bytes;\r
-  }\r
-\r
-#else\r
-\r
-  int async_subprocess::read_stdout (std::string& buffer)\r
-  {\r
-    if (m_child_out == -1) return -1;\r
-    // rely on the pipe being non-blocking\r
-    int buffer_size = 256;\r
-    char* tmp = new char[buffer_size];\r
-    int bytes = read(m_child_out, tmp, buffer_size);\r
-    if (bytes == -1 && errno == EAGAIN)\r
-    {\r
-      // not ready\r
-      delete[] tmp;\r
-      return 0;\r
-    }\r
-    if (bytes == -1)\r
-    {\r
-      // error\r
-      set_error(errno);\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stdout();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    // successful read\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return bytes;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  int async_subprocess::read_stderr (std::string& buffer)\r
-  {\r
-    if (m_child_err == 0) return -1;\r
-    // peek at the buffer to see how much data there is in the first place\r
-    DWORD buffer_size = 0;\r
-    if (!PeekNamedPipe(m_child_err, 0, 0, 0, &buffer_size, 0))\r
-    {\r
-      if (GetLastError() != ERROR_BROKEN_PIPE)\r
-        set_error(GetLastError());\r
-      close_stderr();\r
-      return -1;\r
-    }\r
-    if (buffer_size == 0) return 0;\r
-    DWORD bytes = 0;\r
-    char* tmp = new char[buffer_size];\r
-    if (!ReadFile(m_child_err, tmp, buffer_size, &bytes, 0))\r
-    {\r
-      set_error(GetLastError());\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return (int)bytes;\r
-  }\r
-\r
-#else\r
-\r
-  int async_subprocess::read_stderr (std::string& buffer)\r
-  {\r
-    if (m_child_err == -1) return -1;\r
-    // rely on the pipe being non-blocking\r
-    int buffer_size = 256;\r
-    char* tmp = new char[buffer_size];\r
-    int bytes = read(m_child_err, tmp, buffer_size);\r
-    if (bytes == -1 && errno == EAGAIN)\r
-    {\r
-      // not ready\r
-      delete[] tmp;\r
-      return 0;\r
-    }\r
-    if (bytes == -1)\r
-    {\r
-      // error\r
-      set_error(errno);\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    if (bytes == 0)\r
-    {\r
-      // EOF\r
-      close_stderr();\r
-      delete[] tmp;\r
-      return -1;\r
-    }\r
-    // successful read\r
-    buffer.append(tmp, bytes);\r
-    delete[] tmp;\r
-    return bytes;\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  void async_subprocess::close_stdin (void)\r
-  {\r
-    if (m_child_in)\r
-    {\r
-      CloseHandle(m_child_in);\r
-      m_child_in = 0;\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  void async_subprocess::close_stdin (void)\r
-  {\r
-    if (m_child_in != -1)\r
-    {\r
-      ::close(m_child_in);\r
-      m_child_in = -1;\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  void async_subprocess::close_stdout (void)\r
-  {\r
-    if (m_child_out)\r
-    {\r
-      CloseHandle(m_child_out);\r
-      m_child_out = 0;\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  void async_subprocess::close_stdout (void)\r
-  {\r
-    if (m_child_out != -1)\r
-    {\r
-      ::close(m_child_out);\r
-      m_child_out = -1;\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  void async_subprocess::close_stderr (void)\r
-  {\r
-    if (m_child_err)\r
-    {\r
-      CloseHandle(m_child_err);\r
-      m_child_err = 0;\r
-    }\r
-  }\r
-\r
-#else\r
-\r
-  void async_subprocess::close_stderr (void)\r
-  {\r
-    if (m_child_err != -1)\r
-    {\r
-      ::close(m_child_err);\r
-      m_child_err = -1;\r
-    }\r
-  }\r
-\r
-#endif\r
-\r
-  bool async_subprocess::error(void) const\r
-  {\r
-    return m_err != 0;\r
-  }\r
-\r
-  int async_subprocess::error_number(void) const\r
-  {\r
-    return m_err;\r
-  }\r
-\r
-#ifdef MSWINDOWS\r
-\r
-  std::string async_subprocess::error_text(void) const\r
-  {\r
-    if (m_err == 0) return std::string();\r
-    char* message;\r
-    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,\r
-                  0,\r
-                  m_err,\r
-                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\r
-                  (LPTSTR)&message,\r
-                  0,0);\r
-    std::string result = message;\r
-    LocalFree(message);\r
-    // the error message is for some perverse reason newline terminated - remove this\r
-    if (result[result.size()-1] == '\n')\r
-      result.erase(result.end()-1);\r
-    if (result[result.size()-1] == '\r')\r
-      result.erase(result.end()-1);\r
-    return result;\r
-  }\r
-\r
-#else\r
-\r
-  std::string async_subprocess::error_text(void) const\r
-  {\r
-    if (m_err == 0) return std::string();\r
-    char* text = strerror(m_err);\r
-    if (text) return std::string(text);\r
-    return "error number " + dformat("%d",m_err);\r
-  }\r
-\r
-#endif\r
-\r
-  int async_subprocess::exit_status(void) const\r
-  {\r
-    return m_status;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Bug fix by Alistair Low: kill on Windows now kills grandchild processes as
+// well as the child process. This is done using jobs - which has to be
+// enabled by stating that the version of Windows is at least 5.0
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include "subprocesses.hpp"
+#include "file_system.hpp"
+#include "dprintf.hpp"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef MSWINDOWS
+#else
+#include <signal.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // argument-vector related stuff
+
+  static void skip_white (const std::string& command, unsigned& i)
+  {
+    while(i < command.size() && isspace(command[i]))
+      i++;
+  }
+
+  // get_argument is the main function for breaking a string down into separate command arguments
+  // it mimics the way shells break down a command into an argv[] and unescapes the escaped characters on the way
+
+  static std::string get_argument (const std::string& command, unsigned& i)
+  {
+    std::string result;
+#ifdef MSWINDOWS
+
+  // as far as I know, there is only double-quoting and no escape character in DOS
+  // so, how do you include a double-quote in an argument???
+
+    bool dquote = false;
+    for ( ; i < command.size(); i++)
+    {
+      char ch = command[i];
+      if (!dquote && isspace(ch)) break;
+      if (dquote)
+      {
+        if (ch == '\"')
+          dquote = false;
+        else
+          result += ch;
+      }
+      else if (ch == '\"')
+        dquote = true;
+      else
+        result += ch;
+    }
+#else
+    bool squote = false;
+    bool dquote = false;
+    bool escaped = false;
+    for ( ; i < command.size(); i++)
+    {
+      char ch = command[i];
+      if (!squote && !dquote && !escaped && isspace(ch)) break;
+      if (escaped)
+      {
+        result += ch;
+        escaped = false;
+      }
+      else if (squote)
+      {
+        if (ch == '\'')
+          squote = false;
+        else
+          result += ch;
+      }
+      else if (ch == '\\')
+        escaped = true;
+      else if (dquote)
+      {
+        if (ch == '\"')
+          dquote = false;
+        else
+          result += ch;
+      }
+      else if (ch == '\'')
+        squote = true;
+      else if (ch == '\"')
+        dquote = true;
+      else
+        result += ch;
+    }
+#endif
+
+    return result;
+  }
+
+
+  // this function performs the reverse of the above on a single argument
+  // it escapes special characters and quotes the argument if necessary ready for shell interpretation
+
+  static std::string make_argument (const std::string& arg)
+  {
+    std::string result;
+    bool needs_quotes = false;
+
+    for (unsigned i = 0; i < arg.size(); i++)
+    {
+      switch (arg[i])
+      {
+        // set of characters requiring escapes
+#ifdef MSWINDOWS
+#else
+      case '\\': case '\'': case '\"': case '`': case '(': case ')': 
+      case '&': case '|': case '<': case '>': case '*': case '?': case '!':
+        result += '\\';
+        result += arg[i];
+        break;
+#endif
+        // set of whitespace characters that force quoting
+      case ' ':
+        result += arg[i];
+        needs_quotes = true;
+        break;
+      default:
+        result += arg[i];
+        break;
+      }
+    }
+
+    if (needs_quotes)
+    {
+      result.insert(result.begin(), '"');
+      result += '"';
+    }
+    return result;
+  }
+
+  static char* copy_string (const char* str)
+  {
+    char* result = new char[strlen(str)+1];
+    strcpy(result,str);
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  arg_vector::arg_vector (void)
+  {
+    m_argv = 0;
+  }
+
+  arg_vector::arg_vector (const arg_vector& a)
+  {
+    m_argv = 0;
+    *this = a;
+  }
+
+  arg_vector::arg_vector (char** a)
+  {
+    m_argv = 0;
+    *this = a;
+  }
+
+  arg_vector::arg_vector (const std::string& command)
+  {
+    m_argv = 0;
+    *this = command;
+  }
+
+  arg_vector::arg_vector (const char* command)
+  {
+    m_argv = 0;
+    *this = command;
+  }
+
+  arg_vector::~arg_vector (void)
+  {
+    clear();
+  }
+
+  arg_vector& arg_vector::operator = (const arg_vector& a)
+  {
+    return *this = a.m_argv;
+  }
+
+  arg_vector& arg_vector::operator = (char** argv)
+  {
+    clear();
+    for (unsigned i = 0; argv[i]; i++)
+      operator += (argv[i]);
+    return *this;
+  }
+
+  arg_vector& arg_vector::operator = (const std::string& command)
+  {
+    clear();
+    for (unsigned i = 0; i < command.size(); )
+    {
+      std::string argument = get_argument(command, i);
+      operator += (argument);
+      skip_white(command, i);
+    }
+    return *this;
+  }
+
+  arg_vector& arg_vector::operator = (const char* command)
+  {
+    return operator = (std::string(command));
+  }
+
+  arg_vector& arg_vector::operator += (const std::string& str)
+  {
+    insert(size(), str);
+    return *this;
+  }
+
+  arg_vector& arg_vector::operator -= (const std::string& str)
+  {
+    insert(0, str);
+    return *this;
+  }
+
+  void arg_vector::insert (unsigned index, const std::string& str) throw(std::out_of_range)
+  {
+    if (index > size()) throw std::out_of_range("arg_vector::insert");
+    // copy up to but not including index, then add the new argument, then copy the rest
+    char** new_argv = new char*[size()+2];
+    unsigned i = 0;
+    for ( ; i < index; i++)
+      new_argv[i] = copy_string(m_argv[i]);
+    new_argv[index] = copy_string(str.c_str());
+    for ( ; i < size(); i++)
+      new_argv[i+1] = copy_string(m_argv[i]);
+    new_argv[i+1] = 0;
+    clear();
+    m_argv = new_argv;
+  }
+
+  void arg_vector::clear (unsigned index) throw(std::out_of_range)
+  {
+    if (index >= size()) throw std::out_of_range("arg_vector::clear");
+    // copy up to index, skip it, then copy the rest
+    char** new_argv = new char*[size()];
+    unsigned i = 0;
+    for ( ; i < index; i++)
+      new_argv[i] = copy_string(m_argv[i]);
+    i++;
+    for ( ; i < size(); i++)
+      new_argv[i-1] = copy_string(m_argv[i]);
+    new_argv[i-1] = 0;
+    clear();
+    m_argv = new_argv;
+  }
+
+  void arg_vector::clear(void)
+  {
+    if (m_argv)
+    {
+      for (unsigned i = 0; m_argv[i]; i++)
+        delete[] m_argv[i];
+      delete[] m_argv;
+      m_argv = 0;
+    }
+  }
+
+  unsigned arg_vector::size (void) const
+  {
+    unsigned i = 0;
+    if (m_argv)
+      while (m_argv[i])
+        i++;
+    return i;
+  }
+
+  arg_vector::operator char** (void) const
+  {
+    return m_argv;
+  }
+
+  char** arg_vector::argv (void) const
+  {
+    return m_argv;
+  }
+
+  char* arg_vector::operator [] (unsigned index) const throw(std::out_of_range)
+  {
+    if (index >= size()) throw std::out_of_range("arg_vector::operator[]");
+    return m_argv[index];
+  }
+
+  char* arg_vector::argv0 (void) const throw(std::out_of_range)
+  {
+    return operator [] (0);
+  }
+
+  std::string arg_vector::image (void) const
+  {
+    std::string result;
+    for (unsigned i = 0; i < size(); i++)
+    {
+      if (i) result += ' ';
+      result += make_argument(m_argv[i]);
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // environment-vector
+
+  // Windoze environment is a single string containing null-terminated
+  // name=value strings and the whole terminated by a null
+
+  // Unix environment is a null-terminated vector of pointers to null-terminated strings
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // platform specifics
+
+#ifdef MSWINDOWS
+  // Windows utilities
+
+  // Windows environment variables are case-insensitive and I do comparisons by converting to lowercase
+  static std::string lowercase(const std::string& val)
+  {
+    std::string text = val;
+    for (unsigned i = 0; i < text.size(); i++)
+      text[i] = tolower(text[i]);
+    return text;
+  }
+
+  static unsigned envp_size(const char* envp)
+  {
+    unsigned size = 0;
+    while (envp[size] || (size > 0 && envp[size-1])) size++;
+    size++;
+    return size;
+  }
+
+  static void envp_extract(std::string& name, std::string& value, const char* envp, unsigned& envi)
+  {
+    name.erase();
+    value.erase();
+    if (!envp[envi]) return;
+    // some special variables start with '=' so ensure at least one character in the name
+    name += envp[envi++];
+    while(envp[envi] != '=')
+      name += envp[envi++];
+    envi++;
+    while(envp[envi])
+      value += envp[envi++];
+    envi++;
+  }
+
+  static void envp_append(const std::string& name, const std::string& value, char* envp, unsigned& envi)
+  {
+    for (unsigned i = 0; i < name.size(); i++)
+      envp[envi++] = name[i];
+    envp[envi++] = '=';
+    for (unsigned j = 0; j < value.size(); j++)
+      envp[envi++] = value[j];
+    envp[envi++] = '\0';
+    envp[envi] = '\0';
+  }
+
+  static char* envp_copy(const char* envp)
+  {
+    unsigned size = envp_size(envp);
+    char* result = new char[size];
+    result[0] = '\0';
+    unsigned i = 0;
+    unsigned j = 0;
+    while(envp[i])
+    {
+      std::string name;
+      std::string value;
+      envp_extract(name, value, envp, i);
+      envp_append(name, value, result, j);
+    }
+    return result;
+  }
+
+  static void envp_clear(char*& envp)
+  {
+    if (envp)
+    {
+      delete[] envp;
+      envp = 0;
+    }
+  }
+
+  static bool envp_equal(const std::string& left, const std::string& right)
+  {
+    return lowercase(left) == lowercase(right);
+  }
+
+  static bool envp_less(const std::string& left, const std::string& right)
+  {
+    return lowercase(left) < lowercase(right);
+  }
+
+#else
+  // Unix utilities
+
+  extern char** environ;
+
+  static unsigned envp_size(char* const* envp)
+  {
+    unsigned size = 0;
+    while(envp[size]) size++;
+    size++;
+    return size;
+  }
+
+  static void envp_extract(std::string& name, std::string& value, char* const* envp, unsigned& envi)
+  {
+    name = "";
+    value = "";
+    if (!envp[envi]) return;
+    unsigned i = 0;
+    while(envp[envi][i] != '=')
+      name += envp[envi][i++];
+    i++;
+    while(envp[envi][i])
+      value += envp[envi][i++];
+    envi++;
+  }
+
+  static void envp_append(const std::string& name, const std::string& value, char** envp, unsigned& envi)
+  {
+    std::string entry = name + "=" + value;
+    envp[envi] = copy_string(entry.c_str());
+    envi++;
+    envp[envi] = 0;
+  }
+
+  static char** envp_copy(char* const* envp)
+  {
+    unsigned size = envp_size(envp);
+    char** result = new char*[size];
+    unsigned i = 0;
+    unsigned j = 0;
+    while(envp[i])
+    {
+      std::string name;
+      std::string value;
+      envp_extract(name, value, envp, i);
+      envp_append(name, value, result, j);
+    }
+    return result;
+  }
+
+  static void envp_clear(char**& envp)
+  {
+    if (envp)
+    {
+      for (unsigned i = 0; envp[i]; i++)
+        delete[] envp[i];
+      delete[] envp;
+      envp = 0;
+    }
+  }
+
+  static bool envp_equal(const std::string& left, const std::string& right)
+  {
+    return left == right;
+  }
+
+  static bool envp_less(const std::string& left, const std::string& right)
+  {
+    return left < right;
+  }
+
+#endif
+  ////////////////////////////////////////////////////////////////////////////////
+
+  env_vector::env_vector(void)
+  {
+#ifdef MSWINDOWS
+    char* env = (char*)GetEnvironmentStringsA();
+    m_env = envp_copy(env);
+    FreeEnvironmentStringsA(env);
+#else
+    m_env = envp_copy(::environ);
+#endif
+  }
+
+  env_vector::env_vector (const env_vector& a)
+  {
+    m_env = 0;
+    *this = a;
+  }
+
+  env_vector::~env_vector (void)
+  {
+    clear();
+  }
+
+  env_vector& env_vector::operator = (const env_vector& a)
+  {
+    clear();
+    m_env = envp_copy(a.m_env);
+    return *this;
+  }
+
+  void env_vector::clear(void)
+  {
+    envp_clear(m_env);
+  }
+
+  void env_vector::add(const std::string& name, const std::string& value)
+  {
+    // the trick is to add the value in alphabetic order
+    // this is done by copying the existing environment string to a new
+    // string, inserting the new value when a name greater than it is found
+    unsigned size = envp_size(m_env);
+#ifdef MSWINDOWS
+    unsigned new_size = size + name.size() + value.size() + 2;
+    char* new_v = new char[new_size];
+    new_v[0] = '\0';
+#else
+    unsigned new_size = size + 1;
+    char** new_v = new char*[new_size];
+    new_v[0] = 0;
+#endif
+    // now extract each name=value pair and check the ordering
+    bool added = false;
+    unsigned i = 0;
+    unsigned j = 0;
+    while(m_env[i])
+    {
+      std::string current_name;
+      std::string current_value;
+      envp_extract(current_name, current_value, m_env, i);
+      if (envp_equal(name,current_name))
+      {
+        // replace an existing value
+        envp_append(name, value, new_v, j);
+      }
+      else if (!added && envp_less(name,current_name))
+      {
+        // add the new value first, then the existing one
+        envp_append(name, value, new_v, j);
+        envp_append(current_name, current_value, new_v, j);
+        added = true;
+      }
+      else
+      {
+        // just add the existing value
+        envp_append(current_name, current_value, new_v, j);
+      }
+    }
+    if (!added)
+      envp_append(name, value, new_v, j);
+    envp_clear(m_env);
+    m_env = new_v;
+  }
+
+
+  bool env_vector::remove (const std::string& name)
+  {
+    bool result = false;
+    // this is done by copying the existing environment string to a new string, but excluding the specified name
+    unsigned size = envp_size(m_env);
+#ifdef MSWINDOWS
+    char* new_v = new char[size];
+    new_v[0] = '\0';
+#else
+    char** new_v = new char*[size];
+    new_v[0] = 0;
+#endif
+    unsigned i = 0;
+    unsigned j = 0;
+    while(m_env[i])
+    {
+      std::string current_name;
+      std::string current_value;
+      envp_extract(current_name, current_value, m_env, i);
+      if (envp_equal(name,current_name))
+        result = true;
+      else
+        envp_append(current_name, current_value, new_v, j);
+    }
+    envp_clear(m_env);
+    m_env = new_v;
+    return result;
+  }
+
+  std::string env_vector::operator [] (const std::string& name) const
+  {
+    return get(name);
+  }
+
+  std::string env_vector::get (const std::string& name) const
+  {
+    unsigned i = 0;
+    while(m_env[i])
+    {
+      std::string current_name;
+      std::string current_value;
+      envp_extract(current_name, current_value, m_env, i);
+      if (envp_equal(name,current_name))
+        return current_value;
+    }
+    return std::string();
+  }
+
+  unsigned env_vector::size (void) const
+  {
+    unsigned i = 0;
+#ifdef MSWINDOWS
+    unsigned offset = 0;
+    while(m_env[offset])
+    {
+      std::string current_name;
+      std::string current_value;
+      envp_extract(current_name, current_value, m_env, offset);
+      i++;
+    }
+#else
+    while(m_env[i])
+      i++;
+#endif
+
+    return i;
+  }
+
+  std::pair<std::string,std::string> env_vector::operator [] (unsigned index) const throw(std::out_of_range)
+  {
+    return get(index);
+  }
+
+  std::pair<std::string,std::string> env_vector::get (unsigned index) const throw(std::out_of_range)
+  {
+    if (index >= size()) throw std::out_of_range("arg_vector::get");
+    unsigned j = 0;
+    for (unsigned i = 0; i < index; i++)
+    {
+      std::string current_name;
+      std::string current_value;
+      envp_extract(current_name, current_value, m_env, j);
+    }
+    std::string name;
+    std::string value;
+    envp_extract(name, value, m_env, j);
+    return std::make_pair(name,value);
+  }
+
+  ENVIRON_TYPE env_vector::envp (void) const
+  {
+    return m_env;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Synchronous subprocess
+  // Win32 implementation mostly cribbed from MSDN examples and then made (much) more readable
+  // Unix implementation mostly from man pages and bitter experience
+  ////////////////////////////////////////////////////////////////////////////////
+
+#ifdef MSWINDOWS
+
+  subprocess::subprocess(void)
+  {
+    m_pid.hProcess = 0;
+    m_job = 0;
+    m_child_in = 0;
+    m_child_out = 0;
+    m_child_err = 0;
+    m_err = 0;
+    m_status = 0;
+  }
+
+#else
+
+  subprocess::subprocess(void)
+  {
+    m_pid = -1;
+    m_child_in = -1;
+    m_child_out = -1;
+    m_child_err = -1;
+    m_err = 0;
+    m_status = 0;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  subprocess::~subprocess(void)
+  {
+    if (m_pid.hProcess != 0)
+    {
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      kill();
+      WaitForSingleObject(m_pid.hProcess, INFINITE);
+      CloseHandle(m_pid.hThread);
+      CloseHandle(m_pid.hProcess);
+      CloseHandle(m_job);
+    }
+  }
+
+#else
+
+  subprocess::~subprocess(void)
+  {
+    if (m_pid != -1)
+    {
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      kill();
+      for (;;)
+      {
+        int wait_status = 0;
+        int wait_ret_val = waitpid(m_pid, &wait_status, 0);
+        if (wait_ret_val != -1 || errno != EINTR) break;
+      }
+    }
+  }
+
+#endif
+
+  void subprocess::add_variable(const std::string& name, const std::string& value)
+  {
+    m_env.add(name, value);
+  }
+
+  bool subprocess::remove_variable(const std::string& name)
+  {
+    return m_env.remove(name);
+  }
+
+#ifdef MSWINDOWS
+
+  bool subprocess::spawn(const std::string& path, const arg_vector& argv,
+                         bool connect_stdin, bool connect_stdout, bool connect_stderr)
+  {
+    bool result = true;
+    // first create the pipes to be used to connect to the child stdin/out/err
+    // If no pipes requested, then connect to the parent stdin/out/err
+    // for some reason you have to create a pipe handle, then duplicate it
+    // This is not well explained in MSDN but seems to work
+    PIPE_TYPE parent_stdin = 0;
+    if (!connect_stdin)
+      parent_stdin = GetStdHandle(STD_INPUT_HANDLE);
+    else
+    {
+      PIPE_TYPE tmp = 0;
+      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
+      CreatePipe(&parent_stdin, &tmp, &inherit_handles, 0);
+      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_in, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+    }
+
+    PIPE_TYPE parent_stdout = 0;
+    if (!connect_stdout)
+      parent_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+    else
+    {
+      PIPE_TYPE tmp = 0;
+      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
+      CreatePipe(&tmp, &parent_stdout, &inherit_handles, 0);
+      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_out, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+    }
+
+    PIPE_TYPE parent_stderr = 0;
+    if (!connect_stderr)
+      parent_stderr = GetStdHandle(STD_ERROR_HANDLE);
+    else
+    {
+      PIPE_TYPE tmp = 0;
+      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
+      CreatePipe(&tmp, &parent_stderr, &inherit_handles, 0);
+      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_err, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+    }
+
+    // Now create the subprocess
+    // The horrible trick of creating a console window and hiding it seems to be required for the pipes to work
+    // Note that the child will inherit a copy of the pipe handles
+    STARTUPINFOA startup = {sizeof(STARTUPINFO),0,0,0,0,0,0,0,0,0,0,
+                            STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW,SW_HIDE,0,0,
+                            parent_stdin,parent_stdout,parent_stderr};
+    bool created = CreateProcessA(path.c_str(),(char*)argv.image().c_str(),0,0,TRUE,CREATE_SUSPENDED,m_env.envp(),0,&startup,&m_pid) != 0;
+    // close the parent copy of the pipe handles so that the pipes will be closed when the child releases them
+    if (connect_stdin) CloseHandle(parent_stdin);
+    if (connect_stdout) CloseHandle(parent_stdout);
+    if (connect_stderr) CloseHandle(parent_stderr);
+    if (!created)
+    {
+      m_err = GetLastError();
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      result = false;
+    }
+    else
+    {
+      m_job = CreateJobObject(NULL, NULL);
+      AssignProcessToJobObject(m_job, m_pid.hProcess);
+      ResumeThread(m_pid.hThread);
+
+      // The child process is now running so call the user's callback
+      // The convention is that the callback can return false, in which case this will kill the child (if its still running)
+      if (!callback())
+      {
+        result = false;
+        kill();
+      }
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      // wait for the child to finish
+      // TODO - kill the child if a timeout happens
+      WaitForSingleObject(m_pid.hProcess, INFINITE);
+      DWORD exit_status = 0;
+      if (!GetExitCodeProcess(m_pid.hProcess, &exit_status))
+      {
+        m_err = GetLastError();
+        result = false;
+      }
+      else if (exit_status != 0)
+        result = false;
+      m_status = (int)exit_status;
+      CloseHandle(m_pid.hThread);
+      CloseHandle(m_pid.hProcess);
+      CloseHandle(m_job);
+    }
+    m_pid.hProcess = 0;
+    return result;
+  }
+
+#else
+
+  bool subprocess::spawn(const std::string& path, const arg_vector& argv,
+                         bool connect_stdin, bool connect_stdout, bool connect_stderr)
+  {
+    bool result = true;
+    // first create the pipes to be used to connect to the child stdin/out/err
+
+    int stdin_pipe [2] = {-1, -1};
+    if (connect_stdin)
+      pipe(stdin_pipe);
+
+    int stdout_pipe [2] = {-1, -1};
+    if (connect_stdout)
+      pipe(stdout_pipe);
+
+    int stderr_pipe [2] = {-1, -1};
+    if (connect_stderr)
+      pipe(stderr_pipe);
+
+    // now create the subprocess
+    // In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec
+    m_pid = ::fork();
+    switch(m_pid)
+    {
+    case -1:   // failed to fork
+      m_err = errno;
+      if (connect_stdin)
+      {
+        ::close(stdin_pipe[0]);
+        ::close(stdin_pipe[1]);
+      }
+      if (connect_stdout)
+      {
+        ::close(stdout_pipe[0]);
+        ::close(stdout_pipe[1]);
+      }
+      if (connect_stderr)
+      {
+        ::close(stderr_pipe[0]);
+        ::close(stderr_pipe[1]);
+      }
+      result = false;
+      break;
+    case 0:  // in child;
+    {
+      // for each pipe, close the end of the duplicated pipe that is being used by the parent
+      // and connect the child's end of the pipe to the appropriate standard I/O device
+      if (connect_stdin)
+      {
+        ::close(stdin_pipe[1]);
+        dup2(stdin_pipe[0],STDIN_FILENO);
+      }
+      if (connect_stdout)
+      {
+        ::close(stdout_pipe[0]);
+        dup2(stdout_pipe[1],STDOUT_FILENO);
+      }
+      if (connect_stderr)
+      {
+        ::close(stderr_pipe[0]);
+        dup2(stderr_pipe[1],STDERR_FILENO);
+      }
+      execve(path.c_str(), argv.argv(), m_env.envp());
+      // will only ever get here if the exec() failed completely - *must* now exit the child process
+      // by using errno, the parent has some chance of diagnosing the cause of the problem
+      exit(errno);
+    }
+    break;
+    default:  // in parent
+    {
+      // for each pipe, close the end of the duplicated pipe that is being used by the child
+      // and connect the parent's end of the pipe to the class members so that they are visible to the parent() callback
+      if (connect_stdin)
+      {
+        ::close(stdin_pipe[0]);
+        m_child_in = stdin_pipe[1];
+      }
+      if (connect_stdout)
+      {
+        ::close(stdout_pipe[1]);
+        m_child_out = stdout_pipe[0];
+      }
+      if (connect_stderr)
+      {
+        ::close(stderr_pipe[1]);
+        m_child_err = stderr_pipe[0];
+      }
+      // call the user's callback
+      if (!callback())
+      {
+        result = false;
+        kill();
+      }
+      // close the pipes and wait for the child to finish
+      // wait exits on a signal which may be the child signalling its exit or may be an interrupt
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      int wait_status = 0;
+      for (;;)
+      {
+        int wait_ret_val = waitpid(m_pid, &wait_status, 0);
+        if (wait_ret_val != -1 || errno != EINTR) break;
+      }
+      // establish whether an error occurred
+      if (WIFSIGNALED(wait_status))
+      {
+        // set_error(errno);
+        m_status = WTERMSIG(wait_status);
+        result = false;
+      }
+      else if (WIFEXITED(wait_status))
+      {
+        m_status = WEXITSTATUS(wait_status);
+        if (m_status != 0)
+          result = false;
+      }
+      m_pid = -1;
+    }
+    break;
+    }
+    return result;
+  }
+
+#endif
+
+  bool subprocess::spawn(const std::string& command_line,
+                                  bool connect_stdin, bool connect_stdout, bool connect_stderr)
+  {
+    arg_vector arguments = command_line;
+    if (arguments.size() == 0) return false;
+    std::string path = path_lookup(arguments.argv0());
+    if (path.empty()) return false;
+    return spawn(path, arguments, connect_stdin, connect_stdout, connect_stderr);
+  }
+
+  bool subprocess::callback(void)
+  {
+    return true;
+  }
+
+#ifdef MSWINDOWS
+
+  bool subprocess::kill (void)
+  {
+    if (!m_pid.hProcess) return false;
+    close_stdin();
+    close_stdout();
+    close_stderr();
+    if (!TerminateJobObject(m_job, (UINT)-1))
+    {
+      m_err = GetLastError();
+      return false;
+    }
+    return true;
+  }
+
+#else
+
+  bool subprocess::kill (void)
+  {
+    if (m_pid == -1) return false;
+    close_stdin();
+    close_stdout();
+    close_stderr();
+    if (::kill(m_pid, SIGINT) == -1)
+    {
+      m_err = errno;
+      return false;
+    }
+    return true;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  int subprocess::write_stdin (std::string& buffer)
+  {
+    if (m_child_in == 0) return -1;
+    // do a blocking write of the whole buffer
+    DWORD bytes = 0;
+    if (!WriteFile(m_child_in, buffer.c_str(), (DWORD)buffer.size(), &bytes, 0))
+    {
+      m_err = GetLastError();
+      close_stdin();
+      return -1;
+    }
+    // now discard that part of the buffer that was written
+    if (bytes > 0)
+      buffer.erase(0, bytes);
+    return bytes;
+  }
+
+#else
+
+  int subprocess::write_stdin (std::string& buffer)
+  {
+    if (m_child_in == -1) return -1;
+    // do a blocking write of the whole buffer
+    int bytes = write(m_child_in, buffer.c_str(), buffer.size());
+    if (bytes == -1)
+    {
+      m_err = errno;
+      close_stdin();
+      return -1;
+    }
+    // now discard that part of the buffer that was written
+    if (bytes > 0)
+      buffer.erase(0, bytes);
+    return bytes;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  int subprocess::read_stdout (std::string& buffer)
+  {
+    if (m_child_out == 0) return -1;
+    DWORD bytes = 0;
+    DWORD buffer_size = 256;
+    char* tmp = new char[buffer_size];
+    if (!ReadFile(m_child_out, tmp, buffer_size, &bytes, 0))
+    {
+      if (GetLastError() != ERROR_BROKEN_PIPE)
+        m_err = GetLastError();
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return (int)bytes;
+  }
+
+#else
+
+  int subprocess::read_stdout (std::string& buffer)
+  {
+    if (m_child_out == -1) return -1;
+    int buffer_size = 256;
+    char* tmp = new char[buffer_size];
+    int bytes = read(m_child_out, tmp, buffer_size);
+    if (bytes == -1)
+    {
+      m_err = errno;
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return bytes;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  int subprocess::read_stderr(std::string& buffer)
+  {
+    if (m_child_err == 0) return -1;
+    DWORD bytes = 0;
+    DWORD buffer_size = 256;
+    char* tmp = new char[buffer_size];
+    if (!ReadFile(m_child_err, tmp, buffer_size, &bytes, 0))
+    {
+      if (GetLastError() != ERROR_BROKEN_PIPE)
+        m_err = GetLastError();
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return (int)bytes;
+  }
+
+#else
+
+  int subprocess::read_stderr (std::string& buffer)
+  {
+    if (m_child_err == -1) return -1;
+    int buffer_size = 256;
+    char* tmp = new char[buffer_size];
+    int bytes = read(m_child_err, tmp, buffer_size);
+    if (bytes == -1)
+    {
+      m_err = errno;
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return bytes;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  void subprocess::close_stdin (void)
+  {
+    if (m_child_in)
+    {
+      CloseHandle(m_child_in);
+      m_child_in = 0;
+    }
+  }
+
+#else
+
+  void subprocess::close_stdin (void)
+  {
+    if (m_child_in != -1)
+    {
+      ::close(m_child_in);
+      m_child_in = -1;
+    }
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  void subprocess::close_stdout (void)
+  {
+    if (m_child_out)
+    {
+      CloseHandle(m_child_out);
+      m_child_out = 0;
+    }
+  }
+
+#else
+
+  void subprocess::close_stdout (void)
+  {
+    if (m_child_out != -1)
+    {
+      ::close(m_child_out);
+      m_child_out = -1;
+    }
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  void subprocess::close_stderr (void)
+  {
+    if (m_child_err)
+    {
+      CloseHandle(m_child_err);
+      m_child_err = 0;
+    }
+  }
+
+#else
+
+  void subprocess::close_stderr (void)
+  {
+    if (m_child_err != -1)
+    {
+      ::close(m_child_err);
+      m_child_err = -1;
+    }
+  }
+
+#endif
+
+  bool subprocess::error(void) const
+  {
+    return m_err != 0;
+  }
+
+  int subprocess::error_number(void) const
+  {
+    return m_err;
+  }
+
+#ifdef MSWINDOWS
+
+  std::string subprocess::error_text(void) const
+  {
+    if (m_err == 0) return std::string();
+    char* message;
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+                  0,
+                  m_err,
+                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                  (LPTSTR)&message,
+                  0,0);
+    std::string result = message;
+    LocalFree(message);
+    // the error message is for some perverse reason newline terminated - remove this
+    if (result[result.size()-1] == '\n')
+      result.erase(result.end()-1);
+    if (result[result.size()-1] == '\r')
+      result.erase(result.end()-1);
+    return result;
+  }
+
+#else
+
+  std::string subprocess::error_text(void) const
+  {
+    if (m_err == 0) return std::string();
+    char* text = strerror(m_err);
+    if (text) return std::string(text);
+    return "error number " + dformat("%d",m_err);
+  }
+
+#endif
+
+  int subprocess::exit_status(void) const
+  {
+    return m_status;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // backtick subprocess and operations
+
+  backtick_subprocess::backtick_subprocess(void) : subprocess()
+  {
+  }
+
+  bool backtick_subprocess::callback(void)
+  {
+    for (;;)
+    {
+      std::string buffer;
+      int read_size = read_stdout(buffer);
+      if (read_size < 0) break;
+      m_text += buffer;
+    }
+    return !error();
+  }
+
+  bool backtick_subprocess::spawn(const std::string& path, const arg_vector& argv)
+  {
+    return subprocess::spawn(path, argv, false, true, false);
+  }
+
+  bool backtick_subprocess::spawn(const std::string& command_line)
+  {
+    return subprocess::spawn(command_line, false, true, false);
+  }
+
+  std::vector<std::string> backtick_subprocess::text(void) const
+  {
+    std::vector<std::string> result;
+    // convert the raw text into a vector of strings, each corresponding to a line
+    // in the process, strip out platform-specific line-endings
+    for (unsigned i = 0; i < m_text.size(); i++)
+    {
+      // handle any kind of line-ending - Dos, Unix or MacOS
+      switch(m_text[i])
+      {
+      case '\xd': // carriage-return - optionally followed by linefeed
+      {
+        // discard optional following linefeed
+        if ((i+1 < m_text.size()) && (m_text[i+1] == '\xa'))
+          i++;
+        // add a new line to the end of the vector
+        result.push_back(std::string());
+        break;
+      }
+      case '\xa': // linefeed
+      {
+        // add a new line to the end of the vector
+        result.push_back(std::string());
+        break;
+      }
+      default:
+      {
+        result.back() += m_text[i];
+        break;
+      }
+      }
+    }
+    // tidy up - if the last line ended with a newline, the vector will end with an empty string - discard this
+    if ((result.size()) > 0 && result.back().empty())
+      result.erase(result.end()-1);
+    return result;
+  }
+
+  std::vector<std::string> backtick(const std::string& path, const arg_vector& argv)
+  {
+    backtick_subprocess sub;
+    sub.spawn(path, argv);
+    return sub.text();
+  }
+
+  std::vector<std::string> backtick(const std::string& command_line)
+  {
+    backtick_subprocess sub;
+    sub.spawn(command_line);
+    return sub.text();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Asynchronous subprocess
+
+#ifdef MSWINDOWS
+
+  async_subprocess::async_subprocess(void)
+  {
+    m_pid.hProcess = 0;
+    m_job = 0;
+    m_child_in = 0;
+    m_child_out = 0;
+    m_child_err = 0;
+    m_err = 0;
+    m_status = 0;
+  }
+
+#else
+
+  async_subprocess::async_subprocess(void)
+  {
+    m_pid = -1;
+    m_child_in = -1;
+    m_child_out = -1;
+    m_child_err = -1;
+    m_err = 0;
+    m_status = 0;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  async_subprocess::~async_subprocess(void)
+  {
+    if (m_pid.hProcess != 0)
+    {
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      kill();
+      WaitForSingleObject(m_pid.hProcess, INFINITE);
+      CloseHandle(m_pid.hThread);
+      CloseHandle(m_pid.hProcess);
+      CloseHandle(m_job);
+    }
+  }
+
+#else
+
+  async_subprocess::~async_subprocess(void)
+  {
+    if (m_pid != -1)
+    {
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      kill();
+      for (;;)
+      {
+        int wait_status = 0;
+        int wait_ret_val = waitpid(m_pid, &wait_status, 0);
+        if (wait_ret_val != -1 || errno != EINTR) break;
+      }
+    }
+  }
+
+#endif
+
+  void async_subprocess::set_error(int e)
+  {
+    m_err = e;
+  }
+
+  void async_subprocess::add_variable(const std::string& name, const std::string& value)
+  {
+    m_env.add(name, value);
+  }
+
+  bool async_subprocess::remove_variable(const std::string& name)
+  {
+    return m_env.remove(name);
+  }
+
+#ifdef MSWINDOWS
+
+  bool async_subprocess::spawn(const std::string& path, const arg_vector& argv,
+                                        bool connect_stdin, bool connect_stdout, bool connect_stderr)
+  {
+    bool result = true;
+    // first create the pipes to be used to connect to the child stdin/out/err
+    // If no pipes requested, then connect to the parent stdin/out/err
+    // for some reason you have to create a pipe handle, then duplicate it
+    // This is not well explained in MSDN but seems to work
+    PIPE_TYPE parent_stdin = 0;
+    if (!connect_stdin)
+      parent_stdin = GetStdHandle(STD_INPUT_HANDLE);
+    else
+    {
+      PIPE_TYPE tmp = 0;
+      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
+      CreatePipe(&parent_stdin, &tmp, &inherit_handles, 0);
+      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_in, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+    }
+
+    PIPE_TYPE parent_stdout = 0;
+    if (!connect_stdout)
+      parent_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
+    else
+    {
+      PIPE_TYPE tmp = 0;
+      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
+      CreatePipe(&tmp, &parent_stdout, &inherit_handles, 0);
+      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_out, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+    }
+
+    PIPE_TYPE parent_stderr = 0;
+    if (!connect_stderr)
+      parent_stderr = GetStdHandle(STD_ERROR_HANDLE);
+    else
+    {
+      PIPE_TYPE tmp = 0;
+      SECURITY_ATTRIBUTES inherit_handles = {sizeof(SECURITY_ATTRIBUTES), 0, TRUE};
+      CreatePipe(&tmp, &parent_stderr, &inherit_handles, 0);
+      DuplicateHandle(GetCurrentProcess(), tmp, GetCurrentProcess(), &m_child_err, 0, FALSE, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
+    }
+
+    // Now create the subprocess
+    // The horrible trick of creating a console window and hiding it seems to be required for the pipes to work
+    // Note that the child will inherit a copy of the pipe handles
+    STARTUPINFOA startup = {sizeof(STARTUPINFO),0,0,0,0,0,0,0,0,0,0,
+                            STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW,SW_HIDE,0,0,
+                            parent_stdin,parent_stdout,parent_stderr};
+    bool created = CreateProcessA(path.c_str(),(char*)argv.image().c_str(),0,0,TRUE,CREATE_SUSPENDED,m_env.envp(),0,&startup,&m_pid) != 0;
+    // close the parent copy of the pipe handles so that the pipes will be closed when the child releases them
+    if (connect_stdin) CloseHandle(parent_stdin);
+    if (connect_stdout) CloseHandle(parent_stdout);
+    if (connect_stderr) CloseHandle(parent_stderr);
+    if (!created)
+    {
+      set_error(GetLastError());
+      close_stdin();
+      close_stdout();
+      close_stderr();
+      result = false;
+    }
+    else
+    {
+      m_job = CreateJobObject(NULL, NULL);
+      AssignProcessToJobObject(m_job, m_pid.hProcess);
+      ResumeThread(m_pid.hThread);
+    }
+    return result;
+  }
+
+#else
+
+  bool async_subprocess::spawn(const std::string& path, const arg_vector& argv,
+                               bool connect_stdin, bool connect_stdout, bool connect_stderr)
+  {
+    bool result = true;
+    // first create the pipes to be used to connect to the child stdin/out/err
+
+    int stdin_pipe [2] = {-1, -1};
+    if (connect_stdin)
+      pipe(stdin_pipe);
+
+    int stdout_pipe [2] = {-1, -1};
+    if (connect_stdout)
+      pipe(stdout_pipe);
+
+    int stderr_pipe [2] = {-1, -1};
+    if (connect_stderr)
+      pipe(stderr_pipe);
+
+    // now create the subprocess
+    // In Unix, this is done by forking (creating two copies of the parent), then overwriting the child copy using exec
+    m_pid = ::fork();
+    switch(m_pid)
+    {
+    case -1:   // failed to fork
+      set_error(errno);
+      if (connect_stdin)
+      {
+        ::close(stdin_pipe[0]);
+        ::close(stdin_pipe[1]);
+      }
+      if (connect_stdout)
+      {
+        ::close(stdout_pipe[0]);
+        ::close(stdout_pipe[1]);
+      }
+      if (connect_stderr)
+      {
+        ::close(stderr_pipe[0]);
+        ::close(stderr_pipe[1]);
+      }
+      result = false;
+      break;
+    case 0:  // in child;
+    {
+      // for each pipe, close the end of the duplicated pipe that is being used by the parent
+      // and connect the child's end of the pipe to the appropriate standard I/O device
+      if (connect_stdin)
+      {
+        ::close(stdin_pipe[1]);
+        dup2(stdin_pipe[0],STDIN_FILENO);
+      }
+      if (connect_stdout)
+      {
+        ::close(stdout_pipe[0]);
+        dup2(stdout_pipe[1],STDOUT_FILENO);
+      }
+      if (connect_stderr)
+      {
+        ::close(stderr_pipe[0]);
+        dup2(stderr_pipe[1],STDERR_FILENO);
+      }
+      execve(path.c_str(), argv.argv(), m_env.envp());
+      // will only ever get here if the exec() failed completely - *must* now exit the child process
+      // by using errno, the parent has some chance of diagnosing the cause of the problem
+      exit(errno);
+    }
+    break;
+    default:  // in parent
+    {
+      // for each pipe, close the end of the duplicated pipe that is being used by the child
+      // and connect the parent's end of the pipe to the class members so that they are visible to the parent() callback
+      if (connect_stdin)
+      {
+        ::close(stdin_pipe[0]);
+        m_child_in = stdin_pipe[1];
+        if (fcntl(m_child_in, F_SETFL, O_NONBLOCK) == -1)
+        {
+          set_error(errno);
+          result = false;
+        }
+      }
+      if (connect_stdout)
+      {
+        ::close(stdout_pipe[1]);
+        m_child_out = stdout_pipe[0];
+        if (fcntl(m_child_out, F_SETFL, O_NONBLOCK) == -1)
+        {
+          set_error(errno);
+          result = false;
+        }
+      }
+      if (connect_stderr)
+      {
+        ::close(stderr_pipe[1]);
+        m_child_err = stderr_pipe[0];
+        if (fcntl(m_child_err, F_SETFL, O_NONBLOCK) == -1)
+        {
+          set_error(errno);
+          result = false;
+        }
+      }
+    }
+    break;
+    }
+    return result;
+  }
+
+#endif
+
+  bool async_subprocess::spawn(const std::string& command_line,
+                               bool connect_stdin, bool connect_stdout, bool connect_stderr)
+  {
+    arg_vector arguments = command_line;
+    if (arguments.size() == 0) return false;
+    std::string path = path_lookup(arguments.argv0());
+    if (path.empty()) return false;
+    return spawn(path, arguments, connect_stdin, connect_stdout, connect_stderr);
+  }
+
+  bool async_subprocess::callback(void)
+  {
+    return true;
+  }
+
+#ifdef MSWINDOWS
+
+  bool async_subprocess::tick(void)
+  {
+    bool result = true;
+    if (!callback())
+      kill();
+    DWORD exit_status = 0;
+    if (!GetExitCodeProcess(m_pid.hProcess, &exit_status))
+    {
+      set_error(GetLastError());
+      result = false;
+    }
+    else if (exit_status != STILL_ACTIVE)
+    {
+      CloseHandle(m_pid.hThread);
+      CloseHandle(m_pid.hProcess);
+      CloseHandle(m_job);
+      m_pid.hProcess = 0;
+      result = false;
+    }
+    m_status = (int)exit_status;
+    return result;
+  }
+
+#else
+
+  bool async_subprocess::tick(void)
+  {
+    bool result = true;
+    if (!callback())
+      kill();
+    int wait_status = 0;
+    int wait_ret_val = waitpid(m_pid, &wait_status, WNOHANG);
+    if (wait_ret_val == -1 && errno != EINTR)
+    {
+      set_error(errno);
+      result = false;
+    }
+    else if (wait_ret_val != 0)
+    {
+      // the only states that indicate a terminated child are WIFSIGNALLED and WIFEXITED
+      if (WIFSIGNALED(wait_status))
+      {
+        // set_error(errno);
+        m_status = WTERMSIG(wait_status);
+        result = false;
+      }
+      else if (WIFEXITED(wait_status))
+      {
+        // child has exited
+        m_status = WEXITSTATUS(wait_status);
+        result = false;
+      }
+    }
+    if (!result)
+      m_pid = -1;
+    return result;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  bool async_subprocess::kill(void)
+  {
+    if (!m_pid.hProcess) return false;
+    close_stdin();
+    close_stdout();
+    close_stderr();
+    if (!TerminateJobObject(m_job, (UINT)-1))
+    {
+      set_error(GetLastError());
+      return false;
+    }
+    return true;
+  }
+
+#else
+
+  bool async_subprocess::kill(void)
+  {
+    if (m_pid == -1) return false;
+    close_stdin();
+    close_stdout();
+    close_stderr();
+    if (::kill(m_pid, SIGINT) == -1)
+    {
+      set_error(errno);
+      return false;
+    }
+    return true;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  int async_subprocess::write_stdin (std::string& buffer)
+  {
+    if (m_child_in == 0) return -1;
+    // there doesn't seem to be a way of doing non-blocking writes under Windoze
+    DWORD bytes = 0;
+    if (!WriteFile(m_child_in, buffer.c_str(), (DWORD)buffer.size(), &bytes, 0))
+    {
+      set_error(GetLastError());
+      close_stdin();
+      return -1;
+    }
+    // now discard that part of the buffer that was written
+    if (bytes > 0)
+      buffer.erase(0, bytes);
+    return (int)bytes;
+  }
+
+#else
+
+  int async_subprocess::write_stdin (std::string& buffer)
+  {
+    if (m_child_in == -1) return -1;
+    // relies on the pipe being non-blocking
+    // This does block under Windoze
+    int bytes = write(m_child_in, buffer.c_str(), buffer.size());
+    if (bytes == -1 && errno == EAGAIN)
+    {
+      // not ready
+      return 0;
+    }
+    if (bytes == -1)
+    {
+      // error on write - close the pipe and give up
+      set_error(errno);
+      close_stdin();
+      return -1;
+    }
+    // successful write
+    // now discard that part of the buffer that was written
+    if (bytes > 0)
+      buffer.erase(0, bytes);
+    return bytes;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  int async_subprocess::read_stdout (std::string& buffer)
+  {
+    if (m_child_out == 0) return -1;
+    // peek at the buffer to see how much data there is in the first place
+    DWORD buffer_size = 0;
+    if (!PeekNamedPipe(m_child_out, 0, 0, 0, &buffer_size, 0))
+    {
+      if (GetLastError() != ERROR_BROKEN_PIPE)
+        set_error(GetLastError());
+      close_stdout();
+      return -1;
+    }
+    if (buffer_size == 0) return 0;
+    DWORD bytes = 0;
+    char* tmp = new char[buffer_size];
+    if (!ReadFile(m_child_out, tmp, buffer_size, &bytes, 0))
+    {
+      set_error(GetLastError());
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return (int)bytes;
+  }
+
+#else
+
+  int async_subprocess::read_stdout (std::string& buffer)
+  {
+    if (m_child_out == -1) return -1;
+    // rely on the pipe being non-blocking
+    int buffer_size = 256;
+    char* tmp = new char[buffer_size];
+    int bytes = read(m_child_out, tmp, buffer_size);
+    if (bytes == -1 && errno == EAGAIN)
+    {
+      // not ready
+      delete[] tmp;
+      return 0;
+    }
+    if (bytes == -1)
+    {
+      // error
+      set_error(errno);
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stdout();
+      delete[] tmp;
+      return -1;
+    }
+    // successful read
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return bytes;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  int async_subprocess::read_stderr (std::string& buffer)
+  {
+    if (m_child_err == 0) return -1;
+    // peek at the buffer to see how much data there is in the first place
+    DWORD buffer_size = 0;
+    if (!PeekNamedPipe(m_child_err, 0, 0, 0, &buffer_size, 0))
+    {
+      if (GetLastError() != ERROR_BROKEN_PIPE)
+        set_error(GetLastError());
+      close_stderr();
+      return -1;
+    }
+    if (buffer_size == 0) return 0;
+    DWORD bytes = 0;
+    char* tmp = new char[buffer_size];
+    if (!ReadFile(m_child_err, tmp, buffer_size, &bytes, 0))
+    {
+      set_error(GetLastError());
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return (int)bytes;
+  }
+
+#else
+
+  int async_subprocess::read_stderr (std::string& buffer)
+  {
+    if (m_child_err == -1) return -1;
+    // rely on the pipe being non-blocking
+    int buffer_size = 256;
+    char* tmp = new char[buffer_size];
+    int bytes = read(m_child_err, tmp, buffer_size);
+    if (bytes == -1 && errno == EAGAIN)
+    {
+      // not ready
+      delete[] tmp;
+      return 0;
+    }
+    if (bytes == -1)
+    {
+      // error
+      set_error(errno);
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    if (bytes == 0)
+    {
+      // EOF
+      close_stderr();
+      delete[] tmp;
+      return -1;
+    }
+    // successful read
+    buffer.append(tmp, bytes);
+    delete[] tmp;
+    return bytes;
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  void async_subprocess::close_stdin (void)
+  {
+    if (m_child_in)
+    {
+      CloseHandle(m_child_in);
+      m_child_in = 0;
+    }
+  }
+
+#else
+
+  void async_subprocess::close_stdin (void)
+  {
+    if (m_child_in != -1)
+    {
+      ::close(m_child_in);
+      m_child_in = -1;
+    }
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  void async_subprocess::close_stdout (void)
+  {
+    if (m_child_out)
+    {
+      CloseHandle(m_child_out);
+      m_child_out = 0;
+    }
+  }
+
+#else
+
+  void async_subprocess::close_stdout (void)
+  {
+    if (m_child_out != -1)
+    {
+      ::close(m_child_out);
+      m_child_out = -1;
+    }
+  }
+
+#endif
+
+#ifdef MSWINDOWS
+
+  void async_subprocess::close_stderr (void)
+  {
+    if (m_child_err)
+    {
+      CloseHandle(m_child_err);
+      m_child_err = 0;
+    }
+  }
+
+#else
+
+  void async_subprocess::close_stderr (void)
+  {
+    if (m_child_err != -1)
+    {
+      ::close(m_child_err);
+      m_child_err = -1;
+    }
+  }
+
+#endif
+
+  bool async_subprocess::error(void) const
+  {
+    return m_err != 0;
+  }
+
+  int async_subprocess::error_number(void) const
+  {
+    return m_err;
+  }
+
+#ifdef MSWINDOWS
+
+  std::string async_subprocess::error_text(void) const
+  {
+    if (m_err == 0) return std::string();
+    char* message;
+    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+                  0,
+                  m_err,
+                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                  (LPTSTR)&message,
+                  0,0);
+    std::string result = message;
+    LocalFree(message);
+    // the error message is for some perverse reason newline terminated - remove this
+    if (result[result.size()-1] == '\n')
+      result.erase(result.end()-1);
+    if (result[result.size()-1] == '\r')
+      result.erase(result.end()-1);
+    return result;
+  }
+
+#else
+
+  std::string async_subprocess::error_text(void) const
+  {
+    if (m_err == 0) return std::string();
+    char* text = strerror(m_err);
+    if (text) return std::string(text);
+    return "error number " + dformat("%d",m_err);
+  }
+
+#endif
+
+  int async_subprocess::exit_status(void) const
+  {
+    return m_status;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 0369daad40b6b5c645c52e4533968ab5a54772bd..50564633fae4a6a0ee67edf95a2c20459a928b37 100644 (file)
-#ifndef STLPLUS_SUBPROCESSES\r
-#define STLPLUS_SUBPROCESSES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-  \r
-//   Platform-independent wrapper around the very platform-specific handling of\r
-//   subprocesses. Uses the C++ convention that all resources must be contained in\r
-//   an object so that when a subprocess object goes out of scope the subprocess\r
-//   itself gets closed down.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#ifdef MSWINDOWS\r
-#include <windows.h>\r
-#endif\r
-#include <stdexcept>\r
-#include <vector>\r
-#include <string>\r
-#include <map> // for std::pair - why is this not defined separately?\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Argument vector class\r
-  // allows manipulation of argv-like vectors\r
-  // includes splitting of command lines into argvectors as per the shell\r
-  // (removing quotes) and the reverse conversion (adding quotes where necessary)\r
-\r
-  class arg_vector\r
-  {\r
-  private:\r
-    char** m_argv;\r
-\r
-  public:\r
-    // create an empty vector\r
-    arg_vector (void);\r
-\r
-    // copy constructor (yes it copies)\r
-    arg_vector (const arg_vector&);\r
-\r
-    // construct from an argv\r
-    arg_vector (char**);\r
-\r
-    // construct from a command-line string\r
-    // includes de-quoting of values\r
-    arg_vector (const std::string&);\r
-    arg_vector (const char*);\r
-\r
-    ~arg_vector (void);\r
-\r
-    // assignment operators are compatible with the constructors\r
-    arg_vector& operator = (const arg_vector&);\r
-    arg_vector& operator = (char**);\r
-    arg_vector& operator = (const std::string&);\r
-    arg_vector& operator = (const char*);\r
-\r
-    // add an argument to the vector\r
-    arg_vector& operator += (const std::string&);\r
-    arg_vector& operator -= (const std::string&);\r
-\r
-    // insert/clear an argument at a certain index\r
-    // adding is like the other array classes - it moves the current item at index\r
-    // up one (and all subsequent values) to make room\r
-    void insert (unsigned index, const std::string&) throw(std::out_of_range);\r
-    void clear (unsigned index) throw(std::out_of_range);\r
-    void clear (void);\r
-\r
-    // number of values in the vector (including argv[0], the command itself\r
-    unsigned size (void) const;\r
-\r
-    // type conversion to the argv type\r
-    operator char** (void) const;\r
-    // function-based version of the above for people who don't like type conversions\r
-    char** argv (void) const;\r
-\r
-    // access individual values in the vector\r
-    char* operator [] (unsigned index) const throw(std::out_of_range);\r
-\r
-    // special-case access of the command name (e.g. to do path lookup on the command)\r
-    char* argv0 (void) const throw(std::out_of_range);\r
-\r
-    // get the command-line string represented by this vector\r
-    // includes escaping of special characters and quoting\r
-    std::string image (void) const;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Environment class\r
-  // Allows manipulation of an environment vector\r
-  // This is typically used to create an environment to be used by a subprocess\r
-  // It does NOT modify the environment of the current process\r
-\r
-#ifdef MSWINDOWS\r
-#define ENVIRON_TYPE char*\r
-#else\r
-#define ENVIRON_TYPE char**\r
-#endif\r
-\r
-  class env_vector\r
-  {\r
-  private:\r
-    ENVIRON_TYPE m_env;\r
-\r
-  public:\r
-    // create an env_vector vector from the current process\r
-    env_vector (void);\r
-    env_vector (const env_vector&);\r
-    ~env_vector (void);\r
-\r
-    env_vector& operator = (const env_vector&);\r
-\r
-    void clear (void);\r
-\r
-    // manipulate the env_vector by adding or removing variables\r
-    // adding a name that already exists replaces its value\r
-    void add (const std::string& name, const std::string& value);\r
-    bool remove (const std::string& name);\r
-\r
-    // get the value associated with a name\r
-    // the first uses an indexed notation (e.g. env["PATH"] )\r
-    // the second is a function based form (e.g. env.get("PATH"))\r
-    std::string operator [] (const std::string& name) const;\r
-    std::string get (const std::string& name) const;\r
-\r
-    // number of name=value pairs in the env_vector\r
-    unsigned size (void) const;\r
-\r
-    // get the name=value pairs by index (in the range 0 to size()-1)\r
-    std::pair<std::string,std::string> operator [] (unsigned index) const throw(std::out_of_range);\r
-    std::pair<std::string,std::string> get (unsigned index) const throw(std::out_of_range);\r
-\r
-    // access the env_vector as an envp type - used for passing to subprocesses\r
-    ENVIRON_TYPE envp (void) const;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef MSWINDOWS\r
-#define PID_TYPE PROCESS_INFORMATION\r
-#define PIPE_TYPE HANDLE\r
-#else\r
-#define PID_TYPE int\r
-#define PIPE_TYPE int\r
-#endif\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Synchronous subprocess\r
-\r
-  class subprocess\r
-  {\r
-  private:\r
-\r
-    PID_TYPE m_pid;\r
-#ifdef MSWINDOWS\r
-    HANDLE m_job;\r
-#endif\r
-    PIPE_TYPE m_child_in;\r
-    PIPE_TYPE m_child_out;\r
-    PIPE_TYPE m_child_err;\r
-    env_vector m_env;\r
-    int m_err;\r
-    int m_status;\r
-\r
-  public:\r
-    subprocess(void);\r
-    virtual ~subprocess(void);\r
-\r
-    void add_variable(const std::string& name, const std::string& value);\r
-    bool remove_variable(const std::string& name);\r
-\r
-    bool spawn(const std::string& path, const arg_vector& argv,\r
-               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);\r
-    bool spawn(const std::string& command_line,\r
-               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);\r
-\r
-    virtual bool callback(void);\r
-    bool kill(void);\r
-\r
-    int write_stdin(std::string& buffer);\r
-    int read_stdout(std::string& buffer);\r
-    int read_stderr(std::string& buffer);\r
-\r
-    void close_stdin(void);\r
-    void close_stdout(void);\r
-    void close_stderr(void);\r
-\r
-    bool error(void) const;\r
-    int error_number(void) const;\r
-    std::string error_text(void) const;\r
-\r
-    int exit_status(void) const;\r
-\r
-  private:\r
-    // disallow copying\r
-    subprocess(const subprocess&);\r
-    subprocess& operator=(const subprocess&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Preconfigured subprocess which executes a command and captures its output\r
-\r
-  class backtick_subprocess : public subprocess\r
-  {\r
-  private:\r
-    std::string m_text;\r
-  public:\r
-    backtick_subprocess(void);\r
-    virtual bool callback(void);\r
-    bool spawn(const std::string& path, const arg_vector& argv);\r
-    bool spawn(const std::string& command_line);\r
-    std::vector<std::string> text(void) const;\r
-  };\r
-\r
-  std::vector<std::string> backtick(const std::string& path, const arg_vector& argv);\r
-  std::vector<std::string> backtick(const std::string& command_line);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Asynchronous subprocess\r
-\r
-  class async_subprocess\r
-  {\r
-  private:\r
-    PID_TYPE m_pid;\r
-#ifdef MSWINDOWS\r
-    HANDLE m_job;\r
-#endif\r
-    PIPE_TYPE m_child_in;\r
-    PIPE_TYPE m_child_out;\r
-    PIPE_TYPE m_child_err;\r
-    env_vector m_env;\r
-    int m_err;\r
-    int m_status;\r
-    void set_error(int);\r
-\r
-  public:\r
-    async_subprocess(void);\r
-    virtual ~async_subprocess(void);\r
-\r
-    void add_variable(const std::string& name, const std::string& value);\r
-    bool remove_variable(const std::string& name);\r
-\r
-    bool spawn(const std::string& path, const arg_vector& argv,\r
-               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);\r
-    bool spawn(const std::string& command_line,\r
-               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);\r
-\r
-    virtual bool callback(void);\r
-    bool tick(void);\r
-    bool kill(void);\r
-\r
-    int write_stdin(std::string& buffer);\r
-    int read_stdout(std::string& buffer);\r
-    int read_stderr(std::string& buffer);\r
-\r
-    void close_stdin(void);\r
-    void close_stdout(void);\r
-    void close_stderr(void);\r
-\r
-    bool error(void) const;\r
-    int error_number(void) const;\r
-    std::string error_text(void) const;\r
-\r
-    int exit_status(void) const;\r
-\r
-  private:\r
-    // disallow copying\r
-    async_subprocess(const async_subprocess&);\r
-    async_subprocess& operator=(const async_subprocess&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_SUBPROCESSES
+#define STLPLUS_SUBPROCESSES
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+  
+//   Platform-independent wrapper around the very platform-specific handling of
+//   subprocesses. Uses the C++ convention that all resources must be contained in
+//   an object so that when a subprocess object goes out of scope the subprocess
+//   itself gets closed down.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#ifdef MSWINDOWS
+#include <windows.h>
+#endif
+#include <stdexcept>
+#include <vector>
+#include <string>
+#include <map> // for std::pair - why is this not defined separately?
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Argument vector class
+  // allows manipulation of argv-like vectors
+  // includes splitting of command lines into argvectors as per the shell
+  // (removing quotes) and the reverse conversion (adding quotes where necessary)
+
+  class arg_vector
+  {
+  private:
+    char** m_argv;
+
+  public:
+    // create an empty vector
+    arg_vector (void);
+
+    // copy constructor (yes it copies)
+    arg_vector (const arg_vector&);
+
+    // construct from an argv
+    arg_vector (char**);
+
+    // construct from a command-line string
+    // includes de-quoting of values
+    arg_vector (const std::string&);
+    arg_vector (const char*);
+
+    ~arg_vector (void);
+
+    // assignment operators are compatible with the constructors
+    arg_vector& operator = (const arg_vector&);
+    arg_vector& operator = (char**);
+    arg_vector& operator = (const std::string&);
+    arg_vector& operator = (const char*);
+
+    // add an argument to the vector
+    arg_vector& operator += (const std::string&);
+    arg_vector& operator -= (const std::string&);
+
+    // insert/clear an argument at a certain index
+    // adding is like the other array classes - it moves the current item at index
+    // up one (and all subsequent values) to make room
+    void insert (unsigned index, const std::string&) throw(std::out_of_range);
+    void clear (unsigned index) throw(std::out_of_range);
+    void clear (void);
+
+    // number of values in the vector (including argv[0], the command itself
+    unsigned size (void) const;
+
+    // type conversion to the argv type
+    operator char** (void) const;
+    // function-based version of the above for people who don't like type conversions
+    char** argv (void) const;
+
+    // access individual values in the vector
+    char* operator [] (unsigned index) const throw(std::out_of_range);
+
+    // special-case access of the command name (e.g. to do path lookup on the command)
+    char* argv0 (void) const throw(std::out_of_range);
+
+    // get the command-line string represented by this vector
+    // includes escaping of special characters and quoting
+    std::string image (void) const;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Environment class
+  // Allows manipulation of an environment vector
+  // This is typically used to create an environment to be used by a subprocess
+  // It does NOT modify the environment of the current process
+
+#ifdef MSWINDOWS
+#define ENVIRON_TYPE char*
+#else
+#define ENVIRON_TYPE char**
+#endif
+
+  class env_vector
+  {
+  private:
+    ENVIRON_TYPE m_env;
+
+  public:
+    // create an env_vector vector from the current process
+    env_vector (void);
+    env_vector (const env_vector&);
+    ~env_vector (void);
+
+    env_vector& operator = (const env_vector&);
+
+    void clear (void);
+
+    // manipulate the env_vector by adding or removing variables
+    // adding a name that already exists replaces its value
+    void add (const std::string& name, const std::string& value);
+    bool remove (const std::string& name);
+
+    // get the value associated with a name
+    // the first uses an indexed notation (e.g. env["PATH"] )
+    // the second is a function based form (e.g. env.get("PATH"))
+    std::string operator [] (const std::string& name) const;
+    std::string get (const std::string& name) const;
+
+    // number of name=value pairs in the env_vector
+    unsigned size (void) const;
+
+    // get the name=value pairs by index (in the range 0 to size()-1)
+    std::pair<std::string,std::string> operator [] (unsigned index) const throw(std::out_of_range);
+    std::pair<std::string,std::string> get (unsigned index) const throw(std::out_of_range);
+
+    // access the env_vector as an envp type - used for passing to subprocesses
+    ENVIRON_TYPE envp (void) const;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+#ifdef MSWINDOWS
+#define PID_TYPE PROCESS_INFORMATION
+#define PIPE_TYPE HANDLE
+#else
+#define PID_TYPE int
+#define PIPE_TYPE int
+#endif
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Synchronous subprocess
+
+  class subprocess
+  {
+  private:
+
+    PID_TYPE m_pid;
+#ifdef MSWINDOWS
+    HANDLE m_job;
+#endif
+    PIPE_TYPE m_child_in;
+    PIPE_TYPE m_child_out;
+    PIPE_TYPE m_child_err;
+    env_vector m_env;
+    int m_err;
+    int m_status;
+
+  public:
+    subprocess(void);
+    virtual ~subprocess(void);
+
+    void add_variable(const std::string& name, const std::string& value);
+    bool remove_variable(const std::string& name);
+
+    bool spawn(const std::string& path, const arg_vector& argv,
+               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
+    bool spawn(const std::string& command_line,
+               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
+
+    virtual bool callback(void);
+    bool kill(void);
+
+    int write_stdin(std::string& buffer);
+    int read_stdout(std::string& buffer);
+    int read_stderr(std::string& buffer);
+
+    void close_stdin(void);
+    void close_stdout(void);
+    void close_stderr(void);
+
+    bool error(void) const;
+    int error_number(void) const;
+    std::string error_text(void) const;
+
+    int exit_status(void) const;
+
+  private:
+    // disallow copying
+    subprocess(const subprocess&);
+    subprocess& operator=(const subprocess&);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Preconfigured subprocess which executes a command and captures its output
+
+  class backtick_subprocess : public subprocess
+  {
+  private:
+    std::string m_text;
+  public:
+    backtick_subprocess(void);
+    virtual bool callback(void);
+    bool spawn(const std::string& path, const arg_vector& argv);
+    bool spawn(const std::string& command_line);
+    std::vector<std::string> text(void) const;
+  };
+
+  std::vector<std::string> backtick(const std::string& path, const arg_vector& argv);
+  std::vector<std::string> backtick(const std::string& command_line);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Asynchronous subprocess
+
+  class async_subprocess
+  {
+  private:
+    PID_TYPE m_pid;
+#ifdef MSWINDOWS
+    HANDLE m_job;
+#endif
+    PIPE_TYPE m_child_in;
+    PIPE_TYPE m_child_out;
+    PIPE_TYPE m_child_err;
+    env_vector m_env;
+    int m_err;
+    int m_status;
+    void set_error(int);
+
+  public:
+    async_subprocess(void);
+    virtual ~async_subprocess(void);
+
+    void add_variable(const std::string& name, const std::string& value);
+    bool remove_variable(const std::string& name);
+
+    bool spawn(const std::string& path, const arg_vector& argv,
+               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
+    bool spawn(const std::string& command_line,
+               bool connect_stdin = false, bool connect_stdout = false, bool connect_stderr = false);
+
+    virtual bool callback(void);
+    bool tick(void);
+    bool kill(void);
+
+    int write_stdin(std::string& buffer);
+    int read_stdout(std::string& buffer);
+    int read_stderr(std::string& buffer);
+
+    void close_stdin(void);
+    void close_stdout(void);
+    void close_stderr(void);
+
+    bool error(void) const;
+    int error_number(void) const;
+    std::string error_text(void) const;
+
+    int exit_status(void) const;
+
+  private:
+    // disallow copying
+    async_subprocess(const async_subprocess&);
+    async_subprocess& operator=(const async_subprocess&);
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 3af0d3ffac989022b3652df7bc8b8d4bc9e7de8d..023b174f54ff6208193ac474a8baf1f9f4181cd7 100644 (file)
@@ -1,17 +1,17 @@
-#ifndef STLPLUS_TCP\r
-#define STLPLUS_TCP\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A deprecated legacy header - please use tcp_socket.hpp\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "portability_fixes.hpp"\r
-#include "tcp_sockets.hpp"\r
-\r
-#endif\r
+#ifndef STLPLUS_TCP
+#define STLPLUS_TCP
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A deprecated legacy header - please use tcp_socket.hpp
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "portability_fixes.hpp"
+#include "tcp_sockets.hpp"
+
+#endif
index 84152f49e65c1d49412f6630ed3d8881ad270b20..b15f6382f4fc2bc63ded58e2746b33b81ba07281 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "tcp_sockets.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // TCP Connection\r
-\r
-\r
-  TCP_connection::TCP_connection(const IP_socket& socket) : IP_socket(socket)\r
-  {\r
-  }\r
-\r
-  TCP_connection::TCP_connection(void) : IP_socket(TCP)\r
-  {\r
-  }\r
-\r
-  unsigned short TCP_connection::port(void) const\r
-  {\r
-    return remote_port();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Server\r
-\r
-  TCP_server::TCP_server(void) : IP_socket(TCP)\r
-  {\r
-  }\r
-\r
-  TCP_server::TCP_server(unsigned short port, unsigned short queue) : IP_socket(TCP)\r
-  {\r
-    initialise(port,queue);\r
-  }\r
-\r
-  bool TCP_server::initialise(unsigned short port, unsigned short queue)\r
-  {\r
-    if (!IP_socket::bind_any(port)) return false;\r
-    return IP_socket::listen(queue);\r
-  }\r
-\r
-  TCP_connection TCP_server::accept(void)\r
-  {\r
-    return TCP_connection(IP_socket::accept());\r
-  }\r
-\r
-  bool TCP_server::connection_ready(unsigned timeout)\r
-  {\r
-    return accept_ready(timeout);\r
-  }\r
-\r
-  TCP_connection TCP_server::connection(void)\r
-  {\r
-    return accept();\r
-  }\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // Client\r
-\r
-  TCP_client::TCP_client(void) : IP_socket(TCP)\r
-  {\r
-  }\r
-\r
-  TCP_client::TCP_client(const std::string& address, unsigned short port, unsigned int timeout) : IP_socket(TCP)\r
-  {\r
-    initialise(address,port,timeout);\r
-  }\r
-\r
-  TCP_client::TCP_client(unsigned long address, unsigned short port, unsigned int timeout) : IP_socket(TCP)\r
-  {\r
-    initialise(address,port,timeout);\r
-  }\r
-\r
-  bool TCP_client::initialise(unsigned long remote_address, unsigned short remote_port, unsigned int timeout)\r
-  {\r
-    if (!IP_socket::connect(remote_address, remote_port))\r
-    {\r
-      close();\r
-      return false;\r
-    }\r
-    if (timeout && !IP_socket::connected(timeout))\r
-    {\r
-      close();\r
-      return false;\r
-    }\r
-    return true;\r
-  }\r
-\r
-  bool TCP_client::initialise(const std::string& address, unsigned short remote_port, unsigned int timeout)\r
-  {\r
-    // lookup the address and convert it into an IP number\r
-    unsigned long remote_address = IP_socket::ip_lookup(address);\r
-    if (!remote_address) return false;\r
-    return initialise(remote_address, remote_port, timeout);\r
-  }\r
-\r
-  unsigned short TCP_client::port(void) const\r
-  {\r
-    return remote_port();\r
-  }\r
-\r
-  unsigned long TCP_client::address(void) const\r
-  {\r
-    return remote_address();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "tcp_sockets.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  //////////////////////////////////////////////////////////////////////////////
+  // TCP Connection
+
+
+  TCP_connection::TCP_connection(const IP_socket& socket) : IP_socket(socket)
+  {
+  }
+
+  TCP_connection::TCP_connection(void) : IP_socket(TCP)
+  {
+  }
+
+  unsigned short TCP_connection::port(void) const
+  {
+    return remote_port();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Server
+
+  TCP_server::TCP_server(void) : IP_socket(TCP)
+  {
+  }
+
+  TCP_server::TCP_server(unsigned short port, unsigned short queue) : IP_socket(TCP)
+  {
+    initialise(port,queue);
+  }
+
+  bool TCP_server::initialise(unsigned short port, unsigned short queue)
+  {
+    if (!IP_socket::bind_any(port)) return false;
+    return IP_socket::listen(queue);
+  }
+
+  TCP_connection TCP_server::accept(void)
+  {
+    return TCP_connection(IP_socket::accept());
+  }
+
+  bool TCP_server::connection_ready(unsigned timeout)
+  {
+    return accept_ready(timeout);
+  }
+
+  TCP_connection TCP_server::connection(void)
+  {
+    return accept();
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Client
+
+  TCP_client::TCP_client(void) : IP_socket(TCP)
+  {
+  }
+
+  TCP_client::TCP_client(const std::string& address, unsigned short port, unsigned int timeout) : IP_socket(TCP)
+  {
+    initialise(address,port,timeout);
+  }
+
+  TCP_client::TCP_client(unsigned long address, unsigned short port, unsigned int timeout) : IP_socket(TCP)
+  {
+    initialise(address,port,timeout);
+  }
+
+  bool TCP_client::initialise(unsigned long remote_address, unsigned short remote_port, unsigned int timeout)
+  {
+    if (!IP_socket::connect(remote_address, remote_port))
+    {
+      close();
+      return false;
+    }
+    if (timeout && !IP_socket::connected(timeout))
+    {
+      close();
+      return false;
+    }
+    return true;
+  }
+
+  bool TCP_client::initialise(const std::string& address, unsigned short remote_port, unsigned int timeout)
+  {
+    // lookup the address and convert it into an IP number
+    unsigned long remote_address = IP_socket::ip_lookup(address);
+    if (!remote_address) return false;
+    return initialise(remote_address, remote_port, timeout);
+  }
+
+  unsigned short TCP_client::port(void) const
+  {
+    return remote_port();
+  }
+
+  unsigned long TCP_client::address(void) const
+  {
+    return remote_address();
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 94b98c55bb9725d2a5aa97bbfae95ed405a1fcbe..df46f0b335da64ae73634f45791ccfeb0ff14ee5 100644 (file)
-#ifndef STLPLUS_TCP_SOCKET\r
-#define STLPLUS_TCP_SOCKET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A platform-independent (Unix and Windows anyway) interface to TCP sockets\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "portability_fixes.hpp"\r
-#include "ip_sockets.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // Server Classes: A server creates a listening port which waits for incoming\r
-  // connections. This is placed on the port number appropriate for the service\r
-  // - for example, a Telnet server would typically use port 23. For a new\r
-  // service you should of course use any port not allocated to a standard\r
-  // service. I believe that RFC 1700 defines the standard service port numbers.\r
-  // When an incoming connection is made, the server accepts it and in the\r
-  // process creates a new connection on a different port. This leaves the\r
-  // standard port listening for further connections. In effect, the server\r
-  // farms out the handling of the connections themselves and only takes\r
-  // responsibility for accepting the connection. This is reflected in the class\r
-  // structure. A TCP_server performs the listening and accepting roles, but\r
-  // creates a TCP_connection to handle the accepted connection.\r
-  //////////////////////////////////////////////////////////////////////////////\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // connection class created by TCP_server when a connection is accepted\r
-  // this is then used to perform any communications with the remote client\r
-\r
-  class TCP_connection : protected IP_socket\r
-  {\r
-  private:\r
-    // constructor to actually initialise the class - can only be constructed by TCP_server\r
-    friend class TCP_server;\r
-    TCP_connection(const IP_socket& socket);\r
-\r
-  public:\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // constructors/destructors\r
-\r
-    // create an uninitialised connection\r
-    TCP_connection(void);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // initialisation, connection control\r
-    // Note: TCP connections can only be initialised by a TCP server\r
-\r
-    // test whether this is an initialised socket\r
-    // - returns whether this is initialised\r
-    // bool initialised(void) const;\r
-    using IP_socket::initialised;\r
-\r
-    // close, i.e. disconnect the socket\r
-    // - returns a success flag\r
-    // bool close(void);\r
-    using IP_socket::close;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // sending/receiving\r
-\r
-    // test whether a socket is connected and ready to send data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool send_ready(unsigned timeout = 0);\r
-    using IP_socket::send_ready;\r
-\r
-    // send data through the socket - if the data is long only part of it may\r
-    // be sent. The sent part is removed from the data, so the same string can\r
-    // be sent again and again until it is empty.\r
-    // - data: string containing data to be sent - any data successfully sent is removed\r
-    // - returns success flag\r
-    // bool send (std::string& data);\r
-    using IP_socket::send;\r
-\r
-    // test whether a socket is connected and ready to receive data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool receive_ready(unsigned timeout = 0);\r
-    using IP_socket::receive_ready;\r
-\r
-    // receive data through the socket - if the data is long only part of it\r
-    // may be received. The received data is appended to the string, building\r
-    // it up in stages, so the same string can be received again and again\r
-    // until all information has been received.\r
-    // - data: string receiving data from socket - any data successfully received is appended\r
-    // - returns success flag\r
-    // bool receive (std::string& data);\r
-    using IP_socket::receive;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // informational\r
-\r
-    // the local port number of the connection\r
-    // - returns the port number, 0 if not bound to a port\r
-    // unsigned short local_port(void) const;\r
-    using IP_socket::local_port;\r
-\r
-    // the remote address of the connection\r
-    // - returns the address, 0 if not connected\r
-    // unsigned long remote_address(void) const;\r
-    using IP_socket::remote_address;\r
-\r
-    // the remote port number of the connection\r
-    // - returns the port number, 0 if not connected to a port\r
-    // unsigned short remote_port(void) const;\r
-    using IP_socket::remote_port;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error handling\r
-    // errors are set internally\r
-    // an error code of 0 is the test for no error, don't rely on the message being an empty string\r
-    // an error code != 0 means an error, then there will be a message explaining the error\r
-\r
-    // if an error is set it stays set - so you must clear it before further operations\r
-    // void clear_error(void) const;\r
-    using IP_socket::clear_error;\r
-\r
-    // get the error code of the last error\r
-    // int error(void) const;\r
-    using IP_socket::error;\r
-\r
-    // get the explanatory message of the last error\r
-    // std::string message(void) const;\r
-    using IP_socket::message;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-\r
-    // deprecated version of remote_port\r
-    unsigned short port(void) const;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-  };\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // server class that does the listening on the designated port\r
-  // incoming connections can be queued up to a maximum queue length specified\r
-  // in the constructor/initialise\r
-\r
-  class TCP_server : protected IP_socket\r
-  {\r
-  public:\r
-\r
-    // create an uninitialised server\r
-    TCP_server(void);\r
-\r
-    // initialise a socket and set it up to be a listening port\r
-    // - port: port to listen on\r
-    // - queue: length of backlog queue to manage - may be zero\r
-    // - returns success status\r
-    TCP_server(unsigned short port, unsigned short queue = 0);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // initialisation\r
-\r
-    // initialise a socket and set it up to be a listening port\r
-    // - port: port to listen on\r
-    // - queue: length of backlog queue to manage - may be zero\r
-    // - returns success status\r
-    bool initialise(unsigned short port, unsigned short queue = 0);\r
-\r
-    // test whether this is an initialised socket\r
-    // - returns whether this is initialised\r
-    // bool initialised(void) const;\r
-    using IP_socket::initialised;\r
-\r
-    // close, i.e. disconnect the socket\r
-    // - returns a success flag\r
-    // bool close(void);\r
-    using IP_socket::close;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // server operation - accepting a connection\r
-\r
-    // test for a connection on the object's socket - only applicable if it has been set up as a listening port\r
-    // - timeout: how long to wait in microseconds if not connected yet\r
-    // - returns true if a connection is ready to be accepted\r
-    // bool accept_ready(unsigned timeout = 0);\r
-    using IP_socket::accept_ready;\r
-\r
-    // accept a connection on the object's socket - only applicable if it has been set up as a listening port\r
-    // - returns the connection as a new socket\r
-    TCP_connection accept(void);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error handling\r
-    // errors are set internally\r
-    // an error code of 0 is the test for no error, don't rely on the message being an empty string\r
-    // an error code != 0 means an error, then there will be a message explaining the error\r
-\r
-    // if an error is set it stays set - so you must clear it before further operations\r
-    // void clear_error (void) const;\r
-    using IP_socket::clear_error;\r
-\r
-    // get the error code of the last error\r
-    // int error(void) const;\r
-    using IP_socket::error;\r
-\r
-    // get the explanatory message of the last error\r
-    // std::string message(void) const;\r
-    using IP_socket::message;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-\r
-    // deprecated versions of accept_ready and accept\r
-    bool connection_ready(unsigned timeout = 0);\r
-    TCP_connection connection(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Client Class: a client is simpler in that there is no listening port - you\r
-  // just create a connection and get on with it. Thus the client class does the\r
-  // whole job - create the connection and handle communications to/from it.\r
-  //\r
-  // Blocking mode: To use the client in blocking mode, use non-zero timeout for\r
-  // the initialisation method. In this mode, the connection operation must\r
-  // complete before the call will return or an error is indicated if the\r
-  // timeout is reached without completion. This usage was designed for\r
-  // applications which either just to TCP and nothing else or which do TCP\r
-  // operations in a separate thread.\r
-  //\r
-  // Non-blocking mode: To use the client in non-blocking mode, use a zero\r
-  // timeout for the initialisation method. Instead, you can ask it if it has\r
-  // connected once you've initialised it. It is not an error for it to be\r
-  // initialised but not connected. This usage was designed so that you can poll\r
-  // the connection periodically to implement a timeout for as long as you like for\r
-  // the connection to occur without blocking the thread that uses the client.\r
-  //\r
-  // In both modes, the send_ready/receive_ready methods can be called with any\r
-  // timeout including zero.\r
-\r
-  class TCP_client : protected IP_socket\r
-  {\r
-  public:\r
-\r
-    // create an uninitialised client\r
-    TCP_client(void);\r
-\r
-    // client connect to a server\r
-    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-    // - remote_port: port number of remote host\r
-    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed\r
-    TCP_client(const std::string& remote_address, unsigned short remote_port, unsigned timeout = 0);\r
-\r
-    // client connect to a server\r
-    // - remote_address: IP address as a long integer - generated by stlplus::ip_lookup\r
-    // - remote_port: port number of remote host\r
-    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed\r
-    TCP_client(unsigned long remote_address, unsigned short remote_port, unsigned timeout = 0);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // initialisation, connection\r
-\r
-    // function for performing IP lookup (i.e. gethostbyname)\r
-    // could be standalone but making it a member means that it can use the socket's error handler\r
-    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again\r
-    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-    // - returns the IP address as a long integer - zero if there's an error\r
-    // unsigned long ip_lookup(const std::string& remote_address);\r
-    using IP_socket::ip_lookup;\r
-\r
-    // client connect to a server\r
-    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-    // - remote_port: port number of remote host\r
-    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed\r
-    // - returns a success flag\r
-    bool initialise(const std::string& remote_address, unsigned short remote_port, unsigned timeout = 0);\r
-\r
-    // client connect to a server\r
-    // - remote_address: IP address as a long integer - generated by stlplus::ip_lookup\r
-    // - remote_port: port number of remote host\r
-    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed\r
-    // - returns a success flag\r
-    bool initialise(unsigned long remote_address, unsigned short remote_port, unsigned timeout = 0);\r
-\r
-    // test whether this is an initialised socket\r
-    // - returns whether this is initialised\r
-    // bool initialised(void) const;\r
-    using IP_socket::initialised;\r
-\r
-    // test whether a socket is connected and ready to communicate, returns on successful connect or timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet\r
-    // - returns success flag\r
-    // bool connected(unsigned timeout = 0);\r
-    using IP_socket::connected;\r
-\r
-    // close, i.e. disconnect the socket\r
-    // - returns a success flag\r
-    // bool close(void);\r
-    using IP_socket::close;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // sending/receiving\r
-\r
-    // test whether a socket is connected and ready to send data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool send_ready(unsigned timeout = 0);\r
-    using IP_socket::send_ready;\r
-\r
-    // send data through the socket - if the data is long only part of it may\r
-    // be sent. The sent part is removed from the data, so the same string can\r
-    // be sent again and again until it is empty.\r
-    // - data: string containing data to be sent - any data successfully sent is removed\r
-    // - returns success flag\r
-    // bool send (std::string& data);\r
-    using IP_socket::send;\r
-\r
-    // test whether a socket is connected and ready to receive data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool receive_ready(unsigned timeout = 0);\r
-    using IP_socket::receive_ready;\r
-\r
-    // receive data through the socket - if the data is long only part of it\r
-    // may be received. The received data is appended to the string, building\r
-    // it up in stages, so the same string can be received again and again\r
-    // until all information has been received.\r
-    // - data: string receiving data from socket - any data successfully received is appended\r
-    // - returns success flag\r
-    // bool receive (std::string& data);\r
-    using IP_socket::receive;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // informational\r
-\r
-    // the local port number of the connection\r
-    // - returns the port number, 0 if not bound to a port\r
-    // unsigned short local_port(void) const;\r
-    using IP_socket::local_port;\r
-\r
-    // the remote address of the connection\r
-    // - returns the address, 0 if not connected\r
-    // unsigned long remote_address(void) const;\r
-    using IP_socket::remote_address;\r
-\r
-    // the remote port number of the connection\r
-    // - returns the port number, 0 if not connected to a port\r
-    // unsigned short remote_port(void) const;\r
-    using IP_socket::remote_port;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error handling\r
-    // errors are set internally\r
-    // an error code of 0 is the test for no error, don't rely on the message being an empty string\r
-    // an error code != 0 means an error, then there will be a message explaining the error\r
-\r
-    // if an error is set it stays set - so you must clear it before further operations\r
-    // void clear_error (void) const;\r
-    using IP_socket::clear_error;\r
-\r
-    // get the error code of the last error\r
-    // int error(void) const;\r
-    using IP_socket::error;\r
-\r
-    // get the explanatory message of the last error\r
-    // std::string message(void) const;\r
-    using IP_socket::message;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-\r
-    // deprecated versions\r
-    unsigned long address(void) const;\r
-    unsigned short port(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_TCP_SOCKET
+#define STLPLUS_TCP_SOCKET
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A platform-independent (Unix and Windows anyway) interface to TCP sockets
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "portability_fixes.hpp"
+#include "ip_sockets.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  //////////////////////////////////////////////////////////////////////////////
+  // Server Classes: A server creates a listening port which waits for incoming
+  // connections. This is placed on the port number appropriate for the service
+  // - for example, a Telnet server would typically use port 23. For a new
+  // service you should of course use any port not allocated to a standard
+  // service. I believe that RFC 1700 defines the standard service port numbers.
+  // When an incoming connection is made, the server accepts it and in the
+  // process creates a new connection on a different port. This leaves the
+  // standard port listening for further connections. In effect, the server
+  // farms out the handling of the connections themselves and only takes
+  // responsibility for accepting the connection. This is reflected in the class
+  // structure. A TCP_server performs the listening and accepting roles, but
+  // creates a TCP_connection to handle the accepted connection.
+  //////////////////////////////////////////////////////////////////////////////
+
+  //////////////////////////////////////////////////////////////////////////////
+  // connection class created by TCP_server when a connection is accepted
+  // this is then used to perform any communications with the remote client
+
+  class TCP_connection : protected IP_socket
+  {
+  private:
+    // constructor to actually initialise the class - can only be constructed by TCP_server
+    friend class TCP_server;
+    TCP_connection(const IP_socket& socket);
+
+  public:
+
+    ////////////////////////////////////////////////////////////////////////////
+    // constructors/destructors
+
+    // create an uninitialised connection
+    TCP_connection(void);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // initialisation, connection control
+    // Note: TCP connections can only be initialised by a TCP server
+
+    // test whether this is an initialised socket
+    // - returns whether this is initialised
+    // bool initialised(void) const;
+    using IP_socket::initialised;
+
+    // close, i.e. disconnect the socket
+    // - returns a success flag
+    // bool close(void);
+    using IP_socket::close;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // sending/receiving
+
+    // test whether a socket is connected and ready to send data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool send_ready(unsigned timeout = 0);
+    using IP_socket::send_ready;
+
+    // send data through the socket - if the data is long only part of it may
+    // be sent. The sent part is removed from the data, so the same string can
+    // be sent again and again until it is empty.
+    // - data: string containing data to be sent - any data successfully sent is removed
+    // - returns success flag
+    // bool send (std::string& data);
+    using IP_socket::send;
+
+    // test whether a socket is connected and ready to receive data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool receive_ready(unsigned timeout = 0);
+    using IP_socket::receive_ready;
+
+    // receive data through the socket - if the data is long only part of it
+    // may be received. The received data is appended to the string, building
+    // it up in stages, so the same string can be received again and again
+    // until all information has been received.
+    // - data: string receiving data from socket - any data successfully received is appended
+    // - returns success flag
+    // bool receive (std::string& data);
+    using IP_socket::receive;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // informational
+
+    // the local port number of the connection
+    // - returns the port number, 0 if not bound to a port
+    // unsigned short local_port(void) const;
+    using IP_socket::local_port;
+
+    // the remote address of the connection
+    // - returns the address, 0 if not connected
+    // unsigned long remote_address(void) const;
+    using IP_socket::remote_address;
+
+    // the remote port number of the connection
+    // - returns the port number, 0 if not connected to a port
+    // unsigned short remote_port(void) const;
+    using IP_socket::remote_port;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error handling
+    // errors are set internally
+    // an error code of 0 is the test for no error, don't rely on the message being an empty string
+    // an error code != 0 means an error, then there will be a message explaining the error
+
+    // if an error is set it stays set - so you must clear it before further operations
+    // void clear_error(void) const;
+    using IP_socket::clear_error;
+
+    // get the error code of the last error
+    // int error(void) const;
+    using IP_socket::error;
+
+    // get the explanatory message of the last error
+    // std::string message(void) const;
+    using IP_socket::message;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    // deprecated version of remote_port
+    unsigned short port(void) const;
+
+    ////////////////////////////////////////////////////////////////////////////
+  };
+
+  //////////////////////////////////////////////////////////////////////////////
+  // server class that does the listening on the designated port
+  // incoming connections can be queued up to a maximum queue length specified
+  // in the constructor/initialise
+
+  class TCP_server : protected IP_socket
+  {
+  public:
+
+    // create an uninitialised server
+    TCP_server(void);
+
+    // initialise a socket and set it up to be a listening port
+    // - port: port to listen on
+    // - queue: length of backlog queue to manage - may be zero
+    // - returns success status
+    TCP_server(unsigned short port, unsigned short queue = 0);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // initialisation
+
+    // initialise a socket and set it up to be a listening port
+    // - port: port to listen on
+    // - queue: length of backlog queue to manage - may be zero
+    // - returns success status
+    bool initialise(unsigned short port, unsigned short queue = 0);
+
+    // test whether this is an initialised socket
+    // - returns whether this is initialised
+    // bool initialised(void) const;
+    using IP_socket::initialised;
+
+    // close, i.e. disconnect the socket
+    // - returns a success flag
+    // bool close(void);
+    using IP_socket::close;
+
+    //////////////////////////////////////////////////////////////////////////////
+    // server operation - accepting a connection
+
+    // test for a connection on the object's socket - only applicable if it has been set up as a listening port
+    // - timeout: how long to wait in microseconds if not connected yet
+    // - returns true if a connection is ready to be accepted
+    // bool accept_ready(unsigned timeout = 0);
+    using IP_socket::accept_ready;
+
+    // accept a connection on the object's socket - only applicable if it has been set up as a listening port
+    // - returns the connection as a new socket
+    TCP_connection accept(void);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error handling
+    // errors are set internally
+    // an error code of 0 is the test for no error, don't rely on the message being an empty string
+    // an error code != 0 means an error, then there will be a message explaining the error
+
+    // if an error is set it stays set - so you must clear it before further operations
+    // void clear_error (void) const;
+    using IP_socket::clear_error;
+
+    // get the error code of the last error
+    // int error(void) const;
+    using IP_socket::error;
+
+    // get the explanatory message of the last error
+    // std::string message(void) const;
+    using IP_socket::message;
+
+    //////////////////////////////////////////////////////////////////////////////
+
+    // deprecated versions of accept_ready and accept
+    bool connection_ready(unsigned timeout = 0);
+    TCP_connection connection(void);
+
+    //////////////////////////////////////////////////////////////////////////////
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Client Class: a client is simpler in that there is no listening port - you
+  // just create a connection and get on with it. Thus the client class does the
+  // whole job - create the connection and handle communications to/from it.
+  //
+  // Blocking mode: To use the client in blocking mode, use non-zero timeout for
+  // the initialisation method. In this mode, the connection operation must
+  // complete before the call will return or an error is indicated if the
+  // timeout is reached without completion. This usage was designed for
+  // applications which either just to TCP and nothing else or which do TCP
+  // operations in a separate thread.
+  //
+  // Non-blocking mode: To use the client in non-blocking mode, use a zero
+  // timeout for the initialisation method. Instead, you can ask it if it has
+  // connected once you've initialised it. It is not an error for it to be
+  // initialised but not connected. This usage was designed so that you can poll
+  // the connection periodically to implement a timeout for as long as you like for
+  // the connection to occur without blocking the thread that uses the client.
+  //
+  // In both modes, the send_ready/receive_ready methods can be called with any
+  // timeout including zero.
+
+  class TCP_client : protected IP_socket
+  {
+  public:
+
+    // create an uninitialised client
+    TCP_client(void);
+
+    // client connect to a server
+    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+    // - remote_port: port number of remote host
+    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed
+    TCP_client(const std::string& remote_address, unsigned short remote_port, unsigned timeout = 0);
+
+    // client connect to a server
+    // - remote_address: IP address as a long integer - generated by stlplus::ip_lookup
+    // - remote_port: port number of remote host
+    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed
+    TCP_client(unsigned long remote_address, unsigned short remote_port, unsigned timeout = 0);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // initialisation, connection
+
+    // function for performing IP lookup (i.e. gethostbyname)
+    // could be standalone but making it a member means that it can use the socket's error handler
+    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again
+    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+    // - returns the IP address as a long integer - zero if there's an error
+    // unsigned long ip_lookup(const std::string& remote_address);
+    using IP_socket::ip_lookup;
+
+    // client connect to a server
+    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+    // - remote_port: port number of remote host
+    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed
+    // - returns a success flag
+    bool initialise(const std::string& remote_address, unsigned short remote_port, unsigned timeout = 0);
+
+    // client connect to a server
+    // - remote_address: IP address as a long integer - generated by stlplus::ip_lookup
+    // - remote_port: port number of remote host
+    // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed
+    // - returns a success flag
+    bool initialise(unsigned long remote_address, unsigned short remote_port, unsigned timeout = 0);
+
+    // test whether this is an initialised socket
+    // - returns whether this is initialised
+    // bool initialised(void) const;
+    using IP_socket::initialised;
+
+    // test whether a socket is connected and ready to communicate, returns on successful connect or timeout
+    // - timeout: how long to wait in microseconds if not connected yet
+    // - returns success flag
+    // bool connected(unsigned timeout = 0);
+    using IP_socket::connected;
+
+    // close, i.e. disconnect the socket
+    // - returns a success flag
+    // bool close(void);
+    using IP_socket::close;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // sending/receiving
+
+    // test whether a socket is connected and ready to send data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool send_ready(unsigned timeout = 0);
+    using IP_socket::send_ready;
+
+    // send data through the socket - if the data is long only part of it may
+    // be sent. The sent part is removed from the data, so the same string can
+    // be sent again and again until it is empty.
+    // - data: string containing data to be sent - any data successfully sent is removed
+    // - returns success flag
+    // bool send (std::string& data);
+    using IP_socket::send;
+
+    // test whether a socket is connected and ready to receive data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool receive_ready(unsigned timeout = 0);
+    using IP_socket::receive_ready;
+
+    // receive data through the socket - if the data is long only part of it
+    // may be received. The received data is appended to the string, building
+    // it up in stages, so the same string can be received again and again
+    // until all information has been received.
+    // - data: string receiving data from socket - any data successfully received is appended
+    // - returns success flag
+    // bool receive (std::string& data);
+    using IP_socket::receive;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // informational
+
+    // the local port number of the connection
+    // - returns the port number, 0 if not bound to a port
+    // unsigned short local_port(void) const;
+    using IP_socket::local_port;
+
+    // the remote address of the connection
+    // - returns the address, 0 if not connected
+    // unsigned long remote_address(void) const;
+    using IP_socket::remote_address;
+
+    // the remote port number of the connection
+    // - returns the port number, 0 if not connected to a port
+    // unsigned short remote_port(void) const;
+    using IP_socket::remote_port;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error handling
+    // errors are set internally
+    // an error code of 0 is the test for no error, don't rely on the message being an empty string
+    // an error code != 0 means an error, then there will be a message explaining the error
+
+    // if an error is set it stays set - so you must clear it before further operations
+    // void clear_error (void) const;
+    using IP_socket::clear_error;
+
+    // get the error code of the last error
+    // int error(void) const;
+    using IP_socket::error;
+
+    // get the explanatory message of the last error
+    // std::string message(void) const;
+    using IP_socket::message;
+
+    //////////////////////////////////////////////////////////////////////////////
+
+    // deprecated versions
+    unsigned long address(void) const;
+    unsigned short port(void) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 250a825dccc70809372bbb2a67a809bda3be585a..3ceac3596751a5e35013713f610a96ea63a397dd 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "time.hpp"\r
-#include "dprintf.hpp"\r
-#include <ctype.h>\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  time_t time_now(void)\r
-  {\r
-    return time(0);\r
-  }\r
-\r
-  time_t localtime_create(int year, int month, int day, int hour, int minute, int second)\r
-  {\r
-    tm tm_time;\r
-    tm_time.tm_year = year-1900;  // years are represented as an offset from 1900, for reasons unknown\r
-    tm_time.tm_mon = month-1;     // internal format represents month as 0-11, but it is friendlier to take an input 1-12\r
-    tm_time.tm_mday = day;\r
-    tm_time.tm_hour = hour;\r
-    tm_time.tm_min = minute;\r
-    tm_time.tm_sec = second;\r
-    tm_time.tm_isdst = -1;        // specify that the function should work out daylight savings\r
-    time_t result = mktime(&tm_time);\r
-    return result;\r
-  }\r
-\r
-  int localtime_year(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_year + 1900;\r
-  }\r
-\r
-  int localtime_month(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_mon + 1;\r
-  }\r
-\r
-  int localtime_day(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_mday;\r
-  }\r
-\r
-  int localtime_hour(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_hour;\r
-  }\r
-\r
-  int localtime_minute(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_min;\r
-  }\r
-\r
-  int localtime_second(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_sec;\r
-  }\r
-\r
-  int localtime_weekday(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_wday;\r
-  }\r
-\r
-  int localtime_yearday(time_t t)\r
-  {\r
-    tm* tm_time = localtime(&t);\r
-    return tm_time->tm_yday;\r
-  }\r
-\r
-  std::string localtime_string(time_t t)\r
-  {\r
-    tm* local = localtime(&t);\r
-    std::string result = local ? asctime(local) : "*time not available*";\r
-    // ctime appends a newline for no apparent reason - clean up\r
-    while (!result.empty() && isspace(result[result.size()-1]))\r
-      result.erase(result.size()-1,1);\r
-    return result;\r
-  }\r
-\r
-  std::string delaytime_string(time_t seconds)\r
-  {\r
-    unsigned minutes = (unsigned)seconds / 60;\r
-    seconds %= 60;\r
-    unsigned hours = minutes / 60;\r
-    minutes %= 60;\r
-    unsigned days = hours / 24;\r
-    hours %= 24;\r
-    unsigned weeks = days / 7;\r
-    days %= 7;\r
-    std::string result;\r
-    if (weeks > 0)\r
-      result += dformat("%dw ",weeks);\r
-    if (!result.empty() || days > 0)\r
-      result += dformat("%dd ", days);\r
-    if (!result.empty() || hours > 0)\r
-      result += dformat("%d:", hours);\r
-    if (!result.empty() || minutes > 0)\r
-    {\r
-      if (!result.empty())\r
-        result += dformat("%02d:", minutes);\r
-      else\r
-        result += dformat("%d:", minutes);\r
-    }\r
-    if (!result.empty())\r
-      result += dformat("%02d:", seconds);\r
-    else\r
-      result += dformat("%ds", seconds);\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "time.hpp"
+#include "dprintf.hpp"
+#include <ctype.h>
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  time_t time_now(void)
+  {
+    return time(0);
+  }
+
+  time_t localtime_create(int year, int month, int day, int hour, int minute, int second)
+  {
+    tm tm_time;
+    tm_time.tm_year = year-1900;  // years are represented as an offset from 1900, for reasons unknown
+    tm_time.tm_mon = month-1;     // internal format represents month as 0-11, but it is friendlier to take an input 1-12
+    tm_time.tm_mday = day;
+    tm_time.tm_hour = hour;
+    tm_time.tm_min = minute;
+    tm_time.tm_sec = second;
+    tm_time.tm_isdst = -1;        // specify that the function should work out daylight savings
+    time_t result = mktime(&tm_time);
+    return result;
+  }
+
+  int localtime_year(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_year + 1900;
+  }
+
+  int localtime_month(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_mon + 1;
+  }
+
+  int localtime_day(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_mday;
+  }
+
+  int localtime_hour(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_hour;
+  }
+
+  int localtime_minute(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_min;
+  }
+
+  int localtime_second(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_sec;
+  }
+
+  int localtime_weekday(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_wday;
+  }
+
+  int localtime_yearday(time_t t)
+  {
+    tm* tm_time = localtime(&t);
+    return tm_time->tm_yday;
+  }
+
+  std::string localtime_string(time_t t)
+  {
+    tm* local = localtime(&t);
+    std::string result = local ? asctime(local) : "*time not available*";
+    // ctime appends a newline for no apparent reason - clean up
+    while (!result.empty() && isspace(result[result.size()-1]))
+      result.erase(result.size()-1,1);
+    return result;
+  }
+
+  std::string delaytime_string(time_t seconds)
+  {
+    unsigned minutes = (unsigned)seconds / 60;
+    seconds %= 60;
+    unsigned hours = minutes / 60;
+    minutes %= 60;
+    unsigned days = hours / 24;
+    hours %= 24;
+    unsigned weeks = days / 7;
+    days %= 7;
+    std::string result;
+    if (weeks > 0)
+      result += dformat("%dw ",weeks);
+    if (!result.empty() || days > 0)
+      result += dformat("%dd ", days);
+    if (!result.empty() || hours > 0)
+      result += dformat("%d:", hours);
+    if (!result.empty() || minutes > 0)
+    {
+      if (!result.empty())
+        result += dformat("%02d:", minutes);
+      else
+        result += dformat("%d:", minutes);
+    }
+    if (!result.empty())
+      result += dformat("%02d:", seconds);
+    else
+      result += dformat("%ds", seconds);
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index f8abe6cfedd6c7e65f824423af943c9247c18370..d9907e63590b5c7d8cbec32ecb5861cc8445b37f 100644 (file)
@@ -1,55 +1,55 @@
-#ifndef STLPLUS_TIME\r
-#define STLPLUS_TIME\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Simplified access to representations of time and conversions between them.\r
-//   The motivation for this package is that the low-level system calls for\r
-//   accessing time are ugly and therefore potentially error-prone. I hope that\r
-//   this interface is much simpler and therefore easier to use and more likely\r
-//   to yield first-time right programs.\r
-\r
-//   time is represented as the built-in integer type time_t - this is the\r
-//   standard representation of system time in computerland and represents the\r
-//   number of seconds since midnight 1 Jan 1970, believe it or not.\r
-\r
-//   Functions are provided here for converting to and from more\r
-//   human-comprehendable forms.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-#include <time.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // get the integer representing the time now\r
-  time_t time_now(void);\r
-\r
-  // get the integer representing the requested time - the local time is expressed in the local timezone\r
-  time_t localtime_create(int year, int month, int day, int hour, int minute, int second);\r
-\r
-  // extract human-centric form of the machine representation time_t\r
-  int localtime_year(time_t);    // the year e.g. 1962\r
-  int localtime_month(time_t);   // the month, numbered 1-12 e.g. August = 8\r
-  int localtime_day(time_t);     // the day of the month numbered 1-31 e.g. 29\r
-  int localtime_hour(time_t);    // the hour of day numbered 0-23\r
-  int localtime_minute(time_t);  // minute past the hour numbered 0-59\r
-  int localtime_second(time_t);  // second past the minute numbered 0-59\r
-  int localtime_weekday(time_t); // the day of the week numbered 0-6 with 0=Sunday\r
-  int localtime_yearday(time_t); // the number of days into the year\r
-\r
-  // convert the integer representation of time to a human-readable form\r
-  std::string localtime_string(time_t);\r
-\r
-  // convert a time delay in seconds to human-readable form\r
-  std::string delaytime_string(time_t);\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_TIME
+#define STLPLUS_TIME
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Simplified access to representations of time and conversions between them.
+//   The motivation for this package is that the low-level system calls for
+//   accessing time are ugly and therefore potentially error-prone. I hope that
+//   this interface is much simpler and therefore easier to use and more likely
+//   to yield first-time right programs.
+
+//   time is represented as the built-in integer type time_t - this is the
+//   standard representation of system time in computerland and represents the
+//   number of seconds since midnight 1 Jan 1970, believe it or not.
+
+//   Functions are provided here for converting to and from more
+//   human-comprehendable forms.
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+#include <time.h>
+
+namespace stlplus
+{
+
+  // get the integer representing the time now
+  time_t time_now(void);
+
+  // get the integer representing the requested time - the local time is expressed in the local timezone
+  time_t localtime_create(int year, int month, int day, int hour, int minute, int second);
+
+  // extract human-centric form of the machine representation time_t
+  int localtime_year(time_t);    // the year e.g. 1962
+  int localtime_month(time_t);   // the month, numbered 1-12 e.g. August = 8
+  int localtime_day(time_t);     // the day of the month numbered 1-31 e.g. 29
+  int localtime_hour(time_t);    // the hour of day numbered 0-23
+  int localtime_minute(time_t);  // minute past the hour numbered 0-59
+  int localtime_second(time_t);  // second past the minute numbered 0-59
+  int localtime_weekday(time_t); // the day of the week numbered 0-6 with 0=Sunday
+  int localtime_yearday(time_t); // the number of days into the year
+
+  // convert the integer representation of time to a human-readable form
+  std::string localtime_string(time_t);
+
+  // convert a time delay in seconds to human-readable form
+  std::string delaytime_string(time_t);
+
+} // end namespace stlplus
+
+#endif
index 137be3d3d7a2c33baf38ae872d4ea699700467a7..92f909d4c4dae11d25ce5d95d6a46130d24cdd4e 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Daniel Milton adapted by Andy Rushton\r
-//   Copyright: (c) Daniel Milton, Andy Rushton 2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "udp_sockets.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // UDP client\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // create an uninitialised socket\r
-  UDP_client::UDP_client(void) : IP_socket(UDP)\r
-  {\r
-  }\r
-\r
-  // Send/Receive datagram packets to/from the given address/remote port on the local port.\r
-  // Enables default send to remote address/port\r
-  // - remote_address: IP name or number of remote host\r
-  // - remote_port: port number of remote host\r
-  // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-  UDP_client::UDP_client(const std::string& remote_address, unsigned short remote_port, unsigned short local_port) :\r
-    IP_socket(UDP)\r
-  {\r
-    initialise(remote_address, remote_port, local_port);\r
-  }\r
-\r
-  // Send/Receive datagram packets to/from the given address/remote port on the given local port\r
-  // Enables default send to remote address/port\r
-  // - remote_address: IP address of remote host - pre-looked-up using ip_lookup\r
-  // - remote_port: port number of remote host\r
-  // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-  UDP_client::UDP_client(unsigned long remote_address, unsigned short remote_port, unsigned short local_port) :\r
-    IP_socket(UDP)\r
-  {\r
-    initialise(remote_address, remote_port, local_port);\r
-  }\r
-\r
-  // Send/Receive datagram packets to/from the given address/remote port on the local port.\r
-  // Enables default send to remote address/port\r
-  // - remote_address: IP name or number of remote host\r
-  // - remote_port: port number of remote host\r
-  // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-  // - returns a success flag\r
-  bool UDP_client::initialise(const std::string& address, unsigned short remote_port, unsigned short local_port)\r
-  {\r
-    // lookup the address and convert it into an IP number\r
-    unsigned long remote_address = IP_socket::ip_lookup(address);\r
-    if (!remote_address) return false;\r
-    return initialise(remote_address, remote_port, local_port);\r
-  }\r
-\r
-  // Send/Receive datagram packets to/from the given address/remote port on the given local port\r
-  // Enables default send to remote address/port\r
-  // - remote_address: IP address of remote host - pre-looked-up using ip_lookup\r
-  // - remote_port: port number of remote host\r
-  // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-  // - returns a success flag\r
-  bool UDP_client::initialise(unsigned long remote_address, unsigned short remote_port, unsigned short local_port)\r
-  {\r
-    if (!IP_socket::bind(remote_address, local_port)) return false;\r
-    return IP_socket::connect(remote_address, remote_port);\r
-  }\r
-\r
-  // send to the remote address/port setup in initialise, from the local port also setup in initialise.\r
-  // send data through the socket as a single datagram\r
-  // - packet: string containing data to be sent - if data is successfully sent it is removed\r
-  // - returns success flag\r
-  bool UDP_client::send(std::string& packet)\r
-  {\r
-    return IP_socket::send_packet(packet);\r
-  }\r
-\r
-  // datagram receive\r
-  // - packet: string to receive data from datagram - if data is successfully sent it is appended\r
-  // - returns success flag - i.e. packet successfully received\r
-  bool UDP_client::receive(std::string& packet)\r
-  {\r
-    return IP_socket::receive_packet(packet);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // UDP Server\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // create an uninitialised socket\r
-  UDP_server::UDP_server(void) : IP_socket(UDP)\r
-  {\r
-  }\r
-\r
-  // Initialise socket.\r
-  // Receive datagram packets from any address on provided local receiving port.\r
-  // No default send possible.\r
-  // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-  UDP_server::UDP_server(unsigned short local_port) : IP_socket(UDP)\r
-  {\r
-    initialise(local_port);\r
-  }\r
-\r
-  // Initialise socket.\r
-  // Receive datagram packets from any address on provided local receiving port.\r
-  // No default send possible.\r
-  // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-  // - returns a success flag\r
-  bool UDP_server::initialise(unsigned short local_port)\r
-  {\r
-    return IP_socket::bind_any(local_port);\r
-  }\r
-\r
-  // send to the address/port given here, from the local port setup in initialise.\r
-  // send data through the socket as a single datagram\r
-  // - packet: string containing data to be sent - if data is successfully sent it is removed\r
-  // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-  // - remote_port: port number of remote host\r
-  // - returns success flag\r
-  bool UDP_server::send(std::string& packet, const std::string& remote_address, unsigned short remote_port)\r
-  {\r
-    unsigned long ip_address = ip_lookup(remote_address);\r
-    if (ip_address == 0) return false;\r
-    return send(packet, ip_address, remote_port);\r
-  }\r
-\r
-  // send to the address/port given here, from the local port setup in initialise.\r
-  // send data through the socket as a single datagram\r
-  // - packet: string containing data to be sent - if data is successfully sent it is removed\r
-  // - remote_address: pre-looked-up IP address of remote host\r
-  // - remote_port: port number of remote host\r
-  // - returns success flag\r
-  bool UDP_server::send(std::string& packet, unsigned long remote_address, unsigned short remote_port)\r
-  {\r
-    return IP_socket::send_packet(packet, remote_address, remote_port);\r
-  }\r
-\r
-  // datagram receive\r
-  // - packet: string to receive data from datagram - if data is successfully sent it is appended\r
-  // - remote_address: the address of the client that sent the packet, can then be used to reply\r
-  // - remote_port: the port of the client that sent the packet, can then be used to reply\r
-  // - returns success flag - i.e. packet successfully received\r
-  bool UDP_server::receive(std::string& packet, unsigned long& remote_address, unsigned short& remote_port)\r
-  {\r
-    return IP_socket::receive_packet(packet, remote_address, remote_port);\r
-  }\r
-\r
-  /////////////////////////////////////////////////////////////////////////////\r
-  // fire and forget UDP client packet send function\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  bool UDP_send(const std::string& packet,\r
-                const std::string& remote_address, unsigned short remote_port, unsigned short local_port)\r
-  {\r
-    UDP_client client(remote_address, remote_port, local_port);\r
-    if (!client.initialised()) return false;\r
-    std::string packet_copy = packet;\r
-    return client.send(packet_copy);\r
-  }\r
-\r
-  /////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Daniel Milton adapted by Andy Rushton
+//   Copyright: (c) Daniel Milton, Andy Rushton 2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "udp_sockets.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // UDP client
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // create an uninitialised socket
+  UDP_client::UDP_client(void) : IP_socket(UDP)
+  {
+  }
+
+  // Send/Receive datagram packets to/from the given address/remote port on the local port.
+  // Enables default send to remote address/port
+  // - remote_address: IP name or number of remote host
+  // - remote_port: port number of remote host
+  // - local_port: port number to receive on - 0 to get an ephemeral port.
+  UDP_client::UDP_client(const std::string& remote_address, unsigned short remote_port, unsigned short local_port) :
+    IP_socket(UDP)
+  {
+    initialise(remote_address, remote_port, local_port);
+  }
+
+  // Send/Receive datagram packets to/from the given address/remote port on the given local port
+  // Enables default send to remote address/port
+  // - remote_address: IP address of remote host - pre-looked-up using ip_lookup
+  // - remote_port: port number of remote host
+  // - local_port: port number to receive on - 0 to get an ephemeral port.
+  UDP_client::UDP_client(unsigned long remote_address, unsigned short remote_port, unsigned short local_port) :
+    IP_socket(UDP)
+  {
+    initialise(remote_address, remote_port, local_port);
+  }
+
+  // Send/Receive datagram packets to/from the given address/remote port on the local port.
+  // Enables default send to remote address/port
+  // - remote_address: IP name or number of remote host
+  // - remote_port: port number of remote host
+  // - local_port: port number to receive on - 0 to get an ephemeral port.
+  // - returns a success flag
+  bool UDP_client::initialise(const std::string& address, unsigned short remote_port, unsigned short local_port)
+  {
+    // lookup the address and convert it into an IP number
+    unsigned long remote_address = IP_socket::ip_lookup(address);
+    if (!remote_address) return false;
+    return initialise(remote_address, remote_port, local_port);
+  }
+
+  // Send/Receive datagram packets to/from the given address/remote port on the given local port
+  // Enables default send to remote address/port
+  // - remote_address: IP address of remote host - pre-looked-up using ip_lookup
+  // - remote_port: port number of remote host
+  // - local_port: port number to receive on - 0 to get an ephemeral port.
+  // - returns a success flag
+  bool UDP_client::initialise(unsigned long remote_address, unsigned short remote_port, unsigned short local_port)
+  {
+    if (!IP_socket::bind(remote_address, local_port)) return false;
+    return IP_socket::connect(remote_address, remote_port);
+  }
+
+  // send to the remote address/port setup in initialise, from the local port also setup in initialise.
+  // send data through the socket as a single datagram
+  // - packet: string containing data to be sent - if data is successfully sent it is removed
+  // - returns success flag
+  bool UDP_client::send(std::string& packet)
+  {
+    return IP_socket::send_packet(packet);
+  }
+
+  // datagram receive
+  // - packet: string to receive data from datagram - if data is successfully sent it is appended
+  // - returns success flag - i.e. packet successfully received
+  bool UDP_client::receive(std::string& packet)
+  {
+    return IP_socket::receive_packet(packet);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // UDP Server
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // create an uninitialised socket
+  UDP_server::UDP_server(void) : IP_socket(UDP)
+  {
+  }
+
+  // Initialise socket.
+  // Receive datagram packets from any address on provided local receiving port.
+  // No default send possible.
+  // - local_port: port number to receive on - 0 to get an ephemeral port.
+  UDP_server::UDP_server(unsigned short local_port) : IP_socket(UDP)
+  {
+    initialise(local_port);
+  }
+
+  // Initialise socket.
+  // Receive datagram packets from any address on provided local receiving port.
+  // No default send possible.
+  // - local_port: port number to receive on - 0 to get an ephemeral port.
+  // - returns a success flag
+  bool UDP_server::initialise(unsigned short local_port)
+  {
+    return IP_socket::bind_any(local_port);
+  }
+
+  // send to the address/port given here, from the local port setup in initialise.
+  // send data through the socket as a single datagram
+  // - packet: string containing data to be sent - if data is successfully sent it is removed
+  // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+  // - remote_port: port number of remote host
+  // - returns success flag
+  bool UDP_server::send(std::string& packet, const std::string& remote_address, unsigned short remote_port)
+  {
+    unsigned long ip_address = ip_lookup(remote_address);
+    if (ip_address == 0) return false;
+    return send(packet, ip_address, remote_port);
+  }
+
+  // send to the address/port given here, from the local port setup in initialise.
+  // send data through the socket as a single datagram
+  // - packet: string containing data to be sent - if data is successfully sent it is removed
+  // - remote_address: pre-looked-up IP address of remote host
+  // - remote_port: port number of remote host
+  // - returns success flag
+  bool UDP_server::send(std::string& packet, unsigned long remote_address, unsigned short remote_port)
+  {
+    return IP_socket::send_packet(packet, remote_address, remote_port);
+  }
+
+  // datagram receive
+  // - packet: string to receive data from datagram - if data is successfully sent it is appended
+  // - remote_address: the address of the client that sent the packet, can then be used to reply
+  // - remote_port: the port of the client that sent the packet, can then be used to reply
+  // - returns success flag - i.e. packet successfully received
+  bool UDP_server::receive(std::string& packet, unsigned long& remote_address, unsigned short& remote_port)
+  {
+    return IP_socket::receive_packet(packet, remote_address, remote_port);
+  }
+
+  /////////////////////////////////////////////////////////////////////////////
+  // fire and forget UDP client packet send function
+  ////////////////////////////////////////////////////////////////////////////////
+
+  bool UDP_send(const std::string& packet,
+                const std::string& remote_address, unsigned short remote_port, unsigned short local_port)
+  {
+    UDP_client client(remote_address, remote_port, local_port);
+    if (!client.initialised()) return false;
+    std::string packet_copy = packet;
+    return client.send(packet_copy);
+  }
+
+  /////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 5097d44c0f334becf7514edb9fa563b3d9c75dc6..b6be81a3e9fc62ee4c9b4be21d051d480921117f 100644 (file)
-#ifndef STLPLUS_UDP_SOCKET\r
-#define STLPLUS_UDP_SOCKET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// Author:    Andy Rushton\r
-// Copyright: (c) Southampton University 1999-2004\r
-//            (c) Andy Rushton           2004-2009\r
-// License:   BSD License, see ../docs/license.html\r
-\r
-// A platform-independent (Unix and Windows anyway) interface to UDP sockets\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "portability_fixes.hpp"\r
-#include "ip_sockets.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // UDP client - creates a connectioned socket\r
-\r
-  class UDP_client : protected IP_socket\r
-  {\r
-  public:\r
-\r
-    // create an uninitialised socket\r
-    UDP_client(void);\r
-\r
-    // Send/Receive datagram packets to/from the given address/remote port on the local port.\r
-    // - remote_address: IP name or number of remote host\r
-    // - remote_port: port number of remote host\r
-    // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-    UDP_client(const std::string& remote_address, unsigned short remote_port, unsigned short local_port=0);\r
-\r
-    // Send/Receive datagram packets to/from the given address/remote port on the given local port\r
-    // Enables default send to remote address/port\r
-    // - remote_address: IP address of remote host - pre-looked-up using ip_lookup\r
-    // - remote_port: port number of remote host\r
-    // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-    UDP_client(unsigned long remote_address, unsigned short remote_port, unsigned short local_port=0);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // initialisation, connection\r
-\r
-    // function for performing IP lookup (i.e. gethostbyname)\r
-    // could be standalone but making it a member means that it can use the socket's error handler\r
-    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again\r
-    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-    // - returns the IP address as a long integer - zero if there's an error\r
-    // unsigned long ip_lookup(const std::string& remote_address);\r
-    using IP_socket::ip_lookup;\r
-\r
-    // Send/Receive datagram packets to/from the given address/remote port on the local port.\r
-    // Enables default send to remote address/port\r
-    // - remote_address: IP name or number of remote host\r
-    // - remote_port: port number of remote host\r
-    // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-    // - returns a success flag\r
-    bool initialise(const std::string& remote_address, unsigned short remote_port, unsigned short local_port=0);\r
-\r
-    // Send/Receive datagram packets to/from the given address/remote port on the given local port\r
-    // Enables default send to remote address/port\r
-    // - remote_address: IP address of remote host - pre-looked-up using ip_lookup\r
-    // - remote_port: port number of remote host\r
-    // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-    // - returns a success flag\r
-    bool initialise(unsigned long remote_address, unsigned short remote_port, unsigned short local_port=0);\r
-\r
-    // test whether this is an initialised socket\r
-    // - returns whether this is initialised\r
-    // bool initialised(void) const;\r
-    using IP_socket::initialised;\r
-\r
-    // close, i.e. disconnect the socket\r
-    // - returns a success flag\r
-    // bool close(void);\r
-    using IP_socket::close;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // sending/receiving\r
-\r
-    // test whether a socket is connected and ready to send data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool send_ready(unsigned timeout = 0);\r
-    using IP_socket::send_ready;\r
-\r
-    // send to the remote address/port setup in initialise, from the local port also setup in initialise.\r
-    // send data through the socket as a single datagram\r
-    // - packet: string containing data to be sent - if data is successfully sent it is removed\r
-    // - returns success flag\r
-    bool send(std::string& packet);\r
-\r
-    // test whether a socket is connected and ready to receive data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool receive_ready(unsigned timeout = 0);\r
-    using IP_socket::receive_ready;\r
-\r
-    // datagram receive\r
-    // - packet: string to receive data from datagram - if data is successfully sent it is appended\r
-    // - returns success flag - i.e. packet successfully received\r
-    bool receive(std::string& packet);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // informational\r
-\r
-    // the local port number of the connection\r
-    // returns the port number, 0 if not bound to a port\r
-    // unsigned short local_port(void) const;\r
-    using IP_socket::local_port;\r
-\r
-    // the remote address of the connection\r
-    // returns the address, 0 if ANY address\r
-    // unsigned long remote_address(void) const;\r
-    using IP_socket::remote_address;\r
-\r
-    // the remote port number of the connection\r
-    // returns the port number, 0 if not bound to a port\r
-    // unsigned short remote_port(void) const;\r
-    using IP_socket::remote_port;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error handling\r
-    // errors are set internally\r
-    // an error code of 0 is the test for no error, don't rely on the message being an empty string\r
-    // an error code != 0 means an error, then there will be a message explaining the error\r
-\r
-    // if an error is set it stays set - so you must clear it before further operations\r
-    // void clear_error (void);\r
-    using IP_socket::clear_error ;\r
-\r
-    // get the error code of the last error\r
-    // int error(void) const;\r
-    using IP_socket::error;\r
-\r
-    // get the explanatory message of the last error\r
-    // std::string message(void) const;\r
-    using IP_socket::message;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-\r
-  private:\r
-    IP_socket m_socket;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // UDP server - creates a connectionless (multicast) listener socket\r
-\r
-  class UDP_server : protected IP_socket\r
-  {\r
-  public:\r
-\r
-    // create an uninitialised socket\r
-    UDP_server(void);\r
-\r
-    // Initialise socket.\r
-    // Receive datagram packets from any address on provided local receiving port.\r
-    // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-    UDP_server(unsigned short local_port);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // initialisation, connection\r
-\r
-    // function for performing IP lookup (i.e. gethostbyname)\r
-    // could be standalone but making it a member means that it can use the socket's error handler\r
-    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again\r
-    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-    // - returns the IP address as a long integer - zero if there's an error\r
-    // unsigned long ip_lookup(const std::string& remote_address);\r
-    using IP_socket::ip_lookup;\r
-\r
-    // Initialise socket.\r
-    // Receive datagram packets from any address on provided local receiving port.\r
-    // - local_port: port number to receive on - 0 to get an ephemeral port.\r
-    // - returns a success flag\r
-    bool initialise(unsigned short local_port);\r
-\r
-    // test whether this is an initialised socket\r
-    // - returns whether this is initialised\r
-    // bool initialised(void) const;\r
-    using IP_socket::initialised;\r
-\r
-    // close, i.e. disconnect the socket\r
-    // - returns a success flag\r
-    // bool close(void);\r
-    using IP_socket::close;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // sending/receiving\r
-\r
-    // test whether a socket is connected and ready to send data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool send_ready(unsigned timeout = 0);\r
-    using IP_socket::send_ready;\r
-\r
-    // send to the address/port given here, from the local port setup in initialise.\r
-    // send data through the socket as a single datagram\r
-    // - packet: string containing data to be sent - if data is successfully sent it is removed\r
-    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)\r
-    // - remote_port: port number of remote host\r
-    // - returns success flag\r
-    bool send(std::string& packet, const std::string& remote_address, unsigned short remote_port);\r
-\r
-    // send to the address/port given here, from the local port setup in initialise.\r
-    // send data through the socket as a single datagram\r
-    // - packet: string containing data to be sent - if data is successfully sent it is removed\r
-    // - remote_address: pre-looked-up IP address of remote host\r
-    // - remote_port: port number of remote host\r
-    // - returns success flag\r
-    bool send(std::string& packet, unsigned long remote_address, unsigned short remote_port);\r
-\r
-    // test whether a socket is connected and ready to receive data, returns if ready or on timeout\r
-    // - timeout: how long to wait in microseconds if not connected yet (blocking)\r
-    // - returns status\r
-    // bool receive_ready(unsigned timeout = 0);\r
-    using IP_socket::receive_ready;\r
-\r
-    // datagram receive\r
-    // - packet: string to receive data from datagram - if data is successfully sent it is appended\r
-    // - remote_address: the address of the client that sent the packet, can then be used to reply\r
-    // - remote_port: the port of the client that sent the packet, can then be used to reply\r
-    // - returns success flag - i.e. packet successfully received\r
-    bool receive(std::string& packet, unsigned long& remote_address, unsigned short& remote_port);\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // informational\r
-\r
-    // the local port number of the connection\r
-    // returns the port number, 0 if not bound to a port\r
-    // unsigned short local_port(void) const;\r
-    using IP_socket::local_port;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-    // error handling\r
-    // errors are set internally\r
-    // an error code of 0 is the test for no error, don't rely on the message being an empty string\r
-    // an error code != 0 means an error, then there will be a message explaining the error\r
-\r
-    // if an error is set it stays set - so you must clear it before further operations\r
-    // void clear_error(void);\r
-    using IP_socket::clear_error;\r
-\r
-    // get the error code of the last error\r
-    // int error(void) const;\r
-    using IP_socket::error;\r
-\r
-    // get the explanatory message of the last error\r
-    // std::string message(void) const;\r
-    using IP_socket::message;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////\r
-  };\r
-\r
-  /////////////////////////////////////////////////////////////////////////////\r
-  // fire and forget UDP client packet send function\r
-\r
-  bool UDP_send(const std::string& packet,\r
-                const std::string& remote_address, unsigned short remote_port, unsigned short local_port = 0);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_UDP_SOCKET
+#define STLPLUS_UDP_SOCKET
+////////////////////////////////////////////////////////////////////////////////
+
+// Author:    Andy Rushton
+// Copyright: (c) Southampton University 1999-2004
+//            (c) Andy Rushton           2004-2009
+// License:   BSD License, see ../docs/license.html
+
+// A platform-independent (Unix and Windows anyway) interface to UDP sockets
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "portability_fixes.hpp"
+#include "ip_sockets.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  //////////////////////////////////////////////////////////////////////////////
+  // UDP client - creates a connectioned socket
+
+  class UDP_client : protected IP_socket
+  {
+  public:
+
+    // create an uninitialised socket
+    UDP_client(void);
+
+    // Send/Receive datagram packets to/from the given address/remote port on the local port.
+    // - remote_address: IP name or number of remote host
+    // - remote_port: port number of remote host
+    // - local_port: port number to receive on - 0 to get an ephemeral port.
+    UDP_client(const std::string& remote_address, unsigned short remote_port, unsigned short local_port=0);
+
+    // Send/Receive datagram packets to/from the given address/remote port on the given local port
+    // Enables default send to remote address/port
+    // - remote_address: IP address of remote host - pre-looked-up using ip_lookup
+    // - remote_port: port number of remote host
+    // - local_port: port number to receive on - 0 to get an ephemeral port.
+    UDP_client(unsigned long remote_address, unsigned short remote_port, unsigned short local_port=0);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // initialisation, connection
+
+    // function for performing IP lookup (i.e. gethostbyname)
+    // could be standalone but making it a member means that it can use the socket's error handler
+    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again
+    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+    // - returns the IP address as a long integer - zero if there's an error
+    // unsigned long ip_lookup(const std::string& remote_address);
+    using IP_socket::ip_lookup;
+
+    // Send/Receive datagram packets to/from the given address/remote port on the local port.
+    // Enables default send to remote address/port
+    // - remote_address: IP name or number of remote host
+    // - remote_port: port number of remote host
+    // - local_port: port number to receive on - 0 to get an ephemeral port.
+    // - returns a success flag
+    bool initialise(const std::string& remote_address, unsigned short remote_port, unsigned short local_port=0);
+
+    // Send/Receive datagram packets to/from the given address/remote port on the given local port
+    // Enables default send to remote address/port
+    // - remote_address: IP address of remote host - pre-looked-up using ip_lookup
+    // - remote_port: port number of remote host
+    // - local_port: port number to receive on - 0 to get an ephemeral port.
+    // - returns a success flag
+    bool initialise(unsigned long remote_address, unsigned short remote_port, unsigned short local_port=0);
+
+    // test whether this is an initialised socket
+    // - returns whether this is initialised
+    // bool initialised(void) const;
+    using IP_socket::initialised;
+
+    // close, i.e. disconnect the socket
+    // - returns a success flag
+    // bool close(void);
+    using IP_socket::close;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // sending/receiving
+
+    // test whether a socket is connected and ready to send data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool send_ready(unsigned timeout = 0);
+    using IP_socket::send_ready;
+
+    // send to the remote address/port setup in initialise, from the local port also setup in initialise.
+    // send data through the socket as a single datagram
+    // - packet: string containing data to be sent - if data is successfully sent it is removed
+    // - returns success flag
+    bool send(std::string& packet);
+
+    // test whether a socket is connected and ready to receive data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool receive_ready(unsigned timeout = 0);
+    using IP_socket::receive_ready;
+
+    // datagram receive
+    // - packet: string to receive data from datagram - if data is successfully sent it is appended
+    // - returns success flag - i.e. packet successfully received
+    bool receive(std::string& packet);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // informational
+
+    // the local port number of the connection
+    // returns the port number, 0 if not bound to a port
+    // unsigned short local_port(void) const;
+    using IP_socket::local_port;
+
+    // the remote address of the connection
+    // returns the address, 0 if ANY address
+    // unsigned long remote_address(void) const;
+    using IP_socket::remote_address;
+
+    // the remote port number of the connection
+    // returns the port number, 0 if not bound to a port
+    // unsigned short remote_port(void) const;
+    using IP_socket::remote_port;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error handling
+    // errors are set internally
+    // an error code of 0 is the test for no error, don't rely on the message being an empty string
+    // an error code != 0 means an error, then there will be a message explaining the error
+
+    // if an error is set it stays set - so you must clear it before further operations
+    // void clear_error (void);
+    using IP_socket::clear_error ;
+
+    // get the error code of the last error
+    // int error(void) const;
+    using IP_socket::error;
+
+    // get the explanatory message of the last error
+    // std::string message(void) const;
+    using IP_socket::message;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+  private:
+    IP_socket m_socket;
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // UDP server - creates a connectionless (multicast) listener socket
+
+  class UDP_server : protected IP_socket
+  {
+  public:
+
+    // create an uninitialised socket
+    UDP_server(void);
+
+    // Initialise socket.
+    // Receive datagram packets from any address on provided local receiving port.
+    // - local_port: port number to receive on - 0 to get an ephemeral port.
+    UDP_server(unsigned short local_port);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // initialisation, connection
+
+    // function for performing IP lookup (i.e. gethostbyname)
+    // could be standalone but making it a member means that it can use the socket's error handler
+    // i.e. if this fails, the sockets error code will be set - clear it to use the socket again
+    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+    // - returns the IP address as a long integer - zero if there's an error
+    // unsigned long ip_lookup(const std::string& remote_address);
+    using IP_socket::ip_lookup;
+
+    // Initialise socket.
+    // Receive datagram packets from any address on provided local receiving port.
+    // - local_port: port number to receive on - 0 to get an ephemeral port.
+    // - returns a success flag
+    bool initialise(unsigned short local_port);
+
+    // test whether this is an initialised socket
+    // - returns whether this is initialised
+    // bool initialised(void) const;
+    using IP_socket::initialised;
+
+    // close, i.e. disconnect the socket
+    // - returns a success flag
+    // bool close(void);
+    using IP_socket::close;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // sending/receiving
+
+    // test whether a socket is connected and ready to send data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool send_ready(unsigned timeout = 0);
+    using IP_socket::send_ready;
+
+    // send to the address/port given here, from the local port setup in initialise.
+    // send data through the socket as a single datagram
+    // - packet: string containing data to be sent - if data is successfully sent it is removed
+    // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96)
+    // - remote_port: port number of remote host
+    // - returns success flag
+    bool send(std::string& packet, const std::string& remote_address, unsigned short remote_port);
+
+    // send to the address/port given here, from the local port setup in initialise.
+    // send data through the socket as a single datagram
+    // - packet: string containing data to be sent - if data is successfully sent it is removed
+    // - remote_address: pre-looked-up IP address of remote host
+    // - remote_port: port number of remote host
+    // - returns success flag
+    bool send(std::string& packet, unsigned long remote_address, unsigned short remote_port);
+
+    // test whether a socket is connected and ready to receive data, returns if ready or on timeout
+    // - timeout: how long to wait in microseconds if not connected yet (blocking)
+    // - returns status
+    // bool receive_ready(unsigned timeout = 0);
+    using IP_socket::receive_ready;
+
+    // datagram receive
+    // - packet: string to receive data from datagram - if data is successfully sent it is appended
+    // - remote_address: the address of the client that sent the packet, can then be used to reply
+    // - remote_port: the port of the client that sent the packet, can then be used to reply
+    // - returns success flag - i.e. packet successfully received
+    bool receive(std::string& packet, unsigned long& remote_address, unsigned short& remote_port);
+
+    ////////////////////////////////////////////////////////////////////////////
+    // informational
+
+    // the local port number of the connection
+    // returns the port number, 0 if not bound to a port
+    // unsigned short local_port(void) const;
+    using IP_socket::local_port;
+
+    ////////////////////////////////////////////////////////////////////////////
+    // error handling
+    // errors are set internally
+    // an error code of 0 is the test for no error, don't rely on the message being an empty string
+    // an error code != 0 means an error, then there will be a message explaining the error
+
+    // if an error is set it stays set - so you must clear it before further operations
+    // void clear_error(void);
+    using IP_socket::clear_error;
+
+    // get the error code of the last error
+    // int error(void) const;
+    using IP_socket::error;
+
+    // get the explanatory message of the last error
+    // std::string message(void) const;
+    using IP_socket::message;
+
+    ////////////////////////////////////////////////////////////////////////////
+  };
+
+  /////////////////////////////////////////////////////////////////////////////
+  // fire and forget UDP client packet send function
+
+  bool UDP_send(const std::string& packet,
+                const std::string& remote_address, unsigned short remote_port, unsigned short local_port = 0);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 8a34c6ea6ba0344f9ebc2d29a0faf1ded3225482..a271b9f35604495e98a97ac79123770ee141fbf7 100644 (file)
@@ -1,20 +1,20 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "version.hpp"\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  std::string version(void)\r
-  {\r
-    return STLPLUS_VERSION;\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "version.hpp"
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  std::string version(void)
+  {
+    return STLPLUS_VERSION;
+  }
+
+} // end namespace stlplus
index 027e131e766b9c152970701bee757158f280c2c7..852efce28e10bf3fdc74b6bd4c072eca995e1dd9 100644 (file)
@@ -1,24 +1,24 @@
-#ifndef STLPLUS_VERSION\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Contains just the STLplus version number\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-\r
-#define STLPLUS_VERSION "3.5"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  std::string version(void);\r
-\r
-}\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_VERSION
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Contains just the STLplus version number
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+
+#define STLPLUS_VERSION "3.5"
+
+namespace stlplus
+{
+
+  std::string version(void);
+
+}
+////////////////////////////////////////////////////////////////////////////////
+#endif
index c15252e670209b91a2e469906acad2fc506f8291..2efdbca6b330bba0e7b5c98792039ae6b3b96d0f 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Simple wildcard matching function.\r
-\r
-//   WARNING: wheel re-invention follows\r
-//   Given that all shells perform wildcard matching, why don't the library writers put it in the C run-time????????\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "wildcard.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // function for testing whether a character matches a set\r
-  // I can't remember the exact rules and I have no definitive references but:\r
-  // a set contains characters, escaped characters (I think) and ranges in the form a-z\r
-  // The character '-' can only appear at the start of the set where it is not interpreted as a range\r
-  // This is a horrible mess - blame the Unix folks for making a hash of wildcards\r
-  // first expand any ranges and remove escape characters to make life more palatable\r
-\r
-  static bool match_set (const std::string& set, char match)\r
-  {\r
-    std::string simple_set;\r
-    for (std::string::const_iterator i = set.begin(); i != set.end(); ++i)\r
-    {\r
-      switch(*i)\r
-      {\r
-      case '-':\r
-      {\r
-        if (i == set.begin())\r
-        {\r
-          simple_set += *i;\r
-        }\r
-        else if (i+1 == set.end())\r
-        {\r
-          return false;\r
-        }\r
-        else\r
-        {\r
-          // found a set. The first character is already in the result, so first remove it (the set might be empty)\r
-          simple_set.erase(simple_set.end()-1);\r
-          char last = *++i;\r
-          for (char ch = *(i-2); ch <= last; ch++)\r
-          {\r
-            simple_set += ch;\r
-          }\r
-        }\r
-        break;\r
-      }\r
-      case '\\':\r
-        if (i+1 == set.end()) {return false;}\r
-        simple_set += *++i;\r
-        break;\r
-      default:\r
-        simple_set += *i;\r
-        break;\r
-      }\r
-    }\r
-    std::string::size_type result = simple_set.find(match);\r
-    return result != std::string::npos;\r
-  }\r
-\r
-  // the recursive bit - basically whenever a * is found you recursively call this for each candidate substring match\r
-  // until either it succeeds or you run out of string to match\r
-  // for each * in the wildcard another level of recursion is created\r
-\r
-  static bool match_remainder (const std::string& wild, std::string::const_iterator wildi, const std::string& match, std::string::const_iterator matchi)\r
-  {\r
-    //cerr << "match_remainder called at " << *matchi << " with wildcard " << *wildi << endl;\r
-    while (wildi != wild.end() && matchi != match.end())\r
-    {\r
-      //cerr << "trying to match " << *matchi << " with wildcard " << *wildi << endl;\r
-      switch(*wildi)\r
-      {\r
-      case '*':\r
-      {\r
-        ++wildi;\r
-        ++matchi;\r
-        for (std::string::const_iterator i = matchi; i != match.end(); ++i)\r
-        {\r
-          // deal with * at the end of the wildcard - there is no remainder then\r
-          if (wildi == wild.end())\r
-          {\r
-            if (i == match.end()-1)\r
-              return true;\r
-          }\r
-          else if (match_remainder(wild, wildi, match, i))\r
-          {\r
-            return true;\r
-          }\r
-        }\r
-        return false;\r
-      }\r
-      case '[':\r
-      {\r
-        // scan for the end of the set using a similar method for avoiding escaped characters\r
-        bool found = false;\r
-        std::string::const_iterator end = wildi + 1;\r
-        for (; !found && end != wild.end(); ++end)\r
-        {\r
-          switch(*end)\r
-          {\r
-          case ']':\r
-          {\r
-            // found the set, now match with its contents excluding the brackets\r
-            if (!match_set(wild.substr(wildi - wild.begin() + 1, end - wildi - 1), *matchi))\r
-              return false;\r
-            found = true;\r
-            break;\r
-          }\r
-          case '\\':\r
-            if (end == wild.end()-1)\r
-              return false;\r
-            ++end;\r
-            break;\r
-          default:\r
-            break;\r
-          }\r
-        }\r
-        if (!found)\r
-          return false;\r
-        ++matchi;\r
-        wildi = end;\r
-        break;\r
-      }\r
-      case '?':\r
-        ++wildi;\r
-        ++matchi;\r
-        break;\r
-      case '\\':\r
-        if (wildi == wild.end()-1)\r
-          return false;\r
-        ++wildi;\r
-        if (*wildi != *matchi)\r
-          return false;\r
-        ++wildi;\r
-        ++matchi;\r
-        break;\r
-      default:\r
-        if (*wildi != *matchi)\r
-          return false;\r
-        ++wildi;\r
-        ++matchi;\r
-        break;\r
-      }\r
-    }\r
-    bool result = wildi == wild.end() && matchi == match.end();\r
-    return result;\r
-  }\r
-\r
-  // like all recursions the exported function has a simpler interface than the\r
-  // recursive function and is just a 'seed' to the recursion itself\r
-\r
-  bool wildcard(const std::string& wild, const std::string& match)\r
-  {\r
-    return match_remainder(wild, wild.begin(), match, match.begin());\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Simple wildcard matching function.
+
+//   WARNING: wheel re-invention follows
+//   Given that all shells perform wildcard matching, why don't the library writers put it in the C run-time????????
+
+////////////////////////////////////////////////////////////////////////////////
+#include "wildcard.hpp"
+
+namespace stlplus
+{
+
+  // function for testing whether a character matches a set
+  // I can't remember the exact rules and I have no definitive references but:
+  // a set contains characters, escaped characters (I think) and ranges in the form a-z
+  // The character '-' can only appear at the start of the set where it is not interpreted as a range
+  // This is a horrible mess - blame the Unix folks for making a hash of wildcards
+  // first expand any ranges and remove escape characters to make life more palatable
+
+  static bool match_set (const std::string& set, char match)
+  {
+    std::string simple_set;
+    for (std::string::const_iterator i = set.begin(); i != set.end(); ++i)
+    {
+      switch(*i)
+      {
+      case '-':
+      {
+        if (i == set.begin())
+        {
+          simple_set += *i;
+        }
+        else if (i+1 == set.end())
+        {
+          return false;
+        }
+        else
+        {
+          // found a set. The first character is already in the result, so first remove it (the set might be empty)
+          simple_set.erase(simple_set.end()-1);
+          char last = *++i;
+          for (char ch = *(i-2); ch <= last; ch++)
+          {
+            simple_set += ch;
+          }
+        }
+        break;
+      }
+      case '\\':
+        if (i+1 == set.end()) {return false;}
+        simple_set += *++i;
+        break;
+      default:
+        simple_set += *i;
+        break;
+      }
+    }
+    std::string::size_type result = simple_set.find(match);
+    return result != std::string::npos;
+  }
+
+  // the recursive bit - basically whenever a * is found you recursively call this for each candidate substring match
+  // until either it succeeds or you run out of string to match
+  // for each * in the wildcard another level of recursion is created
+
+  static bool match_remainder (const std::string& wild, std::string::const_iterator wildi, const std::string& match, std::string::const_iterator matchi)
+  {
+    //cerr << "match_remainder called at " << *matchi << " with wildcard " << *wildi << endl;
+    while (wildi != wild.end() && matchi != match.end())
+    {
+      //cerr << "trying to match " << *matchi << " with wildcard " << *wildi << endl;
+      switch(*wildi)
+      {
+      case '*':
+      {
+        ++wildi;
+        ++matchi;
+        for (std::string::const_iterator i = matchi; i != match.end(); ++i)
+        {
+          // deal with * at the end of the wildcard - there is no remainder then
+          if (wildi == wild.end())
+          {
+            if (i == match.end()-1)
+              return true;
+          }
+          else if (match_remainder(wild, wildi, match, i))
+          {
+            return true;
+          }
+        }
+        return false;
+      }
+      case '[':
+      {
+        // scan for the end of the set using a similar method for avoiding escaped characters
+        bool found = false;
+        std::string::const_iterator end = wildi + 1;
+        for (; !found && end != wild.end(); ++end)
+        {
+          switch(*end)
+          {
+          case ']':
+          {
+            // found the set, now match with its contents excluding the brackets
+            if (!match_set(wild.substr(wildi - wild.begin() + 1, end - wildi - 1), *matchi))
+              return false;
+            found = true;
+            break;
+          }
+          case '\\':
+            if (end == wild.end()-1)
+              return false;
+            ++end;
+            break;
+          default:
+            break;
+          }
+        }
+        if (!found)
+          return false;
+        ++matchi;
+        wildi = end;
+        break;
+      }
+      case '?':
+        ++wildi;
+        ++matchi;
+        break;
+      case '\\':
+        if (wildi == wild.end()-1)
+          return false;
+        ++wildi;
+        if (*wildi != *matchi)
+          return false;
+        ++wildi;
+        ++matchi;
+        break;
+      default:
+        if (*wildi != *matchi)
+          return false;
+        ++wildi;
+        ++matchi;
+        break;
+      }
+    }
+    bool result = wildi == wild.end() && matchi == match.end();
+    return result;
+  }
+
+  // like all recursions the exported function has a simpler interface than the
+  // recursive function and is just a 'seed' to the recursion itself
+
+  bool wildcard(const std::string& wild, const std::string& match)
+  {
+    return match_remainder(wild, wild.begin(), match, match.begin());
+  }
+
+} // end namespace stlplus
index 398c3dd43621951b89a7418cc7e6e3eda647d0be..585a7868067eda49c9883bf15d44a41581baee0f 100644 (file)
@@ -1,35 +1,35 @@
-#ifndef STLPLUS_WILDCARD\r
-#define STLPLUS_WILDCARD\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   This is a portable interface to wildcard matching.\r
-\r
-//   The problem:\r
-//     *  matches any number of characters - this is achieved by matching 1 and seeing if the remainder matches\r
-//        if not, try 2 characters and see if the remainder matches etc.\r
-//        this must be recursive, not iterative, so that multiple *s can appear in the same wildcard expression\r
-//     ?  matches exactly one character so doesn't need the what-if approach\r
-//     \  escapes special characters such as *, ? and [\r
-//     [] matches exactly one character in the set - the difficulty is the set can contain ranges, e.g [a-zA-Z0-9]\r
-//        a set cannot be empty and the ] character can be included by making it the first character\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "portability_fixes.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // wild = the wildcard expression\r
-  // match = the string to test against that expression\r
-  // e.g. wildcard("[a-f]*", "fred") returns true\r
-  bool wildcard(const std::string& wild, const std::string& match);\r
-\r
-}\r
-\r
-#endif\r
+#ifndef STLPLUS_WILDCARD
+#define STLPLUS_WILDCARD
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   This is a portable interface to wildcard matching.
+
+//   The problem:
+//     *  matches any number of characters - this is achieved by matching 1 and seeing if the remainder matches
+//        if not, try 2 characters and see if the remainder matches etc.
+//        this must be recursive, not iterative, so that multiple *s can appear in the same wildcard expression
+//     ?  matches exactly one character so doesn't need the what-if approach
+//     \  escapes special characters such as *, ? and [
+//     [] matches exactly one character in the set - the difficulty is the set can contain ranges, e.g [a-zA-Z0-9]
+//        a set cannot be empty and the ] character can be included by making it the first character
+
+////////////////////////////////////////////////////////////////////////////////
+#include "portability_fixes.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  // wild = the wildcard expression
+  // match = the string to test against that expression
+  // e.g. wildcard("[a-f]*", "fred") returns true
+  bool wildcard(const std::string& wild, const std::string& match);
+
+}
+
+#endif
index 5df771124489e89a4f226118ea6452a6d80637c1..c9711c35490e941a8ab13246f185399542a94a8b 100644 (file)
@@ -1,60 +1,60 @@
-#ifndef STLPLUS_FORMAT_TYPES\r
-#define STLPLUS_FORMAT_TYPES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A Set of enumerations controlling the string formatting of numbers.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Integer radix display representations:\r
-//   There are three ways in which the radix is represented:\r
-//     - none - the number is just printed as a number (e.g. 12345). Can be confusing for non-decimal radix\r
-//     - C style - for binary, octal and hex, the C-style prefices 0b, 0 and 0x are used\r
-//       note that this is an unsigned representation\r
-//     - Hash style - in the form radix#value - the value may be signed, e.g. 10#-9\r
-\r
-enum radix_display_t \r
-{\r
-  radix_none,               // just print the number with no radix indicated\r
-  radix_hash_style,         // none for decimal, hash style for all others\r
-  radix_hash_style_all,     // hash style for all radices including decimal\r
-  radix_c_style,            // C style for hex and octal, none for others\r
-  radix_c_style_or_hash     // C style for hex and octal, none for decimal, hash style for others\r
-};\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Floating-point display representations:\r
-// There are three formats for the printout:\r
-//   - fixed - formatted as a fixed-point number, so no mantissa is printed (equivalent to %f in printf)\r
-//   - floating - formatted as a normalised floating-point number (equivalent to %e in printf)\r
-//   - mixed - formatted as fixed-point if appropriate, otherwise the floating format (equivalent to %g in printf)\r
-\r
-enum real_display_t\r
-{\r
-  display_fixed,    // %f\r
-  display_floating, // %e\r
-  display_mixed     // %g\r
-};\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Alignment:\r
-//   There are three field alignments:\r
-//     - left aligned - the value is to the left of the field which is padded to the right with spaces\r
-//     - right aligned - the value is to the right of the field which is padded to the left with spaces\r
-//     - centred - the value is in the centre of the field and spaces added to both left and right\r
-\r
-enum alignment_t\r
-{\r
-  align_left,\r
-  align_right,\r
-  align_centre\r
-};\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_FORMAT_TYPES
+#define STLPLUS_FORMAT_TYPES
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   A Set of enumerations controlling the string formatting of numbers.
+
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Integer radix display representations:
+//   There are three ways in which the radix is represented:
+//     - none - the number is just printed as a number (e.g. 12345). Can be confusing for non-decimal radix
+//     - C style - for binary, octal and hex, the C-style prefices 0b, 0 and 0x are used
+//       note that this is an unsigned representation
+//     - Hash style - in the form radix#value - the value may be signed, e.g. 10#-9
+
+enum radix_display_t 
+{
+  radix_none,               // just print the number with no radix indicated
+  radix_hash_style,         // none for decimal, hash style for all others
+  radix_hash_style_all,     // hash style for all radices including decimal
+  radix_c_style,            // C style for hex and octal, none for others
+  radix_c_style_or_hash     // C style for hex and octal, none for decimal, hash style for others
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Floating-point display representations:
+// There are three formats for the printout:
+//   - fixed - formatted as a fixed-point number, so no mantissa is printed (equivalent to %f in printf)
+//   - floating - formatted as a normalised floating-point number (equivalent to %e in printf)
+//   - mixed - formatted as fixed-point if appropriate, otherwise the floating format (equivalent to %g in printf)
+
+enum real_display_t
+{
+  display_fixed,    // %f
+  display_floating, // %e
+  display_mixed     // %g
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Alignment:
+//   There are three field alignments:
+//     - left aligned - the value is to the left of the field which is padded to the right with spaces
+//     - right aligned - the value is to the right of the field which is padded to the left with spaces
+//     - centred - the value is in the centre of the field and spaces added to both left and right
+
+enum alignment_t
+{
+  align_left,
+  align_right,
+  align_centre
+};
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
index 3962557a3999965cb78b8018a3fd449fdd39a704..74e416fdcc3ade89f7858178492dfc6d0aa7a2c1 100644 (file)
@@ -1,28 +1,28 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   use the unsigned long representation for pointers\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_address.hpp"\r
-#include "print_int.hpp"\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void print_address(std::ostream& device, const void* i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    print_unsigned_long(device, (unsigned long)i, radix, display, width);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   use the unsigned long representation for pointers
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_address.hpp"
+#include "print_int.hpp"
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void print_address(std::ostream& device, const void* i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    print_unsigned_long(device, (unsigned long)i, radix, display, width);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index f89bdae67f371bd56d048a77c6b27bfb099c3d6d..6ba90bc18250658d76404cb247efba6567d42637 100644 (file)
@@ -1,33 +1,33 @@
-#ifndef STLPLUS_PRINT_ADDRESS\r
-#define STLPLUS_PRINT_ADDRESS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void print_address(std::ostream& device, \r
-                     const void*,\r
-                     unsigned radix = 16,\r
-                     radix_display_t display = radix_c_style_or_hash,\r
-                     unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_ADDRESS
+#define STLPLUS_PRINT_ADDRESS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <string>
+#include <iostream>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void print_address(std::ostream& device, 
+                     const void*,
+                     unsigned radix = 16,
+                     radix_display_t display = radix_c_style_or_hash,
+                     unsigned width = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 9d67862921d51bd7a728779ed078bd336a72ff69..f85b00eec2523a1bc79e885c77e3e106d23a2bbc 100644 (file)
@@ -1,21 +1,21 @@
-#ifndef STLPLUS_PRINT_BASIC\r
-#define STLPLUS_PRINT_BASIC\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Utilities for converting printing basic C types\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "print_address.hpp"\r
-#include "print_bool.hpp"\r
-#include "print_cstring.hpp"\r
-#include "print_float.hpp"\r
-#include "print_int.hpp"\r
-#include "print_pointer.hpp"\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_BASIC
+#define STLPLUS_PRINT_BASIC
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Utilities for converting printing basic C types
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "print_address.hpp"
+#include "print_bool.hpp"
+#include "print_cstring.hpp"
+#include "print_float.hpp"
+#include "print_int.hpp"
+#include "print_pointer.hpp"
+
+#endif
index f7151ddcc733fff8decaea059021148c0bd818e7..d87ee20275ded9d94d63545ea1cec71d74698aa0 100644 (file)
@@ -1,27 +1,27 @@
-#ifndef STLPLUS_PRINT_BITSET\r
-#define STLPLUS_PRINT_BITSET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a bitset\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <bitset>\r
-#include <string>\r
-#include <iostream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<size_t N>\r
-  void print_bitset(std::ostream& device, const std::bitset<N>& data);\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_bitset.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_BITSET
+#define STLPLUS_PRINT_BITSET
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a bitset
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <bitset>
+#include <string>
+#include <iostream>
+
+namespace stlplus
+{
+
+  template<size_t N>
+  void print_bitset(std::ostream& device, const std::bitset<N>& data);
+
+} // end namespace stlplus
+
+#include "print_bitset.tpp"
+#endif
index 833103a888e772878868ebf793e7ca7065a828ab..5514beaf3888e93c7b867858723d8181d002e2b8 100644 (file)
@@ -1,20 +1,20 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_bitset.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<size_t N>\r
-  void print_bitset(std::ostream& device, const std::bitset<N>& data)\r
-  {\r
-    device << bitset_to_string(data);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_bitset.hpp"
+
+namespace stlplus
+{
+
+  template<size_t N>
+  void print_bitset(std::ostream& device, const std::bitset<N>& data)
+  {
+    device << bitset_to_string(data);
+  }
+
+} // end namespace stlplus
index adcebc1bd5db275afdf47c1c393768a8931c25b9..0d63debea874fb7c84d678359d0e695ac7db29c2 100644 (file)
@@ -1,27 +1,27 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   use the unsigned short representation for bool\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_bool.hpp"\r
-#include "print_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void print_bool(std::ostream& device, bool i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    print_unsigned_short(device, (unsigned short)i, radix, display, width);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   use the unsigned short representation for bool
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_bool.hpp"
+#include "print_int.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void print_bool(std::ostream& device, bool i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    print_unsigned_short(device, (unsigned short)i, radix, display, width);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 5e808d165d9b63951028f678a4d1d7194c649198..f22a1c0a8074fb842cb368d32135003546de319d 100644 (file)
@@ -1,34 +1,34 @@
-#ifndef STLPLUS_PRINT_BOOL\r
-#define STLPLUS_PRINT_BOOL\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Conversion of string to/from bool\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void print_bool(std::ostream& device, bool i,\r
-                  unsigned radix = 10,\r
-                  radix_display_t display = radix_c_style_or_hash,\r
-                  unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_BOOL
+#define STLPLUS_PRINT_BOOL
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Conversion of string to/from bool
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <string>
+#include <iostream>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void print_bool(std::ostream& device, bool i,
+                  unsigned radix = 10,
+                  radix_display_t display = radix_c_style_or_hash,
+                  unsigned width = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 423c7417749e67c7f6b925809a786c7d9b5f7bd0..50c733d657c1328507522589bfffb4cbc460b21f 100644 (file)
@@ -1,19 +1,19 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_cstring.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void print_cstring(std::ostream& device, const char* value)\r
-  {\r
-    device << value;\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_cstring.hpp"
+
+namespace stlplus
+{
+
+  void print_cstring(std::ostream& device, const char* value)
+  {
+    device << value;
+  }
+
+} // end namespace stlplus
index 57cdbcd72022466fc19c1da17da3ae43b9b513cc..d705015cd15070c21247d4b1ebff80c7b3c6e10e 100644 (file)
@@ -1,27 +1,27 @@
-#ifndef STLPLUS_PRINT_CSTRING\r
-#define STLPLUS_PRINT_CSTRING\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Functions for converting C/STL strings to string\r
-\r
-//   This is necessary for completeness\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void print_cstring(std::ostream& device, const char* value);\r
-\r
-}\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_CSTRING
+#define STLPLUS_PRINT_CSTRING
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Functions for converting C/STL strings to string
+
+//   This is necessary for completeness
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  void print_cstring(std::ostream& device, const char* value);
+
+}
+
+#endif
index e5c2ff8f6d727a7746a019aa51f3a10aa3f9fbff..126b8a33645961859921f20dbf49201d3f7cdd14 100644 (file)
@@ -1,33 +1,33 @@
-#ifndef STLPLUS_PRINT_DIGRAPH\r
-#define STLPLUS_PRINT_DIGRAPH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a digraph\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "digraph.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename NT, typename AT, typename NS, typename AS>\r
-  void print_digraph(std::ostream& device,\r
-                     const digraph<NT,AT>& values,\r
-                     NS node_print_fn,\r
-                     AS arc_print_fn,\r
-                     const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_digraph.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_DIGRAPH
+#define STLPLUS_PRINT_DIGRAPH
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a digraph
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "digraph.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename NT, typename AT, typename NS, typename AS>
+  void print_digraph(std::ostream& device,
+                     const digraph<NT,AT>& values,
+                     NS node_print_fn,
+                     AS arc_print_fn,
+                     const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "print_digraph.tpp"
+#endif
index 69e8018dc6a8e8c2b37f17908fc16419295754b6..af2818fca05367e8b9ecf274c5e870492f1a89eb 100644 (file)
@@ -1,31 +1,31 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT, typename NS, typename AS>\r
-  void print_digraph(std::ostream& device, const digraph<NT,AT>& values,\r
-                     NS node_print_fn,\r
-                     AS arc_print_fn,\r
-                     const std::string& separator)\r
-  {\r
-    device << "nodes:";\r
-    device << separator;\r
-    print_sequence(device, values.begin(), values.end(), node_print_fn, separator);\r
-    device << "arcs:";\r
-    device << separator;\r
-    print_sequence(device, values.arc_begin(), values.arc_end(), arc_print_fn, separator);\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_sequence.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename NT, typename AT, typename NS, typename AS>
+  void print_digraph(std::ostream& device, const digraph<NT,AT>& values,
+                     NS node_print_fn,
+                     AS arc_print_fn,
+                     const std::string& separator)
+  {
+    device << "nodes:";
+    device << separator;
+    print_sequence(device, values.begin(), values.end(), node_print_fn, separator);
+    device << "arcs:";
+    device << separator;
+    print_sequence(device, values.arc_begin(), values.arc_end(), arc_print_fn, separator);
+  }
+
+} // end namespace stlplus
+
index a36c2c110875cd8b0a9489c87ef98354387d490a..dc10b200f503ea43c9b35e716c5c6b9b19979874 100644 (file)
@@ -1,32 +1,32 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_float.hpp"\r
-#include "string_float.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // floating-point types\r
-\r
-  void print_float(std::ostream& device, float f, real_display_t display, unsigned width, unsigned precision)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << float_to_string(f, display, width, precision);\r
-  }\r
-\r
-  void print_double(std::ostream& device, double f, real_display_t display, unsigned width, unsigned precision)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << double_to_string(f, display, width, precision);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_float.hpp"
+#include "string_float.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // floating-point types
+
+  void print_float(std::ostream& device, float f, real_display_t display, unsigned width, unsigned precision)
+    throw(std::invalid_argument)
+  {
+    device << float_to_string(f, display, width, precision);
+  }
+
+  void print_double(std::ostream& device, double f, real_display_t display, unsigned width, unsigned precision)
+    throw(std::invalid_argument)
+  {
+    device << double_to_string(f, display, width, precision);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 2de8b8fb0898a007ad4d619bc7e87b3cddca8242..9ee54ee68b823e8bce27567ebd00a1b96000dc72 100644 (file)
@@ -1,47 +1,47 @@
-#ifndef STLPLUS_PRINT_FLOAT\r
-#define STLPLUS_PRINT_FLOAT\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Convert a float/double to/from string\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // convert a real type to string\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // Only decimal radix is supported\r
-\r
-  // The way in which the number is displayed is defined in radix_types.hpp\r
-  // Using any other value for the display type causes std::invalid_argument to be thrown\r
-\r
-  void print_float(std::ostream& device, float f,\r
-                   real_display_t display = display_mixed,\r
-                   unsigned width = 0,\r
-                   unsigned precision = 6)\r
-    throw(std::invalid_argument);\r
-\r
-  void print_double(std::ostream& device, double f,\r
-                    real_display_t display = display_mixed,\r
-                    unsigned width = 0,\r
-                    unsigned precision = 6)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_FLOAT
+#define STLPLUS_PRINT_FLOAT
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Convert a float/double to/from string
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <string>
+#include <iostream>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // convert a real type to string
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // Only decimal radix is supported
+
+  // The way in which the number is displayed is defined in radix_types.hpp
+  // Using any other value for the display type causes std::invalid_argument to be thrown
+
+  void print_float(std::ostream& device, float f,
+                   real_display_t display = display_mixed,
+                   unsigned width = 0,
+                   unsigned precision = 6)
+    throw(std::invalid_argument);
+
+  void print_double(std::ostream& device, double f,
+                    real_display_t display = display_mixed,
+                    unsigned width = 0,
+                    unsigned precision = 6)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 3ee3696107809a0fcceee3ad850c9f8260c39a6a..899915f83b38eeb8646bb9284a7a038dfb629667 100644 (file)
@@ -1,35 +1,35 @@
-#ifndef STLPLUS_PRINT_FOURSOME\r
-#define STLPLUS_PRINT_FOURSOME\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a foursome\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "foursome.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>\r
-  void print_foursome(std::ostream& device,\r
-                      const foursome<T1,T2,T3,T4>& values,\r
-                      S1 print_fn1,\r
-                      S2 print_fn2,\r
-                      S3 print_fn3,\r
-                      S4 print_fn4,\r
-                      const std::string& separator = ":");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_foursome.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_FOURSOME
+#define STLPLUS_PRINT_FOURSOME
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a foursome
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "foursome.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>
+  void print_foursome(std::ostream& device,
+                      const foursome<T1,T2,T3,T4>& values,
+                      S1 print_fn1,
+                      S2 print_fn2,
+                      S3 print_fn3,
+                      S4 print_fn4,
+                      const std::string& separator = ":");
+
+} // end namespace stlplus
+
+#include "print_foursome.tpp"
+#endif
index 8b9f319eb5147a5b01b9401b4ef487d7d69ff569..adec37d7f82cf8178b9fdcc3ea8dae7543e13346 100644 (file)
@@ -1,33 +1,33 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>\r
-  void print_foursome(std::ostream& device,\r
-                      const foursome<T1,T2,T3,T4>& values,\r
-                      S1 print_fn1,\r
-                      S2 print_fn2,\r
-                      S3 print_fn3,\r
-                      S4 print_fn4,\r
-                      const std::string& separator)\r
-  {\r
-    print_fn1(device, values.first);\r
-    device << separator;\r
-    print_fn2(device, values.second);\r
-    device << separator;\r
-    print_fn3(device, values.third);\r
-    device << separator;\r
-    print_fn4(device, values.fourth);\r
-  }\r
-\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>
+  void print_foursome(std::ostream& device,
+                      const foursome<T1,T2,T3,T4>& values,
+                      S1 print_fn1,
+                      S2 print_fn2,
+                      S3 print_fn3,
+                      S4 print_fn4,
+                      const std::string& separator)
+  {
+    print_fn1(device, values.first);
+    device << separator;
+    print_fn2(device, values.second);
+    device << separator;
+    print_fn3(device, values.third);
+    device << separator;
+    print_fn4(device, values.fourth);
+  }
+
+
+} // end namespace stlplus
+
index 43a76f4a67a69a3976c5be7d8fee5c75f5762574..36915b552aac56854aaff1d3c6604e5ed3aa32f9 100644 (file)
@@ -1,34 +1,34 @@
-#ifndef STLPLUS_PRINT_HASH\r
-#define STLPLUS_PRINT_HASH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a hash\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "hash.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename H, typename E, typename KS, typename TS>\r
-  void print_hash(std::ostream& device,\r
-                  const hash<K,T,H,E>& values,\r
-                  KS key_print_fn,\r
-                  TS value_print_fn,\r
-                  const std::string& pair_separator = ":",\r
-                  const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_hash.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_HASH
+#define STLPLUS_PRINT_HASH
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a hash
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "hash.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename K, typename T, typename H, typename E, typename KS, typename TS>
+  void print_hash(std::ostream& device,
+                  const hash<K,T,H,E>& values,
+                  KS key_print_fn,
+                  TS value_print_fn,
+                  const std::string& pair_separator = ":",
+                  const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "print_hash.tpp"
+#endif
index 5b3bd96f588dabb0ae813f47be129113b5bfda54..84d2fe4d3b5d83131a693aee55f48db5e6b1b267 100644 (file)
@@ -1,29 +1,29 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename H, typename E, typename KS, typename TS>\r
-  void print_hash(std::ostream& device,\r
-                  const hash<K,T,H,E>& values,\r
-                  KS key_print_fn,\r
-                  TS value_print_fn,\r
-                  const std::string& pair_separator,\r
-                  const std::string& separator)\r
-  {\r
-    print_pair_sequence(device, \r
-                        values.begin(), values.end(),\r
-                        key_print_fn, value_print_fn,\r
-                        pair_separator, separator);\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_sequence.hpp"
+
+namespace stlplus
+{
+
+  template<typename K, typename T, typename H, typename E, typename KS, typename TS>
+  void print_hash(std::ostream& device,
+                  const hash<K,T,H,E>& values,
+                  KS key_print_fn,
+                  TS value_print_fn,
+                  const std::string& pair_separator,
+                  const std::string& separator)
+  {
+    print_pair_sequence(device, 
+                        values.begin(), values.end(),
+                        key_print_fn, value_print_fn,
+                        pair_separator, separator);
+  }
+
+} // end namespace stlplus
+
index 8a12f40e54935a0baabdca571eeb37a225cd11bc..fb55917aec0a761301cf82f8446a1007b18f03d7 100644 (file)
@@ -1,38 +1,38 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   String conversion functions for the infinite precision integer type inf\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// can be excluded from the build to break the dependency on the portability library\r
-#ifndef NO_STLPLUS_INF\r
-\r
-#include "print_inf.hpp"\r
-#include "string_inf.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void print_inf(std::ostream& device,\r
-                 const stlplus::inf& data,\r
-                 unsigned radix,\r
-                 radix_display_t display,\r
-                 unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << inf_to_string(data, radix, display, width);\r
-  }\r
-\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   String conversion functions for the infinite precision integer type inf
+
+////////////////////////////////////////////////////////////////////////////////
+
+// can be excluded from the build to break the dependency on the portability library
+#ifndef NO_STLPLUS_INF
+
+#include "print_inf.hpp"
+#include "string_inf.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  void print_inf(std::ostream& device,
+                 const stlplus::inf& data,
+                 unsigned radix,
+                 radix_display_t display,
+                 unsigned width)
+    throw(std::invalid_argument)
+  {
+    device << inf_to_string(data, radix, display, width);
+  }
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 51b037715d49246dad83f71a343299906e46467e..b3bfc277bc4ab9969de2b429c92846a52295b9ec 100644 (file)
@@ -1,40 +1,40 @@
-#ifndef STLPLUS_PRINT_INF\r
-#define STLPLUS_PRINT_INF\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   String conversion functions for the infinite precision integer type inf\r
-\r
-//   The conversion supports all the formatting modes defined on format_types\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "strings_fixes.hpp"\r
-#include "inf.hpp"\r
-#include "format_types.hpp"\r
-#include <stdexcept>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void print_inf(std::ostream& device,\r
-                 const inf&,\r
-                 unsigned radix = 10,\r
-                 radix_display_t display = radix_c_style_or_hash,\r
-                 unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-} // end namespace stlplus\r
-\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_INF
+#define STLPLUS_PRINT_INF
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   String conversion functions for the infinite precision integer type inf
+
+//   The conversion supports all the formatting modes defined on format_types
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "strings_fixes.hpp"
+#include "inf.hpp"
+#include "format_types.hpp"
+#include <stdexcept>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void print_inf(std::ostream& device,
+                 const inf&,
+                 unsigned radix = 10,
+                 radix_display_t display = radix_c_style_or_hash,
+                 unsigned width = 0)
+    throw(std::invalid_argument);
+
+////////////////////////////////////////////////////////////////////////////////
+} // end namespace stlplus
+
+
+#endif
index e2b63beb9531b07eee04cae828ea2a2b677bef52..cde00eecc9172d758511f5f5b37f9d3a60e86f32 100644 (file)
@@ -1,55 +1,55 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_int.hpp"\r
-#include "string_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void print_short(std::ostream& device, short i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << short_to_string(i, radix, display, width);\r
-  }\r
-\r
-  void print_unsigned_short(std::ostream& device, unsigned short i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << unsigned_short_to_string(i, radix, display, width);\r
-  }\r
-\r
-  void print_int(std::ostream& device, int i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << int_to_string(i, radix, display, width);\r
-  }\r
-\r
-  void print_unsigned(std::ostream& device, unsigned i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << unsigned_to_string(i, radix, display, width);\r
-  }\r
-\r
-  void print_long(std::ostream& device, long i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << long_to_string(i, radix, display, width);\r
-  }\r
-\r
-  void print_unsigned_long(std::ostream& device, unsigned long i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    device << unsigned_long_to_string(i, radix, display, width);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_int.hpp"
+#include "string_int.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void print_short(std::ostream& device, short i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    device << short_to_string(i, radix, display, width);
+  }
+
+  void print_unsigned_short(std::ostream& device, unsigned short i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    device << unsigned_short_to_string(i, radix, display, width);
+  }
+
+  void print_int(std::ostream& device, int i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    device << int_to_string(i, radix, display, width);
+  }
+
+  void print_unsigned(std::ostream& device, unsigned i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    device << unsigned_to_string(i, radix, display, width);
+  }
+
+  void print_long(std::ostream& device, long i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    device << long_to_string(i, radix, display, width);
+  }
+
+  void print_unsigned_long(std::ostream& device, unsigned long i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    device << unsigned_long_to_string(i, radix, display, width);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 4f9729373b9043386b01a96853f137e6242de4a3..d09ef70c769886068e4f0b6a5ae0b559f827dc3f 100644 (file)
@@ -1,81 +1,81 @@
-#ifndef STLPLUS_PRINT_INT\r
-#define STLPLUS_PRINT_INT\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Print integer types\r
-\r
-//   This extends the formatting available from iostream\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <iostream>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Conversions of Integer types to string\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // The radix (i.e. base) for these conversions can be any value from base 2 to base 36\r
-  // specifying any other radix causes std::invalid_argument to be thrown\r
-\r
-  // The way in which the radix is displayed is defined in radix_types.hpp\r
-  // If any other value is used, std::invalid_argument is thrown\r
-\r
-  // The width argument specifies the number of numerical digits to use in the result\r
-  // This is a minimum - if the value requires more digits then it will be wider than the width argument\r
-  // However, if it is smaller, then it will be extended to the specified width\r
-  // Then, the radix display prefix is added to this width\r
-\r
-  // For example, using the hash representation of 0 in hex with width=4 gives:\r
-  // 16#0000 - so there's 4 digits in the number part\r
-\r
-  void print_short(std::ostream& device, short i,\r
-                   unsigned radix = 10,\r
-                   radix_display_t display = radix_c_style_or_hash,\r
-                   unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  void print_unsigned_short(std::ostream& device, unsigned short i,\r
-                            unsigned radix = 10,\r
-                            radix_display_t display = radix_c_style_or_hash,\r
-                            unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  void print_int(std::ostream& device, int i,\r
-                 unsigned radix = 10,\r
-                 radix_display_t display = radix_c_style_or_hash,\r
-                 unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  void print_unsigned(std::ostream& device, unsigned i,\r
-                      unsigned radix = 10,\r
-                      radix_display_t display = radix_c_style_or_hash,\r
-                      unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  void print_long(std::ostream& device, long i,\r
-                  unsigned radix = 10,\r
-                  radix_display_t display = radix_c_style_or_hash,\r
-                  unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  void print_unsigned_long(std::ostream& device, unsigned long i,\r
-                           unsigned radix = 10,\r
-                           radix_display_t display = radix_c_style_or_hash,\r
-                           unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_INT
+#define STLPLUS_PRINT_INT
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Print integer types
+
+//   This extends the formatting available from iostream
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <iostream>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Conversions of Integer types to string
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // The radix (i.e. base) for these conversions can be any value from base 2 to base 36
+  // specifying any other radix causes std::invalid_argument to be thrown
+
+  // The way in which the radix is displayed is defined in radix_types.hpp
+  // If any other value is used, std::invalid_argument is thrown
+
+  // The width argument specifies the number of numerical digits to use in the result
+  // This is a minimum - if the value requires more digits then it will be wider than the width argument
+  // However, if it is smaller, then it will be extended to the specified width
+  // Then, the radix display prefix is added to this width
+
+  // For example, using the hash representation of 0 in hex with width=4 gives:
+  // 16#0000 - so there's 4 digits in the number part
+
+  void print_short(std::ostream& device, short i,
+                   unsigned radix = 10,
+                   radix_display_t display = radix_c_style_or_hash,
+                   unsigned width = 0)
+    throw(std::invalid_argument);
+
+  void print_unsigned_short(std::ostream& device, unsigned short i,
+                            unsigned radix = 10,
+                            radix_display_t display = radix_c_style_or_hash,
+                            unsigned width = 0)
+    throw(std::invalid_argument);
+
+  void print_int(std::ostream& device, int i,
+                 unsigned radix = 10,
+                 radix_display_t display = radix_c_style_or_hash,
+                 unsigned width = 0)
+    throw(std::invalid_argument);
+
+  void print_unsigned(std::ostream& device, unsigned i,
+                      unsigned radix = 10,
+                      radix_display_t display = radix_c_style_or_hash,
+                      unsigned width = 0)
+    throw(std::invalid_argument);
+
+  void print_long(std::ostream& device, long i,
+                  unsigned radix = 10,
+                  radix_display_t display = radix_c_style_or_hash,
+                  unsigned width = 0)
+    throw(std::invalid_argument);
+
+  void print_unsigned_long(std::ostream& device, unsigned long i,
+                           unsigned radix = 10,
+                           radix_display_t display = radix_c_style_or_hash,
+                           unsigned width = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index d1767b2ce637c12ee3fb523981b76facb9950f5c..fd1027a61d68c9277ed4ebc6ad0bac27c47f11ee 100644 (file)
@@ -1,30 +1,30 @@
-#ifndef STLPLUS_PRINT_LIST\r
-#define STLPLUS_PRINT_LIST\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a list\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <list>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_list(std::ostream& device,\r
-                  const std::list<T>& values,\r
-                  S print_fn,\r
-                  const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_list.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_LIST
+#define STLPLUS_PRINT_LIST
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a list
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+#include <list>
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_list(std::ostream& device,
+                  const std::list<T>& values,
+                  S print_fn,
+                  const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "print_list.tpp"
+#endif
index e60c39a3454dd74352f59a4c6f3a8826d62c056f..a573175f5fa5db813b49670e5d4dedce09d7bebe 100644 (file)
@@ -1,25 +1,25 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   template implementations\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_list(std::ostream& device,\r
-                  const std::list<T>& values,\r
-                  S print_fn,\r
-                  const std::string& separator)\r
-  {\r
-    print_sequence(device, values.begin(), values.end(), print_fn, separator);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   template implementations
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_sequence.hpp"
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_list(std::ostream& device,
+                  const std::list<T>& values,
+                  S print_fn,
+                  const std::string& separator)
+  {
+    print_sequence(device, values.begin(), values.end(), print_fn, separator);
+  }
+
+} // end namespace stlplus
index 69350379ef0c9441e7d017a7522fa6bffc60fc9e..83c0048f34bc08f4d9ab398896cf6a0797838155 100644 (file)
@@ -1,38 +1,38 @@
-#ifndef STLPLUS_PRINT_MAP\r
-#define STLPLUS_PRINT_MAP\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a map/multimap\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <map>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  void print_map(std::ostream& device, const std::map<K,T,C>& values,\r
-                 SK key_print_fn,\r
-                 ST value_print_fn,\r
-                 const std::string& pair_separator = ":",\r
-                 const std::string& separator = ",");\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  void print_multimap(std::ostream& device, const std::multimap<K,T,C>& values,\r
-                      SK key_print_fn,\r
-                      ST value_print_fn,\r
-                      const std::string& pair_separator = ":",\r
-                      const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_map.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_MAP
+#define STLPLUS_PRINT_MAP
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a map/multimap
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+#include <map>
+
+namespace stlplus
+{
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  void print_map(std::ostream& device, const std::map<K,T,C>& values,
+                 SK key_print_fn,
+                 ST value_print_fn,
+                 const std::string& pair_separator = ":",
+                 const std::string& separator = ",");
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  void print_multimap(std::ostream& device, const std::multimap<K,T,C>& values,
+                      SK key_print_fn,
+                      ST value_print_fn,
+                      const std::string& pair_separator = ":",
+                      const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "print_map.tpp"
+#endif
index b3a727aba3bf3cdea0465ccbf76a9ab9e53248f2..f499e8fd69a87709f8d8ac84adc306d83c071c6f 100644 (file)
@@ -1,46 +1,46 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // map\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  void print_map(std::ostream& device, const std::map<K,T,C>& values,\r
-                 SK key_print_fn,\r
-                 ST value_print_fn,\r
-                 const std::string& pair_separator,\r
-                 const std::string& separator)\r
-  {\r
-    print_pair_sequence(values.begin(), values.end(),\r
-                        key_print_fn, value_print_fn,\r
-                        pair_separator, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // multimap\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  void print_multimap(std::ostream& device, const std::multimap<K,T,C>& values,\r
-                      SK key_print_fn,\r
-                      ST value_print_fn,\r
-                      const std::string& pair_separator,\r
-                      const std::string& separator)\r
-  {\r
-    print_pair_sequence(device,\r
-                        values.begin(), values.end(),\r
-                        key_print_fn, value_print_fn,\r
-                        pair_separator, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_sequence.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // map
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  void print_map(std::ostream& device, const std::map<K,T,C>& values,
+                 SK key_print_fn,
+                 ST value_print_fn,
+                 const std::string& pair_separator,
+                 const std::string& separator)
+  {
+    print_pair_sequence(values.begin(), values.end(),
+                        key_print_fn, value_print_fn,
+                        pair_separator, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // multimap
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  void print_multimap(std::ostream& device, const std::multimap<K,T,C>& values,
+                      SK key_print_fn,
+                      ST value_print_fn,
+                      const std::string& pair_separator,
+                      const std::string& separator)
+  {
+    print_pair_sequence(device,
+                        values.begin(), values.end(),
+                        key_print_fn, value_print_fn,
+                        pair_separator, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+} // end namespace stlplus
index f3fb8d540aaed543b5b1792b97fe93cc96e03f77..b7f321a9f0f42078058be5eb9db948f49123988c 100644 (file)
@@ -1,33 +1,33 @@
-#ifndef STLPLUS_PRINT_MATRIX\r
-#define STLPLUS_PRINT_MATRIX\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a matrix\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "matrix.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_matrix(std::ostream& device,\r
-                    const matrix<T>& values,\r
-                    S print_fn,\r
-                    const std::string& column_separator = "|",\r
-                    const std::string& row_separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_matrix.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_MATRIX
+#define STLPLUS_PRINT_MATRIX
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a matrix
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "matrix.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_matrix(std::ostream& device,
+                    const matrix<T>& values,
+                    S print_fn,
+                    const std::string& column_separator = "|",
+                    const std::string& row_separator = ",");
+
+} // end namespace stlplus
+
+#include "print_matrix.tpp"
+#endif
index 406c69facb7c655c5e91c55b5f3e1b305b86d150..a31bd5426f34294916e1bdb13394aed913b72924 100644 (file)
@@ -1,33 +1,33 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename S>\r
-  void print_matrix(std::ostream& device, const matrix<T>& values,\r
-                    S print_fn,\r
-                    const std::string& column_separator,\r
-                    const std::string& row_separator)\r
-  {\r
-    for (unsigned r = 0; r < values.rows(); r++)\r
-    {\r
-      if (r != 0) device << row_separator;\r
-      for (unsigned c = 0; c < values.columns(); c++)\r
-      {\r
-        if (c != 0) device << column_separator;\r
-        print_fn(device, values(r,c));\r
-      }\r
-    }\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T, typename S>
+  void print_matrix(std::ostream& device, const matrix<T>& values,
+                    S print_fn,
+                    const std::string& column_separator,
+                    const std::string& row_separator)
+  {
+    for (unsigned r = 0; r < values.rows(); r++)
+    {
+      if (r != 0) device << row_separator;
+      for (unsigned c = 0; c < values.columns(); c++)
+      {
+        if (c != 0) device << column_separator;
+        print_fn(device, values(r,c));
+      }
+    }
+  }
+
+} // end namespace stlplus
+
index 47c1a460c0c7cbe98869e49a167d965f6d7670c9..f09ea730a5aa69874c614b0c8f423cb6959af241 100644 (file)
@@ -1,33 +1,33 @@
-#ifndef STLPLUS_PRINT_NTREE\r
-#define STLPLUS_PRINT_NTREE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of an ntree\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "ntree.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_ntree(std::ostream& device,\r
-                   const ntree<T>& values,\r
-                   S print_fn,\r
-                   const std::string& separator = "|",\r
-                   const std::string& indent_string = "  ");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_ntree.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_NTREE
+#define STLPLUS_PRINT_NTREE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of an ntree
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "ntree.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_ntree(std::ostream& device,
+                   const ntree<T>& values,
+                   S print_fn,
+                   const std::string& separator = "|",
+                   const std::string& indent_string = "  ");
+
+} // end namespace stlplus
+
+#include "print_ntree.tpp"
+#endif
index ab85611f0e544de63af1d87e7c1e02fdd565717a..f78895a5b857dcc7ccb43996cd1fe889108c41df 100644 (file)
@@ -1,30 +1,30 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_ntree(std::ostream& device,\r
-                   const ntree<T>& values,\r
-                   S print_fn,\r
-                   const std::string& separator,\r
-                   const std::string& indent_string)\r
-  {\r
-    for (TYPENAME ntree<T>::const_prefix_iterator i = values.prefix_begin(); i != values.prefix_end(); i++)\r
-    {\r
-      if (i != values.prefix_begin()) device << separator;\r
-      for (unsigned indent = values.depth(i.simplify()); --indent; )\r
-        device << indent_string;\r
-      print_fn(device, *i);\r
-    }\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_ntree(std::ostream& device,
+                   const ntree<T>& values,
+                   S print_fn,
+                   const std::string& separator,
+                   const std::string& indent_string)
+  {
+    for (TYPENAME ntree<T>::const_prefix_iterator i = values.prefix_begin(); i != values.prefix_end(); i++)
+    {
+      if (i != values.prefix_begin()) device << separator;
+      for (unsigned indent = values.depth(i.simplify()); --indent; )
+        device << indent_string;
+      print_fn(device, *i);
+    }
+  }
+
+} // end namespace stlplus
+
index 144461f253103d990dd0e4ecd68e0ea35ff6e04f..58dff79cd8f7bbf26e11d46545e097841ab04bd6 100644 (file)
@@ -1,31 +1,31 @@
-#ifndef STLPLUS_PRINT_PAIR\r
-#define STLPLUS_PRINT_PAIR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a pair\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <map>\r
-#include <string>\r
-#include <iostream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename V1, typename V2, typename S1, typename S2>\r
-  void print_pair(std::ostream& device,\r
-                  const std::pair<V1,V2>& values,\r
-                  S1 print_fn1,\r
-                  S2 print_fn2,\r
-                  const std::string& separator = ":");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_pair.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_PAIR
+#define STLPLUS_PRINT_PAIR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a pair
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <map>
+#include <string>
+#include <iostream>
+
+namespace stlplus
+{
+
+  template<typename V1, typename V2, typename S1, typename S2>
+  void print_pair(std::ostream& device,
+                  const std::pair<V1,V2>& values,
+                  S1 print_fn1,
+                  S2 print_fn2,
+                  const std::string& separator = ":");
+
+} // end namespace stlplus
+
+#include "print_pair.tpp"
+#endif
index a93c0c0482fbd8e02624c3d86e9b69efeb1a04fe..1d98050c0d8edd2f76e2580003df22b88b01d68f 100644 (file)
@@ -1,25 +1,25 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename V1, typename V2, typename S1, typename S2>\r
-  void print_pair(std::ostream& device,\r
-                  const std::pair<V1,V2>& values,\r
-                  S1 print_fn1,\r
-                  S2 print_fn2,\r
-                  const std::string& separator)\r
-  {\r
-    print_fn1(device, values.first);\r
-    device << separator;\r
-    print__fn2(device, values.second);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename V1, typename V2, typename S1, typename S2>
+  void print_pair(std::ostream& device,
+                  const std::pair<V1,V2>& values,
+                  S1 print_fn1,
+                  S2 print_fn2,
+                  const std::string& separator)
+  {
+    print_fn1(device, values.first);
+    device << separator;
+    print__fn2(device, values.second);
+  }
+
+} // end namespace stlplus
index cb738cca846f824e68809b7a08a6968afcb15872..971c0ac640b0b4f5b710cd359e46a504c64bf810 100644 (file)
@@ -1,32 +1,32 @@
-#ifndef STLPLUS_PRINT_POINTER\r
-#define STLPLUS_PRINT_POINTER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of an object pointed to\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template <typename T, typename S>\r
-  void print_pointer(std::ostream& device,\r
-                     const T* value,\r
-                     S print_fn,\r
-                     const std::string& null_string = "<null>",\r
-                     const std::string& prefix = "(",\r
-                     const std::string& suffix = ")");\r
-\r
-\r
-}\r
-\r
-#include "print_pointer.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_POINTER
+#define STLPLUS_PRINT_POINTER
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of an object pointed to
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+
+namespace stlplus
+{
+
+  template <typename T, typename S>
+  void print_pointer(std::ostream& device,
+                     const T* value,
+                     S print_fn,
+                     const std::string& null_string = "<null>",
+                     const std::string& prefix = "(",
+                     const std::string& suffix = ")");
+
+
+}
+
+#include "print_pointer.tpp"
+#endif
index be96d91c6bd1e8e3cc775d85d1350d8d6048c6e5..ade9273c9d746da9141743ac00acde3cc30052b1 100644 (file)
@@ -1,34 +1,34 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template <typename T, typename S>\r
-  void print_pointer(std::ostream& device,\r
-                     const T* value,\r
-                     S print_fn,\r
-                     const std::string& null_string,\r
-                     const std::string& prefix,\r
-                     const std::string& suffix)\r
-  {\r
-    if (value)\r
-    {\r
-      device << prefix;\r
-      print_fn(device, *value);\r
-      device << suffix;\r
-    }\r
-    else\r
-    {\r
-      device << null_string;\r
-    }\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include <string>
+
+namespace stlplus
+{
+
+  template <typename T, typename S>
+  void print_pointer(std::ostream& device,
+                     const T* value,
+                     S print_fn,
+                     const std::string& null_string,
+                     const std::string& prefix,
+                     const std::string& suffix)
+  {
+    if (value)
+    {
+      device << prefix;
+      print_fn(device, *value);
+      device << suffix;
+    }
+    else
+    {
+      device << null_string;
+    }
+  }
+
+} // end namespace stlplus
index 411ddd58b29e83c702eda3b44b5c8a1a1134b0c4..317fbf23a0c61a5d40f207fa66a98f688b2d7759 100644 (file)
@@ -1,46 +1,46 @@
-#ifndef STLPLUS_PRINT_SEQUENCE\r
-#define STLPLUS_PRINT_SEQUENCE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate string representations of sequences represented by forward iterators\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any forward iterator sequence\r
-\r
-  template <typename I, typename S>\r
-  void print_sequence(std::ostream& device,\r
-                      I begin, I end, \r
-                      S print_fn,\r
-                      const std::string& separator);\r
-\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any forward iterator sequence of pairs\r
-\r
-  template <typename I, typename S1, typename S2>\r
-  void print_pair_sequence(std::ostream& device,\r
-                           I begin, I end,\r
-                           S1 print_fn1,\r
-                           S2 print_fn2,\r
-                           const std::string& pair_separator,\r
-                           const std::string& separator);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_sequence.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_SEQUENCE
+#define STLPLUS_PRINT_SEQUENCE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate string representations of sequences represented by forward iterators
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any forward iterator sequence
+
+  template <typename I, typename S>
+  void print_sequence(std::ostream& device,
+                      I begin, I end, 
+                      S print_fn,
+                      const std::string& separator);
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any forward iterator sequence of pairs
+
+  template <typename I, typename S1, typename S2>
+  void print_pair_sequence(std::ostream& device,
+                           I begin, I end,
+                           S1 print_fn1,
+                           S2 print_fn2,
+                           const std::string& pair_separator,
+                           const std::string& separator);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "print_sequence.tpp"
+#endif
index cea8056e2296a9ec90c865c4aaa644d5c3e3fd4c..8600ca834c99404cb3a4c176e877059a60a561b3 100644 (file)
@@ -1,50 +1,50 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_pair.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any forward iterator sequence\r
-\r
-  template <typename I, typename S>\r
-  void print_sequence(std::ostream& device,\r
-                      I begin, I end, \r
-                      S print_fn,\r
-                      const std::string& separator)\r
-  {\r
-    for (I i = begin; i != end; i++)\r
-    {\r
-      if (i != begin) device << separator;\r
-      print_fn(device, *i);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any sequence where the value is a pair\r
-\r
-  template <typename I, typename S1, typename S2>\r
-  void print_pair_sequence(std::ostream& device,\r
-                           I begin, I end,\r
-                           S1 print_fn1,\r
-                           S2 print_fn2,\r
-                           const std::string& pair_separator,\r
-                           const std::string& separator)\r
-  {\r
-    for (I i = begin; i != end; i++)\r
-    {\r
-      if (i != begin) device << separator;\r
-      print_pair(device, *i, print_fn1, print_fn2, pair_separator);\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_pair.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any forward iterator sequence
+
+  template <typename I, typename S>
+  void print_sequence(std::ostream& device,
+                      I begin, I end, 
+                      S print_fn,
+                      const std::string& separator)
+  {
+    for (I i = begin; i != end; i++)
+    {
+      if (i != begin) device << separator;
+      print_fn(device, *i);
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any sequence where the value is a pair
+
+  template <typename I, typename S1, typename S2>
+  void print_pair_sequence(std::ostream& device,
+                           I begin, I end,
+                           S1 print_fn1,
+                           S2 print_fn2,
+                           const std::string& pair_separator,
+                           const std::string& separator)
+  {
+    for (I i = begin; i != end; i++)
+    {
+      if (i != begin) device << separator;
+      print_pair(device, *i, print_fn1, print_fn2, pair_separator);
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 33c3835c40005fab42497f0bee78d33eac766c84..a032ccf1cdfed88809dd791d785de591a2e61721 100644 (file)
@@ -1,36 +1,36 @@
-#ifndef STLPLUS_PRINT_SET\r
-#define STLPLUS_PRINT_SET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a set/multiset\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <set>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename C, typename S>\r
-  void print_set(std::ostream& device,\r
-                 const std::set<K,C>& values,\r
-                 S print_fn,\r
-                 const std::string& separator = ",");\r
-\r
-  template<typename K, typename C, typename S>\r
-  void print_multiset(std::ostream& device,\r
-                      const std::multiset<K,C>& values,\r
-                      S print_fn,\r
-                      const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_set.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_SET
+#define STLPLUS_PRINT_SET
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a set/multiset
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+#include <set>
+
+namespace stlplus
+{
+
+  template<typename K, typename C, typename S>
+  void print_set(std::ostream& device,
+                 const std::set<K,C>& values,
+                 S print_fn,
+                 const std::string& separator = ",");
+
+  template<typename K, typename C, typename S>
+  void print_multiset(std::ostream& device,
+                      const std::multiset<K,C>& values,
+                      S print_fn,
+                      const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "print_set.tpp"
+#endif
index 25c88ef739ce558ed7708e5e9d24f8acb4a3b192..ba29fd7091c3f13de7ddfb9be803e036c112a96c 100644 (file)
@@ -1,41 +1,41 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   template implementations\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // set\r
-\r
-  template<typename K, typename C, typename S>\r
-  void print_set(std::ostream& device,\r
-                 const std::set<K,C>& values,\r
-                 S print_fn,\r
-                 const std::string& separator)\r
-  {\r
-    print_sequence(device, values.begin(), values.end(), print_fn, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // multiset\r
-\r
-  template<typename K, typename C, typename S>\r
-  void print_multiset(std::ostream& device,\r
-                      const std::multiset<K,C>& values,\r
-                      S print_fn,\r
-                      const std::string& separator)\r
-  {\r
-    print_sequence(device, values.begin(), values.end(), print_fn, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   template implementations
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_sequence.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // set
+
+  template<typename K, typename C, typename S>
+  void print_set(std::ostream& device,
+                 const std::set<K,C>& values,
+                 S print_fn,
+                 const std::string& separator)
+  {
+    print_sequence(device, values.begin(), values.end(), print_fn, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // multiset
+
+  template<typename K, typename C, typename S>
+  void print_multiset(std::ostream& device,
+                      const std::multiset<K,C>& values,
+                      S print_fn,
+                      const std::string& separator)
+  {
+    print_sequence(device, values.begin(), values.end(), print_fn, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+} // end namespace stlplus
index e34a8ecc23e220b402cd4eecf6b4baa5529de1a1..de4c17d13a9a23534b49b0f6364734d2f70e962f 100644 (file)
@@ -1,51 +1,51 @@
-#ifndef STLPLUS_PRINT_SIMPLE_PTR\r
-#define STLPLUS_PRINT_SIMPLE_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a smart pointer\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "simple_ptr.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_simple_ptr(std::ostream& device,\r
-                       const simple_ptr<T>& value,\r
-                       S print_fn,\r
-                       const std::string& null_string = "<null>",\r
-                       const std::string& prefix = "(",\r
-                       const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  void print_simple_ptr_clone(std::ostream& device,\r
-                             const simple_ptr_clone<T>& value,\r
-                             S print_fn,\r
-                             const std::string& null_string = "<null>",\r
-                             const std::string& prefix = "(",\r
-                             const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  void print_simple_ptr_nocopy(std::ostream& device,\r
-                              const simple_ptr_nocopy<T>& value,\r
-                              S print_fn,\r
-                              const std::string& null_string = "<null>",\r
-                              const std::string& prefix = "(",\r
-                              const std::string& suffix = ")");\r
-\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_simple_ptr.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_SIMPLE_PTR
+#define STLPLUS_PRINT_SIMPLE_PTR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a smart pointer
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "simple_ptr.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_simple_ptr(std::ostream& device,
+                       const simple_ptr<T>& value,
+                       S print_fn,
+                       const std::string& null_string = "<null>",
+                       const std::string& prefix = "(",
+                       const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  void print_simple_ptr_clone(std::ostream& device,
+                             const simple_ptr_clone<T>& value,
+                             S print_fn,
+                             const std::string& null_string = "<null>",
+                             const std::string& prefix = "(",
+                             const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  void print_simple_ptr_nocopy(std::ostream& device,
+                              const simple_ptr_nocopy<T>& value,
+                              S print_fn,
+                              const std::string& null_string = "<null>",
+                              const std::string& prefix = "(",
+                              const std::string& suffix = ")");
+
+
+} // end namespace stlplus
+
+#include "print_simple_ptr.tpp"
+#endif
index 30af07e5101d5d6c23f64b7627b195f2d9d8f7f0..e4171f2b9a54d2b98f0e08ab0dc7a39374fd52fa 100644 (file)
@@ -1,74 +1,74 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_simple_ptr(std::ostream& device,\r
-                       const simple_ptr<T>& value,\r
-                       S print_fn,\r
-                       const std::string& null_string,\r
-                       const std::string& prefix,\r
-                       const std::string& suffix)\r
-  {\r
-    if (value)\r
-    {\r
-      device << prefix;\r
-      print_fn(device, *value);\r
-      device << suffix;\r
-    }\r
-    else\r
-    {\r
-      device << null_string;\r
-    }\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  void print_simple_ptr_clone(std::ostream& device,\r
-                             const simple_ptr_clone<T>& value,\r
-                             S print_fn,\r
-                             const std::string& null_string,\r
-                             const std::string& prefix,\r
-                             const std::string& suffix)\r
-  {\r
-    if (value)\r
-    {\r
-      device << prefix;\r
-      print_fn(device, *value);\r
-      device << suffix;\r
-    }\r
-    else\r
-    {\r
-      device << null_string;\r
-    }\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  void print_simple_ptr_nocopy(std::ostream& device,\r
-                              const simple_ptr_nocopy<T>& value,\r
-                              S print_fn,\r
-                              const std::string& null_string,\r
-                              const std::string& prefix,\r
-                              const std::string& suffix)\r
-  {\r
-    if (value)\r
-    {\r
-      device << prefix;\r
-      print_fn(device, *value);\r
-      device << suffix;\r
-    }\r
-    else\r
-    {\r
-      device << null_string;\r
-    }\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_simple_ptr(std::ostream& device,
+                       const simple_ptr<T>& value,
+                       S print_fn,
+                       const std::string& null_string,
+                       const std::string& prefix,
+                       const std::string& suffix)
+  {
+    if (value)
+    {
+      device << prefix;
+      print_fn(device, *value);
+      device << suffix;
+    }
+    else
+    {
+      device << null_string;
+    }
+  }
+
+  template<typename T, typename S>
+  void print_simple_ptr_clone(std::ostream& device,
+                             const simple_ptr_clone<T>& value,
+                             S print_fn,
+                             const std::string& null_string,
+                             const std::string& prefix,
+                             const std::string& suffix)
+  {
+    if (value)
+    {
+      device << prefix;
+      print_fn(device, *value);
+      device << suffix;
+    }
+    else
+    {
+      device << null_string;
+    }
+  }
+
+  template<typename T, typename S>
+  void print_simple_ptr_nocopy(std::ostream& device,
+                              const simple_ptr_nocopy<T>& value,
+                              S print_fn,
+                              const std::string& null_string,
+                              const std::string& prefix,
+                              const std::string& suffix)
+  {
+    if (value)
+    {
+      device << prefix;
+      print_fn(device, *value);
+      device << suffix;
+    }
+    else
+    {
+      device << null_string;
+    }
+  }
+
+} // end namespace stlplus
+
index 031c814efb80246cb02d3270e87a6da9ac1a6ed5..da8a8b9784cf45c2a31c19a984370b1838f31205 100644 (file)
@@ -1,51 +1,51 @@
-#ifndef STLPLUS_PRINT_SMART_PTR\r
-#define STLPLUS_PRINT_SMART_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a smart pointer\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "smart_ptr.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_smart_ptr(std::ostream& device,\r
-                       const smart_ptr<T>& value,\r
-                       S print_fn,\r
-                       const std::string& null_string = "<null>",\r
-                       const std::string& prefix = "(",\r
-                       const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  void print_smart_ptr_clone(std::ostream& device,\r
-                             const smart_ptr_clone<T>& value,\r
-                             S print_fn,\r
-                             const std::string& null_string = "<null>",\r
-                             const std::string& prefix = "(",\r
-                             const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  void print_smart_ptr_nocopy(std::ostream& device,\r
-                              const smart_ptr_nocopy<T>& value,\r
-                              S print_fn,\r
-                              const std::string& null_string = "<null>",\r
-                              const std::string& prefix = "(",\r
-                              const std::string& suffix = ")");\r
-\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_smart_ptr.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_SMART_PTR
+#define STLPLUS_PRINT_SMART_PTR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a smart pointer
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "smart_ptr.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_smart_ptr(std::ostream& device,
+                       const smart_ptr<T>& value,
+                       S print_fn,
+                       const std::string& null_string = "<null>",
+                       const std::string& prefix = "(",
+                       const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  void print_smart_ptr_clone(std::ostream& device,
+                             const smart_ptr_clone<T>& value,
+                             S print_fn,
+                             const std::string& null_string = "<null>",
+                             const std::string& prefix = "(",
+                             const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  void print_smart_ptr_nocopy(std::ostream& device,
+                              const smart_ptr_nocopy<T>& value,
+                              S print_fn,
+                              const std::string& null_string = "<null>",
+                              const std::string& prefix = "(",
+                              const std::string& suffix = ")");
+
+
+} // end namespace stlplus
+
+#include "print_smart_ptr.tpp"
+#endif
index 51877c70963efbd02547c2925a62e47405651169..e57fc984aace34798bfdbf4075d4d8f9ea6efe23 100644 (file)
@@ -1,74 +1,74 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_smart_ptr(std::ostream& device,\r
-                       const smart_ptr<T>& value,\r
-                       S print_fn,\r
-                       const std::string& null_string,\r
-                       const std::string& prefix,\r
-                       const std::string& suffix)\r
-  {\r
-    if (value)\r
-    {\r
-      device << prefix;\r
-      print_fn(device, *value);\r
-      device << suffix;\r
-    }\r
-    else\r
-    {\r
-      device << null_string;\r
-    }\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  void print_smart_ptr_clone(std::ostream& device,\r
-                             const smart_ptr_clone<T>& value,\r
-                             S print_fn,\r
-                             const std::string& null_string,\r
-                             const std::string& prefix,\r
-                             const std::string& suffix)\r
-  {\r
-    if (value)\r
-    {\r
-      device << prefix;\r
-      print_fn(device, *value);\r
-      device << suffix;\r
-    }\r
-    else\r
-    {\r
-      device << null_string;\r
-    }\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  void print_smart_ptr_nocopy(std::ostream& device,\r
-                              const smart_ptr_nocopy<T>& value,\r
-                              S print_fn,\r
-                              const std::string& null_string,\r
-                              const std::string& prefix,\r
-                              const std::string& suffix)\r
-  {\r
-    if (value)\r
-    {\r
-      device << prefix;\r
-      print_fn(device, *value);\r
-      device << suffix;\r
-    }\r
-    else\r
-    {\r
-      device << null_string;\r
-    }\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_smart_ptr(std::ostream& device,
+                       const smart_ptr<T>& value,
+                       S print_fn,
+                       const std::string& null_string,
+                       const std::string& prefix,
+                       const std::string& suffix)
+  {
+    if (value)
+    {
+      device << prefix;
+      print_fn(device, *value);
+      device << suffix;
+    }
+    else
+    {
+      device << null_string;
+    }
+  }
+
+  template<typename T, typename S>
+  void print_smart_ptr_clone(std::ostream& device,
+                             const smart_ptr_clone<T>& value,
+                             S print_fn,
+                             const std::string& null_string,
+                             const std::string& prefix,
+                             const std::string& suffix)
+  {
+    if (value)
+    {
+      device << prefix;
+      print_fn(device, *value);
+      device << suffix;
+    }
+    else
+    {
+      device << null_string;
+    }
+  }
+
+  template<typename T, typename S>
+  void print_smart_ptr_nocopy(std::ostream& device,
+                              const smart_ptr_nocopy<T>& value,
+                              S print_fn,
+                              const std::string& null_string,
+                              const std::string& prefix,
+                              const std::string& suffix)
+  {
+    if (value)
+    {
+      device << prefix;
+      print_fn(device, *value);
+      device << suffix;
+    }
+    else
+    {
+      device << null_string;
+    }
+  }
+
+} // end namespace stlplus
+
index fb2b55374f5f1ab70ba21684776ac206759fb0f9..0d02839ab979d27778ce50400170c0d85e3e2a79 100644 (file)
@@ -1,23 +1,23 @@
-#ifndef STLPLUS_PRINT_STL\r
-#define STLPLUS_PRINT_STL\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Template string conversions for pointers and STL containers\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "print_bitset.hpp"\r
-#include "print_list.hpp"\r
-#include "print_map.hpp"\r
-#include "print_pair.hpp"\r
-#include "print_sequence.hpp"\r
-#include "print_set.hpp"\r
-#include "print_string.hpp"\r
-#include "print_vector.hpp"\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_STL
+#define STLPLUS_PRINT_STL
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Template string conversions for pointers and STL containers
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "print_bitset.hpp"
+#include "print_list.hpp"
+#include "print_map.hpp"
+#include "print_pair.hpp"
+#include "print_sequence.hpp"
+#include "print_set.hpp"
+#include "print_string.hpp"
+#include "print_vector.hpp"
+
+#endif
index 3f2cd46daf45ffba21f7f6496029da3eb27881ae..cccec48796bed50268ef9cb31fe3be6ab57417d9 100644 (file)
@@ -1,26 +1,26 @@
-#ifndef STLPLUS_PRINT_STLPLUS\r
-#define STLPLUS_PRINT_STLPLUS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Template string conversions for the STLplus containers\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifndef NO_STLPLUS_CONTAINERS\r
-#include "print_digraph.hpp"\r
-#include "print_foursome.hpp"\r
-#include "print_hash.hpp"\r
-#include "print_matrix.hpp"\r
-#include "print_ntree.hpp"\r
-#include "print_smart_ptr.hpp"\r
-#include "print_triple.hpp"\r
-#endif\r
-\r
-#include "print_inf.hpp"\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_STLPLUS
+#define STLPLUS_PRINT_STLPLUS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Template string conversions for the STLplus containers
+
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef NO_STLPLUS_CONTAINERS
+#include "print_digraph.hpp"
+#include "print_foursome.hpp"
+#include "print_hash.hpp"
+#include "print_matrix.hpp"
+#include "print_ntree.hpp"
+#include "print_smart_ptr.hpp"
+#include "print_triple.hpp"
+#endif
+
+#include "print_inf.hpp"
+
+#endif
index 8cf3b5bc6d2048650c670eeece3f1317587dcf66..acd25b74dcf744840ecea823a49c8f8d1650baa5 100644 (file)
@@ -1,22 +1,22 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_string.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // strings\r
-\r
-  void print_string(std::ostream& device, const std::string& value)\r
-  {\r
-    device << value;\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_string.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // strings
+
+  void print_string(std::ostream& device, const std::string& value)
+  {
+    device << value;
+  }
+
+} // end namespace stlplus
index dd23f56646c126d32570bbb382d14f4db7227c85..42ba9abfa4e12ceee43639df335709bdc9256aba 100644 (file)
@@ -1,26 +1,26 @@
-#ifndef STLPLUS_PRINT_STRING\r
-#define STLPLUS_PRINT_STRING\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Functions for converting C/STL strings to string\r
-\r
-//   This is necessary for completeness, e.g. for use in print_vector for vector<string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  void print_string(std::ostream& device, const std::string& value);\r
-}\r
-\r
-#endif\r
+#ifndef STLPLUS_PRINT_STRING
+#define STLPLUS_PRINT_STRING
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Functions for converting C/STL strings to string
+
+//   This is necessary for completeness, e.g. for use in print_vector for vector<string>
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  void print_string(std::ostream& device, const std::string& value);
+}
+
+#endif
index 37b7af95a06fe344b97d1e57bec4bcd3bae497e4..c5867c8e49dbae2c6e39b2e36abefe12d7ae1253 100644 (file)
@@ -1,34 +1,34 @@
-#ifndef STLPLUS_PRINT_TRIPLE\r
-#define STLPLUS_PRINT_TRIPLE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a triple\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "triple.hpp"\r
-#include <string>\r
-#include <iostream>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>\r
-  void print_triple(std::ostream& device,\r
-                    const triple<T1,T2,T3>& values,\r
-                    S1 print_fn1,\r
-                    S2 print_fn2,\r
-                    S3 print_fn3,\r
-                    const std::string& separator = ":");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_triple.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_TRIPLE
+#define STLPLUS_PRINT_TRIPLE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a triple
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "triple.hpp"
+#include <string>
+#include <iostream>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>
+  void print_triple(std::ostream& device,
+                    const triple<T1,T2,T3>& values,
+                    S1 print_fn1,
+                    S2 print_fn2,
+                    S3 print_fn3,
+                    const std::string& separator = ":");
+
+} // end namespace stlplus
+
+#include "print_triple.tpp"
+#endif
index 079c5929a5134bd6f8c9c89d79241d2ffd7cdc9f..08867bf363dda0024c788c00620440c4e0dcbc82 100644 (file)
@@ -1,30 +1,30 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>\r
-  void print_triple(std::ostream& device,\r
-                    const triple<T1,T2,T3>& values,\r
-                    S1 print_fn1,\r
-                    S2 print_fn2,\r
-                    S3 print_fn3,\r
-                    const std::string& separator)\r
-  {\r
-    \r
-    print_fn1(device, values.first);\r
-    device << separator;\r
-    print_fn2(device, values.second);\r
-    device << separator;\r
-    print_fn3(device, values.third);\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>
+  void print_triple(std::ostream& device,
+                    const triple<T1,T2,T3>& values,
+                    S1 print_fn1,
+                    S2 print_fn2,
+                    S3 print_fn3,
+                    const std::string& separator)
+  {
+    
+    print_fn1(device, values.first);
+    device << separator;
+    print_fn2(device, values.second);
+    device << separator;
+    print_fn3(device, values.third);
+  }
+
+} // end namespace stlplus
+
index 41ea42e6ec57de28244fe31acd7f5cf95484fed3..c5b662f8c98c2a3608e378ab1ee9b8fa495423a7 100644 (file)
@@ -1,25 +1,25 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_vector.hpp"\r
-#include "string_vector.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // special case of vector<bool>\r
-\r
-  void print_bool_vector(std::ostream& device, const std::vector<bool>& values)\r
-  {\r
-    device << bool_vector_to_string(values);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_vector.hpp"
+#include "string_vector.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // special case of vector<bool>
+
+  void print_bool_vector(std::ostream& device, const std::vector<bool>& values)
+  {
+    device << bool_vector_to_string(values);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 5916532c8319655889690f5c4599c6c33a3cc3d2..56d5aeb8d729630af0fa91687ebde6ddb7b2667b 100644 (file)
@@ -1,38 +1,38 @@
-#ifndef STLPLUS_PRINT_VECTOR\r
-#define STLPLUS_PRINT_VECTOR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a vector\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <iostream>\r
-#include <vector>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // vector\r
-\r
-  template<typename T, typename S>\r
-  void print_vector(std::ostream& device,\r
-                    const std::vector<T>& values,\r
-                    S print_fn,\r
-                    const std::string& separator);\r
-\r
-  // specialisation for vector<bool> which has a different implementation\r
-  void print_bool_vector(std::ostream& device, const std::vector<bool>& values);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "print_vector.tpp"\r
-#endif\r
+#ifndef STLPLUS_PRINT_VECTOR
+#define STLPLUS_PRINT_VECTOR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a vector
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <iostream>
+#include <vector>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // vector
+
+  template<typename T, typename S>
+  void print_vector(std::ostream& device,
+                    const std::vector<T>& values,
+                    S print_fn,
+                    const std::string& separator);
+
+  // specialisation for vector<bool> which has a different implementation
+  void print_bool_vector(std::ostream& device, const std::vector<bool>& values);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "print_vector.tpp"
+#endif
index 102cfd2ed48ad34841156b17c04ad4b5409fc3b7..ef71bdc61f05d05b68b996cc0f8c0ed5cc241e5c 100644 (file)
@@ -1,22 +1,22 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "print_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  void print_vector(std::ostream& device, const std::vector<T>& values,\r
-                               S print_fn,\r
-                               const std::string& separator)\r
-  {\r
-    print_sequence(device, values.begin(), values.end(), print_fn, separator);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "print_sequence.hpp"
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  void print_vector(std::ostream& device, const std::vector<T>& values,
+                               S print_fn,
+                               const std::string& separator)
+  {
+    print_sequence(device, values.begin(), values.end(), print_fn, separator);
+  }
+
+} // end namespace stlplus
index 74315e0460cef15f86fba575feb5ccde44efdf20..1ab934be83cf0ad9ec2e175ca678491aff2ecd02 100644 (file)
@@ -1,36 +1,36 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   use the unsigned long representation for pointers\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_address.hpp"\r
-#include "string_int.hpp"\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string address_to_string(const void* i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return unsigned_long_to_string((unsigned long)i, radix, display, width);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void* string_to_address(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return (void*)string_to_unsigned_long(str, radix);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   use the unsigned long representation for pointers
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_address.hpp"
+#include "string_int.hpp"
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string address_to_string(const void* i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return unsigned_long_to_string((unsigned long)i, radix, display, width);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void* string_to_address(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return (void*)string_to_unsigned_long(str, radix);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index f73d5816761aaf2b7b018459e06221727efc243a..dea3a5f8d86ad799a6cc1abb3f54db3d754b96b6 100644 (file)
@@ -1,39 +1,39 @@
-#ifndef STLPLUS_STRING_ADDRESS\r
-#define STLPLUS_STRING_ADDRESS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Functions for converting addresses to/from strings\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string address_to_string(const void*,\r
-                                unsigned radix = 16,\r
-                                radix_display_t display = radix_c_style_or_hash,\r
-                                unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void* string_to_address(const std::string& value,\r
-                          unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_ADDRESS
+#define STLPLUS_STRING_ADDRESS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Functions for converting addresses to/from strings
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string address_to_string(const void*,
+                                unsigned radix = 16,
+                                radix_display_t display = radix_c_style_or_hash,
+                                unsigned width = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  void* string_to_address(const std::string& value,
+                          unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index f88dbcd887dee9e1a8a4b45a5e68a59d16bec243..d402dfd3eb0076906c3dfba2fa2d0f334643fad6 100644 (file)
@@ -1,21 +1,21 @@
-#ifndef STLPLUS_STRING_BASIC\r
-#define STLPLUS_STRING_BASIC\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Utilities for converting basic C types to/from std::strings\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "string_address.hpp"\r
-#include "string_bool.hpp"\r
-#include "string_cstring.hpp"\r
-#include "string_float.hpp"\r
-#include "string_int.hpp"\r
-#include "string_pointer.hpp"\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_BASIC
+#define STLPLUS_STRING_BASIC
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Utilities for converting basic C types to/from std::strings
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "string_address.hpp"
+#include "string_bool.hpp"
+#include "string_cstring.hpp"
+#include "string_float.hpp"
+#include "string_int.hpp"
+#include "string_pointer.hpp"
+
+#endif
index 8c96ef3e4c6bb9d64ec7a41f61abcc5ae7fc0745..ec275cd84f3825f79d79f6898bb678e809711f76 100644 (file)
@@ -1,26 +1,26 @@
-#ifndef STLPLUS_STRING_BITSET\r
-#define STLPLUS_STRING_BITSET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a bitset\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <bitset>\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<size_t N>\r
-  std::string bitset_to_string(const std::bitset<N>& data);\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_bitset.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_BITSET
+#define STLPLUS_STRING_BITSET
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a bitset
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <bitset>
+#include <string>
+
+namespace stlplus
+{
+
+  template<size_t N>
+  std::string bitset_to_string(const std::bitset<N>& data);
+
+} // end namespace stlplus
+
+#include "string_bitset.tpp"
+#endif
index 13b78a32a3f0879473e6762c9c2931de26c1c89b..b86a6120216a27de8af9a490636f27534094c62a 100644 (file)
@@ -1,22 +1,22 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<size_t N>\r
-  std::string bitset_to_string(const std::bitset<N>& data)\r
-  {\r
-    std::string result;\r
-    for (unsigned i = data.size(); i--; )\r
-      result += data.test(i) ? '1' : '0';\r
-    return result;\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<size_t N>
+  std::string bitset_to_string(const std::bitset<N>& data)
+  {
+    std::string result;
+    for (unsigned i = data.size(); i--; )
+      result += data.test(i) ? '1' : '0';
+    return result;
+  }
+
+} // end namespace stlplus
index ee2523181fbe0dc949390d10eedf60b02760386a..9c70090b52e3ac1008964a135785b8313006fa48 100644 (file)
@@ -1,35 +1,35 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   use the unsigned short representation for bool\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_bool.hpp"\r
-#include "string_int.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string bool_to_string(bool i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return unsigned_short_to_string((unsigned short)i, radix, display, width);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  bool string_to_bool(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return string_to_unsigned_short(str, radix) != 0;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   use the unsigned short representation for bool
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_bool.hpp"
+#include "string_int.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string bool_to_string(bool i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return unsigned_short_to_string((unsigned short)i, radix, display, width);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  bool string_to_bool(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return string_to_unsigned_short(str, radix) != 0;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index adadcc6f6109a3d838d2651d6996e86b24eef63e..fea8a854824a17cb5d87f11f3050e1827e69dabe 100644 (file)
@@ -1,39 +1,39 @@
-#ifndef STLPLUS_STRING_BOOL\r
-#define STLPLUS_STRING_BOOL\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Conversion of string to/from bool\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string bool_to_string(bool i,\r
-                             unsigned radix = 10,\r
-                             radix_display_t display = radix_c_style_or_hash,\r
-                             unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  bool string_to_bool(const std::string& value,\r
-                      unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_BOOL
+#define STLPLUS_STRING_BOOL
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Conversion of string to/from bool
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string bool_to_string(bool i,
+                             unsigned radix = 10,
+                             radix_display_t display = radix_c_style_or_hash,
+                             unsigned width = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  bool string_to_bool(const std::string& value,
+                      unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 0745049a8452012c40011da8819afb4a7d496e3f..b1129a942daedb0e4b5fe1f65e8e5428ed3bcf1a 100644 (file)
@@ -1,19 +1,19 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_cstring.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  std::string cstring_to_string(const char* value)\r
-  {\r
-    return std::string(value);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_cstring.hpp"
+
+namespace stlplus
+{
+
+  std::string cstring_to_string(const char* value)
+  {
+    return std::string(value);
+  }
+
+} // end namespace stlplus
index 554fbe39441f676c1fdc2ee59a71f42ee41306c2..7d04940feef00f9c6b8013f0d51e65bdef617613 100644 (file)
@@ -1,26 +1,26 @@
-#ifndef STLPLUS_STRING_CSTRING\r
-#define STLPLUS_STRING_CSTRING\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Functions for converting C strings to string\r
-\r
-//   This is necessary for completeness\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  std::string cstring_to_string(const char* value);\r
-\r
-}\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_CSTRING
+#define STLPLUS_STRING_CSTRING
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Functions for converting C strings to string
+
+//   This is necessary for completeness
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  std::string cstring_to_string(const char* value);
+
+}
+
+#endif
index ea70cc74aa1d21a3f159a15e58cbb8221c2f367f..f49993436488cb6d9ad5bf86ffce27660ea15f8a 100644 (file)
@@ -1,31 +1,31 @@
-#ifndef STLPLUS_STRING_DIGRAPH\r
-#define STLPLUS_STRING_DIGRAPH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a digraph\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "digraph.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename NT, typename AT, typename NS, typename AS>\r
-  std::string digraph_to_string(const digraph<NT,AT>& values,\r
-                                NS node_to_string_fn,\r
-                                AS arc_to_string_fn,\r
-                                const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_digraph.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_DIGRAPH
+#define STLPLUS_STRING_DIGRAPH
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a digraph
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "digraph.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename NT, typename AT, typename NS, typename AS>
+  std::string digraph_to_string(const digraph<NT,AT>& values,
+                                NS node_to_string_fn,
+                                AS arc_to_string_fn,
+                                const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "string_digraph.tpp"
+#endif
index 9fd63d54c1842cd3019204c4a9635ad86167f535..4b81a5c47c83c9f6940c8c477e4c3a31e589936a 100644 (file)
@@ -1,33 +1,33 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename NT, typename AT, typename NS, typename AS>\r
-  std::string digraph_to_string(const digraph<NT,AT>& values,\r
-                                NS node_to_string_fn,\r
-                                AS arc_to_string_fn,\r
-                                const std::string& separator)\r
-  {\r
-    std::string result;\r
-    result += "nodes:";\r
-    result += separator;\r
-    result += sequence_to_string(values.begin(), values.end(), node_to_string_fn, separator);\r
-    result += "arcs:";\r
-    result += separator;\r
-    result += sequence_to_string(values.arc_begin(), values.arc_end(), arc_to_string_fn, separator);\r
-    return result;\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_sequence.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename NT, typename AT, typename NS, typename AS>
+  std::string digraph_to_string(const digraph<NT,AT>& values,
+                                NS node_to_string_fn,
+                                AS arc_to_string_fn,
+                                const std::string& separator)
+  {
+    std::string result;
+    result += "nodes:";
+    result += separator;
+    result += sequence_to_string(values.begin(), values.end(), node_to_string_fn, separator);
+    result += "arcs:";
+    result += separator;
+    result += sequence_to_string(values.arc_begin(), values.arc_end(), arc_to_string_fn, separator);
+    return result;
+  }
+
+} // end namespace stlplus
+
index 0de056f25a192bcd9ea0f23e98c30fbae91bf64a..8ef2a94cf03fe534dfb15b764009fe470c100979 100644 (file)
@@ -1,96 +1,96 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_float.hpp"\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // added as a local copy to break the dependency on the portability library\r
-  static std::string local_dformat(const char* format, ...) throw(std::invalid_argument)\r
-  {\r
-    std::string formatted;\r
-    va_list args;\r
-    va_start(args, format);\r
-#ifdef MSWINDOWS\r
-    int length = 0;\r
-    char* buffer = 0;\r
-    for(int buffer_length = 256; ; buffer_length*=2)\r
-    {\r
-      buffer = (char*)malloc(buffer_length);\r
-      if (!buffer) throw std::invalid_argument("string_float");\r
-      length = _vsnprintf(buffer, buffer_length-1, format, args);\r
-      if (length >= 0)\r
-      {\r
-        buffer[length] = 0;\r
-        formatted += std::string(buffer);\r
-        free(buffer);\r
-        break;\r
-      }\r
-      free(buffer);\r
-    }\r
-#else\r
-    char* buffer = 0;\r
-    int length = vasprintf(&buffer, format, args);\r
-    if (!buffer) throw std::invalid_argument("string_float");\r
-    if (length >= 0)\r
-      formatted += std::string(buffer);\r
-    free(buffer);\r
-#endif\r
-    va_end(args);\r
-    if (length < 0) throw std::invalid_argument("string_float");\r
-    return formatted;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // floating-point types\r
-\r
-  std::string float_to_string(float f, real_display_t display, unsigned width, unsigned precision)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return double_to_string((double)f, display, width, precision);\r
-  }\r
-\r
-  std::string double_to_string(double f, real_display_t display, unsigned width, unsigned precision)\r
-    throw(std::invalid_argument)\r
-  {\r
-    switch(display)\r
-    {\r
-    case display_fixed:\r
-      return local_dformat("%*.*f", width, precision, f);\r
-    case display_floating:\r
-      return local_dformat("%*.*e", width, precision, f);\r
-    case display_mixed:\r
-      return local_dformat("%*.*g", width, precision, f);\r
-    default:\r
-      throw std::invalid_argument("invalid radix display value");\r
-    }\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  float string_to_float(const std::string& value)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return (float)string_to_double(value);\r
-  }\r
-\r
-  double string_to_double(const std::string& value)\r
-    throw(std::invalid_argument)\r
-  {\r
-    // TODO - error checking\r
-    return strtod(value.c_str(), 0);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_float.hpp"
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace stlplus
+{
+
+  // added as a local copy to break the dependency on the portability library
+  static std::string local_dformat(const char* format, ...) throw(std::invalid_argument)
+  {
+    std::string formatted;
+    va_list args;
+    va_start(args, format);
+#ifdef MSWINDOWS
+    int length = 0;
+    char* buffer = 0;
+    for(int buffer_length = 256; ; buffer_length*=2)
+    {
+      buffer = (char*)malloc(buffer_length);
+      if (!buffer) throw std::invalid_argument("string_float");
+      length = _vsnprintf(buffer, buffer_length-1, format, args);
+      if (length >= 0)
+      {
+        buffer[length] = 0;
+        formatted += std::string(buffer);
+        free(buffer);
+        break;
+      }
+      free(buffer);
+    }
+#else
+    char* buffer = 0;
+    int length = vasprintf(&buffer, format, args);
+    if (!buffer) throw std::invalid_argument("string_float");
+    if (length >= 0)
+      formatted += std::string(buffer);
+    free(buffer);
+#endif
+    va_end(args);
+    if (length < 0) throw std::invalid_argument("string_float");
+    return formatted;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // floating-point types
+
+  std::string float_to_string(float f, real_display_t display, unsigned width, unsigned precision)
+    throw(std::invalid_argument)
+  {
+    return double_to_string((double)f, display, width, precision);
+  }
+
+  std::string double_to_string(double f, real_display_t display, unsigned width, unsigned precision)
+    throw(std::invalid_argument)
+  {
+    switch(display)
+    {
+    case display_fixed:
+      return local_dformat("%*.*f", width, precision, f);
+    case display_floating:
+      return local_dformat("%*.*e", width, precision, f);
+    case display_mixed:
+      return local_dformat("%*.*g", width, precision, f);
+    default:
+      throw std::invalid_argument("invalid radix display value");
+    }
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  float string_to_float(const std::string& value)
+    throw(std::invalid_argument)
+  {
+    return (float)string_to_double(value);
+  }
+
+  double string_to_double(const std::string& value)
+    throw(std::invalid_argument)
+  {
+    // TODO - error checking
+    return strtod(value.c_str(), 0);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 797d4a4d04014b930c003185b2ffcf6c05ed7d2f..578225f15476efec0b051e096e0d1dddf26d62c9 100644 (file)
@@ -1,55 +1,55 @@
-#ifndef STLPLUS_STRING_FLOAT\r
-#define STLPLUS_STRING_FLOAT\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Convert a float/double to/from string\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // convert a real type to string\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // Only decimal radix is supported\r
-\r
-  // The way in which the number is displayed is defined in radix_types.hpp\r
-  // Using any other value for the display type causes std::invalid_argument to be thrown\r
-\r
-  std::string float_to_string(float f,\r
-                              real_display_t display = display_mixed,\r
-                              unsigned width = 0,\r
-                              unsigned precision = 6)\r
-    throw(std::invalid_argument);\r
-\r
-  std::string double_to_string(double f,\r
-                               real_display_t display = display_mixed,\r
-                               unsigned width = 0,\r
-                               unsigned precision = 6)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Convert a string to a floating-point type\r
-\r
-  float string_to_float(const std::string& value)\r
-    throw(std::invalid_argument);\r
-\r
-  double string_to_double(const std::string& value)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_FLOAT
+#define STLPLUS_STRING_FLOAT
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Convert a float/double to/from string
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // convert a real type to string
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // Only decimal radix is supported
+
+  // The way in which the number is displayed is defined in radix_types.hpp
+  // Using any other value for the display type causes std::invalid_argument to be thrown
+
+  std::string float_to_string(float f,
+                              real_display_t display = display_mixed,
+                              unsigned width = 0,
+                              unsigned precision = 6)
+    throw(std::invalid_argument);
+
+  std::string double_to_string(double f,
+                               real_display_t display = display_mixed,
+                               unsigned width = 0,
+                               unsigned precision = 6)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Convert a string to a floating-point type
+
+  float string_to_float(const std::string& value)
+    throw(std::invalid_argument);
+
+  double string_to_double(const std::string& value)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 1cf3db7a65f82e9880e4a5174892ac7fc639f931..7481dc7f88d18e85409b80c1964f65d3d4da8bdf 100644 (file)
@@ -1,33 +1,33 @@
-#ifndef STLPLUS_STRING_FOURSOME\r
-#define STLPLUS_STRING_FOURSOME\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a foursome\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "foursome.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>\r
-  std::string foursome_to_string(const foursome<T1,T2,T3,T4>& values,\r
-                                 S1 to_string_fn1,\r
-                                 S2 to_string_fn2,\r
-                                 S3 to_string_fn3,\r
-                                 S4 to_string_fn4,\r
-                                 const std::string& separator = ":");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_foursome.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_FOURSOME
+#define STLPLUS_STRING_FOURSOME
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a foursome
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "foursome.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>
+  std::string foursome_to_string(const foursome<T1,T2,T3,T4>& values,
+                                 S1 to_string_fn1,
+                                 S2 to_string_fn2,
+                                 S3 to_string_fn3,
+                                 S4 to_string_fn4,
+                                 const std::string& separator = ":");
+
+} // end namespace stlplus
+
+#include "string_foursome.tpp"
+#endif
index a3e153613f0bff0a77b0c464cebab93bcf212e3e..db761f4b83461dd1ca452434cee19297167002d2 100644 (file)
@@ -1,33 +1,33 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>\r
-  std::string foursome_to_string(const foursome<T1,T2,T3,T4>& values,\r
-                                 S1 to_string_fn1,\r
-                                 S2 to_string_fn2,\r
-                                 S3 to_string_fn3,\r
-                                 S4 to_string_fn4,\r
-                                 const std::string& separator)\r
-  {\r
-    return \r
-      to_string_fn1(values.first) + \r
-      separator + \r
-      to_string_fn2(values.second) + \r
-      separator + \r
-      to_string_fn3(values.third) +\r
-      separator + \r
-      to_string_fn4(values.fourth);\r
-  }\r
-\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename T4, typename S1, typename S2, typename S3, typename S4>
+  std::string foursome_to_string(const foursome<T1,T2,T3,T4>& values,
+                                 S1 to_string_fn1,
+                                 S2 to_string_fn2,
+                                 S3 to_string_fn3,
+                                 S4 to_string_fn4,
+                                 const std::string& separator)
+  {
+    return 
+      to_string_fn1(values.first) + 
+      separator + 
+      to_string_fn2(values.second) + 
+      separator + 
+      to_string_fn3(values.third) +
+      separator + 
+      to_string_fn4(values.fourth);
+  }
+
+
+} // end namespace stlplus
+
index a01f87b1c91f18e65884dca043be633897aa5c2b..5a94bb2203134bc173bbb50a95c83faf13132e36 100644 (file)
@@ -1,32 +1,32 @@
-#ifndef STLPLUS_STRING_HASH\r
-#define STLPLUS_STRING_HASH\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a hash\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "hash.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename H, typename E, typename KS, typename TS>\r
-  std::string hash_to_string(const hash<K,T,H,E>& values,\r
-                             KS key_to_string_fn,\r
-                             TS value_to_string_fn,\r
-                             const std::string& pair_separator = ":",\r
-                             const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_hash.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_HASH
+#define STLPLUS_STRING_HASH
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a hash
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "hash.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename K, typename T, typename H, typename E, typename KS, typename TS>
+  std::string hash_to_string(const hash<K,T,H,E>& values,
+                             KS key_to_string_fn,
+                             TS value_to_string_fn,
+                             const std::string& pair_separator = ":",
+                             const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "string_hash.tpp"
+#endif
index b3b2a41224437d450fb338834ea075da44b08573..1d77f42bc907f51f60b6e28fa46fd5c86de137d1 100644 (file)
@@ -1,27 +1,27 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename H, typename E, typename KS, typename TS>\r
-  std::string hash_to_string(const hash<K,T,H,E>& values,\r
-                             KS key_to_string_fn,\r
-                             TS value_to_string_fn,\r
-                             const std::string& pair_separator,\r
-                             const std::string& separator)\r
-  {\r
-    return pair_sequence_to_string(values.begin(), values.end(),\r
-                                   key_to_string_fn, value_to_string_fn,\r
-                                   pair_separator, separator);\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_sequence.hpp"
+
+namespace stlplus
+{
+
+  template<typename K, typename T, typename H, typename E, typename KS, typename TS>
+  std::string hash_to_string(const hash<K,T,H,E>& values,
+                             KS key_to_string_fn,
+                             TS value_to_string_fn,
+                             const std::string& pair_separator,
+                             const std::string& separator)
+  {
+    return pair_sequence_to_string(values.begin(), values.end(),
+                                   key_to_string_fn, value_to_string_fn,
+                                   pair_separator, separator);
+  }
+
+} // end namespace stlplus
+
index 1734335d492b3cb6976377cf88c325853dd3453c..e1eb545e046b48359de84fba817bb894e70011d5 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   String conversion functions for the infinite precision integer type inf\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// can be excluded from the build to break the dependency on the portability library\r
-#ifndef NO_STLPLUS_INF\r
-\r
-#include "string_inf.hpp"\r
-#include "string_basic.hpp"\r
-#include <ctype.h>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";\r
-  static int from_char [] = \r
-  {\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,\r
-    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
-    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
-    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
-    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string inf_to_string(const stlplus::inf& data, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    std::string result;\r
-    if (radix < 2 || radix > 36)\r
-      throw std::invalid_argument("invalid radix value");\r
-    inf local_i = data;\r
-    // untangle all the options\r
-    bool hashed = false;\r
-    bool binary = false;\r
-    bool octal = false;\r
-    bool hex = false;\r
-    switch(display)\r
-    {\r
-    case radix_none:\r
-      break;\r
-    case radix_hash_style:\r
-      hashed = radix != 10;\r
-      break;\r
-    case radix_hash_style_all:\r
-      hashed = true;\r
-      break;\r
-    case radix_c_style:\r
-      if (radix == 16)\r
-        hex = true;\r
-      else if (radix == 8)\r
-        octal = true;\r
-      else if (radix == 2)\r
-        binary = true;\r
-      break;\r
-    case radix_c_style_or_hash:\r
-      if (radix == 16)\r
-        hex = true;\r
-      else if (radix == 8)\r
-        octal = true;\r
-      else if (radix == 2)\r
-        binary = true;\r
-      else if (radix != 10)\r
-        hashed = true;\r
-      break;\r
-    default:\r
-      throw std::invalid_argument("invalid radix display value");\r
-    }\r
-    // create constants of the same type as the template parameter to avoid type mismatches\r
-    const inf t_zero(0);\r
-    const inf t_radix(radix);\r
-    // the C representations for binary, octal and hex use 2's-complement representation\r
-    // all other represenations use sign-magnitude\r
-    if (hex || octal || binary)\r
-    {\r
-      // bit-pattern representation\r
-      // this is the binary representation optionally shown in octal or hex\r
-      // first generate the binary by masking the bits\r
-      for (unsigned j = local_i.bits(); j--; )\r
-        result += (local_i.bit(j) ? '1' : '0');\r
-      // the result is now the full width of the type - e.g. int will give a 32-bit result\r
-      // now interpret this as either binary, octal or hex and add the prefix\r
-      if (binary)\r
-      {\r
-        // the result is already binary - but the width may be wrong\r
-        // if this is still smaller than the width field, sign extend\r
-        // otherwise trim down to either the width or the smallest string that preserves the value\r
-        while (result.size() < width)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        while (result.size() > width)\r
-        {\r
-          // do not trim to less than 1 bit (sign only)\r
-          if (result.size() <= 1) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0b");\r
-      }\r
-      else if (octal)\r
-      {\r
-        // the result is currently binary - but before converting get the width right\r
-        // the width is expressed in octal digits so make the binary 3 times this\r
-        // if this is still smaller than the width field, sign extend\r
-        // otherwise trim down to either the width or the smallest string that preserves the value\r
-        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier\r
-        while (result.size() < 3*width)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        while (result.size() > 3*width)\r
-        {\r
-          // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
-          if (result.size() <= 2) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        while (result.size() % 3 != 0)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        // now convert to octal\r
-        std::string octal_result;\r
-        for (unsigned i = 0; i < result.size()/3; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*3] == '0')\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '0';\r
-              else\r
-                octal_result += '1';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '2';\r
-              else\r
-                octal_result += '3';\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '4';\r
-              else\r
-                octal_result += '5';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '6';\r
-              else\r
-                octal_result += '7';\r
-            }\r
-          }\r
-        }\r
-        result = octal_result;\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0");\r
-      }\r
-      else\r
-      {\r
-        // similar to octal\r
-        while (result.size() < 4*width)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        while (result.size() > 4*width)\r
-        {\r
-          // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
-          if (result.size() <= 2) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        while (result.size() % 4 != 0)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        // now convert to hex\r
-        std::string hex_result;\r
-        for (unsigned i = 0; i < result.size()/4; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*4] == '0')\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '0';\r
-                else\r
-                  hex_result += '1';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '2';\r
-                else\r
-                  hex_result += '3';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '4';\r
-                else\r
-                  hex_result += '5';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '6';\r
-                else\r
-                  hex_result += '7';\r
-              }\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '8';\r
-                else\r
-                  hex_result += '9';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'a';\r
-                else\r
-                  hex_result += 'b';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'c';\r
-                else\r
-                  hex_result += 'd';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'e';\r
-                else\r
-                  hex_result += 'f';\r
-              }\r
-            }\r
-          }\r
-        }\r
-        result = hex_result;\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0x");\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // convert to sign-magnitude\r
-      // the representation is:\r
-      // [radix#][sign]magnitude\r
-      bool negative = local_i.negative();\r
-      local_i.abs();\r
-      // create a representation of the magnitude by successive division\r
-      do\r
-      {\r
-        std::pair<inf,inf> divided = local_i.divide(t_radix);\r
-        unsigned remainder = divided.second.to_unsigned();\r
-        char digit = to_char[remainder];\r
-        result.insert((std::string::size_type)0, 1, digit);\r
-        local_i = divided.first;\r
-      }\r
-      while(!local_i.zero() || result.size() < width);\r
-      // add the prefixes\r
-      // add a sign only for negative values\r
-      if (negative)\r
-        result.insert((std::string::size_type)0, 1, '-');\r
-      // then prefix everything with the radix if the hashed representation was requested\r
-      if (hashed)\r
-        result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Conversions FROM string\r
-\r
-  inf string_to_inf(const std::string& str, unsigned radix) throw(std::invalid_argument)\r
-  {\r
-    inf result;\r
-    if (radix != 0 && (radix < 2 || radix > 36))\r
-      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
-    unsigned i = 0;\r
-    // the radix passed as a parameter is just the default - it can be\r
-    // overridden by either the C prefix or the hash prefix\r
-    // Note: a leading zero is the C-style prefix for octal - I only make this\r
-    // override the default when the default radix is not specified\r
-    // first check for a C-style prefix\r
-    bool c_style = false;\r
-    if (i < str.size() && str[i] == '0')\r
-    {\r
-      // binary or hex\r
-      if (i+1 < str.size() && tolower(str[i+1]) == 'x')\r
-      {\r
-        c_style = true;\r
-        radix = 16;\r
-        i += 2;\r
-      }\r
-      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')\r
-      {\r
-        c_style = true;\r
-        radix = 2;\r
-        i += 2;\r
-      }\r
-      else if (radix == 0)\r
-      {\r
-        c_style = true;\r
-        radix = 8;\r
-        i += 1;\r
-      }\r
-    }\r
-    // now check for a hash-style prefix if a C-style prefix was not found\r
-    if (i == 0)\r
-    {\r
-      // scan for the sequence {digits}#\r
-      bool hash_found = false;\r
-      unsigned j = i;\r
-      for (; j < str.size(); j++)\r
-      {\r
-        if (!isdigit(str[j]))\r
-        {\r
-          if (str[j] == '#')\r
-            hash_found = true;\r
-          break;\r
-        }\r
-      }\r
-      if (hash_found)\r
-      {\r
-        // use the hash prefix to define the radix\r
-        // i points to the start of the radix and j points to the # character\r
-        std::string slice = str.substr(i, j-i);\r
-        radix = string_to_unsigned(slice);\r
-        i = j+1;\r
-      }\r
-    }\r
-    if (radix == 0)\r
-      radix = 10;\r
-    if (radix < 2 || radix > 36)\r
-      throw std::invalid_argument("invalid radix value");\r
-    if (c_style)\r
-    {\r
-      // the C style formats are bit patterns not integer values - these need\r
-      // to be sign-extended to get the right value\r
-      std::string binary;\r
-      if (radix == 2)\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += '0';\r
-            break;\r
-          case '1':\r
-            binary += '1';\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid binary character in string " + str);\r
-          }\r
-        }\r
-      }\r
-      else if (radix == 8)\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += "000";\r
-            break;\r
-          case '1':\r
-            binary += "001";\r
-            break;\r
-          case '2':\r
-            binary += "010";\r
-            break;\r
-          case '3':\r
-            binary += "011";\r
-            break;\r
-          case '4':\r
-            binary += "100";\r
-            break;\r
-          case '5':\r
-            binary += "101";\r
-            break;\r
-          case '6':\r
-            binary += "110";\r
-            break;\r
-          case '7':\r
-            binary += "111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid octal character in string " + str);\r
-          }\r
-        }\r
-      }\r
-      else\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(tolower(str[j]))\r
-          {\r
-          case '0':\r
-            binary += "0000";\r
-            break;\r
-          case '1':\r
-            binary += "0001";\r
-            break;\r
-          case '2':\r
-            binary += "0010";\r
-            break;\r
-          case '3':\r
-            binary += "0011";\r
-            break;\r
-          case '4':\r
-            binary += "0100";\r
-            break;\r
-          case '5':\r
-            binary += "0101";\r
-            break;\r
-          case '6':\r
-            binary += "0110";\r
-            break;\r
-          case '7':\r
-            binary += "0111";\r
-            break;\r
-          case '8':\r
-            binary += "1000";\r
-            break;\r
-          case '9':\r
-            binary += "1001";\r
-            break;\r
-          case 'a':\r
-            binary += "1010";\r
-            break;\r
-          case 'b':\r
-            binary += "1011";\r
-            break;\r
-          case 'c':\r
-            binary += "1100";\r
-            break;\r
-          case 'd':\r
-            binary += "1101";\r
-            break;\r
-          case 'e':\r
-            binary += "1110";\r
-            break;\r
-          case 'f':\r
-            binary += "1111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid hex character in string " + str);\r
-          }\r
-        }\r
-      }\r
-      // now convert the value\r
-      result.resize(binary.size());\r
-      for (unsigned j = 0; j < binary.size(); j++)\r
-        result.preset(binary.size() - j - 1, binary[j] == '1');\r
-    }\r
-    else\r
-    {\r
-      // now scan for a sign and find whether this is a negative number\r
-      bool negative = false;\r
-      if (i < str.size())\r
-      {\r
-        switch (str[i])\r
-        {\r
-        case '-':\r
-          negative = true;\r
-          i++;\r
-          break;\r
-        case '+':\r
-          i++;\r
-          break;\r
-        }\r
-      }\r
-      for (; i < str.size(); i++)\r
-      {\r
-        result *= inf(radix);\r
-        int ch = from_char[(unsigned char)str[i]] ;\r
-        if (ch == -1)\r
-          throw std::invalid_argument("invalid character in string " + str + " for radix " + unsigned_to_string(radix));\r
-        result += inf(ch);\r
-      }\r
-      if (negative)\r
-        result.negate();\r
-    }\r
-    return result;\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   String conversion functions for the infinite precision integer type inf
+
+////////////////////////////////////////////////////////////////////////////////
+
+// can be excluded from the build to break the dependency on the portability library
+#ifndef NO_STLPLUS_INF
+
+#include "string_inf.hpp"
+#include "string_basic.hpp"
+#include <ctype.h>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";
+  static int from_char [] = 
+  {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string inf_to_string(const stlplus::inf& data, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    std::string result;
+    if (radix < 2 || radix > 36)
+      throw std::invalid_argument("invalid radix value");
+    inf local_i = data;
+    // untangle all the options
+    bool hashed = false;
+    bool binary = false;
+    bool octal = false;
+    bool hex = false;
+    switch(display)
+    {
+    case radix_none:
+      break;
+    case radix_hash_style:
+      hashed = radix != 10;
+      break;
+    case radix_hash_style_all:
+      hashed = true;
+      break;
+    case radix_c_style:
+      if (radix == 16)
+        hex = true;
+      else if (radix == 8)
+        octal = true;
+      else if (radix == 2)
+        binary = true;
+      break;
+    case radix_c_style_or_hash:
+      if (radix == 16)
+        hex = true;
+      else if (radix == 8)
+        octal = true;
+      else if (radix == 2)
+        binary = true;
+      else if (radix != 10)
+        hashed = true;
+      break;
+    default:
+      throw std::invalid_argument("invalid radix display value");
+    }
+    // create constants of the same type as the template parameter to avoid type mismatches
+    const inf t_zero(0);
+    const inf t_radix(radix);
+    // the C representations for binary, octal and hex use 2's-complement representation
+    // all other represenations use sign-magnitude
+    if (hex || octal || binary)
+    {
+      // bit-pattern representation
+      // this is the binary representation optionally shown in octal or hex
+      // first generate the binary by masking the bits
+      for (unsigned j = local_i.bits(); j--; )
+        result += (local_i.bit(j) ? '1' : '0');
+      // the result is now the full width of the type - e.g. int will give a 32-bit result
+      // now interpret this as either binary, octal or hex and add the prefix
+      if (binary)
+      {
+        // the result is already binary - but the width may be wrong
+        // if this is still smaller than the width field, sign extend
+        // otherwise trim down to either the width or the smallest string that preserves the value
+        while (result.size() < width)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        while (result.size() > width)
+        {
+          // do not trim to less than 1 bit (sign only)
+          if (result.size() <= 1) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        // add the prefix
+        result.insert((std::string::size_type)0, "0b");
+      }
+      else if (octal)
+      {
+        // the result is currently binary - but before converting get the width right
+        // the width is expressed in octal digits so make the binary 3 times this
+        // if this is still smaller than the width field, sign extend
+        // otherwise trim down to either the width or the smallest string that preserves the value
+        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
+        while (result.size() < 3*width)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        while (result.size() > 3*width)
+        {
+          // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+          if (result.size() <= 2) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        while (result.size() % 3 != 0)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        // now convert to octal
+        std::string octal_result;
+        for (unsigned i = 0; i < result.size()/3; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*3] == '0')
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '0';
+              else
+                octal_result += '1';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '2';
+              else
+                octal_result += '3';
+            }
+          }
+          else
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '4';
+              else
+                octal_result += '5';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '6';
+              else
+                octal_result += '7';
+            }
+          }
+        }
+        result = octal_result;
+        // add the prefix
+        result.insert((std::string::size_type)0, "0");
+      }
+      else
+      {
+        // similar to octal
+        while (result.size() < 4*width)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        while (result.size() > 4*width)
+        {
+          // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+          if (result.size() <= 2) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        while (result.size() % 4 != 0)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        // now convert to hex
+        std::string hex_result;
+        for (unsigned i = 0; i < result.size()/4; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*4] == '0')
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '0';
+                else
+                  hex_result += '1';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '2';
+                else
+                  hex_result += '3';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '4';
+                else
+                  hex_result += '5';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '6';
+                else
+                  hex_result += '7';
+              }
+            }
+          }
+          else
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '8';
+                else
+                  hex_result += '9';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'a';
+                else
+                  hex_result += 'b';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'c';
+                else
+                  hex_result += 'd';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'e';
+                else
+                  hex_result += 'f';
+              }
+            }
+          }
+        }
+        result = hex_result;
+        // add the prefix
+        result.insert((std::string::size_type)0, "0x");
+      }
+    }
+    else
+    {
+      // convert to sign-magnitude
+      // the representation is:
+      // [radix#][sign]magnitude
+      bool negative = local_i.negative();
+      local_i.abs();
+      // create a representation of the magnitude by successive division
+      do
+      {
+        std::pair<inf,inf> divided = local_i.divide(t_radix);
+        unsigned remainder = divided.second.to_unsigned();
+        char digit = to_char[remainder];
+        result.insert((std::string::size_type)0, 1, digit);
+        local_i = divided.first;
+      }
+      while(!local_i.zero() || result.size() < width);
+      // add the prefixes
+      // add a sign only for negative values
+      if (negative)
+        result.insert((std::string::size_type)0, 1, '-');
+      // then prefix everything with the radix if the hashed representation was requested
+      if (hashed)
+        result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Conversions FROM string
+
+  inf string_to_inf(const std::string& str, unsigned radix) throw(std::invalid_argument)
+  {
+    inf result;
+    if (radix != 0 && (radix < 2 || radix > 36))
+      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+    unsigned i = 0;
+    // the radix passed as a parameter is just the default - it can be
+    // overridden by either the C prefix or the hash prefix
+    // Note: a leading zero is the C-style prefix for octal - I only make this
+    // override the default when the default radix is not specified
+    // first check for a C-style prefix
+    bool c_style = false;
+    if (i < str.size() && str[i] == '0')
+    {
+      // binary or hex
+      if (i+1 < str.size() && tolower(str[i+1]) == 'x')
+      {
+        c_style = true;
+        radix = 16;
+        i += 2;
+      }
+      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')
+      {
+        c_style = true;
+        radix = 2;
+        i += 2;
+      }
+      else if (radix == 0)
+      {
+        c_style = true;
+        radix = 8;
+        i += 1;
+      }
+    }
+    // now check for a hash-style prefix if a C-style prefix was not found
+    if (i == 0)
+    {
+      // scan for the sequence {digits}#
+      bool hash_found = false;
+      unsigned j = i;
+      for (; j < str.size(); j++)
+      {
+        if (!isdigit(str[j]))
+        {
+          if (str[j] == '#')
+            hash_found = true;
+          break;
+        }
+      }
+      if (hash_found)
+      {
+        // use the hash prefix to define the radix
+        // i points to the start of the radix and j points to the # character
+        std::string slice = str.substr(i, j-i);
+        radix = string_to_unsigned(slice);
+        i = j+1;
+      }
+    }
+    if (radix == 0)
+      radix = 10;
+    if (radix < 2 || radix > 36)
+      throw std::invalid_argument("invalid radix value");
+    if (c_style)
+    {
+      // the C style formats are bit patterns not integer values - these need
+      // to be sign-extended to get the right value
+      std::string binary;
+      if (radix == 2)
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += '0';
+            break;
+          case '1':
+            binary += '1';
+            break;
+          default:
+            throw std::invalid_argument("invalid binary character in string " + str);
+          }
+        }
+      }
+      else if (radix == 8)
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += "000";
+            break;
+          case '1':
+            binary += "001";
+            break;
+          case '2':
+            binary += "010";
+            break;
+          case '3':
+            binary += "011";
+            break;
+          case '4':
+            binary += "100";
+            break;
+          case '5':
+            binary += "101";
+            break;
+          case '6':
+            binary += "110";
+            break;
+          case '7':
+            binary += "111";
+            break;
+          default:
+            throw std::invalid_argument("invalid octal character in string " + str);
+          }
+        }
+      }
+      else
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(tolower(str[j]))
+          {
+          case '0':
+            binary += "0000";
+            break;
+          case '1':
+            binary += "0001";
+            break;
+          case '2':
+            binary += "0010";
+            break;
+          case '3':
+            binary += "0011";
+            break;
+          case '4':
+            binary += "0100";
+            break;
+          case '5':
+            binary += "0101";
+            break;
+          case '6':
+            binary += "0110";
+            break;
+          case '7':
+            binary += "0111";
+            break;
+          case '8':
+            binary += "1000";
+            break;
+          case '9':
+            binary += "1001";
+            break;
+          case 'a':
+            binary += "1010";
+            break;
+          case 'b':
+            binary += "1011";
+            break;
+          case 'c':
+            binary += "1100";
+            break;
+          case 'd':
+            binary += "1101";
+            break;
+          case 'e':
+            binary += "1110";
+            break;
+          case 'f':
+            binary += "1111";
+            break;
+          default:
+            throw std::invalid_argument("invalid hex character in string " + str);
+          }
+        }
+      }
+      // now convert the value
+      result.resize(binary.size());
+      for (unsigned j = 0; j < binary.size(); j++)
+        result.preset(binary.size() - j - 1, binary[j] == '1');
+    }
+    else
+    {
+      // now scan for a sign and find whether this is a negative number
+      bool negative = false;
+      if (i < str.size())
+      {
+        switch (str[i])
+        {
+        case '-':
+          negative = true;
+          i++;
+          break;
+        case '+':
+          i++;
+          break;
+        }
+      }
+      for (; i < str.size(); i++)
+      {
+        result *= inf(radix);
+        int ch = from_char[(unsigned char)str[i]] ;
+        if (ch == -1)
+          throw std::invalid_argument("invalid character in string " + str + " for radix " + unsigned_to_string(radix));
+        result += inf(ch);
+      }
+      if (negative)
+        result.negate();
+    }
+    return result;
+  }
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 15432630f83cda555130fb37421ceb13a5e5dd63..b651d725a7a367681f107a83ecef4fbac1a4aa00 100644 (file)
@@ -1,40 +1,40 @@
-#ifndef STLPLUS_STRING_INF\r
-#define STLPLUS_STRING_INF\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   String conversion functions for the infinite precision integer type inf\r
-\r
-//   The conversion supports all the formatting modes defined on format_types\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "inf.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // conversion TO string\r
-  std::string inf_to_string(const inf&,\r
-                            unsigned radix = 10,\r
-                            radix_display_t display = radix_c_style_or_hash,\r
-                            unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  // conversion FROM string\r
-  inf string_to_inf(const std::string&,\r
-                    unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-} // end namespace stlplus\r
-#endif\r
+#ifndef STLPLUS_STRING_INF
+#define STLPLUS_STRING_INF
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   String conversion functions for the infinite precision integer type inf
+
+//   The conversion supports all the formatting modes defined on format_types
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "inf.hpp"
+#include "format_types.hpp"
+#include <string>
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // conversion TO string
+  std::string inf_to_string(const inf&,
+                            unsigned radix = 10,
+                            radix_display_t display = radix_c_style_or_hash,
+                            unsigned width = 0)
+    throw(std::invalid_argument);
+
+  // conversion FROM string
+  inf string_to_inf(const std::string&,
+                    unsigned radix = 0)
+    throw(std::invalid_argument);
+
+////////////////////////////////////////////////////////////////////////////////
+} // end namespace stlplus
+#endif
index 178cf4c86f37e20b581cfd9de6db0d1d92dad148..ec5e10c93f8811d53830da2b7c9d5dcd39b67d21 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_int.hpp"\r
-#include <ctype.h>\r
-#include <stdlib.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // character mappings\r
-\r
-  static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";\r
-  static int from_char [] = \r
-  {\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,\r
-    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
-    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
-    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,\r
-    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\r
-    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Conversions to string\r
-  // Local generic routines\r
-\r
-  // signed version of the generic image generation function for all integer types\r
-  template<typename T>\r
-  static std::string simage (T i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    if (radix < 2 || radix > 36)\r
-      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
-    // untangle all the options\r
-    bool hashed = false;\r
-    bool binary = false;\r
-    bool octal = false;\r
-    bool hex = false;\r
-    switch(display)\r
-    {\r
-    case radix_none:\r
-      break;\r
-    case radix_hash_style:\r
-      hashed = radix != 10;\r
-      break;\r
-    case radix_hash_style_all:\r
-      hashed = true;\r
-      break;\r
-    case radix_c_style:\r
-      if (radix == 16)\r
-        hex = true;\r
-      else if (radix == 8)\r
-        octal = true;\r
-      else if (radix == 2)\r
-        binary = true;\r
-      break;\r
-    case radix_c_style_or_hash:\r
-      if (radix == 16)\r
-        hex = true;\r
-      else if (radix == 8)\r
-        octal = true;\r
-      else if (radix == 2)\r
-        binary = true;\r
-      else if (radix != 10)\r
-        hashed = true;\r
-      break;\r
-    default:\r
-      throw std::invalid_argument("invalid radix display value");\r
-    }\r
-    // create constants of the same type as the template parameter to avoid type mismatches\r
-    const T t_zero(0);\r
-    const T t_radix(radix);\r
-    // the C representations for binary, octal and hex use 2's-complement representation\r
-    // all other represenations use sign-magnitude\r
-    std::string result;\r
-    if (hex || octal || binary)\r
-    {\r
-      // bit-pattern representation\r
-      // this is the binary representation optionally shown in octal or hex\r
-      // first generate the binary by masking the bits\r
-      // ensure that it has at least one bit!\r
-      for (T mask(1); ; mask <<= 1)\r
-      {\r
-        result.insert((std::string::size_type)0, 1, i & mask ? '1' : '0');\r
-        if (mask == t_zero) break;\r
-      }\r
-      // the result is now the full width of the type - e.g. int will give a 32-bit result\r
-      // now interpret this as either binary, octal or hex and add the prefix\r
-      if (binary)\r
-      {\r
-        // the result is already binary - but the width may be wrong\r
-        // if this is still smaller than the width field, sign extend\r
-        // otherwise trim down to either the width or the smallest string that preserves the value\r
-        while (result.size() < width)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        while (result.size() > width)\r
-        {\r
-          // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
-          if (result.size() <= 2) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0b");\r
-      }\r
-      else if (octal)\r
-      {\r
-        // the result is currently binary - but before converting get the width right\r
-        // the width is expressed in octal digits so make the binary 3 times this\r
-        // if this is still smaller than the width field, sign extend\r
-        // otherwise trim down to either the width or the smallest string that preserves the value\r
-        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier\r
-        while (result.size() < 3*width)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        while (result.size() > 3*width)\r
-        {\r
-          // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
-          if (result.size() <= 2) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        while (result.size() % 3 != 0)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        // now convert to octal\r
-        std::string octal_result;\r
-        for (unsigned i = 0; i < result.size()/3; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*3] == '0')\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '0';\r
-              else\r
-                octal_result += '1';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '2';\r
-              else\r
-                octal_result += '3';\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '4';\r
-              else\r
-                octal_result += '5';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '6';\r
-              else\r
-                octal_result += '7';\r
-            }\r
-          }\r
-        }\r
-        result = octal_result;\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0");\r
-      }\r
-      else\r
-      {\r
-        // hex - similar to octal\r
-        while (result.size() < 4*width)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        while (result.size() > 4*width)\r
-        {\r
-          // do not trim to less than 2 bits (sign plus 1-bit magnitude)\r
-          if (result.size() <= 2) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != result[1]) break;\r
-          result.erase(0,1);\r
-        }\r
-        while (result.size() % 4 != 0)\r
-          result.insert((std::string::size_type)0, 1, result[0]);\r
-        // now convert to hex\r
-        std::string hex_result;\r
-        for (unsigned i = 0; i < result.size()/4; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*4] == '0')\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '0';\r
-                else\r
-                  hex_result += '1';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '2';\r
-                else\r
-                  hex_result += '3';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '4';\r
-                else\r
-                  hex_result += '5';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '6';\r
-                else\r
-                  hex_result += '7';\r
-              }\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '8';\r
-                else\r
-                  hex_result += '9';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'a';\r
-                else\r
-                  hex_result += 'b';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'c';\r
-                else\r
-                  hex_result += 'd';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'e';\r
-                else\r
-                  hex_result += 'f';\r
-              }\r
-            }\r
-          }\r
-        }\r
-        result = hex_result;\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0x");\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // convert to sign-magnitude\r
-      // the representation is:\r
-      // [radix#][sign]magnitude\r
-      bool negative = i < t_zero;\r
-      // create a representation of the magnitude by successive division\r
-      do\r
-      {\r
-        T ch = abs(i % t_radix);\r
-        i /= t_radix;\r
-        result.insert((std::string::size_type)0, 1, to_char[ch]);\r
-      }\r
-      while(i != t_zero || result.size() < width);\r
-      // add the prefixes\r
-      // add a sign only for negative values\r
-      if (negative)\r
-        result.insert((std::string::size_type)0, 1, '-');\r
-      // then prefix everything with the radix if the hashed representation was requested\r
-      if (hashed)\r
-        result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");\r
-    }\r
-    return result;\r
-  }\r
-\r
-  // unsigned version\r
-  template<typename T>\r
-  static std::string uimage (T i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    if (radix < 2 || radix > 36)\r
-      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
-    // untangle all the options\r
-    bool hashed = false;\r
-    bool binary = false;\r
-    bool octal = false;\r
-    bool hex = false;\r
-    switch(display)\r
-    {\r
-    case radix_none:\r
-      break;\r
-    case radix_hash_style:\r
-      hashed = radix != 10;\r
-      break;\r
-    case radix_hash_style_all:\r
-      hashed = true;\r
-      break;\r
-    case radix_c_style:\r
-      if (radix == 16)\r
-        hex = true;\r
-      else if (radix == 8)\r
-        octal = true;\r
-      else if (radix == 2)\r
-        binary = true;\r
-      break;\r
-    case radix_c_style_or_hash:\r
-      if (radix == 16)\r
-        hex = true;\r
-      else if (radix == 8)\r
-        octal = true;\r
-      else if (radix == 2)\r
-        binary = true;\r
-      else if (radix != 10)\r
-        hashed = true;\r
-      break;\r
-    default:\r
-      throw std::invalid_argument("invalid radix display value");\r
-    }\r
-    // create constants of the same type as the template parameter to avoid type mismatches\r
-    const T t_zero(0);\r
-    const T t_radix(radix);\r
-    // the C representations for binary, octal and hex use 2's-complement representation\r
-    // all other represenations use sign-magnitude\r
-    std::string result;\r
-    if (hex || octal || binary)\r
-    {\r
-      // bit-pattern representation\r
-      // this is the binary representation optionally shown in octal or hex\r
-      // first generate the binary by masking the bits\r
-      // ensure at least one bit\r
-      for (T mask(1); ; mask <<= 1)\r
-      {\r
-        result.insert((std::string::size_type)0, 1, i & mask ? '1' : '0');\r
-        if (mask == t_zero) break;\r
-      }\r
-      // the result is now the full width of the type - e.g. int will give a 32-bit result\r
-      // now interpret this as either binary, octal or hex and add the prefix\r
-      if (binary)\r
-      {\r
-        // the result is already binary - but the width may be wrong\r
-        // if this is still smaller than the width field, zero extend\r
-        // otherwise trim down to either the width or the smallest string that preserves the value\r
-        while (result.size() < width)\r
-          result.insert((std::string::size_type)0, 1, '0');\r
-        while (result.size() > width)\r
-        {\r
-          // do not trim to less than 1 bit (1-bit magnitude)\r
-          if (result.size() <= 1) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != '0') break;\r
-          result.erase(0,1);\r
-        }\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0b");\r
-      }\r
-      else if (octal)\r
-      {\r
-        // the result is currently binary - but before converting get the width right\r
-        // the width is expressed in octal digits so make the binary 3 times this\r
-        // if this is still smaller than the width field, sign extend\r
-        // otherwise trim down to either the width or the smallest string that preserves the value\r
-        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier\r
-        while (result.size() < 3*width)\r
-          result.insert((std::string::size_type)0, 1, '0');\r
-        while (result.size() > 3*width)\r
-        {\r
-          // do not trim to less than 1 bit (1-bit magnitude)\r
-          if (result.size() <= 1) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != '0') break;\r
-          result.erase(0,1);\r
-        }\r
-        while (result.size() % 3 != 0)\r
-          result.insert((std::string::size_type)0, 1, '0');\r
-        // now convert to octal\r
-        std::string octal_result;\r
-        for (unsigned i = 0; i < result.size()/3; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*3] == '0')\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '0';\r
-              else\r
-                octal_result += '1';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '2';\r
-              else\r
-                octal_result += '3';\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*3+1] == '0')\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '4';\r
-              else\r
-                octal_result += '5';\r
-            }\r
-            else\r
-            {\r
-              if (result[i*3+2] == '0')\r
-                octal_result += '6';\r
-              else\r
-                octal_result += '7';\r
-            }\r
-          }\r
-        }\r
-        result = octal_result;\r
-        // add the prefix if the leading digit is not already 0\r
-        if (result.empty() || result[0] != '0') result.insert((std::string::size_type)0, "0");\r
-      }\r
-      else\r
-      {\r
-        // similar to octal\r
-        while (result.size() < 4*width)\r
-          result.insert((std::string::size_type)0, 1, '0');\r
-        while (result.size() > 4*width)\r
-        {\r
-          // do not trim to less than 1 bit (1-bit magnitude)\r
-          if (result.size() <= 1) break;\r
-          // only trim if it doesn't change the sign and therefore the value\r
-          if (result[0] != '0') break;\r
-          result.erase(0,1);\r
-        }\r
-        while (result.size() % 4 != 0)\r
-          result.insert((std::string::size_type)0, 1, '0');\r
-        // now convert to hex\r
-        std::string hex_result;\r
-        for (unsigned i = 0; i < result.size()/4; i++)\r
-        {\r
-          // yuck - ugly or what?\r
-          if (result[i*4] == '0')\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '0';\r
-                else\r
-                  hex_result += '1';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '2';\r
-                else\r
-                  hex_result += '3';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '4';\r
-                else\r
-                  hex_result += '5';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '6';\r
-                else\r
-                  hex_result += '7';\r
-              }\r
-            }\r
-          }\r
-          else\r
-          {\r
-            if (result[i*4+1] == '0')\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += '8';\r
-                else\r
-                  hex_result += '9';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'a';\r
-                else\r
-                  hex_result += 'b';\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (result[i*4+2] == '0')\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'c';\r
-                else\r
-                  hex_result += 'd';\r
-              }\r
-              else\r
-              {\r
-                if (result[i*4+3] == '0')\r
-                  hex_result += 'e';\r
-                else\r
-                  hex_result += 'f';\r
-              }\r
-            }\r
-          }\r
-        }\r
-        result = hex_result;\r
-        // add the prefix\r
-        result.insert((std::string::size_type)0, "0x");\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // convert to sign-magnitude\r
-      // the representation is:\r
-      // [radix#]magnitude\r
-      // create a representation of the magnitude by successive division\r
-      do\r
-      {\r
-        T ch = i % t_radix;\r
-        i /= t_radix;\r
-        result.insert((std::string::size_type)0, 1, to_char[(int)ch]);\r
-      }\r
-      while(i != t_zero || result.size() < width);\r
-      // prefix everything with the radix if the hashed representation was requested\r
-      if (hashed)\r
-        result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // exported conversions to string\r
-\r
-  std::string short_to_string(short i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return simage(i, radix, display, width);\r
-  }\r
-\r
-  std::string unsigned_short_to_string(unsigned short i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return uimage(i, radix, display, width);\r
-  }\r
-\r
-  std::string int_to_string(int i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return simage(i, radix, display, width);\r
-  }\r
-\r
-  std::string unsigned_to_string(unsigned i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return uimage(i, radix, display, width);\r
-  }\r
-\r
-  std::string long_to_string(long i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return simage(i, radix, display, width);\r
-  }\r
-\r
-  std::string unsigned_long_to_string(unsigned long i, unsigned radix, radix_display_t display, unsigned width)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return uimage(i, radix, display, width);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Conversions FROM string\r
-  // local template function\r
-  // Note: this has been copied and modified for the inf class - so any changes here must be made there too\r
-\r
-  // signed version\r
-  template<typename T>\r
-  static T svalue(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    if (radix != 0 && (radix < 2 || radix > 36))\r
-      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
-    std::string::size_type i = 0;\r
-    // the radix passed as a parameter is just the default - it can be\r
-    // overridden by either the C prefix or the hash prefix. Note: a leading zero\r
-    // is the C-style prefix for octal - I only make this override the default\r
-    // when the default prefix is not specified\r
-    // First check for a C-style prefix\r
-    bool c_style = false;\r
-    if (i < str.size() && str[i] == '0')\r
-    {\r
-      // octal, binary or hex\r
-      if (i+1 < str.size() && tolower(str[i+1]) == 'x')\r
-      {\r
-        radix = 16;\r
-        i += 2;\r
-        c_style = true;\r
-      }\r
-      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')\r
-      {\r
-        radix = 2;\r
-        i += 2;\r
-        c_style = true;\r
-      }\r
-      else if (radix == 0)\r
-      {\r
-        radix = 8;\r
-        i += 1;\r
-        c_style = true;\r
-      }\r
-    }\r
-    // now check for a hash-style prefix if a C-style prefix was not found\r
-    if (i == 0)\r
-    {\r
-      // scan for the sequence {digits}#\r
-      bool hash_found = false;\r
-      std::string::size_type j = i;\r
-      for (; j < str.size(); j++)\r
-      {\r
-        if (!isdigit(str[j]))\r
-        {\r
-          if (str[j] == '#')\r
-            hash_found = true;\r
-          break;\r
-        }\r
-      }\r
-      if (hash_found)\r
-      {\r
-        // use the hash prefix to define the radix\r
-        // i points to the start of the radix and j points to the # character\r
-        std::string slice = str.substr(i, j-i);\r
-        radix = string_to_unsigned(slice);\r
-        i = j+1;\r
-      }\r
-    }\r
-    if (radix == 0)\r
-      radix = 10;\r
-    if (radix < 2 || radix > 36)\r
-      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
-    T val(0);\r
-    if (c_style)\r
-    {\r
-      // the C style formats are bit patterns not integer values - these need\r
-      // to be sign-extended to get the right value\r
-      std::string binary;\r
-      if (radix == 2)\r
-      {\r
-        for (std::string::size_type j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += '0';\r
-            break;\r
-          case '1':\r
-            binary += '1';\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid binary character in string " + str);\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      else if (radix == 8)\r
-      {\r
-        for (std::string::size_type j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += "000";\r
-            break;\r
-          case '1':\r
-            binary += "001";\r
-            break;\r
-          case '2':\r
-            binary += "010";\r
-            break;\r
-          case '3':\r
-            binary += "011";\r
-            break;\r
-          case '4':\r
-            binary += "100";\r
-            break;\r
-          case '5':\r
-            binary += "101";\r
-            break;\r
-          case '6':\r
-            binary += "110";\r
-            break;\r
-          case '7':\r
-            binary += "111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid octal character in string " + str);\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      else\r
-      {\r
-        for (std::string::size_type j = i; j < str.size(); j++)\r
-        {\r
-          switch(tolower(str[j]))\r
-          {\r
-          case '0':\r
-            binary += "0000";\r
-            break;\r
-          case '1':\r
-            binary += "0001";\r
-            break;\r
-          case '2':\r
-            binary += "0010";\r
-            break;\r
-          case '3':\r
-            binary += "0011";\r
-            break;\r
-          case '4':\r
-            binary += "0100";\r
-            break;\r
-          case '5':\r
-            binary += "0101";\r
-            break;\r
-          case '6':\r
-            binary += "0110";\r
-            break;\r
-          case '7':\r
-            binary += "0111";\r
-            break;\r
-          case '8':\r
-            binary += "1000";\r
-            break;\r
-          case '9':\r
-            binary += "1001";\r
-            break;\r
-          case 'a':\r
-            binary += "1010";\r
-            break;\r
-          case 'b':\r
-            binary += "1011";\r
-            break;\r
-          case 'c':\r
-            binary += "1100";\r
-            break;\r
-          case 'd':\r
-            binary += "1101";\r
-            break;\r
-          case 'e':\r
-            binary += "1110";\r
-            break;\r
-          case 'f':\r
-            binary += "1111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid hex character in string " + str);\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      // now sign-extend to the right number of bits for the type\r
-      while (binary.size() < sizeof(T)*8)\r
-        binary.insert((std::string::size_type)0, 1, binary.empty() ? '0' : binary[0]);\r
-      // now convert the value\r
-      for (std::string::size_type j = 0; j < binary.size(); j++)\r
-      {\r
-        val *= 2;\r
-        int ch = from_char[(unsigned char)binary[j]] ;\r
-        val += T(ch);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // now scan for a sign and find whether this is a negative number\r
-      bool negative = false;\r
-      if (i < str.size())\r
-      {\r
-        switch (str[i])\r
-        {\r
-        case '-':\r
-          negative = true;\r
-          i++;\r
-          break;\r
-        case '+':\r
-          i++;\r
-          break;\r
-        }\r
-      }\r
-      for (; i < str.size(); i++)\r
-      {\r
-        val *= T(radix);\r
-        int ch = from_char[(unsigned char)str[i]] ;\r
-        if (ch == -1 || (unsigned)ch >= radix)\r
-          throw std::invalid_argument("invalid character in string " + str);\r
-        val += T(ch);\r
-      }\r
-      if (negative)\r
-        val = -val;\r
-    }\r
-    return val;\r
-  }\r
-\r
-  // unsigned version\r
-  template<typename T>\r
-  static T uvalue(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    if (radix != 0 && (radix < 2 || radix > 36))\r
-      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
-    unsigned i = 0;\r
-    // the radix passed as a parameter is just the default - it can be\r
-    // overridden by either the C prefix or the hash prefix. Note: a leading\r
-    // zero is the C-style prefix for octal - I only make this override the\r
-    // default when the default prefix is not specified\r
-    // First check for a C-style prefix\r
-    bool c_style = false;\r
-    if (i < str.size() && str[i] == '0')\r
-    {\r
-      // binary or hex\r
-      if (i+1 < str.size() && tolower(str[i+1]) == 'x')\r
-      {\r
-        radix = 16;\r
-        i += 2;\r
-        c_style = true;\r
-      }\r
-      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')\r
-      {\r
-        radix = 2;\r
-        i += 2;\r
-        c_style = true;\r
-      }\r
-      else if (radix == 0)\r
-      {\r
-        radix = 8;\r
-        i += 1;\r
-        c_style = true;\r
-      }\r
-    }\r
-    // now check for a hash-style prefix if a C-style prefix was not found\r
-    if (i == 0)\r
-    {\r
-      // scan for the sequence {digits}#\r
-      bool hash_found = false;\r
-      unsigned j = i;\r
-      for (; j < str.size(); j++)\r
-      {\r
-        if (!isdigit(str[j]))\r
-        {\r
-          if (str[j] == '#')\r
-            hash_found = true;\r
-          break;\r
-        }\r
-      }\r
-      if (hash_found)\r
-      {\r
-        // use the hash prefix to define the radix\r
-        // i points to the start of the radix and j points to the # character\r
-        std::string slice = str.substr(i, j-i);\r
-        radix = string_to_unsigned(slice);\r
-        i = j+1;\r
-      }\r
-    }\r
-    if (radix == 0)\r
-      radix = 10;\r
-    if (radix < 2 || radix > 36)\r
-      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));\r
-    T val(0);\r
-    if (c_style)\r
-    {\r
-      // the C style formats are bit patterns not integer values - these need\r
-      // to be sign-extended to get the right value\r
-      std::string binary;\r
-      if (radix == 2)\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += '0';\r
-            break;\r
-          case '1':\r
-            binary += '1';\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid hex character in string " + str);\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      else if (radix == 8)\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(str[j])\r
-          {\r
-          case '0':\r
-            binary += "000";\r
-            break;\r
-          case '1':\r
-            binary += "001";\r
-            break;\r
-          case '2':\r
-            binary += "010";\r
-            break;\r
-          case '3':\r
-            binary += "011";\r
-            break;\r
-          case '4':\r
-            binary += "100";\r
-            break;\r
-          case '5':\r
-            binary += "101";\r
-            break;\r
-          case '6':\r
-            binary += "110";\r
-            break;\r
-          case '7':\r
-            binary += "111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid octal character in string " + str);\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      else\r
-      {\r
-        for (unsigned j = i; j < str.size(); j++)\r
-        {\r
-          switch(tolower(str[j]))\r
-          {\r
-          case '0':\r
-            binary += "0000";\r
-            break;\r
-          case '1':\r
-            binary += "0001";\r
-            break;\r
-          case '2':\r
-            binary += "0010";\r
-            break;\r
-          case '3':\r
-            binary += "0011";\r
-            break;\r
-          case '4':\r
-            binary += "0100";\r
-            break;\r
-          case '5':\r
-            binary += "0101";\r
-            break;\r
-          case '6':\r
-            binary += "0110";\r
-            break;\r
-          case '7':\r
-            binary += "0111";\r
-            break;\r
-          case '8':\r
-            binary += "1000";\r
-            break;\r
-          case '9':\r
-            binary += "1001";\r
-            break;\r
-          case 'a':\r
-            binary += "1010";\r
-            break;\r
-          case 'b':\r
-            binary += "1011";\r
-            break;\r
-          case 'c':\r
-            binary += "1100";\r
-            break;\r
-          case 'd':\r
-            binary += "1101";\r
-            break;\r
-          case 'e':\r
-            binary += "1110";\r
-            break;\r
-          case 'f':\r
-            binary += "1111";\r
-            break;\r
-          default:\r
-            throw std::invalid_argument("invalid hex character in string " + str);\r
-            break;\r
-          }\r
-        }\r
-      }\r
-      // now zero-extend to the right number of bits for the type\r
-      while (binary.size() < sizeof(T)*8)\r
-        binary.insert((std::string::size_type)0, 1, '0');\r
-      // now convert the value\r
-      for (unsigned j = 0; j < binary.size(); j++)\r
-      {\r
-        val *= 2;\r
-        int ch = from_char[(unsigned char)binary[j]] ;\r
-        val += T(ch);\r
-      }\r
-    }\r
-    else\r
-    {\r
-      // now scan for a sign and find whether this is a negative number\r
-      if (i < str.size())\r
-      {\r
-        switch (str[i])\r
-        {\r
-        case '-':\r
-          throw std::invalid_argument("invalid sign character in string " + str + " for unsigned value");\r
-          i++;\r
-          break;\r
-        case '+':\r
-          i++;\r
-          break;\r
-        }\r
-      }\r
-      for (; i < str.size(); i++)\r
-      {\r
-        val *= T(radix);\r
-        int ch = from_char[(unsigned char)str[i]] ;\r
-        if (ch == -1 || (unsigned)ch >= radix)\r
-        {\r
-          throw std::invalid_argument("invalid character in string " + str);\r
-        }\r
-        val += T(ch);\r
-      }\r
-    }\r
-    return val;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // exported functions\r
-\r
-  short string_to_short(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return svalue<short>(str, radix);\r
-  }\r
-\r
-  unsigned short string_to_unsigned_short(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return uvalue<unsigned short>(str, radix);\r
-  }\r
-\r
-  int string_to_int(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return svalue<int>(str, radix);\r
-  }\r
-\r
-  unsigned string_to_unsigned(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return uvalue<unsigned>(str, radix);\r
-  }\r
-\r
-  long string_to_long(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return svalue<long>(str, radix);\r
-  }\r
-\r
-  unsigned long string_to_unsigned_long(const std::string& str, unsigned radix)\r
-    throw(std::invalid_argument)\r
-  {\r
-    return uvalue<unsigned long>(str, radix);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_int.hpp"
+#include <ctype.h>
+#include <stdlib.h>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // character mappings
+
+  static char to_char [] = "0123456789abcdefghijklmnopqrstuvwxyz";
+  static int from_char [] = 
+  {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+    -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+    25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+  };
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Conversions to string
+  // Local generic routines
+
+  // signed version of the generic image generation function for all integer types
+  template<typename T>
+  static std::string simage (T i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    if (radix < 2 || radix > 36)
+      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+    // untangle all the options
+    bool hashed = false;
+    bool binary = false;
+    bool octal = false;
+    bool hex = false;
+    switch(display)
+    {
+    case radix_none:
+      break;
+    case radix_hash_style:
+      hashed = radix != 10;
+      break;
+    case radix_hash_style_all:
+      hashed = true;
+      break;
+    case radix_c_style:
+      if (radix == 16)
+        hex = true;
+      else if (radix == 8)
+        octal = true;
+      else if (radix == 2)
+        binary = true;
+      break;
+    case radix_c_style_or_hash:
+      if (radix == 16)
+        hex = true;
+      else if (radix == 8)
+        octal = true;
+      else if (radix == 2)
+        binary = true;
+      else if (radix != 10)
+        hashed = true;
+      break;
+    default:
+      throw std::invalid_argument("invalid radix display value");
+    }
+    // create constants of the same type as the template parameter to avoid type mismatches
+    const T t_zero(0);
+    const T t_radix(radix);
+    // the C representations for binary, octal and hex use 2's-complement representation
+    // all other represenations use sign-magnitude
+    std::string result;
+    if (hex || octal || binary)
+    {
+      // bit-pattern representation
+      // this is the binary representation optionally shown in octal or hex
+      // first generate the binary by masking the bits
+      // ensure that it has at least one bit!
+      for (T mask(1); ; mask <<= 1)
+      {
+        result.insert((std::string::size_type)0, 1, i & mask ? '1' : '0');
+        if (mask == t_zero) break;
+      }
+      // the result is now the full width of the type - e.g. int will give a 32-bit result
+      // now interpret this as either binary, octal or hex and add the prefix
+      if (binary)
+      {
+        // the result is already binary - but the width may be wrong
+        // if this is still smaller than the width field, sign extend
+        // otherwise trim down to either the width or the smallest string that preserves the value
+        while (result.size() < width)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        while (result.size() > width)
+        {
+          // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+          if (result.size() <= 2) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        // add the prefix
+        result.insert((std::string::size_type)0, "0b");
+      }
+      else if (octal)
+      {
+        // the result is currently binary - but before converting get the width right
+        // the width is expressed in octal digits so make the binary 3 times this
+        // if this is still smaller than the width field, sign extend
+        // otherwise trim down to either the width or the smallest string that preserves the value
+        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
+        while (result.size() < 3*width)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        while (result.size() > 3*width)
+        {
+          // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+          if (result.size() <= 2) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        while (result.size() % 3 != 0)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        // now convert to octal
+        std::string octal_result;
+        for (unsigned i = 0; i < result.size()/3; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*3] == '0')
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '0';
+              else
+                octal_result += '1';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '2';
+              else
+                octal_result += '3';
+            }
+          }
+          else
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '4';
+              else
+                octal_result += '5';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '6';
+              else
+                octal_result += '7';
+            }
+          }
+        }
+        result = octal_result;
+        // add the prefix
+        result.insert((std::string::size_type)0, "0");
+      }
+      else
+      {
+        // hex - similar to octal
+        while (result.size() < 4*width)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        while (result.size() > 4*width)
+        {
+          // do not trim to less than 2 bits (sign plus 1-bit magnitude)
+          if (result.size() <= 2) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != result[1]) break;
+          result.erase(0,1);
+        }
+        while (result.size() % 4 != 0)
+          result.insert((std::string::size_type)0, 1, result[0]);
+        // now convert to hex
+        std::string hex_result;
+        for (unsigned i = 0; i < result.size()/4; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*4] == '0')
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '0';
+                else
+                  hex_result += '1';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '2';
+                else
+                  hex_result += '3';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '4';
+                else
+                  hex_result += '5';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '6';
+                else
+                  hex_result += '7';
+              }
+            }
+          }
+          else
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '8';
+                else
+                  hex_result += '9';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'a';
+                else
+                  hex_result += 'b';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'c';
+                else
+                  hex_result += 'd';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'e';
+                else
+                  hex_result += 'f';
+              }
+            }
+          }
+        }
+        result = hex_result;
+        // add the prefix
+        result.insert((std::string::size_type)0, "0x");
+      }
+    }
+    else
+    {
+      // convert to sign-magnitude
+      // the representation is:
+      // [radix#][sign]magnitude
+      bool negative = i < t_zero;
+      // create a representation of the magnitude by successive division
+      do
+      {
+        T ch = abs(i % t_radix);
+        i /= t_radix;
+        result.insert((std::string::size_type)0, 1, to_char[ch]);
+      }
+      while(i != t_zero || result.size() < width);
+      // add the prefixes
+      // add a sign only for negative values
+      if (negative)
+        result.insert((std::string::size_type)0, 1, '-');
+      // then prefix everything with the radix if the hashed representation was requested
+      if (hashed)
+        result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");
+    }
+    return result;
+  }
+
+  // unsigned version
+  template<typename T>
+  static std::string uimage (T i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    if (radix < 2 || radix > 36)
+      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+    // untangle all the options
+    bool hashed = false;
+    bool binary = false;
+    bool octal = false;
+    bool hex = false;
+    switch(display)
+    {
+    case radix_none:
+      break;
+    case radix_hash_style:
+      hashed = radix != 10;
+      break;
+    case radix_hash_style_all:
+      hashed = true;
+      break;
+    case radix_c_style:
+      if (radix == 16)
+        hex = true;
+      else if (radix == 8)
+        octal = true;
+      else if (radix == 2)
+        binary = true;
+      break;
+    case radix_c_style_or_hash:
+      if (radix == 16)
+        hex = true;
+      else if (radix == 8)
+        octal = true;
+      else if (radix == 2)
+        binary = true;
+      else if (radix != 10)
+        hashed = true;
+      break;
+    default:
+      throw std::invalid_argument("invalid radix display value");
+    }
+    // create constants of the same type as the template parameter to avoid type mismatches
+    const T t_zero(0);
+    const T t_radix(radix);
+    // the C representations for binary, octal and hex use 2's-complement representation
+    // all other represenations use sign-magnitude
+    std::string result;
+    if (hex || octal || binary)
+    {
+      // bit-pattern representation
+      // this is the binary representation optionally shown in octal or hex
+      // first generate the binary by masking the bits
+      // ensure at least one bit
+      for (T mask(1); ; mask <<= 1)
+      {
+        result.insert((std::string::size_type)0, 1, i & mask ? '1' : '0');
+        if (mask == t_zero) break;
+      }
+      // the result is now the full width of the type - e.g. int will give a 32-bit result
+      // now interpret this as either binary, octal or hex and add the prefix
+      if (binary)
+      {
+        // the result is already binary - but the width may be wrong
+        // if this is still smaller than the width field, zero extend
+        // otherwise trim down to either the width or the smallest string that preserves the value
+        while (result.size() < width)
+          result.insert((std::string::size_type)0, 1, '0');
+        while (result.size() > width)
+        {
+          // do not trim to less than 1 bit (1-bit magnitude)
+          if (result.size() <= 1) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != '0') break;
+          result.erase(0,1);
+        }
+        // add the prefix
+        result.insert((std::string::size_type)0, "0b");
+      }
+      else if (octal)
+      {
+        // the result is currently binary - but before converting get the width right
+        // the width is expressed in octal digits so make the binary 3 times this
+        // if this is still smaller than the width field, sign extend
+        // otherwise trim down to either the width or the smallest string that preserves the value
+        // also ensure that the binary is a multiple of 3 bits to make the conversion to octal easier
+        while (result.size() < 3*width)
+          result.insert((std::string::size_type)0, 1, '0');
+        while (result.size() > 3*width)
+        {
+          // do not trim to less than 1 bit (1-bit magnitude)
+          if (result.size() <= 1) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != '0') break;
+          result.erase(0,1);
+        }
+        while (result.size() % 3 != 0)
+          result.insert((std::string::size_type)0, 1, '0');
+        // now convert to octal
+        std::string octal_result;
+        for (unsigned i = 0; i < result.size()/3; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*3] == '0')
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '0';
+              else
+                octal_result += '1';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '2';
+              else
+                octal_result += '3';
+            }
+          }
+          else
+          {
+            if (result[i*3+1] == '0')
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '4';
+              else
+                octal_result += '5';
+            }
+            else
+            {
+              if (result[i*3+2] == '0')
+                octal_result += '6';
+              else
+                octal_result += '7';
+            }
+          }
+        }
+        result = octal_result;
+        // add the prefix if the leading digit is not already 0
+        if (result.empty() || result[0] != '0') result.insert((std::string::size_type)0, "0");
+      }
+      else
+      {
+        // similar to octal
+        while (result.size() < 4*width)
+          result.insert((std::string::size_type)0, 1, '0');
+        while (result.size() > 4*width)
+        {
+          // do not trim to less than 1 bit (1-bit magnitude)
+          if (result.size() <= 1) break;
+          // only trim if it doesn't change the sign and therefore the value
+          if (result[0] != '0') break;
+          result.erase(0,1);
+        }
+        while (result.size() % 4 != 0)
+          result.insert((std::string::size_type)0, 1, '0');
+        // now convert to hex
+        std::string hex_result;
+        for (unsigned i = 0; i < result.size()/4; i++)
+        {
+          // yuck - ugly or what?
+          if (result[i*4] == '0')
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '0';
+                else
+                  hex_result += '1';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '2';
+                else
+                  hex_result += '3';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '4';
+                else
+                  hex_result += '5';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '6';
+                else
+                  hex_result += '7';
+              }
+            }
+          }
+          else
+          {
+            if (result[i*4+1] == '0')
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += '8';
+                else
+                  hex_result += '9';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'a';
+                else
+                  hex_result += 'b';
+              }
+            }
+            else
+            {
+              if (result[i*4+2] == '0')
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'c';
+                else
+                  hex_result += 'd';
+              }
+              else
+              {
+                if (result[i*4+3] == '0')
+                  hex_result += 'e';
+                else
+                  hex_result += 'f';
+              }
+            }
+          }
+        }
+        result = hex_result;
+        // add the prefix
+        result.insert((std::string::size_type)0, "0x");
+      }
+    }
+    else
+    {
+      // convert to sign-magnitude
+      // the representation is:
+      // [radix#]magnitude
+      // create a representation of the magnitude by successive division
+      do
+      {
+        T ch = i % t_radix;
+        i /= t_radix;
+        result.insert((std::string::size_type)0, 1, to_char[(int)ch]);
+      }
+      while(i != t_zero || result.size() < width);
+      // prefix everything with the radix if the hashed representation was requested
+      if (hashed)
+        result.insert((std::string::size_type)0, unsigned_to_string(radix) + "#");
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // exported conversions to string
+
+  std::string short_to_string(short i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return simage(i, radix, display, width);
+  }
+
+  std::string unsigned_short_to_string(unsigned short i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return uimage(i, radix, display, width);
+  }
+
+  std::string int_to_string(int i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return simage(i, radix, display, width);
+  }
+
+  std::string unsigned_to_string(unsigned i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return uimage(i, radix, display, width);
+  }
+
+  std::string long_to_string(long i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return simage(i, radix, display, width);
+  }
+
+  std::string unsigned_long_to_string(unsigned long i, unsigned radix, radix_display_t display, unsigned width)
+    throw(std::invalid_argument)
+  {
+    return uimage(i, radix, display, width);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Conversions FROM string
+  // local template function
+  // Note: this has been copied and modified for the inf class - so any changes here must be made there too
+
+  // signed version
+  template<typename T>
+  static T svalue(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    if (radix != 0 && (radix < 2 || radix > 36))
+      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+    std::string::size_type i = 0;
+    // the radix passed as a parameter is just the default - it can be
+    // overridden by either the C prefix or the hash prefix. Note: a leading zero
+    // is the C-style prefix for octal - I only make this override the default
+    // when the default prefix is not specified
+    // First check for a C-style prefix
+    bool c_style = false;
+    if (i < str.size() && str[i] == '0')
+    {
+      // octal, binary or hex
+      if (i+1 < str.size() && tolower(str[i+1]) == 'x')
+      {
+        radix = 16;
+        i += 2;
+        c_style = true;
+      }
+      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')
+      {
+        radix = 2;
+        i += 2;
+        c_style = true;
+      }
+      else if (radix == 0)
+      {
+        radix = 8;
+        i += 1;
+        c_style = true;
+      }
+    }
+    // now check for a hash-style prefix if a C-style prefix was not found
+    if (i == 0)
+    {
+      // scan for the sequence {digits}#
+      bool hash_found = false;
+      std::string::size_type j = i;
+      for (; j < str.size(); j++)
+      {
+        if (!isdigit(str[j]))
+        {
+          if (str[j] == '#')
+            hash_found = true;
+          break;
+        }
+      }
+      if (hash_found)
+      {
+        // use the hash prefix to define the radix
+        // i points to the start of the radix and j points to the # character
+        std::string slice = str.substr(i, j-i);
+        radix = string_to_unsigned(slice);
+        i = j+1;
+      }
+    }
+    if (radix == 0)
+      radix = 10;
+    if (radix < 2 || radix > 36)
+      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+    T val(0);
+    if (c_style)
+    {
+      // the C style formats are bit patterns not integer values - these need
+      // to be sign-extended to get the right value
+      std::string binary;
+      if (radix == 2)
+      {
+        for (std::string::size_type j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += '0';
+            break;
+          case '1':
+            binary += '1';
+            break;
+          default:
+            throw std::invalid_argument("invalid binary character in string " + str);
+            break;
+          }
+        }
+      }
+      else if (radix == 8)
+      {
+        for (std::string::size_type j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += "000";
+            break;
+          case '1':
+            binary += "001";
+            break;
+          case '2':
+            binary += "010";
+            break;
+          case '3':
+            binary += "011";
+            break;
+          case '4':
+            binary += "100";
+            break;
+          case '5':
+            binary += "101";
+            break;
+          case '6':
+            binary += "110";
+            break;
+          case '7':
+            binary += "111";
+            break;
+          default:
+            throw std::invalid_argument("invalid octal character in string " + str);
+            break;
+          }
+        }
+      }
+      else
+      {
+        for (std::string::size_type j = i; j < str.size(); j++)
+        {
+          switch(tolower(str[j]))
+          {
+          case '0':
+            binary += "0000";
+            break;
+          case '1':
+            binary += "0001";
+            break;
+          case '2':
+            binary += "0010";
+            break;
+          case '3':
+            binary += "0011";
+            break;
+          case '4':
+            binary += "0100";
+            break;
+          case '5':
+            binary += "0101";
+            break;
+          case '6':
+            binary += "0110";
+            break;
+          case '7':
+            binary += "0111";
+            break;
+          case '8':
+            binary += "1000";
+            break;
+          case '9':
+            binary += "1001";
+            break;
+          case 'a':
+            binary += "1010";
+            break;
+          case 'b':
+            binary += "1011";
+            break;
+          case 'c':
+            binary += "1100";
+            break;
+          case 'd':
+            binary += "1101";
+            break;
+          case 'e':
+            binary += "1110";
+            break;
+          case 'f':
+            binary += "1111";
+            break;
+          default:
+            throw std::invalid_argument("invalid hex character in string " + str);
+            break;
+          }
+        }
+      }
+      // now sign-extend to the right number of bits for the type
+      while (binary.size() < sizeof(T)*8)
+        binary.insert((std::string::size_type)0, 1, binary.empty() ? '0' : binary[0]);
+      // now convert the value
+      for (std::string::size_type j = 0; j < binary.size(); j++)
+      {
+        val *= 2;
+        int ch = from_char[(unsigned char)binary[j]] ;
+        val += T(ch);
+      }
+    }
+    else
+    {
+      // now scan for a sign and find whether this is a negative number
+      bool negative = false;
+      if (i < str.size())
+      {
+        switch (str[i])
+        {
+        case '-':
+          negative = true;
+          i++;
+          break;
+        case '+':
+          i++;
+          break;
+        }
+      }
+      for (; i < str.size(); i++)
+      {
+        val *= T(radix);
+        int ch = from_char[(unsigned char)str[i]] ;
+        if (ch == -1 || (unsigned)ch >= radix)
+          throw std::invalid_argument("invalid character in string " + str);
+        val += T(ch);
+      }
+      if (negative)
+        val = -val;
+    }
+    return val;
+  }
+
+  // unsigned version
+  template<typename T>
+  static T uvalue(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    if (radix != 0 && (radix < 2 || radix > 36))
+      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+    unsigned i = 0;
+    // the radix passed as a parameter is just the default - it can be
+    // overridden by either the C prefix or the hash prefix. Note: a leading
+    // zero is the C-style prefix for octal - I only make this override the
+    // default when the default prefix is not specified
+    // First check for a C-style prefix
+    bool c_style = false;
+    if (i < str.size() && str[i] == '0')
+    {
+      // binary or hex
+      if (i+1 < str.size() && tolower(str[i+1]) == 'x')
+      {
+        radix = 16;
+        i += 2;
+        c_style = true;
+      }
+      else if (i+1 < str.size() && tolower(str[i+1]) == 'b')
+      {
+        radix = 2;
+        i += 2;
+        c_style = true;
+      }
+      else if (radix == 0)
+      {
+        radix = 8;
+        i += 1;
+        c_style = true;
+      }
+    }
+    // now check for a hash-style prefix if a C-style prefix was not found
+    if (i == 0)
+    {
+      // scan for the sequence {digits}#
+      bool hash_found = false;
+      unsigned j = i;
+      for (; j < str.size(); j++)
+      {
+        if (!isdigit(str[j]))
+        {
+          if (str[j] == '#')
+            hash_found = true;
+          break;
+        }
+      }
+      if (hash_found)
+      {
+        // use the hash prefix to define the radix
+        // i points to the start of the radix and j points to the # character
+        std::string slice = str.substr(i, j-i);
+        radix = string_to_unsigned(slice);
+        i = j+1;
+      }
+    }
+    if (radix == 0)
+      radix = 10;
+    if (radix < 2 || radix > 36)
+      throw std::invalid_argument("invalid radix value " + unsigned_to_string(radix));
+    T val(0);
+    if (c_style)
+    {
+      // the C style formats are bit patterns not integer values - these need
+      // to be sign-extended to get the right value
+      std::string binary;
+      if (radix == 2)
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += '0';
+            break;
+          case '1':
+            binary += '1';
+            break;
+          default:
+            throw std::invalid_argument("invalid hex character in string " + str);
+            break;
+          }
+        }
+      }
+      else if (radix == 8)
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(str[j])
+          {
+          case '0':
+            binary += "000";
+            break;
+          case '1':
+            binary += "001";
+            break;
+          case '2':
+            binary += "010";
+            break;
+          case '3':
+            binary += "011";
+            break;
+          case '4':
+            binary += "100";
+            break;
+          case '5':
+            binary += "101";
+            break;
+          case '6':
+            binary += "110";
+            break;
+          case '7':
+            binary += "111";
+            break;
+          default:
+            throw std::invalid_argument("invalid octal character in string " + str);
+            break;
+          }
+        }
+      }
+      else
+      {
+        for (unsigned j = i; j < str.size(); j++)
+        {
+          switch(tolower(str[j]))
+          {
+          case '0':
+            binary += "0000";
+            break;
+          case '1':
+            binary += "0001";
+            break;
+          case '2':
+            binary += "0010";
+            break;
+          case '3':
+            binary += "0011";
+            break;
+          case '4':
+            binary += "0100";
+            break;
+          case '5':
+            binary += "0101";
+            break;
+          case '6':
+            binary += "0110";
+            break;
+          case '7':
+            binary += "0111";
+            break;
+          case '8':
+            binary += "1000";
+            break;
+          case '9':
+            binary += "1001";
+            break;
+          case 'a':
+            binary += "1010";
+            break;
+          case 'b':
+            binary += "1011";
+            break;
+          case 'c':
+            binary += "1100";
+            break;
+          case 'd':
+            binary += "1101";
+            break;
+          case 'e':
+            binary += "1110";
+            break;
+          case 'f':
+            binary += "1111";
+            break;
+          default:
+            throw std::invalid_argument("invalid hex character in string " + str);
+            break;
+          }
+        }
+      }
+      // now zero-extend to the right number of bits for the type
+      while (binary.size() < sizeof(T)*8)
+        binary.insert((std::string::size_type)0, 1, '0');
+      // now convert the value
+      for (unsigned j = 0; j < binary.size(); j++)
+      {
+        val *= 2;
+        int ch = from_char[(unsigned char)binary[j]] ;
+        val += T(ch);
+      }
+    }
+    else
+    {
+      // now scan for a sign and find whether this is a negative number
+      if (i < str.size())
+      {
+        switch (str[i])
+        {
+        case '-':
+          throw std::invalid_argument("invalid sign character in string " + str + " for unsigned value");
+          i++;
+          break;
+        case '+':
+          i++;
+          break;
+        }
+      }
+      for (; i < str.size(); i++)
+      {
+        val *= T(radix);
+        int ch = from_char[(unsigned char)str[i]] ;
+        if (ch == -1 || (unsigned)ch >= radix)
+        {
+          throw std::invalid_argument("invalid character in string " + str);
+        }
+        val += T(ch);
+      }
+    }
+    return val;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // exported functions
+
+  short string_to_short(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return svalue<short>(str, radix);
+  }
+
+  unsigned short string_to_unsigned_short(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return uvalue<unsigned short>(str, radix);
+  }
+
+  int string_to_int(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return svalue<int>(str, radix);
+  }
+
+  unsigned string_to_unsigned(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return uvalue<unsigned>(str, radix);
+  }
+
+  long string_to_long(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return svalue<long>(str, radix);
+  }
+
+  unsigned long string_to_unsigned_long(const std::string& str, unsigned radix)
+    throw(std::invalid_argument)
+  {
+    return uvalue<unsigned long>(str, radix);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index a45b9821e045de285e6be5329dd37760bbf2f442..af790986780e2ec06bb37de72ac215f7130247ee 100644 (file)
-#ifndef STLPLUS_STRING_INT\r
-#define STLPLUS_STRING_INT\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Convert integer types to/from string\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Conversions of Integer types to string\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // The radix (i.e. base) for these conversions can be any value from base 2 to base 36\r
-  // specifying any other radix causes std::invalid_argument to be thrown\r
-\r
-  // The way in which the radix is displayed is defined in radix_types.hpp\r
-  // If any other value is used, std::invalid_argument is thrown\r
-\r
-  // The width argument specifies the number of numerical digits to use in the result\r
-  // This is a minimum - if the value requires more digits then it will be wider than the width argument\r
-  // However, if it is smaller, then it will be extended to the specified width\r
-  // Then, the radix display prefix is added to this width\r
-\r
-  // For example, using the hash representation of 0 in hex with width=4 gives:\r
-  // 16#0000 - so there's 4 digits in the number part\r
-\r
-  std::string short_to_string(short i,\r
-                              unsigned radix = 10,\r
-                              radix_display_t display = radix_c_style_or_hash,\r
-                              unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  std::string unsigned_short_to_string(unsigned short i,\r
-                                       unsigned radix = 10,\r
-                                       radix_display_t display = radix_c_style_or_hash,\r
-                                       unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  std::string int_to_string(int i,\r
-                            unsigned radix = 10,\r
-                            radix_display_t display = radix_c_style_or_hash,\r
-                            unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  std::string unsigned_to_string(unsigned i,\r
-                                 unsigned radix = 10,\r
-                                 radix_display_t display = radix_c_style_or_hash,\r
-                                 unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  std::string long_to_string(long i,\r
-                             unsigned radix = 10,\r
-                             radix_display_t display = radix_c_style_or_hash,\r
-                             unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  std::string unsigned_long_to_string(unsigned long i,\r
-                                      unsigned radix = 10,\r
-                                      radix_display_t display = radix_c_style_or_hash,\r
-                                      unsigned width = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Convert a string to an integer type\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // supports all the formats described above for the reverse conversion\r
-  // If the radix is set to zero, the conversions deduce the radix from the string representation\r
-  // So,\r
-  //   0b prefix is binary,\r
-  //   0 prefix is octal,\r
-  //   0x is hex\r
-  //   <base># prefix is my hash format\r
-  // The radix must be either zero as explained above, or in the range 2 to 16\r
-  // A non-zero radix should be used when the string value has no radix information and is non-decimal\r
-  // e.g. the hex value FEDCBA has no indication that it is hex, so specify radix 16\r
-  // Any other value of radix will cause std::invalid_argument to be thrown\r
-\r
-  short string_to_short(const std::string& value,\r
-                        unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  unsigned short string_to_unsigned_short(const std::string& value,\r
-                                          unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  int string_to_int(const std::string& value,\r
-                    unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  unsigned string_to_unsigned(const std::string& value,\r
-                              unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  long string_to_long(const std::string& value,\r
-                      unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  unsigned long string_to_unsigned_long(const std::string& value,\r
-                                        unsigned radix = 0)\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_INT
+#define STLPLUS_STRING_INT
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Convert integer types to/from string
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Conversions of Integer types to string
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // The radix (i.e. base) for these conversions can be any value from base 2 to base 36
+  // specifying any other radix causes std::invalid_argument to be thrown
+
+  // The way in which the radix is displayed is defined in radix_types.hpp
+  // If any other value is used, std::invalid_argument is thrown
+
+  // The width argument specifies the number of numerical digits to use in the result
+  // This is a minimum - if the value requires more digits then it will be wider than the width argument
+  // However, if it is smaller, then it will be extended to the specified width
+  // Then, the radix display prefix is added to this width
+
+  // For example, using the hash representation of 0 in hex with width=4 gives:
+  // 16#0000 - so there's 4 digits in the number part
+
+  std::string short_to_string(short i,
+                              unsigned radix = 10,
+                              radix_display_t display = radix_c_style_or_hash,
+                              unsigned width = 0)
+    throw(std::invalid_argument);
+
+  std::string unsigned_short_to_string(unsigned short i,
+                                       unsigned radix = 10,
+                                       radix_display_t display = radix_c_style_or_hash,
+                                       unsigned width = 0)
+    throw(std::invalid_argument);
+
+  std::string int_to_string(int i,
+                            unsigned radix = 10,
+                            radix_display_t display = radix_c_style_or_hash,
+                            unsigned width = 0)
+    throw(std::invalid_argument);
+
+  std::string unsigned_to_string(unsigned i,
+                                 unsigned radix = 10,
+                                 radix_display_t display = radix_c_style_or_hash,
+                                 unsigned width = 0)
+    throw(std::invalid_argument);
+
+  std::string long_to_string(long i,
+                             unsigned radix = 10,
+                             radix_display_t display = radix_c_style_or_hash,
+                             unsigned width = 0)
+    throw(std::invalid_argument);
+
+  std::string unsigned_long_to_string(unsigned long i,
+                                      unsigned radix = 10,
+                                      radix_display_t display = radix_c_style_or_hash,
+                                      unsigned width = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Convert a string to an integer type
+  ////////////////////////////////////////////////////////////////////////////////
+  // supports all the formats described above for the reverse conversion
+  // If the radix is set to zero, the conversions deduce the radix from the string representation
+  // So,
+  //   0b prefix is binary,
+  //   0 prefix is octal,
+  //   0x is hex
+  //   <base># prefix is my hash format
+  // The radix must be either zero as explained above, or in the range 2 to 16
+  // A non-zero radix should be used when the string value has no radix information and is non-decimal
+  // e.g. the hex value FEDCBA has no indication that it is hex, so specify radix 16
+  // Any other value of radix will cause std::invalid_argument to be thrown
+
+  short string_to_short(const std::string& value,
+                        unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  unsigned short string_to_unsigned_short(const std::string& value,
+                                          unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  int string_to_int(const std::string& value,
+                    unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  unsigned string_to_unsigned(const std::string& value,
+                              unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  long string_to_long(const std::string& value,
+                      unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  unsigned long string_to_unsigned_long(const std::string& value,
+                                        unsigned radix = 0)
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index 6728690fad34c90f118850bc2ba66c6958e03e8b..beaef76b7b4ac9e292bdb8df88fed0c6d49e3965 100644 (file)
@@ -1,28 +1,28 @@
-#ifndef STLPLUS_STRING_LIST\r
-#define STLPLUS_STRING_LIST\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a list\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <list>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string list_to_string(const std::list<T>& values,\r
-                             S to_string_fn,\r
-                             const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_list.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_LIST
+#define STLPLUS_STRING_LIST
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a list
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <list>
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string list_to_string(const std::list<T>& values,
+                             S to_string_fn,
+                             const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "string_list.tpp"
+#endif
index 061f427c99e42022018b30725d505eb018b92a2c..eebba421772189797239c6b431e92fee58b1af10 100644 (file)
@@ -1,24 +1,24 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   template implementations\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string list_to_string(const std::list<T>& values,\r
-                             S to_string_fn,\r
-                             const std::string& separator)\r
-  {\r
-    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   template implementations
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_sequence.hpp"
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string list_to_string(const std::list<T>& values,
+                             S to_string_fn,
+                             const std::string& separator)
+  {
+    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);
+  }
+
+} // end namespace stlplus
index 8bf7e8bd3453ff5347e0b081e56c156d9df8c751..64a6b227e279a761dab2424900dc82ea1106163d 100644 (file)
@@ -1,37 +1,37 @@
-#ifndef STLPLUS_STRING_MAP\r
-#define STLPLUS_STRING_MAP\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a map/multimap\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <map>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  std::string map_to_string(const std::map<K,T,C>& values,\r
-                            SK key_to_string_fn,\r
-                            ST value_to_string_fn,\r
-                            const std::string& pair_separator = ":",\r
-                            const std::string& separator = ",");\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  std::string multimap_to_string(const std::multimap<K,T,C>& values,\r
-                                 SK key_to_string_fn,\r
-                                 ST value_to_string_fn,\r
-                                 const std::string& pair_separator = ":",\r
-                                 const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_map.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_MAP
+#define STLPLUS_STRING_MAP
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a map/multimap
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <map>
+
+namespace stlplus
+{
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  std::string map_to_string(const std::map<K,T,C>& values,
+                            SK key_to_string_fn,
+                            ST value_to_string_fn,
+                            const std::string& pair_separator = ":",
+                            const std::string& separator = ",");
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  std::string multimap_to_string(const std::multimap<K,T,C>& values,
+                                 SK key_to_string_fn,
+                                 ST value_to_string_fn,
+                                 const std::string& pair_separator = ":",
+                                 const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "string_map.tpp"
+#endif
index 49cb51f868a9b0e8a14dc665f5f6f7e690cc0f41..ce7d2f0369eaea572e2c96893f1c6729bd73e86e 100644 (file)
@@ -1,45 +1,45 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // map\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  std::string map_to_string(const std::map<K,T,C>& values,\r
-                            SK key_to_string_fn,\r
-                            ST value_to_string_fn,\r
-                            const std::string& pair_separator,\r
-                            const std::string& separator)\r
-  {\r
-    return pair_sequence_to_string(values.begin(), values.end(),\r
-                                   key_to_string_fn, value_to_string_fn,\r
-                                   pair_separator, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // multimap\r
-\r
-  template<typename K, typename T, typename C, typename SK, typename ST>\r
-  std::string multimap_to_string(const std::multimap<K,T,C>& values,\r
-                                 SK key_to_string_fn,\r
-                                 ST value_to_string_fn,\r
-                                 const std::string& pair_separator,\r
-                                 const std::string& separator)\r
-  {\r
-    return pair_sequence_to_string(values.begin(), values.end(),\r
-                                   key_to_string_fn, value_to_string_fn,\r
-                                   pair_separator, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_sequence.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // map
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  std::string map_to_string(const std::map<K,T,C>& values,
+                            SK key_to_string_fn,
+                            ST value_to_string_fn,
+                            const std::string& pair_separator,
+                            const std::string& separator)
+  {
+    return pair_sequence_to_string(values.begin(), values.end(),
+                                   key_to_string_fn, value_to_string_fn,
+                                   pair_separator, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // multimap
+
+  template<typename K, typename T, typename C, typename SK, typename ST>
+  std::string multimap_to_string(const std::multimap<K,T,C>& values,
+                                 SK key_to_string_fn,
+                                 ST value_to_string_fn,
+                                 const std::string& pair_separator,
+                                 const std::string& separator)
+  {
+    return pair_sequence_to_string(values.begin(), values.end(),
+                                   key_to_string_fn, value_to_string_fn,
+                                   pair_separator, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+} // end namespace stlplus
index dd1fa2be737b74c1cef0c202a8d2981753d0ed29..1ab0e82565fbd569f5c67346046e6e19f71a9187 100644 (file)
@@ -1,31 +1,31 @@
-#ifndef STLPLUS_STRING_MATRIX\r
-#define STLPLUS_STRING_MATRIX\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a matrix\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "matrix.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string matrix_to_string(const matrix<T>& values,\r
-                               S to_string_fn,\r
-                               const std::string& column_separator = "|",\r
-                               const std::string& row_separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_matrix.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_MATRIX
+#define STLPLUS_STRING_MATRIX
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a matrix
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "matrix.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string matrix_to_string(const matrix<T>& values,
+                               S to_string_fn,
+                               const std::string& column_separator = "|",
+                               const std::string& row_separator = ",");
+
+} // end namespace stlplus
+
+#include "string_matrix.tpp"
+#endif
index 345d15c1194650be37d60caef23d689db35423e8..41859991a6cb0729200289992f6fac5887f490ad 100644 (file)
@@ -1,35 +1,35 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  template<typename T, typename S>\r
-  std::string matrix_to_string(const matrix<T>& values,\r
-                               S to_string_fn,\r
-                               const std::string& column_separator,\r
-                               const std::string& row_separator)\r
-  {\r
-    std::string result;\r
-    for (unsigned r = 0; r < values.rows(); r++)\r
-    {\r
-      if (r != 0) result += row_separator;\r
-      for (unsigned c = 0; c < values.columns(); c++)\r
-      {\r
-        if (c != 0) result += column_separator;\r
-        result += to_string_fn(values(r,c));\r
-      }\r
-    }\r
-    return result;\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  template<typename T, typename S>
+  std::string matrix_to_string(const matrix<T>& values,
+                               S to_string_fn,
+                               const std::string& column_separator,
+                               const std::string& row_separator)
+  {
+    std::string result;
+    for (unsigned r = 0; r < values.rows(); r++)
+    {
+      if (r != 0) result += row_separator;
+      for (unsigned c = 0; c < values.columns(); c++)
+      {
+        if (c != 0) result += column_separator;
+        result += to_string_fn(values(r,c));
+      }
+    }
+    return result;
+  }
+
+} // end namespace stlplus
+
index 177b53d7d226f6eef612e7a3d06659f8e73304d7..e7b092dec11748a49c9cca8bd9290642918cc35e 100644 (file)
@@ -1,31 +1,31 @@
-#ifndef STLPLUS_STRING_NTREE\r
-#define STLPLUS_STRING_NTREE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of an ntree\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "ntree.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string ntree_to_string(const ntree<T>& values,\r
-                              S to_string_fn,\r
-                              const std::string& separator = "|",\r
-                              const std::string& indent_string = "  ");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_ntree.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_NTREE
+#define STLPLUS_STRING_NTREE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of an ntree
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "ntree.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string ntree_to_string(const ntree<T>& values,
+                              S to_string_fn,
+                              const std::string& separator = "|",
+                              const std::string& indent_string = "  ");
+
+} // end namespace stlplus
+
+#include "string_ntree.tpp"
+#endif
index 040dad342be6a95df60b6f5b619e7bb6d5074bd2..1c62a4c1863f3e17f8f0e596ab5add8a38ce3911 100644 (file)
@@ -1,31 +1,31 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string ntree_to_string(const ntree<T>& values,\r
-                              S to_string_fn,\r
-                              const std::string& separator,\r
-                              const std::string& indent_string)\r
-  {\r
-    std::string result;\r
-    for (TYPENAME ntree<T>::const_prefix_iterator i = values.prefix_begin(); i != values.prefix_end(); i++)\r
-    {\r
-      if (i != values.prefix_begin()) result += separator;\r
-      for (unsigned indent = values.depth(i.simplify()); --indent; )\r
-        result += indent_string;\r
-      result += to_string_fn(*i);\r
-    }\r
-    return result;\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string ntree_to_string(const ntree<T>& values,
+                              S to_string_fn,
+                              const std::string& separator,
+                              const std::string& indent_string)
+  {
+    std::string result;
+    for (TYPENAME ntree<T>::const_prefix_iterator i = values.prefix_begin(); i != values.prefix_end(); i++)
+    {
+      if (i != values.prefix_begin()) result += separator;
+      for (unsigned indent = values.depth(i.simplify()); --indent; )
+        result += indent_string;
+      result += to_string_fn(*i);
+    }
+    return result;
+  }
+
+} // end namespace stlplus
+
index 483a0b16a861baff19d32a8dbd9c265dded12667..c55f51c6f279e2351fb45ddbac146bf106649182 100644 (file)
@@ -1,29 +1,29 @@
-#ifndef STLPLUS_STRING_PAIR\r
-#define STLPLUS_STRING_PAIR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a pair\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <map>\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename V1, typename V2, typename S1, typename S2>\r
-  std::string pair_to_string(const std::pair<V1,V2>& values,\r
-                             S1 to_string_fn1,\r
-                             S2 to_string_fn2,\r
-                             const std::string& separator = ":");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_pair.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_PAIR
+#define STLPLUS_STRING_PAIR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a pair
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <map>
+#include <string>
+
+namespace stlplus
+{
+
+  template<typename V1, typename V2, typename S1, typename S2>
+  std::string pair_to_string(const std::pair<V1,V2>& values,
+                             S1 to_string_fn1,
+                             S2 to_string_fn2,
+                             const std::string& separator = ":");
+
+} // end namespace stlplus
+
+#include "string_pair.tpp"
+#endif
index f458836a797968b257c3eb8caca54e511ebf80ec..cdeda5f717b07460196e964e52eaa46adbfa210a 100644 (file)
@@ -1,22 +1,22 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename V1, typename V2, typename S1, typename S2>\r
-  std::string pair_to_string(const std::pair<V1,V2>& values,\r
-                             S1 to_string_fn1,\r
-                             S2 to_string_fn2,\r
-                             const std::string& separator)\r
-  {\r
-    return to_string_fn1(values.first) + separator + to_string_fn2(values.second);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename V1, typename V2, typename S1, typename S2>
+  std::string pair_to_string(const std::pair<V1,V2>& values,
+                             S1 to_string_fn1,
+                             S2 to_string_fn2,
+                             const std::string& separator)
+  {
+    return to_string_fn1(values.first) + separator + to_string_fn2(values.second);
+  }
+
+} // end namespace stlplus
index 21700002b71ca2113b1fd88c174167031144ba78..abdc825cc287effc4dfea9c304633a1c51a8f405 100644 (file)
@@ -1,30 +1,30 @@
-#ifndef STLPLUS_STRING_POINTER\r
-#define STLPLUS_STRING_POINTER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of an object pointed to\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template <typename T, typename S>\r
-  std::string pointer_to_string(const T* value,\r
-                                S to_string_fn,\r
-                                const std::string& null_string = "<null>",\r
-                                const std::string& prefix = "(",\r
-                                const std::string& suffix = ")");\r
-\r
-\r
-}\r
-\r
-#include "string_pointer.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_POINTER
+#define STLPLUS_STRING_POINTER
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of an object pointed to
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  template <typename T, typename S>
+  std::string pointer_to_string(const T* value,
+                                S to_string_fn,
+                                const std::string& null_string = "<null>",
+                                const std::string& prefix = "(",
+                                const std::string& suffix = ")");
+
+
+}
+
+#include "string_pointer.tpp"
+#endif
index d77a902fcb6def022ebb1c591dc56064ac076858..cd3e5b2783222d3a8aa17a5c27ad6aba7df8bdd3 100644 (file)
@@ -1,24 +1,24 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template <typename T, typename S>\r
-  std::string pointer_to_string(const T* value,\r
-                                S to_string_fn,\r
-                                const std::string& null_string,\r
-                                const std::string& prefix,\r
-                                const std::string& suffix)\r
-  {\r
-    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include <string>
+
+namespace stlplus
+{
+
+  template <typename T, typename S>
+  std::string pointer_to_string(const T* value,
+                                S to_string_fn,
+                                const std::string& null_string,
+                                const std::string& prefix,
+                                const std::string& suffix)
+  {
+    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;
+  }
+
+} // end namespace stlplus
index f029031e65e66f0d45cfaa3ab1b6957312d75be1..591692edf31aa185e07664d41cc55781b58dfb1a 100644 (file)
@@ -1,45 +1,45 @@
-#ifndef STLPLUS_STRING_SEQUENCE\r
-#define STLPLUS_STRING_SEQUENCE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate string representations of sequences represented by forward iterators\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any forward iterator sequence\r
-\r
-  template <typename I, typename S>\r
-  std::string sequence_to_string(I begin,\r
-                                 I end, \r
-                                 S to_string,\r
-                                 const std::string& separator);\r
-\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any forward iterator sequence of pairs\r
-\r
-  template <typename I, typename S1, typename S2>\r
-  std::string pair_sequence_to_string(I begin,\r
-                                      I end,\r
-                                      S1 to_string_fn1,\r
-                                      S2 to_string_fn2,\r
-                                      const std::string& pair_separator,\r
-                                      const std::string& separator);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_sequence.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_SEQUENCE
+#define STLPLUS_STRING_SEQUENCE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate string representations of sequences represented by forward iterators
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any forward iterator sequence
+
+  template <typename I, typename S>
+  std::string sequence_to_string(I begin,
+                                 I end, 
+                                 S to_string,
+                                 const std::string& separator);
+
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any forward iterator sequence of pairs
+
+  template <typename I, typename S1, typename S2>
+  std::string pair_sequence_to_string(I begin,
+                                      I end,
+                                      S1 to_string_fn1,
+                                      S2 to_string_fn2,
+                                      const std::string& pair_separator,
+                                      const std::string& separator);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "string_sequence.tpp"
+#endif
index 0bc522e355093fc1cf5bf6276696bbaf6f7c051c..7c9c82756b3fea3074d4509dd7b3524b78aea674 100644 (file)
@@ -1,54 +1,54 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_pair.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any forward iterator sequence\r
-\r
-  template <typename I, typename S>\r
-  std::string sequence_to_string(I begin,\r
-                                 I end, \r
-                                 S to_string,\r
-                                 const std::string& separator)\r
-  {\r
-    std::string result;\r
-    for (I i = begin; i != end; i++)\r
-    {\r
-      if (i != begin) result += separator;\r
-      result += to_string(*i);\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // any sequence where the value is a pair\r
-\r
-  template <typename I, typename S1, typename S2>\r
-  std::string pair_sequence_to_string(I begin,\r
-                                      I end,\r
-                                      S1 to_string_fn1,\r
-                                      S2 to_string_fn2,\r
-                                      const std::string& pair_separator,\r
-                                      const std::string& separator)\r
-  {\r
-    std::string result;\r
-    for (I i = begin; i != end; i++)\r
-    {\r
-      if (i != begin) result += separator;\r
-      result += pair_to_string(*i, to_string_fn1, to_string_fn2, pair_separator);\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_pair.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any forward iterator sequence
+
+  template <typename I, typename S>
+  std::string sequence_to_string(I begin,
+                                 I end, 
+                                 S to_string,
+                                 const std::string& separator)
+  {
+    std::string result;
+    for (I i = begin; i != end; i++)
+    {
+      if (i != begin) result += separator;
+      result += to_string(*i);
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // any sequence where the value is a pair
+
+  template <typename I, typename S1, typename S2>
+  std::string pair_sequence_to_string(I begin,
+                                      I end,
+                                      S1 to_string_fn1,
+                                      S2 to_string_fn2,
+                                      const std::string& pair_separator,
+                                      const std::string& separator)
+  {
+    std::string result;
+    for (I i = begin; i != end; i++)
+    {
+      if (i != begin) result += separator;
+      result += pair_to_string(*i, to_string_fn1, to_string_fn2, pair_separator);
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index ce06768ae34e0a0448ddec3217a3fc47a6ad4c9f..8c155439c6e93ae4a3f96c529b113b8bcd13fa3d 100644 (file)
@@ -1,33 +1,33 @@
-#ifndef STLPLUS_STRING_SET\r
-#define STLPLUS_STRING_SET\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a set/multiset\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <set>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename K, typename C, typename S>\r
-  std::string set_to_string(const std::set<K,C>& values,\r
-                            S to_string_fn,\r
-                            const std::string& separator = ",");\r
-\r
-  template<typename K, typename C, typename S>\r
-  std::string multiset_to_string(const std::multiset<K,C>& values,\r
-                                 S to_string_fn,\r
-                                 const std::string& separator = ",");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_set.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_SET
+#define STLPLUS_STRING_SET
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a set/multiset
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <set>
+
+namespace stlplus
+{
+
+  template<typename K, typename C, typename S>
+  std::string set_to_string(const std::set<K,C>& values,
+                            S to_string_fn,
+                            const std::string& separator = ",");
+
+  template<typename K, typename C, typename S>
+  std::string multiset_to_string(const std::multiset<K,C>& values,
+                                 S to_string_fn,
+                                 const std::string& separator = ",");
+
+} // end namespace stlplus
+
+#include "string_set.tpp"
+#endif
index d7c7e806d186380d8028e1865c2cfc71bcc5c5de..8dd065b0c170f877eff742141b2ce18d1709e327 100644 (file)
@@ -1,39 +1,39 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   template implementations\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // set\r
-\r
-  template<typename K, typename C, typename S>\r
-  std::string set_to_string(const std::set<K,C>& values,\r
-                            S to_string_fn,\r
-                            const std::string& separator)\r
-  {\r
-    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // multiset\r
-\r
-  template<typename K, typename C, typename S>\r
-  std::string multiset_to_string(const std::multiset<K,C>& values,\r
-                                 S to_string_fn,\r
-                                 const std::string& separator)\r
-  {\r
-    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   template implementations
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_sequence.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // set
+
+  template<typename K, typename C, typename S>
+  std::string set_to_string(const std::set<K,C>& values,
+                            S to_string_fn,
+                            const std::string& separator)
+  {
+    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // multiset
+
+  template<typename K, typename C, typename S>
+  std::string multiset_to_string(const std::multiset<K,C>& values,
+                                 S to_string_fn,
+                                 const std::string& separator)
+  {
+    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+} // end namespace stlplus
index 813432cd8b1884d683d90884e185bd14b7ad22b8..b8d07d89485cf13317453fa6bbf7c97ab233d02c 100644 (file)
@@ -1,47 +1,47 @@
-#ifndef STLPLUS_STRING_SIMPLE_PTR\r
-#define STLPLUS_STRING_SIMPLE_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a smart pointer\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "simple_ptr.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string simple_ptr_to_string(const simple_ptr<T>& value,\r
-                                  S to_string_fn,\r
-                                  const std::string& null_string = "<null>",\r
-                                  const std::string& prefix = "(",\r
-                                  const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  std::string simple_ptr_clone_to_string(const simple_ptr_clone<T>& value,\r
-                                        S to_string_fn,\r
-                                        const std::string& null_string = "<null>",\r
-                                        const std::string& prefix = "(",\r
-                                        const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  std::string simple_ptr__nocopy_to_string(const simple_ptr_nocopy<T>& value,\r
-                                          S to_string_fn,\r
-                                          const std::string& null_string = "<null>",\r
-                                          const std::string& prefix = "(",\r
-                                          const std::string& suffix = ")");\r
-\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_simple_ptr.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_SIMPLE_PTR
+#define STLPLUS_STRING_SIMPLE_PTR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a smart pointer
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "simple_ptr.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string simple_ptr_to_string(const simple_ptr<T>& value,
+                                  S to_string_fn,
+                                  const std::string& null_string = "<null>",
+                                  const std::string& prefix = "(",
+                                  const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  std::string simple_ptr_clone_to_string(const simple_ptr_clone<T>& value,
+                                        S to_string_fn,
+                                        const std::string& null_string = "<null>",
+                                        const std::string& prefix = "(",
+                                        const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  std::string simple_ptr__nocopy_to_string(const simple_ptr_nocopy<T>& value,
+                                          S to_string_fn,
+                                          const std::string& null_string = "<null>",
+                                          const std::string& prefix = "(",
+                                          const std::string& suffix = ")");
+
+
+} // end namespace stlplus
+
+#include "string_simple_ptr.tpp"
+#endif
index 7da84afc0f63006a2bce023686cf516460248f9c..2334b7f0addc241a95231f6d522412c5ebc03461 100644 (file)
@@ -1,44 +1,44 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string simple_ptr_to_string(const simple_ptr<T>& value,\r
-                                  S to_string_fn,\r
-                                  const std::string& null_string,\r
-                                  const std::string& prefix,\r
-                                  const std::string& suffix)\r
-  {\r
-    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  std::string simple_ptr_clone_to_string(const simple_ptr_clone<T>& value,\r
-                                        S to_string_fn,\r
-                                        const std::string& null_string,\r
-                                        const std::string& prefix,\r
-                                        const std::string& suffix)\r
-  {\r
-    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  std::string simple_ptr_nocopy_to_string(const simple_ptr_nocopy<T>& value,\r
-                                         S to_string_fn,\r
-                                         const std::string& null_string,\r
-                                         const std::string& prefix,\r
-                                         const std::string& suffix)\r
-  {\r
-    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string simple_ptr_to_string(const simple_ptr<T>& value,
+                                  S to_string_fn,
+                                  const std::string& null_string,
+                                  const std::string& prefix,
+                                  const std::string& suffix)
+  {
+    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;
+  }
+
+  template<typename T, typename S>
+  std::string simple_ptr_clone_to_string(const simple_ptr_clone<T>& value,
+                                        S to_string_fn,
+                                        const std::string& null_string,
+                                        const std::string& prefix,
+                                        const std::string& suffix)
+  {
+    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;
+  }
+
+  template<typename T, typename S>
+  std::string simple_ptr_nocopy_to_string(const simple_ptr_nocopy<T>& value,
+                                         S to_string_fn,
+                                         const std::string& null_string,
+                                         const std::string& prefix,
+                                         const std::string& suffix)
+  {
+    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;
+  }
+
+} // end namespace stlplus
+
index 3a5e253cb3900f7d5c791bc716b19fd9d1e63ec6..ea8cdd20ca86c72b1690522984340112305e7752 100644 (file)
@@ -1,47 +1,47 @@
-#ifndef STLPLUS_STRING_SMART_PTR\r
-#define STLPLUS_STRING_SMART_PTR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a smart pointer\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "smart_ptr.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string smart_ptr_to_string(const smart_ptr<T>& value,\r
-                                  S to_string_fn,\r
-                                  const std::string& null_string = "<null>",\r
-                                  const std::string& prefix = "(",\r
-                                  const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  std::string smart_ptr_clone_to_string(const smart_ptr_clone<T>& value,\r
-                                        S to_string_fn,\r
-                                        const std::string& null_string = "<null>",\r
-                                        const std::string& prefix = "(",\r
-                                        const std::string& suffix = ")");\r
-\r
-  template<typename T, typename S>\r
-  std::string smart_ptr__nocopy_to_string(const smart_ptr_nocopy<T>& value,\r
-                                          S to_string_fn,\r
-                                          const std::string& null_string = "<null>",\r
-                                          const std::string& prefix = "(",\r
-                                          const std::string& suffix = ")");\r
-\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_smart_ptr.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_SMART_PTR
+#define STLPLUS_STRING_SMART_PTR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a smart pointer
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "smart_ptr.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string smart_ptr_to_string(const smart_ptr<T>& value,
+                                  S to_string_fn,
+                                  const std::string& null_string = "<null>",
+                                  const std::string& prefix = "(",
+                                  const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  std::string smart_ptr_clone_to_string(const smart_ptr_clone<T>& value,
+                                        S to_string_fn,
+                                        const std::string& null_string = "<null>",
+                                        const std::string& prefix = "(",
+                                        const std::string& suffix = ")");
+
+  template<typename T, typename S>
+  std::string smart_ptr__nocopy_to_string(const smart_ptr_nocopy<T>& value,
+                                          S to_string_fn,
+                                          const std::string& null_string = "<null>",
+                                          const std::string& prefix = "(",
+                                          const std::string& suffix = ")");
+
+
+} // end namespace stlplus
+
+#include "string_smart_ptr.tpp"
+#endif
index 7953fbf3f7587f4efca460cec2293f376c367166..994b363dd07912fdfef7b61f2ba936f7dc29b4a6 100644 (file)
@@ -1,44 +1,44 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string smart_ptr_to_string(const smart_ptr<T>& value,\r
-                                  S to_string_fn,\r
-                                  const std::string& null_string,\r
-                                  const std::string& prefix,\r
-                                  const std::string& suffix)\r
-  {\r
-    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  std::string smart_ptr_clone_to_string(const smart_ptr_clone<T>& value,\r
-                                        S to_string_fn,\r
-                                        const std::string& null_string,\r
-                                        const std::string& prefix,\r
-                                        const std::string& suffix)\r
-  {\r
-    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;\r
-  }\r
-\r
-  template<typename T, typename S>\r
-  std::string smart_ptr_nocopy_to_string(const smart_ptr_nocopy<T>& value,\r
-                                         S to_string_fn,\r
-                                         const std::string& null_string,\r
-                                         const std::string& prefix,\r
-                                         const std::string& suffix)\r
-  {\r
-    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string smart_ptr_to_string(const smart_ptr<T>& value,
+                                  S to_string_fn,
+                                  const std::string& null_string,
+                                  const std::string& prefix,
+                                  const std::string& suffix)
+  {
+    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;
+  }
+
+  template<typename T, typename S>
+  std::string smart_ptr_clone_to_string(const smart_ptr_clone<T>& value,
+                                        S to_string_fn,
+                                        const std::string& null_string,
+                                        const std::string& prefix,
+                                        const std::string& suffix)
+  {
+    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;
+  }
+
+  template<typename T, typename S>
+  std::string smart_ptr_nocopy_to_string(const smart_ptr_nocopy<T>& value,
+                                         S to_string_fn,
+                                         const std::string& null_string,
+                                         const std::string& prefix,
+                                         const std::string& suffix)
+  {
+    return value ? (prefix + to_string_fn(*value) + suffix) : null_string;
+  }
+
+} // end namespace stlplus
+
index 11e05fbc15b166c63a3ede3de1a2471f24c24e46..ef934971310bc6a4b586b6c977c13ee9fb307b41 100644 (file)
@@ -1,23 +1,23 @@
-#ifndef STLPLUS_STRING_STL\r
-#define STLPLUS_STRING_STL\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Template string conversions for pointers and STL containers\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "string_bitset.hpp"\r
-#include "string_list.hpp"\r
-#include "string_map.hpp"\r
-#include "string_pair.hpp"\r
-#include "string_sequence.hpp"\r
-#include "string_set.hpp"\r
-#include "string_string.hpp"\r
-#include "string_vector.hpp"\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_STL
+#define STLPLUS_STRING_STL
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Template string conversions for pointers and STL containers
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "string_bitset.hpp"
+#include "string_list.hpp"
+#include "string_map.hpp"
+#include "string_pair.hpp"
+#include "string_sequence.hpp"
+#include "string_set.hpp"
+#include "string_string.hpp"
+#include "string_vector.hpp"
+
+#endif
index bdcad7b67d659abeea29fefc70f8ab8aa7329fb8..23c4bcacc80b7ccf8d66f8caf084d1aafcd46132 100644 (file)
@@ -1,30 +1,30 @@
-#ifndef STLPLUS_STRING_STLPLUS\r
-#define STLPLUS_STRING_STLPLUS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Template string conversions for the STLplus containers\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// can be excluded to break the dependency on the containers library\r
-#ifndef NO_STLPLUS_CONTAINERS\r
-#include "string_digraph.hpp"\r
-#include "string_foursome.hpp"\r
-#include "string_hash.hpp"\r
-#include "string_matrix.hpp"\r
-#include "string_ntree.hpp"\r
-#include "string_smart_ptr.hpp"\r
-#include "string_triple.hpp"\r
-#endif\r
-\r
-// can be excluded to break the dependency on the portability library\r
-#ifndef NO_STLPLUS_INF\r
-#include "string_inf.hpp"\r
-#endif\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_STLPLUS
+#define STLPLUS_STRING_STLPLUS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Template string conversions for the STLplus containers
+
+////////////////////////////////////////////////////////////////////////////////
+
+// can be excluded to break the dependency on the containers library
+#ifndef NO_STLPLUS_CONTAINERS
+#include "string_digraph.hpp"
+#include "string_foursome.hpp"
+#include "string_hash.hpp"
+#include "string_matrix.hpp"
+#include "string_ntree.hpp"
+#include "string_smart_ptr.hpp"
+#include "string_triple.hpp"
+#endif
+
+// can be excluded to break the dependency on the portability library
+#ifndef NO_STLPLUS_INF
+#include "string_inf.hpp"
+#endif
+
+#endif
index 53e8189c0775d381f17d3908defb7d164acf905d..27d5f898c4d2000387c155c3d86694d3e7de2687 100644 (file)
@@ -1,22 +1,22 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_string.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // strings\r
-\r
-  std::string string_to_string(const std::string& value)\r
-  {\r
-    return value;\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_string.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // strings
+
+  std::string string_to_string(const std::string& value)
+  {
+    return value;
+  }
+
+} // end namespace stlplus
index 5f5b044e9d794aeacc0b22558144206d16f67c4f..522f698bc022be0b4d83e00bd2e34837a47eda8e 100644 (file)
@@ -1,26 +1,26 @@
-#ifndef STLPLUS_STRING_STRING\r
-#define STLPLUS_STRING_STRING\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Functions for converting C/STL strings to string\r
-\r
-//   This is necessary for completeness, e.g. for use in vector_to_string for vector<string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  std::string string_to_string(const std::string& value);\r
-\r
-}\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_STRING
+#define STLPLUS_STRING_STRING
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Functions for converting C/STL strings to string
+
+//   This is necessary for completeness, e.g. for use in vector_to_string for vector<string>
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <stdexcept>
+
+namespace stlplus
+{
+
+  std::string string_to_string(const std::string& value);
+
+}
+
+#endif
index c812789eba49c6829eec43f500e228f93f083f9f..030cf0af295c366d7aae19aa7abe2c5b5e4f2411 100644 (file)
@@ -1,32 +1,32 @@
-#ifndef STLPLUS_STRING_TRIPLE\r
-#define STLPLUS_STRING_TRIPLE\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a triple\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "triple.hpp"\r
-#include <string>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>\r
-  std::string triple_to_string(const triple<T1,T2,T3>& values,\r
-                               S1 to_string_fn1,\r
-                               S2 to_string_fn2,\r
-                               S3 to_string_fn3,\r
-                               const std::string& separator = ":");\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_triple.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_TRIPLE
+#define STLPLUS_STRING_TRIPLE
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a triple
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "triple.hpp"
+#include <string>
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>
+  std::string triple_to_string(const triple<T1,T2,T3>& values,
+                               S1 to_string_fn1,
+                               S2 to_string_fn2,
+                               S3 to_string_fn3,
+                               const std::string& separator = ":");
+
+} // end namespace stlplus
+
+#include "string_triple.tpp"
+#endif
index ddd574a108ecd83f4a10753490549d5e3f21854c..8cd1d932c2449b61de48b2ff63aefefb46bfe60c 100644 (file)
@@ -1,29 +1,29 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>\r
-  std::string triple_to_string(const triple<T1,T2,T3>& values,\r
-                               S1 to_string_fn1,\r
-                               S2 to_string_fn2,\r
-                               S3 to_string_fn3,\r
-                               const std::string& separator)\r
-  {\r
-    return \r
-      to_string_fn1(values.first) + \r
-      separator + \r
-      to_string_fn2(values.second) + \r
-      separator + \r
-      to_string_fn3(values.third);\r
-  }\r
-\r
-} // end namespace stlplus\r
-\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+
+namespace stlplus
+{
+
+  template<typename T1, typename T2, typename T3, typename S1, typename S2, typename S3>
+  std::string triple_to_string(const triple<T1,T2,T3>& values,
+                               S1 to_string_fn1,
+                               S2 to_string_fn2,
+                               S3 to_string_fn3,
+                               const std::string& separator)
+  {
+    return 
+      to_string_fn1(values.first) + 
+      separator + 
+      to_string_fn2(values.second) + 
+      separator + 
+      to_string_fn3(values.third);
+  }
+
+} // end namespace stlplus
+
index 9ff5345c7615958264c7160a92ac36e548e1cb9e..7e04824583bdbd4bb09743d03c73e357cf0886db 100644 (file)
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_utilities.hpp"\r
-#include "string_basic.hpp"\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  // added as a local copy to break the dependency on the portability library\r
-  static std::string local_dformat(const char* format, ...) throw(std::invalid_argument)\r
-  {\r
-    std::string formatted;\r
-    va_list args;\r
-    va_start(args, format);\r
-#ifdef MSWINDOWS\r
-    int length = 0;\r
-    char* buffer = 0;\r
-    for(int buffer_length = 256; ; buffer_length*=2)\r
-    {\r
-      buffer = (char*)malloc(buffer_length);\r
-      if (!buffer) throw std::invalid_argument("string_utilities");\r
-      length = _vsnprintf(buffer, buffer_length-1, format, args);\r
-      if (length >= 0)\r
-      {\r
-        buffer[length] = 0;\r
-        formatted += std::string(buffer);\r
-        free(buffer);\r
-        break;\r
-      }\r
-      free(buffer);\r
-    }\r
-#else\r
-    char* buffer = 0;\r
-    int length = vasprintf(&buffer, format, args);\r
-    if (!buffer) throw std::invalid_argument("string_utilities");\r
-    if (length >= 0)\r
-      formatted += std::string(buffer);\r
-    free(buffer);\r
-#endif\r
-    va_end(args);\r
-    if (length < 0) throw std::invalid_argument("string_utilities");\r
-    return formatted;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string pad(const std::string& str, alignment_t alignment, unsigned width, char padch)\r
-    throw(std::invalid_argument)\r
-  {\r
-    std::string result = str;\r
-    switch(alignment)\r
-    {\r
-    case align_left:\r
-    {\r
-      unsigned padding = width>str.size() ? width - str.size() : 0;\r
-      unsigned i = 0;\r
-      while (i++ < padding)\r
-        result.insert(result.end(), padch);\r
-      break;\r
-    }\r
-    case align_right:\r
-    {\r
-      unsigned padding = width>str.size() ? width - str.size() : 0;\r
-      unsigned i = 0;\r
-      while (i++ < padding)\r
-        result.insert(result.begin(), padch);\r
-      break;\r
-    }\r
-    case align_centre:\r
-    {\r
-      unsigned padding = width>str.size() ? width - str.size() : 0;\r
-      unsigned i = 0;\r
-      while (i++ < padding/2)\r
-        result.insert(result.end(), padch);\r
-      i--;\r
-      while (i++ < padding)\r
-        result.insert(result.begin(), padch);\r
-      break;\r
-    }\r
-    default:\r
-      throw std::invalid_argument("invalid alignment value");\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string trim_left(const std::string& val)\r
-  {\r
-    std::string result = val;\r
-    while (!result.empty() && isspace(result[0]))\r
-      result.erase(result.begin());\r
-    return result;\r
-  }\r
-\r
-  std::string trim_right(const std::string& val)\r
-  {\r
-    std::string result = val;\r
-    while (!result.empty() && isspace(result[result.size()-1]))\r
-      result.erase(result.end()-1);\r
-    return result;\r
-  }\r
-\r
-  std::string trim(const std::string& val)\r
-  {\r
-    std::string result = val;\r
-    while (!result.empty() && isspace(result[0]))\r
-      result.erase(result.begin());\r
-    while (!result.empty() && isspace(result[result.size()-1]))\r
-      result.erase(result.end()-1);\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string lowercase(const std::string& val)\r
-  {\r
-    std::string text = val;\r
-    for (unsigned i = 0; i < text.size(); i++)\r
-      text[i] = tolower(text[i]);\r
-    return text;\r
-  }\r
-\r
-  std::string uppercase(const std::string& val)\r
-  {\r
-    std::string text = val;\r
-    for (unsigned i = 0; i < text.size(); i++)\r
-      text[i] = toupper(text[i]);\r
-    return text;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string translate(const std::string& input, const std::string& from_set, const std::string& to_set)\r
-  {\r
-    std::string result;\r
-    for (unsigned i = 0; i < input.size(); i++)\r
-    {\r
-      char ch = input[i];\r
-      // check to see if the character is in the from set\r
-      std::string::size_type found = from_set.find(ch);\r
-      if (found == std::string::npos)\r
-      {\r
-        // not found so just copy across\r
-        result += ch;\r
-      }\r
-      else if (found < to_set.size())\r
-      {\r
-        // found and in range so translate\r
-        result += to_set[found];\r
-      }\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // WARNING: wheel re-invention follows\r
-  // Given that all shells perform wildcard matching, why don't the library writers put it in the C run-time????????\r
-  // The problem:\r
-  //   *  matches any number of characters - this is achieved by matching 1 and seeing if the remainder matches\r
-  //      if not, try 2 characters and see if the remainder matches etc.\r
-  //      this must be recursive, not iterative, so that multiple *s can appear in the same wildcard expression\r
-  //   ?  matches exactly one character so doesn't need the what-if approach\r
-  //   \  escapes special characters such as *, ? and [\r
-  //   [] matches exactly one character in the set - the difficulty is the set can contain ranges, e.g [a-zA-Z0-9]\r
-  //      a set cannot be empty and the ] character can be included by making it the first character\r
-\r
-  // function for testing whether a character matches a set\r
-  // I can't remember the exact rules and I have no definitive references but:\r
-  // a set contains characters, escaped characters (I think) and ranges in the form a-z\r
-  // The character '-' can only appear at the start of the set where it is not interpreted as a range\r
-  // This is a horrible mess - blame the Unix folks for making a hash of wildcards\r
-\r
-  static bool match_set (const std::string& set, char match)\r
-  {\r
-    // first expand any ranges and remove escape characters to make life more palatable\r
-    std::string simple_set;\r
-    for (std::string::const_iterator i = set.begin(); i != set.end(); ++i)\r
-    {\r
-      switch(*i)\r
-      {\r
-      case '-':\r
-      {\r
-        if (i == set.begin())\r
-        {\r
-          simple_set += *i;\r
-        }\r
-        else if (i+1 == set.end())\r
-        {\r
-          return false;\r
-        }\r
-        else\r
-        {\r
-          // found a set. The first character is already in the result, so first remove it (the set might be empty)\r
-          simple_set.erase(simple_set.end()-1);\r
-          char last = *++i;\r
-          for (char ch = *(i-2); ch <= last; ch++)\r
-          {\r
-            simple_set += ch;\r
-          }\r
-        }\r
-        break;\r
-      }\r
-      case '\\':\r
-        if (i+1 == set.end()) {return false;}\r
-        simple_set += *++i;\r
-        break;\r
-      default:\r
-        simple_set += *i;\r
-        break;\r
-      }\r
-    }\r
-    std::string::size_type result = simple_set.find(match);\r
-    return result != std::string::npos;\r
-  }\r
-\r
-  // the recursive bit - basically whenever a * is found you recursively call this for each candidate substring match\r
-  // until either it succeeds or you run out of string to match\r
-  // for each * in the wildcard another level of recursion is created\r
-\r
-  static bool match_remainder (const std::string& wild, std::string::const_iterator wildi,\r
-                               const std::string& match, std::string::const_iterator matchi)\r
-  {\r
-    //cerr << "match_remainder called at " << *matchi << " with wildcard " << *wildi << endl;\r
-    while (wildi != wild.end() && matchi != match.end())\r
-    {\r
-      //cerr << "trying to match " << *matchi << " with wildcard " << *wildi << endl;\r
-      switch(*wildi)\r
-      {\r
-      case '*':\r
-      {\r
-        ++wildi;\r
-        ++matchi;\r
-        for (std::string::const_iterator i = matchi; i != match.end(); ++i)\r
-        {\r
-          // deal with * at the end of the wildcard - there is no remainder then\r
-          if (wildi == wild.end())\r
-          {\r
-            if (i == match.end()-1)\r
-              return true;\r
-          }\r
-          else if (match_remainder(wild, wildi, match, i))\r
-          {\r
-            return true;\r
-          }\r
-        }\r
-        return false;\r
-      }\r
-      case '[':\r
-      {\r
-        // scan for the end of the set using a similar method for avoiding escaped characters\r
-        bool found = false;\r
-        std::string::const_iterator end = wildi + 1;\r
-        for (; !found && end != wild.end(); ++end)\r
-        {\r
-          switch(*end)\r
-          {\r
-          case ']':\r
-          {\r
-            // found the set, now match with its contents excluding the brackets\r
-            if (!match_set(wild.substr(wildi - wild.begin() + 1, end - wildi - 1), *matchi))\r
-              return false;\r
-            found = true;\r
-            break;\r
-          }\r
-          case '\\':\r
-            if (end == wild.end()-1)\r
-              return false;\r
-            ++end;\r
-            break;\r
-          default:\r
-            break;\r
-          }\r
-        }\r
-        if (!found)\r
-          return false;\r
-        ++matchi;\r
-        wildi = end;\r
-        break;\r
-      }\r
-      case '?':\r
-        ++wildi;\r
-        ++matchi;\r
-        break;\r
-      case '\\':\r
-        if (wildi == wild.end()-1)\r
-          return false;\r
-        ++wildi;\r
-        if (*wildi != *matchi)\r
-          return false;\r
-        ++wildi;\r
-        ++matchi;\r
-        break;\r
-      default:\r
-        if (*wildi != *matchi)\r
-          return false;\r
-        ++wildi;\r
-        ++matchi;\r
-        break;\r
-      }\r
-    }\r
-    bool result = wildi == wild.end() && matchi == match.end();\r
-    return result;\r
-  }\r
-\r
-  // like all recursions the exported function has a simpler interface than the\r
-  // recursive function and is just a 'seed' to the recursion itself\r
-\r
-  bool match_wildcard(const std::string& wild, const std::string& match)\r
-  {\r
-    return match_remainder(wild, wild.begin(), match, match.begin());\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::vector<std::string> split(const std::string& str, const std::string& splitter)\r
-  {\r
-    std::vector<std::string> result;\r
-    if (!str.empty())\r
-    {\r
-      for(std::string::size_type offset = 0;;)\r
-      {\r
-        std::string::size_type found = str.find(splitter, offset);\r
-        if (found != std::string::npos)\r
-        {\r
-          result.push_back(str.substr(offset, found-offset));\r
-          offset = found + splitter.size();\r
-        }\r
-        else\r
-        {\r
-          result.push_back(str.substr(offset, str.size()-offset));\r
-          break;\r
-        }\r
-      }\r
-    }\r
-    return result;\r
-  }\r
-\r
-  std::string join (const std::vector<std::string>& str,\r
-                    const std::string& joiner,\r
-                    const std::string& prefix,\r
-                    const std::string& suffix)\r
-  {\r
-    std::string result = prefix;\r
-    for (unsigned i = 0; i < str.size(); i++)\r
-    {\r
-      if (i) result += joiner;\r
-      result += str[i];\r
-    }\r
-    result += suffix;\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string display_bytes(long bytes)\r
-  {\r
-    std::string result;\r
-    if (bytes < 0)\r
-    {\r
-      result += '-';\r
-      bytes = -bytes;\r
-    }\r
-    static const long kB = 1024l;\r
-    static const long MB = kB * kB;\r
-    static const long GB = MB * kB;\r
-    if (bytes < kB)\r
-      result += local_dformat("%i", bytes);\r
-    else if (bytes < (10l * kB))\r
-      result += local_dformat("%.2fk", ((float)bytes / (float)kB));\r
-    else if (bytes < (100l * kB))\r
-      result += local_dformat("%.1fk", ((float)bytes / (float)kB));\r
-    else if (bytes < MB)\r
-      result += local_dformat("%.0fk", ((float)bytes / (float)kB));\r
-    else if (bytes < (10l * MB))\r
-      result += local_dformat("%.2fM", ((float)bytes / (float)MB));\r
-    else if (bytes < (100l * MB))\r
-      result += local_dformat("%.1fM", ((float)bytes / (float)MB));\r
-    else if (bytes < GB)\r
-      result += local_dformat("%.0fM", ((float)bytes / (float)MB));\r
-    else\r
-      result += local_dformat("%.2fG", ((float)bytes / (float)GB));\r
-    return result;\r
-  }\r
-\r
-  std::string display_time(time_t seconds)\r
-  {\r
-    unsigned minutes = (unsigned)seconds / 60;\r
-    seconds %= 60;\r
-    unsigned hours = minutes / 60;\r
-    minutes %= 60;\r
-    unsigned days = hours / 24;\r
-    hours %= 24;\r
-    unsigned weeks = days / 7;\r
-    days %= 7;\r
-    std::string result;\r
-    if (weeks > 0)\r
-    {\r
-      result += unsigned_to_string(weeks, 10, radix_none, 1);\r
-      result += "w ";\r
-    }\r
-    if (!result.empty() || days > 0)\r
-    {\r
-      result += unsigned_to_string(days, 10, radix_none, 1);\r
-      result += "d ";\r
-    }\r
-    if (!result.empty() || hours > 0)\r
-    {\r
-      result += unsigned_to_string(hours, 10, radix_none, 1);\r
-      result += ":";\r
-    }\r
-    if (!result.empty() || minutes > 0)\r
-    {\r
-      if (!result.empty())\r
-        result += unsigned_to_string(minutes, 10, radix_none, 2);\r
-      else\r
-        result += unsigned_to_string(minutes, 10, radix_none, 1);\r
-      result += ":";\r
-    }\r
-    if (!result.empty())\r
-      result += unsigned_to_string((unsigned)seconds, 10, radix_none, 2);\r
-    else\r
-    {\r
-      result += unsigned_to_string((unsigned)seconds, 10, radix_none, 1);\r
-      result += "s";\r
-    }\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_utilities.hpp"
+#include "string_basic.hpp"
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+namespace stlplus
+{
+
+  // added as a local copy to break the dependency on the portability library
+  static std::string local_dformat(const char* format, ...) throw(std::invalid_argument)
+  {
+    std::string formatted;
+    va_list args;
+    va_start(args, format);
+#ifdef MSWINDOWS
+    int length = 0;
+    char* buffer = 0;
+    for(int buffer_length = 256; ; buffer_length*=2)
+    {
+      buffer = (char*)malloc(buffer_length);
+      if (!buffer) throw std::invalid_argument("string_utilities");
+      length = _vsnprintf(buffer, buffer_length-1, format, args);
+      if (length >= 0)
+      {
+        buffer[length] = 0;
+        formatted += std::string(buffer);
+        free(buffer);
+        break;
+      }
+      free(buffer);
+    }
+#else
+    char* buffer = 0;
+    int length = vasprintf(&buffer, format, args);
+    if (!buffer) throw std::invalid_argument("string_utilities");
+    if (length >= 0)
+      formatted += std::string(buffer);
+    free(buffer);
+#endif
+    va_end(args);
+    if (length < 0) throw std::invalid_argument("string_utilities");
+    return formatted;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string pad(const std::string& str, alignment_t alignment, unsigned width, char padch)
+    throw(std::invalid_argument)
+  {
+    std::string result = str;
+    switch(alignment)
+    {
+    case align_left:
+    {
+      unsigned padding = width>str.size() ? width - str.size() : 0;
+      unsigned i = 0;
+      while (i++ < padding)
+        result.insert(result.end(), padch);
+      break;
+    }
+    case align_right:
+    {
+      unsigned padding = width>str.size() ? width - str.size() : 0;
+      unsigned i = 0;
+      while (i++ < padding)
+        result.insert(result.begin(), padch);
+      break;
+    }
+    case align_centre:
+    {
+      unsigned padding = width>str.size() ? width - str.size() : 0;
+      unsigned i = 0;
+      while (i++ < padding/2)
+        result.insert(result.end(), padch);
+      i--;
+      while (i++ < padding)
+        result.insert(result.begin(), padch);
+      break;
+    }
+    default:
+      throw std::invalid_argument("invalid alignment value");
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string trim_left(const std::string& val)
+  {
+    std::string result = val;
+    while (!result.empty() && isspace(result[0]))
+      result.erase(result.begin());
+    return result;
+  }
+
+  std::string trim_right(const std::string& val)
+  {
+    std::string result = val;
+    while (!result.empty() && isspace(result[result.size()-1]))
+      result.erase(result.end()-1);
+    return result;
+  }
+
+  std::string trim(const std::string& val)
+  {
+    std::string result = val;
+    while (!result.empty() && isspace(result[0]))
+      result.erase(result.begin());
+    while (!result.empty() && isspace(result[result.size()-1]))
+      result.erase(result.end()-1);
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string lowercase(const std::string& val)
+  {
+    std::string text = val;
+    for (unsigned i = 0; i < text.size(); i++)
+      text[i] = tolower(text[i]);
+    return text;
+  }
+
+  std::string uppercase(const std::string& val)
+  {
+    std::string text = val;
+    for (unsigned i = 0; i < text.size(); i++)
+      text[i] = toupper(text[i]);
+    return text;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string translate(const std::string& input, const std::string& from_set, const std::string& to_set)
+  {
+    std::string result;
+    for (unsigned i = 0; i < input.size(); i++)
+    {
+      char ch = input[i];
+      // check to see if the character is in the from set
+      std::string::size_type found = from_set.find(ch);
+      if (found == std::string::npos)
+      {
+        // not found so just copy across
+        result += ch;
+      }
+      else if (found < to_set.size())
+      {
+        // found and in range so translate
+        result += to_set[found];
+      }
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // WARNING: wheel re-invention follows
+  // Given that all shells perform wildcard matching, why don't the library writers put it in the C run-time????????
+  // The problem:
+  //   *  matches any number of characters - this is achieved by matching 1 and seeing if the remainder matches
+  //      if not, try 2 characters and see if the remainder matches etc.
+  //      this must be recursive, not iterative, so that multiple *s can appear in the same wildcard expression
+  //   ?  matches exactly one character so doesn't need the what-if approach
+  //   \  escapes special characters such as *, ? and [
+  //   [] matches exactly one character in the set - the difficulty is the set can contain ranges, e.g [a-zA-Z0-9]
+  //      a set cannot be empty and the ] character can be included by making it the first character
+
+  // function for testing whether a character matches a set
+  // I can't remember the exact rules and I have no definitive references but:
+  // a set contains characters, escaped characters (I think) and ranges in the form a-z
+  // The character '-' can only appear at the start of the set where it is not interpreted as a range
+  // This is a horrible mess - blame the Unix folks for making a hash of wildcards
+
+  static bool match_set (const std::string& set, char match)
+  {
+    // first expand any ranges and remove escape characters to make life more palatable
+    std::string simple_set;
+    for (std::string::const_iterator i = set.begin(); i != set.end(); ++i)
+    {
+      switch(*i)
+      {
+      case '-':
+      {
+        if (i == set.begin())
+        {
+          simple_set += *i;
+        }
+        else if (i+1 == set.end())
+        {
+          return false;
+        }
+        else
+        {
+          // found a set. The first character is already in the result, so first remove it (the set might be empty)
+          simple_set.erase(simple_set.end()-1);
+          char last = *++i;
+          for (char ch = *(i-2); ch <= last; ch++)
+          {
+            simple_set += ch;
+          }
+        }
+        break;
+      }
+      case '\\':
+        if (i+1 == set.end()) {return false;}
+        simple_set += *++i;
+        break;
+      default:
+        simple_set += *i;
+        break;
+      }
+    }
+    std::string::size_type result = simple_set.find(match);
+    return result != std::string::npos;
+  }
+
+  // the recursive bit - basically whenever a * is found you recursively call this for each candidate substring match
+  // until either it succeeds or you run out of string to match
+  // for each * in the wildcard another level of recursion is created
+
+  static bool match_remainder (const std::string& wild, std::string::const_iterator wildi,
+                               const std::string& match, std::string::const_iterator matchi)
+  {
+    //cerr << "match_remainder called at " << *matchi << " with wildcard " << *wildi << endl;
+    while (wildi != wild.end() && matchi != match.end())
+    {
+      //cerr << "trying to match " << *matchi << " with wildcard " << *wildi << endl;
+      switch(*wildi)
+      {
+      case '*':
+      {
+        ++wildi;
+        ++matchi;
+        for (std::string::const_iterator i = matchi; i != match.end(); ++i)
+        {
+          // deal with * at the end of the wildcard - there is no remainder then
+          if (wildi == wild.end())
+          {
+            if (i == match.end()-1)
+              return true;
+          }
+          else if (match_remainder(wild, wildi, match, i))
+          {
+            return true;
+          }
+        }
+        return false;
+      }
+      case '[':
+      {
+        // scan for the end of the set using a similar method for avoiding escaped characters
+        bool found = false;
+        std::string::const_iterator end = wildi + 1;
+        for (; !found && end != wild.end(); ++end)
+        {
+          switch(*end)
+          {
+          case ']':
+          {
+            // found the set, now match with its contents excluding the brackets
+            if (!match_set(wild.substr(wildi - wild.begin() + 1, end - wildi - 1), *matchi))
+              return false;
+            found = true;
+            break;
+          }
+          case '\\':
+            if (end == wild.end()-1)
+              return false;
+            ++end;
+            break;
+          default:
+            break;
+          }
+        }
+        if (!found)
+          return false;
+        ++matchi;
+        wildi = end;
+        break;
+      }
+      case '?':
+        ++wildi;
+        ++matchi;
+        break;
+      case '\\':
+        if (wildi == wild.end()-1)
+          return false;
+        ++wildi;
+        if (*wildi != *matchi)
+          return false;
+        ++wildi;
+        ++matchi;
+        break;
+      default:
+        if (*wildi != *matchi)
+          return false;
+        ++wildi;
+        ++matchi;
+        break;
+      }
+    }
+    bool result = wildi == wild.end() && matchi == match.end();
+    return result;
+  }
+
+  // like all recursions the exported function has a simpler interface than the
+  // recursive function and is just a 'seed' to the recursion itself
+
+  bool match_wildcard(const std::string& wild, const std::string& match)
+  {
+    return match_remainder(wild, wild.begin(), match, match.begin());
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::vector<std::string> split(const std::string& str, const std::string& splitter)
+  {
+    std::vector<std::string> result;
+    if (!str.empty())
+    {
+      for(std::string::size_type offset = 0;;)
+      {
+        std::string::size_type found = str.find(splitter, offset);
+        if (found != std::string::npos)
+        {
+          result.push_back(str.substr(offset, found-offset));
+          offset = found + splitter.size();
+        }
+        else
+        {
+          result.push_back(str.substr(offset, str.size()-offset));
+          break;
+        }
+      }
+    }
+    return result;
+  }
+
+  std::string join (const std::vector<std::string>& str,
+                    const std::string& joiner,
+                    const std::string& prefix,
+                    const std::string& suffix)
+  {
+    std::string result = prefix;
+    for (unsigned i = 0; i < str.size(); i++)
+    {
+      if (i) result += joiner;
+      result += str[i];
+    }
+    result += suffix;
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string display_bytes(long bytes)
+  {
+    std::string result;
+    if (bytes < 0)
+    {
+      result += '-';
+      bytes = -bytes;
+    }
+    static const long kB = 1024l;
+    static const long MB = kB * kB;
+    static const long GB = MB * kB;
+    if (bytes < kB)
+      result += local_dformat("%i", bytes);
+    else if (bytes < (10l * kB))
+      result += local_dformat("%.2fk", ((float)bytes / (float)kB));
+    else if (bytes < (100l * kB))
+      result += local_dformat("%.1fk", ((float)bytes / (float)kB));
+    else if (bytes < MB)
+      result += local_dformat("%.0fk", ((float)bytes / (float)kB));
+    else if (bytes < (10l * MB))
+      result += local_dformat("%.2fM", ((float)bytes / (float)MB));
+    else if (bytes < (100l * MB))
+      result += local_dformat("%.1fM", ((float)bytes / (float)MB));
+    else if (bytes < GB)
+      result += local_dformat("%.0fM", ((float)bytes / (float)MB));
+    else
+      result += local_dformat("%.2fG", ((float)bytes / (float)GB));
+    return result;
+  }
+
+  std::string display_time(time_t seconds)
+  {
+    unsigned minutes = (unsigned)seconds / 60;
+    seconds %= 60;
+    unsigned hours = minutes / 60;
+    minutes %= 60;
+    unsigned days = hours / 24;
+    hours %= 24;
+    unsigned weeks = days / 7;
+    days %= 7;
+    std::string result;
+    if (weeks > 0)
+    {
+      result += unsigned_to_string(weeks, 10, radix_none, 1);
+      result += "w ";
+    }
+    if (!result.empty() || days > 0)
+    {
+      result += unsigned_to_string(days, 10, radix_none, 1);
+      result += "d ";
+    }
+    if (!result.empty() || hours > 0)
+    {
+      result += unsigned_to_string(hours, 10, radix_none, 1);
+      result += ":";
+    }
+    if (!result.empty() || minutes > 0)
+    {
+      if (!result.empty())
+        result += unsigned_to_string(minutes, 10, radix_none, 2);
+      else
+        result += unsigned_to_string(minutes, 10, radix_none, 1);
+      result += ":";
+    }
+    if (!result.empty())
+      result += unsigned_to_string((unsigned)seconds, 10, radix_none, 2);
+    else
+    {
+      result += unsigned_to_string((unsigned)seconds, 10, radix_none, 1);
+      result += "s";
+    }
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index d8d39c4770eeff5ab6bba85f169bebd875ac8b75..369477dc8bf8d5af7de2da081d0a6fef5157bd70 100644 (file)
-#ifndef STLPLUS_STRING_UTILITIES\r
-#define STLPLUS_STRING_UTILITIES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Utilities for manipulating std::strings\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include "format_types.hpp"\r
-#include <vector>\r
-#include <string>\r
-#include <stdexcept>\r
-#include <time.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Padding function allows a string to be printed in a fixed-width field\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // The definitions for the alignment are declared in format_types.hpp\r
-  // Any other value will cause std::invalid_argument to be thrown\r
-\r
-  std::string pad(const std::string& str,\r
-                  alignment_t alignment,\r
-                  unsigned width,\r
-                  char padch = ' ')\r
-    throw(std::invalid_argument);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // whitespace trimming\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string trim_left(const std::string& val);\r
-  std::string trim_right(const std::string& val);\r
-  std::string trim(const std::string& val);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // case conversion for std::strings\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::string lowercase(const std::string& val);\r
-  std::string uppercase(const std::string& val);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // character translation - inspired by Unix 'tr' command\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // convert characters represented in from_set to the characters in the same position in to_set\r
-  // for example:\r
-  //   filename = translate(filename,"abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ");\r
-  // converts the filename to uppercase and returns the result (Note that the\r
-  // uppercase function does this more easily). If the from_set is longer than\r
-  // the to_set, then the overlap represents characters to delete (i.e. they map\r
-  // to nothing)\r
-\r
-  std::string translate(const std::string& input,\r
-                        const std::string& from_set,\r
-                        const std::string& to_set = std::string());\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // wildcard matching\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // this function does wildcard matching of the wildcard expression against the candidate std::string\r
-  // wildcards are NOT regular expressions\r
-  // the wildcard characters are * and ? where * matches 1 or more characters and ? matches only one\r
-  // there are also character sets [a-z] [qwertyuiop] etc. which match 1 character\r
-  // TODO: character sets like [:alpha:]\r
-  // TODO eventually: regular expression matching and substitution (3rd party library?)\r
-\r
-  bool match_wildcard(const std::string& wild,\r
-                      const std::string& match);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Perl-inspired split/join functions\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // splits the string at every occurance of splitter and adds it as a separate string to the return value\r
-  // the splitter is removed\r
-  // a string with no splitter in it will give a single-value vector\r
-  // an empty string gives an empty vector\r
-\r
-  std::vector<std::string> split (const std::string& str,\r
-                                  const std::string& splitter = "\n");\r
-\r
-  // the reverse of the above\r
-  // joins the string vector to create a single string with the joiner inserted between the joins\r
-  // Note: the joiner will not be added at the beginning or the end\r
-  // However, there are optional fields to add such prefix and suffix strings\r
-\r
-  std::string join (const std::vector<std::string>&,\r
-                    const std::string& joiner = "\n",\r
-                    const std::string& prefix = "",\r
-                    const std::string& suffix = "");\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // special displays\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // display the parameter as a number in bytes, kbytes, Mbytes, Gbytes depending on range\r
-\r
-  std::string display_bytes(long bytes);\r
-\r
-  // display the parameter in seconds as a string representation in weeks, days, hours, minutes, seconds\r
-  // e.g. "1d 1:01:01" means 1 day, 1 hour, 1 minute and 1 second\r
-\r
-  std::string display_time(time_t seconds);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
+#ifndef STLPLUS_STRING_UTILITIES
+#define STLPLUS_STRING_UTILITIES
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Utilities for manipulating std::strings
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include "format_types.hpp"
+#include <vector>
+#include <string>
+#include <stdexcept>
+#include <time.h>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Padding function allows a string to be printed in a fixed-width field
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // The definitions for the alignment are declared in format_types.hpp
+  // Any other value will cause std::invalid_argument to be thrown
+
+  std::string pad(const std::string& str,
+                  alignment_t alignment,
+                  unsigned width,
+                  char padch = ' ')
+    throw(std::invalid_argument);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // whitespace trimming
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string trim_left(const std::string& val);
+  std::string trim_right(const std::string& val);
+  std::string trim(const std::string& val);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // case conversion for std::strings
+  ////////////////////////////////////////////////////////////////////////////////
+
+  std::string lowercase(const std::string& val);
+  std::string uppercase(const std::string& val);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // character translation - inspired by Unix 'tr' command
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // convert characters represented in from_set to the characters in the same position in to_set
+  // for example:
+  //   filename = translate(filename,"abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+  // converts the filename to uppercase and returns the result (Note that the
+  // uppercase function does this more easily). If the from_set is longer than
+  // the to_set, then the overlap represents characters to delete (i.e. they map
+  // to nothing)
+
+  std::string translate(const std::string& input,
+                        const std::string& from_set,
+                        const std::string& to_set = std::string());
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // wildcard matching
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // this function does wildcard matching of the wildcard expression against the candidate std::string
+  // wildcards are NOT regular expressions
+  // the wildcard characters are * and ? where * matches 1 or more characters and ? matches only one
+  // there are also character sets [a-z] [qwertyuiop] etc. which match 1 character
+  // TODO: character sets like [:alpha:]
+  // TODO eventually: regular expression matching and substitution (3rd party library?)
+
+  bool match_wildcard(const std::string& wild,
+                      const std::string& match);
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // Perl-inspired split/join functions
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // splits the string at every occurance of splitter and adds it as a separate string to the return value
+  // the splitter is removed
+  // a string with no splitter in it will give a single-value vector
+  // an empty string gives an empty vector
+
+  std::vector<std::string> split (const std::string& str,
+                                  const std::string& splitter = "\n");
+
+  // the reverse of the above
+  // joins the string vector to create a single string with the joiner inserted between the joins
+  // Note: the joiner will not be added at the beginning or the end
+  // However, there are optional fields to add such prefix and suffix strings
+
+  std::string join (const std::vector<std::string>&,
+                    const std::string& joiner = "\n",
+                    const std::string& prefix = "",
+                    const std::string& suffix = "");
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // special displays
+  ////////////////////////////////////////////////////////////////////////////////
+
+  // display the parameter as a number in bytes, kbytes, Mbytes, Gbytes depending on range
+
+  std::string display_bytes(long bytes);
+
+  // display the parameter in seconds as a string representation in weeks, days, hours, minutes, seconds
+  // e.g. "1d 1:01:01" means 1 day, 1 hour, 1 minute and 1 second
+
+  std::string display_time(time_t seconds);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#endif
index bee9b88e39d93b204a190c8fe919123f55adeaca..66868bcca2b15e3b7b78b297c2966048064580c2 100644 (file)
@@ -1,27 +1,27 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_vector.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // special case of vector<bool>\r
-\r
-  std::string bool_vector_to_string(const std::vector<bool>& values)\r
-  {\r
-    std::string result;\r
-    for (size_t i = 0; i < values.size(); i++)\r
-      result.append(1, values[i] ? '1' : '0');\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_vector.hpp"
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // special case of vector<bool>
+
+  std::string bool_vector_to_string(const std::vector<bool>& values)
+  {
+    std::string result;
+    for (size_t i = 0; i < values.size(); i++)
+      result.append(1, values[i] ? '1' : '0');
+    return result;
+  }
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
index 6842a98bcbe0d0df2484125a203946cfb9a5a444..204eea90d7e4e7980da996f7c7c2e30901fd5da4 100644 (file)
@@ -1,36 +1,36 @@
-#ifndef STLPLUS_STRING_VECTOR\r
-#define STLPLUS_STRING_VECTOR\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generate a string representation of a vector\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "strings_fixes.hpp"\r
-#include <string>\r
-#include <vector>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // vector\r
-\r
-  template<typename T, typename S>\r
-  std::string vector_to_string(const std::vector<T>& values,\r
-                               S to_string_fn,\r
-                               const std::string& separator = ",");\r
-\r
-  // specialisation for vector<bool> which has a different implementation\r
-  std::string bool_vector_to_string(const std::vector<bool>& values);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#include "string_vector.tpp"\r
-#endif\r
+#ifndef STLPLUS_STRING_VECTOR
+#define STLPLUS_STRING_VECTOR
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Generate a string representation of a vector
+
+////////////////////////////////////////////////////////////////////////////////
+#include "strings_fixes.hpp"
+#include <string>
+#include <vector>
+
+namespace stlplus
+{
+
+  ////////////////////////////////////////////////////////////////////////////////
+  // vector
+
+  template<typename T, typename S>
+  std::string vector_to_string(const std::vector<T>& values,
+                               S to_string_fn,
+                               const std::string& separator = ",");
+
+  // specialisation for vector<bool> which has a different implementation
+  std::string bool_vector_to_string(const std::vector<bool>& values);
+
+  ////////////////////////////////////////////////////////////////////////////////
+
+} // end namespace stlplus
+
+#include "string_vector.tpp"
+#endif
index de535ee9871df3c7dd70744133f60dcd74aa822e..9e2f3859505260ef889a03b7eaf38baf79492f72 100644 (file)
@@ -1,22 +1,22 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "string_sequence.hpp"\r
-\r
-namespace stlplus\r
-{\r
-\r
-  template<typename T, typename S>\r
-  std::string vector_to_string(const std::vector<T>& values,\r
-                               S to_string_fn,\r
-                               const std::string& separator)\r
-  {\r
-    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);\r
-  }\r
-\r
-} // end namespace stlplus\r
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+////////////////////////////////////////////////////////////////////////////////
+#include "string_sequence.hpp"
+
+namespace stlplus
+{
+
+  template<typename T, typename S>
+  std::string vector_to_string(const std::vector<T>& values,
+                               S to_string_fn,
+                               const std::string& separator)
+  {
+    return sequence_to_string(values.begin(), values.end(), to_string_fn, separator);
+  }
+
+} // end namespace stlplus
index 06a6e928c8651ee31874ee12907cc3e80e4c0c00..dba420e02b10de80cb619589ec3466d3d79717ee 100644 (file)
@@ -1,30 +1,30 @@
-#ifndef STLPLUS_STRINGS\r
-#define STLPLUS_STRINGS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Header for including the whole strings library in one go\r
-\r
-//   The strings library prints C and C++ types into a std::string\r
-\r
-//   - it extends the numeric presentation of integers to include any radix from 2 - 36\r
-//   - it allows the printing of data structures - useful for diagnostic dumps\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "string_utilities.hpp"\r
-\r
-#include "string_basic.hpp"\r
-#include "string_stl.hpp"\r
-#include "string_stlplus.hpp"\r
-\r
-#include "print_basic.hpp"\r
-#include "print_stl.hpp"\r
-#include "print_stlplus.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_STRINGS
+#define STLPLUS_STRINGS
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Header for including the whole strings library in one go
+
+//   The strings library prints C and C++ types into a std::string
+
+//   - it extends the numeric presentation of integers to include any radix from 2 - 36
+//   - it allows the printing of data structures - useful for diagnostic dumps
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include "string_utilities.hpp"
+
+#include "string_basic.hpp"
+#include "string_stl.hpp"
+#include "string_stlplus.hpp"
+
+#include "print_basic.hpp"
+#include "print_stl.hpp"
+#include "print_stlplus.hpp"
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
index 2ed1dc5ea16d27b08668fcb23bb5e4d8605913b5..c6368cefb41d3e7efc5ba84a80bec82a8d6d10d8 100644 (file)
@@ -1,56 +1,56 @@
-#ifndef STLPLUS_STRINGS_FIXES\r
-#define STLPLUS_STRINGS_FIXES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Contains work arounds for OS or Compiler specific problems\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Problem with MicroSoft defining two different macros to identify Windows\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#if defined(_WIN32) || defined(_WIN32_WCE)\r
-#define MSWINDOWS\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Unnecessary compiler warnings\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef _MSC_VER\r
-// Microsoft Visual Studio\r
-// shut up the following irritating warnings\r
-//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)\r
-//   4305 - VC6, identifier type was converted to a smaller type\r
-//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)\r
-//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it\r
-//   4290 - VC6, C++ exception specification ignored\r
-//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)\r
-//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program\r
-//   4996 - VC8, 'xxxx' was declared deprecated\r
-#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4675 4996)\r
-#endif\r
-\r
-#ifdef __BORLANDC__\r
-// Borland\r
-// Shut up the following irritating warnings\r
-//   8026 - Functions with exception specifications are not expanded inline\r
-//   8027 - Functions with xxx are not expanded inline\r
-//   8066 - Unreachable code.\r
-//          A break, continue, goto, or return statement was not followed by a\r
-//          label or the end of a loop or function. The compiler checks while,\r
-//          do, and for loops with a constant test condition, and attempts to\r
-//          recognize loops that can't fall through.\r
-#pragma warn -8026\r
-#pragma warn -8027\r
-#pragma warn -8066\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
+#ifndef STLPLUS_STRINGS_FIXES
+#define STLPLUS_STRINGS_FIXES
+////////////////////////////////////////////////////////////////////////////////
+
+//   Author:    Andy Rushton
+//   Copyright: (c) Southampton University 1999-2004
+//              (c) Andy Rushton           2004-2009
+//   License:   BSD License, see ../docs/license.html
+
+//   Contains work arounds for OS or Compiler specific problems
+
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Problem with MicroSoft defining two different macros to identify Windows
+////////////////////////////////////////////////////////////////////////////////
+
+#if defined(_WIN32) || defined(_WIN32_WCE)
+#define MSWINDOWS
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Unnecessary compiler warnings
+////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+// Microsoft Visual Studio
+// shut up the following irritating warnings
+//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)
+//   4305 - VC6, identifier type was converted to a smaller type
+//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)
+//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it
+//   4290 - VC6, C++ exception specification ignored
+//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)
+//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program
+//   4996 - VC8, 'xxxx' was declared deprecated
+#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4675 4996)
+#endif
+
+#ifdef __BORLANDC__
+// Borland
+// Shut up the following irritating warnings
+//   8026 - Functions with exception specifications are not expanded inline
+//   8027 - Functions with xxx are not expanded inline
+//   8066 - Unreachable code.
+//          A break, continue, goto, or return statement was not followed by a
+//          label or the end of a loop or function. The compiler checks while,
+//          do, and for loops with a constant test condition, and attempts to
+//          recognize loops that can't fall through.
+#pragma warn -8026
+#pragma warn -8027
+#pragma warn -8066
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+#endif
diff --git a/src/stlplus/subsystems/cli_parser.cpp b/src/stlplus/subsystems/cli_parser.cpp
deleted file mode 100644 (file)
index 1088f38..0000000
+++ /dev/null
@@ -1,637 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "cli_parser.hpp"\r
-#include "file_system.hpp"\r
-#include "dprintf.hpp"\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus \r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // cli_definition internals\r
-\r
-  const std::string& stlplus::cli_definition::name(void) const\r
-  {\r
-    return m_name;\r
-  }\r
-\r
-  stlplus::cli_kind_t stlplus::cli_definition::kind(void) const\r
-  { \r
-    return m_kind;\r
-  }\r
-\r
-  stlplus::cli_mode_t stlplus::cli_definition::mode(void) const\r
-  {\r
-    return m_mode;\r
-  }\r
-\r
-  const std::string& stlplus::cli_definition::message(void) const\r
-  {\r
-    return m_message;\r
-  }\r
-\r
-  const std::string& stlplus::cli_definition::default_value(void) const\r
-  {\r
-    return m_default;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internal data structures\r
-\r
-  class cli_value\r
-  {\r
-  public:\r
-    unsigned m_definition;\r
-    std::string m_value;\r
-    unsigned m_level;\r
-    std::string m_source;\r
-\r
-    cli_value(unsigned definition, const std::string& value, unsigned level, const std::string& source) :\r
-      m_definition(definition), m_value(value), m_level(level), m_source(source) \r
-      {\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class cli_parser_data\r
-  {\r
-  public:\r
-    message_handler& m_messages;\r
-    std::string m_executable;\r
-    cli_parser::definitions m_definitions;\r
-    std::vector<cli_value> m_values;\r
-    unsigned m_level;\r
-    bool m_valid;\r
-    std::vector<std::string> m_ini_files;\r
-\r
-  public:\r
-\r
-    cli_parser_data(message_handler& messages) : \r
-      m_messages(messages), m_level(1), m_valid(true)\r
-      {\r
-        // ensure that the CLI's messages are in the message handler - these\r
-        // can be overridden from a file later - see message_handler\r
-        if (!m_messages.message_present("CLI_VALUE_MISSING"))\r
-          m_messages.add_message("CLI_VALUE_MISSING", "option @0 requires a value - end of line was reached instead");\r
-        if (!m_messages.message_present("CLI_UNRECOGNISED_OPTION"))\r
-          m_messages.add_message("CLI_UNRECOGNISED_OPTION", "@0 is not a recognised option for this command");\r
-        if (!m_messages.message_present("CLI_NO_VALUES"))\r
-          m_messages.add_message("CLI_NO_VALUES", "argument @0 is invalid - this program doesn't take command-line arguments");\r
-        if (!m_messages.message_present("CLI_USAGE_PROGRAM"))\r
-          m_messages.add_message("CLI_USAGE_PROGRAM", "usage:\n\t@0 { arguments }");\r
-        if (!m_messages.message_present("CLI_USAGE_DEFINITIONS"))\r
-          m_messages.add_message("CLI_USAGE_DEFINITIONS", "arguments:");\r
-        if (!m_messages.message_present("CLI_USAGE_VALUES"))\r
-          m_messages.add_message("CLI_USAGE_VALUES", "values:");\r
-        if (!m_messages.message_present("CLI_USAGE_VALUE_RESULT"))\r
-          m_messages.add_message("CLI_USAGE_VALUE_RESULT", "\t@0 : from @1");\r
-        if (!m_messages.message_present("CLI_USAGE_SWITCH_RESULT"))\r
-          m_messages.add_message("CLI_USAGE_SWITCH_RESULT", "\t-@0 : from @1");\r
-        if (!m_messages.message_present("CLI_USAGE_OPTION_RESULT"))\r
-          m_messages.add_message("CLI_USAGE_OPTION_RESULT", "\t-@0 @1 : from @2");\r
-        if (!m_messages.message_present("CLI_INI_HEADER"))\r
-          m_messages.add_message("CLI_INI_HEADER", "configuration files:");\r
-        if (!m_messages.message_present("CLI_INI_FILE_PRESENT"))\r
-          m_messages.add_message("CLI_INI_FILE_PRESENT", "\t@0");\r
-        if (!m_messages.message_present("CLI_INI_FILE_ABSENT"))\r
-          m_messages.add_message("CLI_INI_FILE_ABSENT", "\t@0 (not found)");\r
-        if (!m_messages.message_present("CLI_INI_VARIABLE"))\r
-          m_messages.add_message("CLI_INI_VARIABLE", "unknown variable \"@0\" found in Ini file");\r
-      }\r
-\r
-    unsigned add_definition(const cli_parser::definition& definition)\r
-      {\r
-        m_definitions.push_back(definition);\r
-        return m_definitions.size()-1;\r
-      }\r
-\r
-    std::string name(unsigned i) const throw(cli_index_error)\r
-      {\r
-        if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range");\r
-        return m_definitions[m_values[i].m_definition].name();\r
-      }\r
-\r
-    unsigned id(unsigned i) const throw(cli_index_error)\r
-      {\r
-        if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range");\r
-        return m_values[i].m_definition;\r
-      }\r
-\r
-    cli_parser::kind_t kind(unsigned i) const throw(cli_index_error)\r
-      {\r
-        if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range");\r
-        return m_definitions[m_values[i].m_definition].kind();\r
-      }\r
-\r
-    cli_parser::mode_t mode(unsigned i) const throw(cli_index_error)\r
-      {\r
-        if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range");\r
-        return m_definitions[m_values[i].m_definition].mode();\r
-      }\r
-\r
-//     unsigned add_definition(const std::string& name,\r
-//                             cli_parser::kind_t kind,\r
-//                             cli_parser::mode_t mode,\r
-//                             const std::string& message)\r
-//       {\r
-//         return add_definition(cli_parser::definition(name, kind, mode, message));\r
-//       }\r
-\r
-    unsigned find_definition(const std::string& name)\r
-      {\r
-        // this does substring matching on the definitions and returns the first\r
-        // match - however, it requires at least one character in the substring so\r
-        // that the "" convention for command line arguments doesn't match with\r
-        // anything. It returns size() if it fails\r
-        for (unsigned i = 0; i < m_definitions.size(); i++)\r
-        {\r
-          std::string candidate = m_definitions[i].name();\r
-          if ((candidate.empty() && name.empty()) ||\r
-              (!name.empty() && candidate.size() >= name.size() && candidate.substr(0,name.size()) == name))\r
-            return i;\r
-        }\r
-        return m_definitions.size();\r
-      }\r
-\r
-    void clear_definitions(void)\r
-      {\r
-        m_definitions.clear();\r
-        m_values.clear();\r
-        reset_level();\r
-        set_valid();\r
-      }\r
-\r
-    void reset_level(void)\r
-      {\r
-        // the starting level is 1 so that later functions can call clear_level with\r
-        // a value of m_level-1 without causing underflow\r
-        m_level = 1;\r
-      }\r
-\r
-    void increase_level(void)\r
-      {\r
-        m_level++;\r
-      }\r
-\r
-    void clear_level(unsigned definition, unsigned level)\r
-      {\r
-        // clears all values with this definition at the specified level or below\r
-        for (std::vector<cli_value>::iterator i = m_values.begin(); i != m_values.end(); )\r
-        {\r
-          if (i->m_definition == definition && i->m_level <= level)\r
-            i = m_values.erase(i);\r
-          else\r
-            i++;\r
-        }\r
-      }\r
-\r
-    void set_valid(void)\r
-      {\r
-        m_valid = true;\r
-      }\r
-\r
-    void set_invalid(void)\r
-      {\r
-        m_valid = false;\r
-      }\r
-\r
-    bool valid(void) const\r
-      {\r
-        return m_valid;\r
-      }\r
-\r
-    unsigned add_value(unsigned definition, const std::string& value, const std::string& source)\r
-      {\r
-        // behaviour depends on mode:\r
-        //  - single: erase all previous values\r
-        //  - multiple: erase values at a lower level than current\r
-        //  - cumulative: erase no previous values\r
-        switch (m_definitions[definition].mode())\r
-        {\r
-        case cli_single_mode:\r
-          clear_level(definition, m_level);\r
-          break;\r
-        case cli_multiple_mode:\r
-          clear_level(definition, m_level-1);\r
-          break;\r
-        case cli_cumulative_mode:\r
-          break;\r
-        }\r
-        m_values.push_back(cli_value(definition,value,m_level,source));\r
-        return m_values.size()-1;\r
-      }\r
-\r
-    unsigned add_switch(unsigned definition, bool value, const std::string& source)\r
-      {\r
-        return add_value(definition, value ? "on" : "off", source);\r
-      }\r
-\r
-    void erase_value(unsigned definition)\r
-      {\r
-        // this simply erases all previous values\r
-        clear_level(definition, m_level);\r
-      }\r
-\r
-    void add_ini_file(const std::string& file)\r
-      {\r
-        m_ini_files.push_back(file);\r
-      }\r
-\r
-    unsigned ini_file_size(void) const\r
-      {\r
-        return m_ini_files.size();\r
-      }\r
-\r
-    const std::string& ini_file(unsigned i) const\r
-      {\r
-        return m_ini_files[i];\r
-      }\r
-\r
-    unsigned add_checked_definition(const cli_parser::definition& definition) throw(cli_mode_error)\r
-      {\r
-        // check for stupid combinations\r
-        // at this stage the only really stupid one is to declare command line arguments to be switch mode\r
-        if (definition.name().empty() && definition.kind() == cli_switch_kind) \r
-        {\r
-          set_invalid();\r
-          throw cli_mode_error("CLI arguments cannot be switch kind");\r
-        }\r
-        // add the definition to the set of all definitions\r
-        unsigned i = add_definition(definition);\r
-        // also add it to the list of values, but only if it has a default value\r
-        if (!definition.default_value().empty())\r
-          add_value(i, definition.default_value(), "builtin default");\r
-        return i;\r
-      }\r
-\r
-    bool switch_value(unsigned i) const throw(cli_mode_error,cli_index_error)\r
-      {\r
-        if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range");\r
-        if (kind(i) != cli_switch_kind) throw cli_mode_error(name(i) + " is not a switch kind");\r
-        std::string value = m_values[i].m_value;\r
-        return value == "on" || value == "true" || value == "1";\r
-      }\r
-\r
-    std::string string_value(unsigned i) const throw(cli_mode_error,cli_index_error)\r
-      {\r
-        if (i >= m_values.size()) throw cli_index_error("Index " + dformat("%u",i) + " out of range");\r
-        if (kind(i) != cli_value_kind) throw cli_mode_error(name(i) + " is not a value kind");\r
-        return m_values[i].m_value;\r
-      }\r
-\r
-    void set_defaults(const ini_manager& defaults, const std::string& ini_section) throw()\r
-      {\r
-        // import default values from the Ini Manager\r
-        increase_level();\r
-        // get the set of all names from the Ini manager so that illegal names generate meaningful error messages\r
-        std::vector<std::string> names = defaults.variable_names(ini_section);\r
-        for (unsigned i = 0; i < names.size(); i++)\r
-        {\r
-          std::string name = names[i];\r
-          unsigned definition = find_definition(name);\r
-          if (definition == (unsigned)-1)\r
-          {\r
-            // not found - give an error report\r
-            message_position position(defaults.variable_filename(ini_section,name),\r
-                                      defaults.variable_linenumber(ini_section,name),\r
-                                      0);\r
-            m_messages.error(position,"CLI_INI_VARIABLE", name);\r
-          }\r
-          else\r
-          {\r
-            // found - so add the value\r
-            // multi-valued variables are entered as a comma-separated list and this is then turned into a vector\r
-            // the vector is empty if the value was empty\r
-            std::vector<std::string> values = defaults.variable_values(ini_section, name);\r
-            // an empty string is used to negate the value\r
-            if (values.empty())\r
-              erase_value(definition);\r
-            else\r
-            {\r
-              std::string source = filespec_to_relative_path(defaults.variable_filename(ini_section, name));\r
-              for (unsigned j = 0; j < values.size(); j++)\r
-                add_value(definition, values[j], source);\r
-            }\r
-          }\r
-        }\r
-        // add the set of ini files to the list for usage reports\r
-        for (unsigned j = 0; j < defaults.size(); j++)\r
-          add_ini_file(defaults.filename(j));\r
-      }\r
-\r
-    bool parse(char* argv[]) throw(cli_argument_error,message_handler_id_error,message_handler_format_error)\r
-      {\r
-        bool result = true;\r
-        if (!argv) throw cli_argument_error("Argument vector cannot be null");\r
-        increase_level();\r
-        if (argv[0])\r
-          m_executable = argv[0];\r
-        for (unsigned i = 1; argv[i]; i++)\r
-        {\r
-          std::string name = argv[i];\r
-          if (!name.empty() && name[0] == '-')\r
-          {\r
-            // we have a command line option\r
-            unsigned found = find_definition(name.substr(1, name.size()-1));\r
-            if (found < m_definitions.size())\r
-            {\r
-              // found it in its positive form\r
-              switch (m_definitions[found].kind())\r
-              {\r
-              case cli_switch_kind:\r
-                add_switch(found, true, "command line");\r
-                break;\r
-              case cli_value_kind:\r
-                // get the next argument in argv as the value of this option\r
-                // first check that there is a next value\r
-                if (!argv[i+1])\r
-                  result &= m_messages.error("CLI_VALUE_MISSING", name);\r
-                else\r
-                  add_value(found, argv[++i], "command line");\r
-                break;\r
-              }\r
-            }\r
-            else if (name.size() > 3 && name.substr(1,2) == "no")\r
-            {\r
-              found = find_definition(name.substr(3, name.size()-3));\r
-              if (found < m_definitions.size())\r
-              {\r
-                // found it in its negated form\r
-                switch (m_definitions[found].kind())\r
-                {\r
-                case cli_switch_kind:\r
-                  add_switch(found, false, "command line");\r
-                  break;\r
-                case cli_value_kind:\r
-                  erase_value(found);\r
-                  break;\r
-                }\r
-              }\r
-              else\r
-              {\r
-                // could not find this option in either its true or negated form\r
-                result &= m_messages.error("CLI_UNRECOGNISED_OPTION", name);\r
-              }\r
-            }\r
-            else\r
-            {\r
-              // could not find this option and it could not be negated\r
-              result &= m_messages.error("CLI_UNRECOGNISED_OPTION", name);\r
-            }\r
-          }\r
-          else\r
-          {\r
-            // we have a command-line value which is represented internally as an option with an empty string as its name\r
-            // some very obscure commands do not have values - only options, so allow for that case too\r
-            unsigned found = find_definition("");\r
-            if (found < m_definitions.size())\r
-              add_value(found, name, "command line");\r
-            else\r
-              result &= m_messages.error("CLI_NO_VALUES", name);\r
-          }\r
-        }\r
-        if (!result) set_invalid();\r
-        return result;\r
-      }\r
-\r
-    void usage(void) const throw(std::runtime_error)\r
-      {\r
-        m_messages.information("CLI_USAGE_PROGRAM", m_executable);\r
-        m_messages.information("CLI_USAGE_DEFINITIONS");\r
-        for (unsigned d = 0; d < m_definitions.size(); d++)\r
-          m_messages.information(m_definitions[d].message());\r
-        if (m_values.size() != 0)\r
-        {\r
-          m_messages.information("CLI_USAGE_VALUES");\r
-          for (unsigned v = 0; v < m_values.size(); v++)\r
-          {\r
-            std::string source = m_values[v].m_source;\r
-            std::string key = name(v);\r
-            if (key.empty())\r
-            {\r
-              // command-line values\r
-              m_messages.information("CLI_USAGE_VALUE_RESULT", string_value(v), source);\r
-            }\r
-            else if (kind(v) == cli_switch_kind)\r
-            {\r
-              // a switch\r
-              m_messages.information("CLI_USAGE_SWITCH_RESULT", (switch_value(v) ? name(v) : "no" + name(v)), source);\r
-            }\r
-            else\r
-            {\r
-              // other values\r
-              std::vector<std::string> args;\r
-              args.push_back(name(v));\r
-              args.push_back(string_value(v));\r
-              args.push_back(source);\r
-              m_messages.information("CLI_USAGE_OPTION_RESULT", args);\r
-            }\r
-          }\r
-        }\r
-        if (ini_file_size() > 0)\r
-        {\r
-          m_messages.information("CLI_INI_HEADER");\r
-          for (unsigned i = 0; i < ini_file_size(); i++)\r
-          {\r
-            if (file_exists(ini_file(i)))\r
-              m_messages.information("CLI_INI_FILE_PRESENT", filespec_to_relative_path(ini_file(i)));\r
-            else\r
-              m_messages.information("CLI_INI_FILE_ABSENT", filespec_to_relative_path(ini_file(i)));\r
-          }\r
-        }\r
-      }\r
-\r
-  private:\r
-    // make this class uncopyable\r
-    cli_parser_data(const cli_parser_data&);\r
-    cli_parser_data& operator = (const cli_parser_data&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  cli_parser::cli_parser(message_handler& messages) throw() : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-  }\r
-\r
-  cli_parser::cli_parser(cli_parser::definitions_t definitions, message_handler& messages) throw(cli_mode_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-  }\r
-\r
-  cli_parser::cli_parser(cli_parser::definitions_t definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages)  throw(cli_mode_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-    set_defaults(defaults, ini_section);\r
-  }\r
-\r
-  cli_parser::cli_parser(char* argv[], cli_parser::definitions_t definitions, message_handler& messages)  throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-    parse(argv);\r
-  }\r
-\r
-  cli_parser::cli_parser(char* argv[], cli_parser::definitions_t definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages)  throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-    set_defaults(defaults, ini_section);\r
-    parse(argv);\r
-  }\r
-\r
-  cli_parser::cli_parser(cli_parser::definitions definitions, message_handler& messages) throw(cli_mode_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-  }\r
-\r
-  cli_parser::cli_parser(cli_parser::definitions definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages)  throw(cli_mode_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-    set_defaults(defaults, ini_section);\r
-  }\r
-\r
-  cli_parser::cli_parser(char* argv[], cli_parser::definitions definitions, message_handler& messages)  throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-    parse(argv);\r
-  }\r
-\r
-  cli_parser::cli_parser(char* argv[], cli_parser::definitions definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& messages)  throw(cli_mode_error,message_handler_id_error,message_handler_format_error) : \r
-    m_data(new cli_parser_data(messages))\r
-  {\r
-    add_definitions(definitions);\r
-    set_defaults(defaults, ini_section);\r
-    parse(argv);\r
-  }\r
-\r
-  cli_parser::~cli_parser(void) throw()\r
-  {\r
-  }\r
-\r
-  void cli_parser::add_definitions(cli_parser::definitions_t definitions) throw(cli_mode_error)\r
-  {\r
-    m_data->clear_definitions();\r
-    // the definitions array is terminated by a definition with a null name pointer\r
-    for (unsigned i = 0; definitions[i].m_name; i++)\r
-      add_definition(definitions[i]);\r
-  }\r
-\r
-  unsigned cli_parser::add_definition(const cli_parser::definition_t& definition) throw(cli_mode_error,cli_argument_error)\r
-  {\r
-    std::string name = definition.m_name ? definition.m_name : "";\r
-    std::string message = definition.m_message ? definition.m_message : "";\r
-    std::string value = definition.m_default ? definition.m_default : "";\r
-    return add_definition(cli_parser::definition(name, definition.m_kind, definition.m_mode, message, value));\r
-  }\r
-\r
-  void cli_parser::add_definitions(cli_parser::definitions definitions) throw(cli_mode_error)\r
-  {\r
-    m_data->clear_definitions();\r
-    for (unsigned i = 0; i < definitions.size(); i++)\r
-      add_definition(definitions[i]);\r
-  }\r
-\r
-  unsigned cli_parser::add_definition(const cli_parser::definition& definition) throw(cli_mode_error)\r
-  {\r
-    return m_data->add_checked_definition(definition);\r
-  }\r
-\r
-  void cli_parser::set_defaults(const ini_manager& defaults, const std::string& ini_section) throw()\r
-  {\r
-    m_data->set_defaults(defaults, ini_section);\r
-  }\r
-\r
-  bool cli_parser::parse(char* argv[]) throw(cli_argument_error,message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return m_data->parse(argv);\r
-  }\r
-\r
-  bool cli_parser::valid(void) throw()\r
-  {\r
-    return m_data->valid();\r
-  }\r
-\r
-  unsigned cli_parser::size(void) const throw()\r
-  {\r
-    return m_data->m_values.size();\r
-  }\r
-\r
-  std::string cli_parser::name(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return m_data->name(i);\r
-  }\r
-\r
-  unsigned cli_parser::id(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return m_data->id(i);\r
-  }\r
-\r
-  cli_parser::kind_t cli_parser::kind(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return m_data->kind(i);\r
-  }\r
-\r
-  bool cli_parser::switch_kind(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return kind(i) == cli_switch_kind;\r
-  }\r
-\r
-  bool cli_parser::value_kind(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return kind(i) == cli_value_kind;\r
-  }\r
-\r
-  cli_parser::mode_t cli_parser::mode(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return m_data->mode(i);\r
-  }\r
-\r
-  bool cli_parser::single_mode(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return mode(i) == cli_single_mode;\r
-  }\r
-\r
-  bool cli_parser::multiple_mode(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return mode(i) == cli_multiple_mode;\r
-  }\r
-\r
-  bool cli_parser::cumulative_mode(unsigned i) const throw(cli_index_error)\r
-  {\r
-    return mode(i) == cli_cumulative_mode;\r
-  }\r
-\r
-  bool cli_parser::switch_value(unsigned i) const throw(cli_mode_error,cli_index_error)\r
-  {\r
-    return m_data->switch_value(i);\r
-  }\r
-\r
-  std::string cli_parser::string_value(unsigned i) const throw(cli_mode_error,cli_index_error)\r
-  {\r
-    return m_data->string_value(i);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void cli_parser::usage(void) const throw(std::runtime_error)\r
-  {\r
-    m_data->usage();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/subsystems/cli_parser.hpp b/src/stlplus/subsystems/cli_parser.hpp
deleted file mode 100644 (file)
index dc9740d..0000000
+++ /dev/null
@@ -1,309 +0,0 @@
-#ifndef STLPLUS_CLI_PARSER\r
-#define STLPLUS_CLI_PARSER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A subsystem for managing command-line parsing, including using INI files to\r
-//   control the default options.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "subsystems_fixes.hpp"\r
-#include "message_handler.hpp"\r
-#include "ini_manager.hpp"\r
-#include "smart_ptr.hpp"\r
-#include <string>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Internals\r
-\r
-  class cli_parser_data;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // declarations\r
-\r
-  // enum to define the basic behaviour of an argument\r
-  //   - a switch is an option with no value but which can be switched on or off e.g. -help and -nohelp\r
-  //   - a value is an option followed by a value e.g. -output results.txt\r
-  //       (a default value can be removed by using the option as a negated switch e.g. -nooutput)\r
-  //   - command-line values (i.e. any strings not preceded by '-') are treated\r
-  //     internally as an option with no name and must be values\r
-  enum cli_kind_t {cli_switch_kind, cli_value_kind};\r
-\r
-  // the mode controls the behaviour if an option appears more than once in either the command-line or the ini files\r
-  //   - a single mode option overrides all previous values so will only be found once in the parsed result\r
-  //   - a multiple mode option can be repeated to define multiple values, but overrides values from ini files\r
-  //   - a cumulative mode option is a multiple mode option which keeps ini file values as well\r
-  enum cli_mode_t {cli_single_mode, cli_multiple_mode, cli_cumulative_mode};\r
-\r
-  // There are two structures used for defining command-line parameters\r
-  //  (1) a C struct which is used in a C array - this is used for declaring\r
-  //      command-line parameters in a static declaration\r
-  //  (2) a C++ class which is used in an STL vector - this is used for building\r
-  //      command-line parameters within code\r
-\r
-  // The C struct for definitions\r
-  struct cli_definition_t\r
-  {\r
-    // the name of the option, e.g. "help"\r
-    const char* m_name;\r
-\r
-    // the kind of the option, e.g. cli_switch_kind\r
-    cli_kind_t m_kind;\r
-\r
-    // the mode e.g. cli_single_mode\r
-    cli_mode_t m_mode;\r
-\r
-    // the mnemonic for the message giving usage information for this option\r
-    const char* m_message;\r
-\r
-    // built-in default value - null if not present\r
-    const char* m_default;\r
-  };\r
-\r
-  // The C array of the C struct. The array must be terminated by END_CLI_DEFINITIONS.\r
-  typedef cli_definition_t cli_definitions_t [];\r
-#define END_CLI_DEFINITIONS {0,stlplus::cli_switch_kind,stlplus::cli_single_mode,"",0}\r
-\r
-  // The C++ class for definitions\r
-  class cli_definition\r
-  {\r
-  public:\r
-    // constructor that allows a definition to be created in one line\r
-    cli_definition(const std::string& name, cli_kind_t kind, cli_mode_t mode, \r
-                   const std::string& message, const std::string& default_value = std::string()) : \r
-      m_name(name), m_kind(kind), m_mode(mode), m_message(message), m_default(default_value) {}\r
-\r
-    // the name of the option, e.g. "help"\r
-    const std::string& name(void) const;\r
-\r
-    // the kind of the option, e.g. switch_kind\r
-    cli_kind_t kind(void) const;\r
-\r
-    // the mode e.g. single_mode\r
-    cli_mode_t mode(void) const;\r
-\r
-    // the mnemonic for the message giving usage\r
-    const std::string& message(void) const;\r
-\r
-    // built-in default value - empty string if not present\r
-    const std::string& default_value(void) const;\r
-\r
-  private:\r
-    std::string m_name;\r
-    cli_kind_t m_kind;\r
-    cli_mode_t m_mode;\r
-    std::string m_message;\r
-    std::string m_default;\r
-  };\r
-\r
-  // The C++ vector of the C++ class\r
-  typedef std::vector<cli_definition> cli_definitions;\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // exceptions that can be thrown by the CLI parser\r
-  // they are all derivatives of std::logic_error because all errors are predictable by code inspection\r
-  // a correct program will never throw an exception\r
-\r
-  // thrown if a command-line argument is accessed with the wrong mode - i.e. attempt to get the value of a switch\r
-  class cli_mode_error : public std::invalid_argument\r
-  {\r
-  public:\r
-    cli_mode_error(const std::string& arg) : std::invalid_argument(arg) {}\r
-    ~cli_mode_error(void) throw() {}\r
-  };\r
-\r
-  // similar to std::out_of_range thrown for using an index out of range\r
-  class cli_index_error : public std::out_of_range\r
-  {\r
-  public:\r
-    cli_index_error(const std::string& arg) : std::out_of_range(arg) {}\r
-    ~cli_index_error(void) throw() {}\r
-  };\r
-\r
-  // similar to std::invalid_argument - thrown for passing an illegal argument to a method\r
-  class cli_argument_error : public std::invalid_argument\r
-  {\r
-  public:\r
-    cli_argument_error(const std::string& arg) : std::invalid_argument(arg) {}\r
-    ~cli_argument_error(void) throw() {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class cli_parser\r
-  {\r
-  public:\r
-    // Type definitions map the global type names onto convenient scoped names\r
-\r
-    typedef cli_kind_t kind_t;\r
-    typedef cli_mode_t mode_t;\r
-    typedef cli_definition_t definition_t;\r
-    typedef cli_definitions_t definitions_t;\r
-    typedef cli_definition definition;\r
-    typedef cli_definitions definitions;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // Methods\r
-\r
-    // various constructors\r
-\r
-    // you have a choice of either creating an uninitialised CLI parser and then\r
-    // calling separate functions to set it up or of calling one of the\r
-    // composite constructors. However, you must set up the error handler in the\r
-    // constructor.\r
-\r
-    // set up the parser with its error handler\r
-    // defer everything else\r
-    cli_parser(message_handler& errors)\r
-      throw();\r
-\r
-    // constructors using the C definitions_t structure\r
-\r
-    // set up the parser with the error handler and define all the command-line options\r
-    // defer default values and parameter parsing\r
-    cli_parser(cli_definitions_t, message_handler& errors)\r
-      throw(cli_mode_error);\r
-    // set up the parser with the error handler and define all the command-line\r
-    // options and their default from the ini files\r
-    // defer parameter parsing\r
-    cli_parser(cli_definitions_t, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
-      throw(cli_mode_error);\r
-    // set up the parser with the error handler and define all the command-line\r
-    // options no ini files used for default values, so only built-in defaults\r
-    // supported then parse the command line\r
-    cli_parser(char* argv[], cli_definitions_t, message_handler& errors)\r
-      throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
-    // set up the parser with the error handler and define all the command-line\r
-    // options and their default from the ini files then parse the command line\r
-    cli_parser(char* argv[], cli_definitions_t, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
-      throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
-\r
-    // constructors using the C++ definitions structure\r
-\r
-    // set up the parser with the error handler and define all the command-line\r
-    // options from a C array of structs\r
-    // defer default values and parameter parsing\r
-    cli_parser(cli_definitions, message_handler& errors)\r
-      throw(cli_mode_error);\r
-    // set up the parser with the error handler and define all the command-line\r
-    // options and their default from the ini files\r
-    // defer parameter parsing\r
-    cli_parser(cli_definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
-      throw(cli_mode_error);\r
-    // set up the parser with the error handler and define all the command-line\r
-    // options no ini files used for default values, so only built-in defaults\r
-    // supported then parse the command line\r
-    cli_parser(char* argv[], cli_definitions, message_handler& errors)\r
-      throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
-    // set up the parser with the error handler and define all the command-line\r
-    // options and their default from the ini files then parse the command line\r
-    cli_parser(char* argv[], cli_definitions, const ini_manager& defaults, const std::string& ini_section, message_handler& errors)\r
-      throw(cli_mode_error,message_handler_id_error,message_handler_format_error);\r
-\r
-    ~cli_parser(void)\r
-      throw();\r
-\r
-    // the separate functions for initialising the parser in steps. These are\r
-    // declared in the order of use. Firts, add definitions of command-line\r
-    // arguments. Then optionally load default values from ini files, then\r
-    // finally parse the command line.\r
-\r
-    // add a set of C definitions. The definitions will be given ID codes from 0\r
-    // to the number of elements - 1 in the array\r
-    void add_definitions(cli_definitions_t)\r
-      throw(cli_mode_error);\r
-    // add a single C definition, returning the ID code for it\r
-    unsigned add_definition(const definition_t&)\r
-      throw(cli_mode_error,cli_argument_error);\r
-    // add a set of C++ definitions. The definitions will be given ID codes from\r
-    // 0 to the number of elements - 1 in the array\r
-    void add_definitions(cli_definitions)\r
-      throw(cli_mode_error);\r
-    // add a single C++ definition, returning the ID code for it\r
-    unsigned add_definition(const definition&)\r
-      throw(cli_mode_error);\r
-\r
-    // All definitions have an optional built-in default value which is stored\r
-    // in the definition types above. However, these can optionally be\r
-    // overridden by a value from an ini file. If you want this functionality,\r
-    // call this function. If you don't want ini file handling, simply don't\r
-    // call it. The values will be searched for only in the named section of the\r
-    // ini file (sections are labelled by e.g. [vassemble]), so in this case you\r
-    // would specify the section name as "vassemble" (exclude the brackets).\r
-    void set_defaults(const ini_manager& defaults, const std::string& ini_section)\r
-      throw();\r
-\r
-    // the final stage of initialisation is to read the command-line and extract\r
-    // the values from it. If parse errors are found, this will report the\r
-    // errors using the error handler and return false.\r
-    bool parse(char* argv[])\r
-      throw(cli_argument_error,message_handler_id_error,message_handler_format_error);\r
-\r
-    // test for whether the CLI parser is still valid (no errors have happened)\r
-    // after the initialisation phase\r
-    bool valid(void)\r
-      throw();\r
-\r
-    // iteration functions avoiding the use of iterators. Just loop through the\r
-    // arguments from 0 to size()-1 and use the index of the loop to interrogate\r
-    // the command-line for the value at that position.\r
-\r
-    // the number of values to read, indexed 0 to size()-1\r
-    unsigned size(void) const\r
-      throw();\r
-\r
-    // the argument name\r
-    std::string name(unsigned i) const\r
-      throw(cli_index_error);\r
-    // the argument ID, that is, the offset into the original definitions\r
-    unsigned id(unsigned i) const\r
-      throw(cli_index_error);\r
-\r
-    // the kind (switch or value) and short-cut tests for the different kinds\r
-    cli_kind_t kind(unsigned i) const\r
-      throw(cli_index_error);\r
-    bool switch_kind(unsigned i) const\r
-      throw(cli_index_error);\r
-    bool value_kind(unsigned i) const\r
-      throw(cli_index_error);\r
-\r
-    // the mode (single, multiple, cumulative) and short-cut tests for the\r
-    // different modes - you rarely need to know this since it mainly controls\r
-    // the parsing\r
-    cli_mode_t mode(unsigned i) const \r
-      throw(cli_index_error);\r
-    bool single_mode(unsigned i) const\r
-      throw(cli_index_error);\r
-    bool multiple_mode(unsigned i) const\r
-      throw(cli_index_error);\r
-    bool cumulative_mode(unsigned i) const\r
-      throw(cli_index_error);\r
-\r
-    // get the switch's value, but only if the value is of switch kind\r
-    bool switch_value(unsigned i) const\r
-      throw(cli_mode_error,cli_index_error);\r
-\r
-    // get the option's value, but only if it is of value kind\r
-    std::string string_value(unsigned i) const\r
-      throw(cli_mode_error,cli_index_error);\r
-\r
-    // print the usage report - typically in response to the -help switch being on\r
-    void usage(void) const\r
-      throw(std::runtime_error);\r
-\r
-  private:\r
-    friend class cli_parser_data;\r
-    smart_ptr_nocopy<cli_parser_data> m_data;\r
-  };\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/subsystems/ini_manager.cpp b/src/stlplus/subsystems/ini_manager.cpp
deleted file mode 100644 (file)
index 41f5b69..0000000
+++ /dev/null
@@ -1,1243 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "ini_manager.hpp"\r
-#include "file_system.hpp"\r
-#include <fstream>\r
-#include <list>\r
-#include <algorithm>\r
-#include <sys/stat.h>\r
-#include <ctype.h>\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // local utilities\r
-\r
-  static std::string trim(const std::string& val)\r
-  {\r
-    std::string result = val;\r
-    while (!result.empty() && isspace(result[0]))\r
-      result.erase(result.begin());\r
-    while (!result.empty() && isspace(result[result.size()-1]))\r
-      result.erase(result.end()-1);\r
-    return result;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internal data structure for storing a single entry (i.e. line) from an ini file\r
-  // lines are categorised as blanks, comments or variables\r
-  // TODO - do I need an error category?\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class ini_entry\r
-  {\r
-  public:\r
-    enum kind_t {BLANK, COMMENT, VARIABLE};\r
-    friend std::string to_string(kind_t kind)\r
-      {\r
-        switch(kind)\r
-        {\r
-        case BLANK: return "BLANK";\r
-        case COMMENT: return "COMMENT";\r
-        case VARIABLE: return "VARIABLE";\r
-        }\r
-        return "<*unknown kind*>";\r
-      }\r
-\r
-  private:\r
-    unsigned m_line;\r
-    kind_t m_kind;\r
-    std::string m_text;\r
-    std::string m_name;\r
-    std::string m_value;\r
-\r
-  public:\r
-    ini_entry(unsigned line) : m_line(line), m_kind(BLANK) {}\r
-    ini_entry(unsigned line, const std::string& comment) : m_line(line), m_kind(COMMENT), m_text("; " + comment) {}\r
-    ini_entry(unsigned line, const std::string& name, const std::string& value) : m_line(line), m_kind(VARIABLE), m_text(name + " = " + value), m_name(name), m_value(value) {}\r
-    ~ini_entry(void) {}\r
-\r
-    unsigned line(void) const {return m_line;}\r
-    kind_t kind(void) const {return m_kind;}\r
-    bool blank(void) const {return m_kind == BLANK;}\r
-    bool comment(void) const {return m_kind == COMMENT;}\r
-    bool variable(void) const {return m_kind == VARIABLE;}\r
-\r
-    const std::string& text(void) const {return m_text;}\r
-    const std::string& variable_name(void) const {return m_name;}\r
-    const std::string& variable_value(void) const {return m_value;}\r
-\r
-    bool print(std::ostream& str) const\r
-      {\r
-        str << "    " << m_line << ":" << to_string(m_kind) << ": " << m_text << std::endl;\r
-        return !str.fail();\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internal data structure representing an ini file section containing all the\r
-  // entries for that section from a single ini file\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class ini_section\r
-  {\r
-  private:\r
-    friend class ini_file;\r
-    std::string m_title;\r
-    std::list<ini_entry> m_entries;\r
-\r
-  public:\r
-    ini_section(const std::string& title) : \r
-      m_title(title)\r
-      {\r
-      }\r
-\r
-    ~ini_section(void)\r
-      {\r
-      }\r
-\r
-    const std::string& title(void) const\r
-      {\r
-        return m_title;\r
-      }\r
-\r
-    bool empty(void) const\r
-      {\r
-        // a section is empty if it contains no variables\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-        {\r
-          if (i->variable())\r
-            return false;\r
-        }\r
-        return true;\r
-      }\r
-\r
-    void clear(void)\r
-      {\r
-        m_entries.clear();\r
-      }\r
-\r
-    bool variable_exists(const std::string variable) const\r
-      {\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-        {\r
-          if (i->variable() && i->variable_name() == variable)\r
-            return true;\r
-        }\r
-        return false;\r
-      }\r
-\r
-    unsigned variables_size(void) const\r
-      {\r
-        unsigned result = 0;\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-          if (i->variable())\r
-            result++;\r
-        return result;\r
-      }\r
-\r
-    std::string variable_name(unsigned offset) const\r
-      {\r
-        unsigned j = 0;\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-        {\r
-          if (i->variable())\r
-          {\r
-            if (j == offset)\r
-              return i->variable_name();\r
-            j++;\r
-          }\r
-        }\r
-        return std::string();\r
-      }\r
-\r
-    std::vector<std::string> variable_names(void) const\r
-      {\r
-        std::vector<std::string> result;\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-          if (i->variable())\r
-            result.push_back(i->variable_name());\r
-        return result;\r
-      }\r
-\r
-    std::string variable_value(unsigned offset) const\r
-      {\r
-        unsigned j = 0;\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-        {\r
-          if (i->variable())\r
-          {\r
-            if (j == offset)\r
-              return i->variable_value();\r
-            j++;\r
-          }\r
-        }\r
-        return std::string();\r
-      }\r
-\r
-    std::string variable_value(const std::string variable) const\r
-      {\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-        {\r
-          if (i->variable() && i->variable_name() == variable)\r
-            return i->variable_value();\r
-        }\r
-        return std::string();\r
-      }\r
-\r
-    unsigned variable_line(const std::string variable) const\r
-      {\r
-        for (std::list<ini_entry>::const_iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-        {\r
-          if (i->variable() && i->variable_name() == variable)\r
-            return i->line();\r
-        }\r
-        return 0;\r
-      }\r
-\r
-    bool add_variable(unsigned line, const std::string& variable, const std::string& value)\r
-      {\r
-        erase_variable(variable);\r
-        m_entries.push_back(ini_entry(line ? line : m_entries.size(), variable, value));\r
-        return true;\r
-      }\r
-\r
-    bool add_comment(unsigned line, const std::string& comment)\r
-      {\r
-        m_entries.push_back(ini_entry(line ? line : m_entries.size(), comment));\r
-        return true;\r
-      }\r
-\r
-    bool add_blank(unsigned line)\r
-      {\r
-        m_entries.push_back(ini_entry(line ? line : m_entries.size()));\r
-        return true;\r
-      }\r
-\r
-    bool erase_variable(const std::string& variable)\r
-      {\r
-        for (std::list<ini_entry>::iterator i = m_entries.begin(); i != m_entries.end(); i++)\r
-        {\r
-          if (i->variable() && i->variable_name() == variable)\r
-          {\r
-            m_entries.erase(i);\r
-            return true;\r
-          }\r
-        }\r
-        return false;\r
-      }\r
-\r
-    bool print(std::ostream& str) const\r
-      {\r
-        str << "  [" << m_title << "]" << std::endl;\r
-        for (std::list<ini_entry>::const_iterator entry = m_entries.begin(); entry != m_entries.end(); entry++)\r
-          entry->print(str);\r
-        return !str.fail();\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // internal data structure representing a single ini file\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class ini_file\r
-  {\r
-  private:\r
-    friend class ini_section;\r
-    std::string m_filename;\r
-    bool m_changed;\r
-    bool m_writable;\r
-    std::list<ini_section> m_sections;\r
-\r
-    std::list<ini_section>::const_iterator find_section(const std::string& section) const\r
-      {\r
-        for (std::list<ini_section>::const_iterator i = m_sections.begin(); i != m_sections.end(); i++)\r
-        {\r
-          if (i->title() == section)\r
-            return i;\r
-        }\r
-        return m_sections.end();\r
-      }\r
-\r
-    std::list<ini_section>::iterator find_section(const std::string& section)\r
-      {\r
-        for (std::list<ini_section>::iterator i = m_sections.begin(); i != m_sections.end(); i++)\r
-        {\r
-          if (i->title() == section)\r
-            return i;\r
-        }\r
-        return m_sections.end();\r
-      }\r
-\r
-  public:\r
-\r
-    ini_file(void) : m_changed(false), m_writable(false)\r
-      {\r
-      }\r
-\r
-    ini_file(const std::string& filename) : m_changed(false), m_writable(false)\r
-      {\r
-        read_file(filename);\r
-      }\r
-\r
-    ~ini_file(void)\r
-      {\r
-        if (writable())\r
-          save_file();\r
-      }\r
-\r
-    bool initialised(void) const\r
-      {\r
-        return !m_filename.empty();\r
-      }\r
-\r
-    bool writable(void) const\r
-      {\r
-        return m_writable;\r
-      }\r
-\r
-    bool read_file(const std::string& filename)\r
-      {\r
-        m_filename = filename;\r
-        m_changed = false;\r
-        // file may not yet exist - possible to create an Ini file using this class\r
-        // so it is writable if the file exists and is writable or if the folder is writable\r
-        m_writable = file_writable(m_filename);\r
-        if (!file_exists(m_filename))\r
-          return true;\r
-        // create a dummy top section to hold file comments\r
-        std::list<ini_section>::iterator section = m_sections.insert(m_sections.end(), ini_section(""));\r
-        std::ifstream source(m_filename.c_str());\r
-        unsigned line_number = 0;\r
-        std::string line;\r
-        while(std::getline(source,line))\r
-        {\r
-          line_number++;\r
-          unsigned i = 0;\r
-          while(i < line.size() && isspace(line[i]))\r
-            i++;\r
-          if (i < line.size() && line[i] == '[')\r
-          {\r
-            // found a section title\r
-            // skip the [\r
-            i++;\r
-            // get the text up to the end ] or the end of the line\r
-            std::string title;\r
-            while (i < line.size() && line[i] != ']')\r
-              title += line[i++];\r
-            // create a new section and make it the current section\r
-            section = m_sections.insert(m_sections.end(), ini_section(title));\r
-          }\r
-          else if (i < line.size() && line[i] == ';')\r
-          {\r
-            // found a comment\r
-            // skip the ; because that is not part of the comment\r
-            i++;\r
-            // add the rest of the line as a comment to the current section\r
-            section->add_comment(line_number, line.substr(i, line.size()-1));\r
-          }\r
-          else if (i == line.size())\r
-          {\r
-            // found a blank line\r
-            section->add_blank(line_number);\r
-          }\r
-          else\r
-          {\r
-            // found a *possible* variable - now scan forwards for the = operator\r
-            std::string name;\r
-            while (i < line.size() && line[i] != '=')\r
-              name += line[i++];\r
-            // skip the = sign\r
-            // TODO - detect a missing = sign here and convert to an error\r
-            if (i < line.size())\r
-              i++;\r
-            // trim trailing whitespace off the name\r
-            name = trim(name);\r
-            // now get the value, minus any leading whitespace\r
-            std::string value;\r
-            while(i < line.size() && isspace(line[i]))\r
-              i++;\r
-            while (i < line.size())\r
-              value += line[i++];\r
-            // trim trailing whitespace off the value\r
-            value = trim(value);\r
-            // and finally add the name/value pair to the data structure\r
-            section->add_variable(line_number, name, value);\r
-          }\r
-        }\r
-        return true;\r
-      }\r
-\r
-    bool save_file(void)\r
-      {\r
-        if (!initialised()) return false;\r
-        if (!m_changed) return true;\r
-        if (!m_writable) return false;\r
-        std::ofstream output(m_filename.c_str());\r
-        for (std::list<ini_section>::iterator section = m_sections.begin(); section != m_sections.end(); section++)\r
-        {\r
-          if (!(section->title().empty()))\r
-            output << "[" << section->title() << "]" << std::endl;\r
-          for (std::list<ini_entry>::iterator entry = section->m_entries.begin(); entry != section->m_entries.end(); entry++)\r
-            output << entry->text() << std::endl;\r
-        }\r
-        m_changed = false;\r
-        return true;\r
-      }\r
-\r
-    std::string filename(void) const\r
-      {\r
-        return m_filename;\r
-      }\r
-\r
-    bool empty(void) const\r
-      {\r
-        // file is empty if it has either no sections or an empty header section\r
-        if (m_sections.empty()) return true;\r
-        if ((m_sections.begin() == --m_sections.end()) && m_sections.begin()->empty()) return true;\r
-        return false;\r
-      }\r
-\r
-    bool section_exists(const std::string& title) const\r
-      {\r
-        return find_section(title) != m_sections.end();\r
-      }\r
-\r
-    bool add_section(const std::string& section)\r
-      {\r
-        if (!m_writable) return false;\r
-        m_sections.push_back(ini_section(section));\r
-        m_changed = true;\r
-        return true;\r
-      }\r
-\r
-    bool empty_section(const std::string& section)\r
-      {\r
-        std::list<ini_section>::iterator found = find_section(section);\r
-        if (found == m_sections.end()) return false;\r
-        return found->empty();\r
-      }\r
-\r
-    bool erase_section(const std::string& section)\r
-      {\r
-        if (!m_writable) return false;\r
-        std::list<ini_section>::iterator found = find_section(section);\r
-        if (found == m_sections.end()) return false;\r
-        m_sections.erase(found);\r
-        m_changed = true;\r
-        return true;\r
-      }\r
-\r
-    bool clear_section(const std::string& section)\r
-      {\r
-        if (!m_writable) return false;\r
-        std::list<ini_section>::iterator found = find_section(section);\r
-        if (found == m_sections.end()) return false;\r
-        found->clear();\r
-        m_changed = true;\r
-        return true;\r
-      }\r
-\r
-    unsigned sections_size(void) const\r
-      {\r
-        return m_sections.size();\r
-      }\r
-\r
-    const std::string& section_name(unsigned i) const\r
-      {\r
-        std::list<ini_section>::const_iterator result = m_sections.begin();\r
-        for (unsigned j = 1; j <= i; j++)\r
-          result++;\r
-        return result->title();\r
-      }\r
-\r
-    std::vector<std::string> section_names(void) const\r
-      {\r
-        std::vector<std::string> result;\r
-        for (unsigned j = 0; j < sections_size(); j++)\r
-          result.push_back(section_name(j));\r
-        return result;\r
-      }\r
-\r
-    bool variable_exists(const std::string& section, const std::string variable) const\r
-      {\r
-        std::list<ini_section>::const_iterator found = find_section(section);\r
-        if (found == m_sections.end()) return false;\r
-        return found->variable_exists(variable);\r
-      }\r
-\r
-    std::vector<std::string> variable_names(const std::string& section) const\r
-      {\r
-        std::list<ini_section>::const_iterator found = find_section(section);\r
-        if (found == m_sections.end()) return std::vector<std::string>();\r
-        return found->variable_names();\r
-      }\r
-\r
-    unsigned variables_size(const std::string& section) const\r
-      {\r
-        std::list<ini_section>::const_iterator found = find_section(section);\r
-        if (found == m_sections.end()) return 0;\r
-        return found->variables_size();\r
-      }\r
-\r
-    unsigned variable_line(const std::string& section, const std::string variable) const\r
-      {\r
-        std::list<ini_section>::const_iterator found = find_section(section);\r
-        if (found == m_sections.end()) return 0;\r
-        return found->variable_line(variable);\r
-      }\r
-\r
-    std::string variable_name(const std::string& section, unsigned i) const\r
-      {\r
-        std::list<ini_section>::const_iterator found = find_section(section);\r
-        if (found == m_sections.end()) return std::string();\r
-        return found->variable_name(i);\r
-      }\r
-\r
-    std::string variable_value(const std::string& section, unsigned i) const\r
-      {\r
-        std::list<ini_section>::const_iterator found = find_section(section);\r
-        if (found == m_sections.end()) return std::string();\r
-        return found->variable_value(i);\r
-      }\r
-\r
-    std::string variable_value(const std::string& section, const std::string variable) const\r
-      {\r
-        std::list<ini_section>::const_iterator found = find_section(section);\r
-        if (found == m_sections.end()) return std::string();\r
-        return found->variable_value(variable);\r
-      }\r
-\r
-    bool add_variable(const std::string& section, const std::string& variable, const std::string& value)\r
-      {\r
-        if (!m_writable) return false;\r
-        std::list<ini_section>::iterator found = find_section(section);\r
-        if (found == m_sections.end()) found = m_sections.insert(m_sections.end(),ini_section(section));\r
-        if (found->add_variable(0,variable,value))\r
-          m_changed = true;\r
-        return true;\r
-      }\r
-\r
-    bool add_comment(const std::string& section, const std::string& comment)\r
-      {\r
-        if (!m_writable) return false;\r
-        std::list<ini_section>::iterator found = find_section(section);\r
-        if (found == m_sections.end()) found = m_sections.insert(m_sections.end(),ini_section(section));\r
-        if (found->add_comment(0,comment))\r
-          m_changed = true;\r
-        return true;\r
-      }\r
-\r
-    bool add_blank(const std::string& section)\r
-      {\r
-        if (!m_writable) return false;\r
-        std::list<ini_section>::iterator found = find_section(section);\r
-        if (found == m_sections.end()) found = m_sections.insert(m_sections.end(),ini_section(section));\r
-        if (found->add_blank(0))\r
-          m_changed = true;\r
-        return true;\r
-      }\r
-\r
-    bool erase_variable(const std::string& section, const std::string& variable)\r
-      {\r
-        if (!m_writable) return false;\r
-        std::list<ini_section>::iterator found = find_section(section);\r
-        if (found == m_sections.end()) return false;\r
-        if (found->erase_variable(variable))\r
-        {\r
-          m_changed = true;\r
-          return true;\r
-        }\r
-        return false;\r
-      }\r
-\r
-    bool print(std::ostream& str) const\r
-      {\r
-        str << "file: " << m_filename << std::endl;\r
-        for (std::list<ini_section>::const_iterator section = m_sections.begin(); section != m_sections.end(); section++)\r
-          section->print(str);\r
-        return !str.fail();\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // body data structure contains all the data and is pointed-to by exported data structure\r
-\r
-  class ini_manager_body\r
-  {\r
-  private:\r
-    std::vector<ini_file> m_files;\r
-    unsigned m_count;\r
-\r
-    ini_manager_body(const ini_manager_body&);\r
-    ini_manager_body& operator= (const ini_manager_body&);\r
-\r
-  public:\r
-\r
-    ini_manager_body(void) : m_count(1)\r
-      {\r
-      }\r
-\r
-    ~ini_manager_body(void)\r
-      {\r
-        save();\r
-      }\r
-\r
-    void increment(void)\r
-      {\r
-        ++m_count;\r
-      }\r
-\r
-    bool decrement(void)\r
-      {\r
-        --m_count;\r
-        return m_count == 0;\r
-      }\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // file management\r
-\r
-    // add files starting with the most local file (e.g. the current project) which has depth 0\r
-    // and working back to the most global (e.g. the installation settings) which has a depth of size()-1\r
-    // This does nothing if the file has already been loaded - it is not permitted to manage the same file twice.\r
-    // Returns true if the file loaded okay or was already loaded (it is counted as successful if the file did\r
-    // not exist, only read errors cause a failure)\r
-    bool add_file(const std::string& filename)\r
-      {\r
-        // if this file has been loaded, don't load it again\r
-        // this is not an error\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (filespec_to_path(filename) == filespec_to_path(m_files[i].filename()))\r
-            return true;\r
-        }\r
-        // add a new file to the back of the list and then load it\r
-        // I do it in two steps rather than passing the filename to the constructor in order to return the load status\r
-        m_files.push_back(ini_file());\r
-        return m_files.back().read_file(filename);\r
-      }\r
-\r
-    // as above, returns false if *none* of the files were added\r
-    // filenames[0] is the local file, and so on\r
-    bool add_files(const std::vector<std::string>& filenames)\r
-      {\r
-        bool result = true;\r
-        for (unsigned i = 0; i < filenames.size(); i++)\r
-          result &= add_file(filenames[i]);\r
-        return result;\r
-      }\r
-\r
-    // saves modified ini files - returns true if all modified files were written successfully\r
-    bool save(void)\r
-      {\r
-        bool result = true;\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-          result &= m_files[i].save_file();\r
-        return result;\r
-      }\r
-\r
-    // get the number of files being managed\r
-    unsigned size(void) const\r
-      {\r
-        return m_files.size();\r
-      }\r
-\r
-    // get the ini filename associated with a depth\r
-    std::string filename(unsigned depth) const\r
-      {\r
-        return m_files[depth].filename();\r
-      }\r
-\r
-    // test whether a file in the ini manager is writable\r
-    bool writable(unsigned depth) const\r
-      {\r
-        return m_files[depth].writable();\r
-      }\r
-\r
-    // test whether a file is empty\r
-    // An ini file is considered empty if it has no named sections and the header is empty or missing\r
-    bool empty(unsigned depth) const\r
-      {\r
-        return m_files[depth].empty();\r
-      }\r
-\r
-    // erase the ini file from the ini manager and from the disk\r
-    bool erase(unsigned depth)\r
-      {\r
-        std::string file = filename(depth);\r
-        remove(depth);\r
-        return file_delete(file);\r
-      }\r
-\r
-    // remove the file from the ini manager but do not erase it from the disk\r
-    bool remove(unsigned depth)\r
-      {\r
-        if (m_files[depth].writable())\r
-          m_files[depth].save_file();\r
-        m_files.erase(m_files.begin() + depth);\r
-        return true;\r
-      }\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // section management\r
-\r
-    // returns the union of all section names in all of the ini files\r
-    std::vector<std::string> section_names(void) const\r
-      {\r
-        std::vector<std::string> result;\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          std::vector<std::string> file_result = section_names(i);\r
-          for (unsigned j = 0; j < file_result.size(); j++)\r
-          {\r
-            if (std::find(result.begin(), result.end(), file_result[j]) == result.end())\r
-              result.push_back(file_result[j]);\r
-          }\r
-        }\r
-        return result;\r
-      }\r
-\r
-    // returns the section names in one of the ini files\r
-    std::vector<std::string> section_names(unsigned depth) const\r
-      {\r
-        return m_files[depth].section_names();\r
-      }\r
-\r
-    // tests whether a section is found in any of the ini files\r
-    bool section_exists(const std::string& title) const\r
-      {\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (m_files[i].section_exists(title))\r
-            return true;\r
-        }\r
-        return false;\r
-      }\r
-\r
-    // tests whether the section is found in the specific ini file\r
-    bool section_exists(const std::string& title, unsigned depth) const\r
-      {\r
-        return m_files[depth].section_exists(title);\r
-      }\r
-\r
-    // adds a section to the specified ini file - does nothing if it is already present\r
-    bool add_section(const std::string& section, unsigned depth)\r
-      {\r
-        return m_files[depth].add_section(section);\r
-      }\r
-\r
-    // test whether a section is empty\r
-    bool empty_section(const std::string& section, unsigned depth)\r
-      {\r
-        return m_files[depth].empty_section(section);\r
-      }\r
-\r
-    // removes a section from the specified ini file if it exists there but cannot remove it from any other file\r
-    bool erase_section(const std::string& section, unsigned depth)\r
-      {\r
-        return m_files[depth].erase_section(section);\r
-      }\r
-\r
-    // removes all the contents of a section from the specified ini file but keeps the empty section\r
-    bool clear_section(const std::string& section, unsigned depth)\r
-      {\r
-        return m_files[depth].clear_section(section);\r
-      }\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // variable management\r
-\r
-    // test whether a variable exists in any of the ini files\r
-    bool variable_exists(const std::string& section, const std::string variable) const\r
-      {\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (variable_exists(section, variable, i))\r
-            return true;\r
-        }\r
-        return false;\r
-      }\r
-\r
-    // test whether a variable exists in specified ini file\r
-    bool variable_exists(const std::string& section, const std::string variable, unsigned depth) const\r
-      {\r
-        return m_files[depth].variable_exists(section, variable);\r
-      }\r
-\r
-    // get the union of all variables declared in all ini files\r
-    std::vector<std::string> variable_names(const std::string& section) const\r
-      {\r
-        std::vector<std::string> result;\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          std::vector<std::string> file_result = variable_names(section, i);\r
-          for (unsigned j = 0; j < file_result.size(); j++)\r
-          {\r
-            if (std::find(result.begin(), result.end(), file_result[j]) == result.end())\r
-              result.push_back(file_result[j]);\r
-          }\r
-        }\r
-        return result;\r
-      }\r
-\r
-    // get the set of all varaibale names from one file\r
-    std::vector<std::string> variable_names(const std::string& section, unsigned depth) const\r
-      {\r
-        return m_files[depth].variable_names(section);\r
-      }\r
-\r
-    // get the depth of the first ini file to define a variable\r
-    // returns 0 if defined in the local ini file, etc. Returns (unsigned)-1 if the variable doesn't exist\r
-    unsigned variable_depth(const std::string& section, const std::string variable) const\r
-      {\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (variable_exists(section, variable, i))\r
-            return i;\r
-        }\r
-        return (unsigned)-1;\r
-      }\r
-\r
-    // get the filename that first defines the variable\r
-    std::string variable_filename(const std::string& section, const std::string variable) const\r
-      {\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (variable_exists(section, variable, i))\r
-            return filename(i);\r
-        }\r
-        return std::string();\r
-      }\r
-\r
-    unsigned variable_linenumber(const std::string& section, const std::string variable) const\r
-      {\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (variable_exists(section, variable, i))\r
-            return m_files[i].variable_line(section,variable);\r
-        }\r
-        return 0;\r
-      }\r
-\r
-    // get the value of a variable as a single unprocessed string\r
-    // if the variable does not exist the string will be empty, but beware that\r
-    // you also get an empty string if a variable exists but has no value\r
-    // you can differentiate between the two cases by using variable_exists_all above\r
-    std::string variable_value(const std::string& section, const std::string variable) const\r
-      {\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (variable_exists(section, variable, i))\r
-            return variable_value(section, variable, i);\r
-        }\r
-        return std::string();\r
-      }\r
-\r
-    // get the value from the specified file\r
-    std::string variable_value(const std::string& section, const std::string variable, unsigned depth) const\r
-      {\r
-        return m_files[depth].variable_value(section, variable);\r
-      }\r
-\r
-    // get the value of a variable as a processed string\r
-    // processing splits the value at commas and furthermore supports quoted\r
-    // strings (so that values can contain commas for example)\r
-    // quoted strings are dequoted before they are added to the result\r
-    // the result is a vector of dequoted strings, one per value in the comma-separated list\r
-    std::vector<std::string> variable_values(const std::string& section, const std::string variable) const\r
-      {\r
-        for (unsigned i = 0; i < m_files.size(); i++)\r
-        {\r
-          if (variable_exists(section, variable, i))\r
-            return variable_values(section, variable, i);\r
-        }\r
-        return std::vector<std::string>();\r
-      }\r
-\r
-    // get the processed variable from the specified file\r
-    std::vector<std::string> variable_values(const std::string& section, const std::string variable, unsigned depth) const\r
-      {\r
-        // get the unprocessed value and then do the processing into processed separate values\r
-        std::string value = variable_value(section, variable, depth);\r
-        std::vector<std::string> result;\r
-        if (!value.empty())\r
-        {\r
-          result.push_back(std::string());\r
-          unsigned i = 0;\r
-          // loop which is repeated for each element in the comma-separated list\r
-          while(i < value.size())\r
-          {\r
-            // skip leading whitespace\r
-            while (i < value.size() && isspace(value[i])) i++;\r
-            // get the value - this means all text up to the next comma or end of line\r
-            // also allow escaped characters\r
-            while (i < value.size())\r
-            {\r
-              if (value[i] == ',') break;\r
-              if (value[i] == '\\')\r
-              {\r
-                // found an escaped character - de-escape it by only getting the next character\r
-                // beware of an escape character at the end of the line which just gets ignored\r
-                i++;\r
-                if (i < value.size()) result.back() += value[i++];\r
-              }\r
-              else if (value[i] == '"')\r
-              {\r
-                // get a quoted substring\r
-                // first skip the opening quote\r
-                i++;\r
-                // keep getting characters until a close-quote, but allow the quote character to be escaped by itself\r
-                while (i < value.size())\r
-                {\r
-                  if (value[i] == '"')\r
-                  {\r
-                    // found a quote skip it\r
-                    i++;\r
-                    // now establish whether its an escaped quote\r
-                    // if it is, keep it, but de-escape it by only getting the next character\r
-                    // it it isn't, break out and continue processing the value as a non-quoted string\r
-                    if (i < value.size() && value[i] != '"') break;\r
-                    if (i < value.size()) result.back() += value[i++];\r
-                  }\r
-                  else\r
-                  {\r
-                    // non-quote and non-escape so just get the character\r
-                    result.back() += value[i++];\r
-                  }\r
-                }\r
-              }\r
-              else\r
-              {\r
-                // non-escape so just get the character\r
-                result.back() += value[i++];\r
-              }\r
-            }\r
-            // trim trailing whitespace off the value\r
-            while (!result.back().empty() && isspace(result.back()[result.back().size()-1])) result.back().erase(result.back().size()-1,1);\r
-            // now check for whether there is a comma or end of line\r
-            if (i <= value.size() && value[i] == ',')\r
-            {\r
-              // skip the comma and add a new string to the result ready for the next iteration\r
-              i++;\r
-              result.push_back(std::string());\r
-            }\r
-            else\r
-            {\r
-              // end of line found so break out\r
-              break;\r
-            }\r
-          }\r
-        }\r
-        return result;\r
-      }\r
-\r
-    // add a variable to the specified file\r
-    bool add_variable(const std::string& section, const std::string& variable, const std::string& value, unsigned depth)\r
-      {\r
-        return m_files[depth].add_variable(section, variable, value);\r
-      }\r
-\r
-    // add a variable as a processed string\r
-    // processing means that the values in the string vector are converted into a comma-separated list\r
-    // values containing reserved characters are automatically quoted - so you should not even try to quote them yourself\r
-    bool add_variable(const std::string& section, const std::string& variable, const std::vector<std::string>& values, unsigned depth)\r
-      {\r
-        // convert the values vector into a comma-separated string with each value escaped so that special characters do not confuse the reader\r
-        // the characters escaped are: '\', ',', '"'\r
-        std::string value;\r
-        for (unsigned v = 0; v < values.size(); v++)\r
-        {\r
-          const std::string& element = values[v];\r
-          // add the comma between values === add a comma before all but the first value\r
-          if (v > 0) value += ',';\r
-          for (unsigned i = 0; i < element.size(); i++)\r
-          {\r
-            // add a character at a time, escaping special characters\r
-            if (element[i] == '"' || element[i] == ',' || element[i] == '\\')\r
-            {\r
-              // escape the character\r
-              value += '\\';\r
-            }\r
-            value += element[i];\r
-          }\r
-        }\r
-        return add_variable(section, variable, value, depth);\r
-      }\r
-\r
-    // erase a variable from the specified file\r
-    // this does not remove the variable from other ini files, so the variable may still exist\r
-    // to mask a global variable, set the variable to an empty string instead\r
-    bool erase_variable(const std::string& section, const std::string& variable, unsigned depth)\r
-      {\r
-        return m_files[depth].erase_variable(section, variable);\r
-      }\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // sundry line-entry management\r
-\r
-    // add a comment to the specified ini file\r
-    bool add_comment(const std::string& section, const std::string& comment, unsigned depth)\r
-      {\r
-        return m_files[depth].add_comment(section, comment);\r
-      }\r
-\r
-    // add a blank line to the specified ini file\r
-    bool add_blank(const std::string& section, unsigned depth)\r
-      {\r
-        return m_files[depth].add_blank(section);\r
-      }\r
-\r
-    bool print(std::ostream& str) const\r
-      {\r
-        str << "----------------------------------------" << std::endl;\r
-        for (unsigned depth = 0; depth < m_files.size(); depth++)\r
-        {\r
-          m_files[depth].print(str);\r
-          str << "----------------------------------------" << std::endl;\r
-        }\r
-        return !str.fail();\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // exported data structure representing the set of all ini files and providing\r
-  // the access functions exported by the class\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // constructors/destructors\r
-\r
-  ini_manager::ini_manager(void) : m_body(new ini_manager_body)\r
-  {\r
-  }\r
-\r
-  ini_manager::ini_manager(const std::vector<std::string>& filenames) : m_body(new ini_manager_body)\r
-  {\r
-    add_files(filenames);\r
-  }\r
-\r
-  ini_manager::ini_manager(const ini_manager& manager) : m_body(0)\r
-  {\r
-    m_body = manager.m_body;\r
-    m_body->increment();\r
-  }\r
-\r
-  ini_manager& ini_manager::operator= (const ini_manager& manager)\r
-  {\r
-    if (m_body == manager.m_body) return *this;\r
-    if (m_body->decrement())\r
-      delete m_body;\r
-    m_body = manager.m_body;\r
-    m_body->increment();\r
-    return *this;\r
-  }\r
-\r
-  ini_manager::~ini_manager(void)\r
-  {\r
-    if (m_body->decrement())\r
-      delete m_body;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // file management\r
-\r
-  bool ini_manager::add_file(const std::string& filename)\r
-  {\r
-    return m_body->add_file(filename);\r
-  }\r
-\r
-  bool ini_manager::add_files(const std::vector<std::string>& filenames)\r
-  {\r
-    return m_body->add_files(filenames);\r
-  }\r
-\r
-  bool ini_manager::save(void)\r
-  {\r
-    return m_body->save();\r
-  }\r
-\r
-  unsigned ini_manager::size(void) const\r
-  {\r
-    return m_body->size();\r
-  }\r
-\r
-  std::string ini_manager::filename(unsigned depth) const\r
-  {\r
-    return m_body->filename(depth);\r
-  }\r
-\r
-  bool ini_manager::writable(unsigned depth) const\r
-  {\r
-    return m_body->writable(depth);\r
-  }\r
-\r
-  bool ini_manager::empty(unsigned depth) const\r
-  {\r
-    return m_body->empty(depth);\r
-  }\r
-\r
-  bool ini_manager::erase(unsigned depth)\r
-  {\r
-    return m_body->erase(depth);\r
-  }\r
-\r
-  bool ini_manager::remove(unsigned depth)\r
-  {\r
-    return m_body->remove(depth);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // section management\r
-\r
-  std::vector<std::string> ini_manager::section_names(void) const\r
-  {\r
-    return m_body->section_names();\r
-  }\r
-\r
-  std::vector<std::string> ini_manager::section_names(unsigned depth) const\r
-  {\r
-    return m_body->section_names(depth);\r
-  }\r
-\r
-  bool ini_manager::section_exists(const std::string& section) const\r
-  {\r
-    return m_body->section_exists(section);\r
-  }\r
-\r
-  bool ini_manager::section_exists(const std::string& section, unsigned depth) const\r
-  {\r
-    return m_body->section_exists(section, depth);\r
-  }\r
-\r
-  bool ini_manager::add_section(const std::string& section, unsigned depth)\r
-  {\r
-    return m_body->add_section(section, depth);  \r
-  }\r
-\r
-  bool ini_manager::empty_section(const std::string& section, unsigned depth)\r
-  {\r
-    return m_body->empty_section(section, depth);  \r
-  }\r
-\r
-  bool ini_manager::erase_section(const std::string& section, unsigned depth)\r
-  {\r
-    return m_body->erase_section(section, depth);  \r
-  }\r
-\r
-  bool ini_manager::clear_section(const std::string& section, unsigned depth)\r
-  {\r
-    return m_body->clear_section(section, depth);  \r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // variable management\r
-\r
-  bool ini_manager::variable_exists(const std::string& section, const std::string variable) const\r
-  {\r
-    return m_body->variable_exists(section, variable);  \r
-  }\r
-\r
-  bool ini_manager::variable_exists(const std::string& section, const std::string variable, unsigned depth) const\r
-  {\r
-    return m_body->variable_exists(section, variable, depth);  \r
-  }\r
-\r
-  std::vector<std::string> ini_manager::variable_names(const std::string& section) const\r
-  {\r
-    return m_body->variable_names(section);  \r
-  }\r
-\r
-  std::vector<std::string> ini_manager::variable_names(const std::string& section, unsigned depth) const\r
-  {\r
-    return m_body->variable_names(section, depth);  \r
-  }\r
-\r
-  unsigned ini_manager::variable_depth(const std::string& section, const std::string variable) const\r
-  {\r
-    return m_body->variable_depth(section, variable);  \r
-  }\r
-\r
-  std::string ini_manager::variable_filename(const std::string& section, const std::string variable) const\r
-  {\r
-    return m_body->variable_filename(section, variable);  \r
-  }\r
-\r
-  unsigned ini_manager::variable_linenumber(const std::string& section, const std::string variable) const\r
-  {\r
-    return m_body->variable_linenumber(section, variable);  \r
-  }\r
-\r
-  std::string ini_manager::variable_value(const std::string& section, const std::string variable) const\r
-  {\r
-    return m_body->variable_value(section, variable);  \r
-  }\r
-\r
-  std::string ini_manager::variable_value(const std::string& section, const std::string variable, unsigned depth) const\r
-  {\r
-    return m_body->variable_value(section, variable, depth);  \r
-  }\r
-\r
-  std::vector<std::string> ini_manager::variable_values(const std::string& section, const std::string variable) const\r
-  {\r
-    return m_body->variable_values(section, variable);  \r
-  }\r
-\r
-  std::vector<std::string> ini_manager::variable_values(const std::string& section, const std::string variable, unsigned depth) const\r
-  {\r
-    return m_body->variable_values(section, variable, depth);  \r
-  }\r
-\r
-  bool ini_manager::add_variable(const std::string& section, const std::string& variable, const std::string& value, unsigned depth)\r
-  {\r
-    return m_body->add_variable(section, variable, value, depth);\r
-  }\r
-\r
-  bool ini_manager::add_variable(const std::string& section, const std::string& variable, const std::vector<std::string>& values, unsigned depth)\r
-  {\r
-    return m_body->add_variable(section, variable, values, depth);\r
-  }\r
-\r
-  bool ini_manager::erase_variable(const std::string& section, const std::string& variable, unsigned depth)\r
-  {\r
-    return m_body->erase_variable(section, variable, depth);\r
-  }\r
-\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // sundry entries\r
-\r
-  bool ini_manager::add_comment(const std::string& section, const std::string& comment, unsigned depth)\r
-  {\r
-    return m_body->add_comment(section, comment, depth);\r
-  }\r
-\r
-  bool ini_manager::add_blank(const std::string& section, unsigned depth)\r
-  {\r
-    return m_body->add_blank(section, depth);\r
-  }\r
-\r
-  bool ini_manager::print(std::ostream& str) const\r
-  {\r
-    return m_body->print(str);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // diagnostic print\r
-\r
-  std::ostream& operator << (std::ostream& str, const ini_manager& manager)\r
-  {\r
-    manager.print(str);\r
-    return str;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/subsystems/ini_manager.hpp b/src/stlplus/subsystems/ini_manager.hpp
deleted file mode 100644 (file)
index f1d7a66..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef STLPLUS_INI_MANAGER\r
-#define STLPLUS_INI_MANAGER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A subsystem for managing INI (i.e. .ini) files\r
-//   An INI file has the following format\r
-\r
-//     file           ::= header { section }*\r
-//     header         ::= { comment | blank }*\r
-//     section        ::= section_header { declaration | comment | blank }*\r
-//     section_header ::= '[' title ']' '\n'\r
-//     declaration    ::= variable '=' value '\n'\r
-//     comment        ::= ';' text '\n'\r
-//     blank          ::= '\n'\r
-//     title          ::= [~']']*\r
-//     variable       ::= [~'=']*\r
-//     value          ::= .*\r
-//     text           ::= .*\r
-\r
-//   Whitespace is trimmed from the leading and trailing ends of title, variable and value\r
-//   Note: a header is represented internally as a Clint section (i.e. a section with no name)\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "subsystems_fixes.hpp"\r
-#include <vector>\r
-#include <string>\r
-#include <iostream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Internals\r
-\r
-  class ini_manager_body;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Ini-file manager class\r
-\r
-  class ini_manager\r
-  {\r
-  public:\r
-\r
-    ini_manager(void);\r
-\r
-    explicit ini_manager(const std::vector<std::string>& filenames);\r
-\r
-    ini_manager(const ini_manager&);\r
-    ini_manager& operator= (const ini_manager&);\r
-\r
-    ~ini_manager(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // file management\r
-\r
-    // add files starting with the most local file (e.g. the current project) which has depth 0\r
-    // and working back to the most global (e.g. the installation settings) which has a depth of size()-1\r
-    // This does nothing if the file has already been loaded - it is not permitted to manage the same file twice.\r
-    // Returns true if the file loaded okay or was already loaded (it is counted as successful if the file did\r
-    // not exist, only read errors cause a failure)\r
-    bool add_file(const std::string& filename);\r
-\r
-    // as above, returns false if *none* of the files were added\r
-    // filenames[0] is the local file, and so on\r
-    bool add_files(const std::vector<std::string>& filenames);\r
-\r
-    // saves modified ini files - returns true if all modified files were written successfully\r
-    bool save(void);\r
-\r
-    // get the number of files being managed\r
-    unsigned size(void) const;\r
-\r
-    // get the ini filename associated with a depth\r
-    std::string filename(unsigned depth = 0) const;\r
-\r
-    // test whether a file in the ini manager is writable\r
-    bool writable(unsigned depth = 0) const;\r
-\r
-    // test whether a file is empty\r
-    // An ini file is considered empty if it has no named sections and the header is empty or missing\r
-    bool empty(unsigned depth = 0) const;\r
-\r
-    // erase the ini file from the ini manager and from the disk\r
-    bool erase(unsigned depth = 0);\r
-\r
-    // remove the file from the ini manager but do not erase it from the disk\r
-    bool remove(unsigned depth = 0);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // section management\r
-\r
-    // returns the union of all section names in all of the ini files\r
-    std::vector<std::string> section_names(void) const;\r
-\r
-    // returns the section names in one of the ini files\r
-    std::vector<std::string> section_names(unsigned depth) const;\r
-\r
-    // tests whether a section is found in any of the ini files\r
-    bool section_exists(const std::string& title) const;\r
-\r
-    // tests whether the section is found in the specific ini file\r
-    bool section_exists(const std::string& title, unsigned depth) const;\r
-\r
-    // adds a section to the specified ini file - does nothing if it is already present\r
-    bool add_section(const std::string& section, unsigned depth = 0);\r
-\r
-    // test whether a section is empty\r
-    bool empty_section(const std::string& section, unsigned depth = 0);\r
-\r
-    // removes a section from the specified ini file if it exists there but cannot remove it from any other file\r
-    bool erase_section(const std::string& section, unsigned depth = 0);\r
-\r
-    // removes all the contents of a section from the specified ini file but keeps the empty section\r
-    bool clear_section(const std::string& section, unsigned depth = 0);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // variable management\r
-\r
-    // test whether a variable exists in any of the ini files\r
-    bool variable_exists(const std::string& section, const std::string variable) const;\r
-\r
-    // test whether a variable exists in specified ini file\r
-    bool variable_exists(const std::string& section, const std::string variable, unsigned depth) const;\r
-\r
-    // get the union of all variables declared in all ini files\r
-    std::vector<std::string> variable_names(const std::string& section) const;\r
-\r
-    // get the set of all varaibale names from one file\r
-    std::vector<std::string> variable_names(const std::string& section, unsigned depth) const;\r
-\r
-    // get the depth of the first ini file to define a variable\r
-    // returns 0 if defined in the local ini file, etc. Returns (unsigned)-1 if the variable doesn't exist\r
-    unsigned variable_depth(const std::string& section, const std::string variable) const;\r
-\r
-    // get the filename that first defines the variable\r
-    std::string variable_filename(const std::string& section, const std::string variable) const;\r
-    // ditto for its linenumber within that file\r
-    unsigned variable_linenumber(const std::string& section, const std::string variable) const;\r
-\r
-    // get the value of a variable as a single unprocessed string\r
-    // if the variable does not exist the string will be empty, but beware that\r
-    // you also get an empty string if a variable exists but has no value\r
-    // you can differentiate between the two cases by using variable_exists_all above\r
-    std::string variable_value(const std::string& section, const std::string variable) const;\r
-\r
-    // get the value from the specified file\r
-    std::string variable_value(const std::string& section, const std::string variable, unsigned depth) const;\r
-\r
-    // get the value of a variable as a processed string\r
-    // processing splits the value at commas and furthermore supports quoted strings (so that values can contain commas for example)\r
-    // quoted strings are dequoted before they are added to the result\r
-    // the result is a vector of dequoted strings, one per value in the comma-separated list\r
-    std::vector<std::string> variable_values(const std::string& section, const std::string variable) const;\r
-\r
-    // get the processed variable from the specified file\r
-    std::vector<std::string> variable_values(const std::string& section, const std::string variable, unsigned depth) const;\r
-\r
-    // add a variable to the specified file\r
-    bool add_variable(const std::string& section, const std::string& variable, const std::string& value, unsigned depth = 0);\r
-\r
-    // add a variable as a processed string\r
-    // processing means that the values in the string vector are converted into a comma-separated list\r
-    // values containing reserved characters are automatically quoted - so you should not even try to quote them yourself\r
-    bool add_variable(const std::string& section, const std::string& variable, const std::vector<std::string>& values, unsigned depth = 0);\r
-\r
-    // erase a variable from the specified file\r
-    // this does not remove the variable from other ini files, so the variable may still exist\r
-    // to mask a global variable, set the variable to an empty string instead\r
-    bool erase_variable(const std::string& section, const std::string& variable, unsigned depth = 0);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // sundry line-entry management\r
-\r
-    // add a comment to the specified ini file\r
-    bool add_comment(const std::string& section, const std::string& comment, unsigned depth = 0);\r
-\r
-    // add a blank line to the specified ini file\r
-    bool add_blank(const std::string& section, unsigned depth = 0);\r
-\r
-    bool print(std::ostream&) const;\r
-\r
-  private:\r
-    friend class ini_manager_body;\r
-    ini_manager_body* m_body;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // diagnostic print routine\r
-\r
-  std::ostream& operator << (std::ostream&, const ini_manager&);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/subsystems/library_manager.cpp b/src/stlplus/subsystems/library_manager.cpp
deleted file mode 100644 (file)
index 0daf1be..0000000
+++ /dev/null
@@ -1,2332 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "library_manager.hpp"\r
-#include "file_system.hpp"\r
-#include <algorithm>\r
-#include <fstream>\r
-#include <ctype.h>\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-static const char* LibraryNameExtension = "lmn";\r
-static const char* HeaderExtension = "lmh";\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// local operations\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-typedef std::map<std::string,stlplus::lm_callback_entry> lm_callback_map;\r
-\r
-static std::string lowercase(const std::string& val)\r
-{\r
-  std::string text = val;\r
-  for (unsigned i = 0; i < text.size(); i++)\r
-    text[i] = tolower(text[i]);\r
-  return text;\r
-}\r
-\r
-// Context file and library operations\r
-// These must be readable/writeable without a library data structure present\r
-// so that the name of the library is known before creation\r
-\r
-static bool read_context(const std::string& path, const std::string& owner, std::string& name, bool& writable)\r
-{\r
-  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
-  name = "";\r
-  writable = false;\r
-  if (!stlplus::file_exists(spec)) return false;\r
-  std::ifstream input(spec.c_str());\r
-  input >> name >> writable;\r
-  return !input.fail();\r
-}\r
-\r
-static bool write_context(const std::string& path, const std::string& owner, const std::string& name, bool writable)\r
-{\r
-  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
-  std::ofstream output(spec.c_str());\r
-  output << name << " " << writable << std::endl;\r
-  return !output.fail();\r
-}\r
-\r
-static bool create_library(const std::string& path, const std::string& owner, const std::string& name, bool writable)\r
-{\r
-  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
-  if (stlplus::is_present(path) && !stlplus::is_folder(path)) return false;\r
-  if (!stlplus::folder_exists(path) && !stlplus::folder_create(path)) return false;\r
-  return write_context(path, owner, name, writable);\r
-}\r
-\r
-static bool erase_library(const std::string& path, const std::string& owner)\r
-{\r
-  // check that it is a library before deleting it!\r
-  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
-  if (!stlplus::file_exists(spec)) return false;\r
-  return stlplus::folder_delete(path, true);\r
-}\r
-\r
-// dependency checking\r
-\r
-typedef std::map<std::pair<std::string,stlplus::lm_unit_name>,stlplus::lm_dependencies> visited_map;\r
-\r
-static stlplus::lm_dependencies& out_of_date_check (visited_map& visited,\r
-                                                    const stlplus::library_manager* manager,\r
-                                                    const std::string& library,\r
-                                                    const stlplus::lm_unit_name& name)\r
-{\r
-  // the visited field contains an entry if a unit has been visited - it also contains the reason for out-of-date-ness\r
-  // this is initially set empty (up to date) since the unit has to be added\r
-  // before it is checked just in case there is a recursive loop\r
-  // the dependencies field is filled in if the unit is subsequently found to be out of date\r
-  std::pair<std::string,stlplus::lm_unit_name> full_name = std::make_pair(library,name);\r
-  // first check whether this unit has already been visited - this should in\r
-  // principle never happen because the same test is performed before trying\r
-  // to recurse, so consider this to be paranoid-mode programming\r
-  visited_map::iterator found = visited.find(full_name);\r
-  if (found != visited.end())\r
-    return found->second;\r
-  // now add this unit to prevent recursion loops later. This entry is added\r
-  // to when out-of-date dependencies are found and is also the return value\r
-  // of the function\r
-  visited[full_name] = stlplus::lm_dependencies();\r
-  // now find the unit\r
-  const stlplus::lm_unit_ptr unit = manager->find(library,name);\r
-  if (!unit)\r
-  {\r
-    // if a unit is missing it fails with a dependency on itself - this is a\r
-    // bit of a work-around, but this again is paranoid-mode programming since\r
-    // the calling function (this function calling itself recursively) should\r
-    // check the unit's existence before recursing\r
-    visited[full_name].unit_add(stlplus::lm_unit_dependency(library,name));\r
-  }\r
-  else\r
-  {\r
-    // we're onto the real checks now - first get the datestamp of this unit:\r
-    // all dependencies must be older than this\r
-    time_t unit_modified = unit->modified();\r
-    // check dependency on source file if there is one\r
-    if (unit->source_file_present())\r
-    {\r
-      std::string source_file = unit->source_file().path_full(unit->library_path());\r
-      time_t source_modified = stlplus::file_modified(source_file);\r
-      if (source_modified == 0 || source_modified > unit_modified)\r
-      {\r
-        visited[full_name].set_source_file(unit->source_file());\r
-      }\r
-    }\r
-    // now check the other file dependencies\r
-    for (unsigned i = 0; i < unit->file_size(); i++)\r
-    {\r
-      // a file dependency is a dependency on a file outside of the library system\r
-      const stlplus::lm_file_dependency& dependency = unit->file_dependency(i);\r
-      std::string file_full = dependency.path_full(unit->library_path());\r
-      time_t source_modified = stlplus::file_modified(file_full);\r
-      if (source_modified == 0 || source_modified > unit_modified)\r
-      {\r
-        visited[full_name].file_add(dependency);\r
-      }\r
-    }\r
-    // now check and recurse on unit dependencies\r
-    for (unsigned j = 0; j < unit->unit_size(); j++)\r
-    {\r
-      const stlplus::lm_unit_dependency& dependency = unit->unit_dependency(j);\r
-      std::pair<std::string,stlplus::lm_unit_name> other_name = std::make_pair(dependency.library(), dependency.unit_name());\r
-      // perform the datestamp checking at this level and only recurse if this does not detect an error\r
-      const stlplus::lm_unit_ptr other_unit = manager->find(other_name.first, other_name.second);\r
-      if (!other_unit)\r
-      {\r
-        visited[full_name].unit_add(dependency);\r
-      }\r
-      else\r
-      {\r
-        time_t other_modified = other_unit->modified();\r
-        if (other_modified == 0 || other_modified > unit_modified)\r
-        {\r
-          visited[full_name].unit_add(dependency);\r
-        }\r
-        else\r
-        {\r
-          // prevent recursion before doing it\r
-          visited_map::iterator other_found = visited.find(other_name);\r
-          if (other_found != visited.end())\r
-          {\r
-            // if the unit was found to be out of date on the previous visit, add it to the failed dependencies\r
-            if (!other_found->second.empty())\r
-            {\r
-              visited[full_name].unit_add(dependency);\r
-            }\r
-          }\r
-          else\r
-          {\r
-            // the unit hasn't been visited before, so recurse on it now\r
-            stlplus::lm_dependencies other_dependencies = \r
-              out_of_date_check(visited, manager, other_name.first, other_name.second);\r
-            if (!other_dependencies.empty())\r
-            {\r
-              visited[full_name].unit_add(dependency);\r
-            }\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }\r
-  return visited[full_name];\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// class lm_unit_name\r
-\r
-stlplus::lm_unit_name::lm_unit_name(const std::string& name, const std::string& type) :\r
-  m_name(name), m_type(type)\r
-{\r
-}\r
-\r
-stlplus::lm_unit_name::~lm_unit_name(void)\r
-{\r
-}\r
-\r
-const std::string& stlplus::lm_unit_name::name(void) const\r
-{\r
-  return m_name;\r
-}\r
-\r
-void stlplus::lm_unit_name::set_name(const std::string& name)\r
-{\r
-  m_name = name;\r
-}\r
-\r
-void stlplus::lm_unit_name::lowercase(void)\r
-{\r
-  m_name = ::lowercase(m_name);\r
-}\r
-\r
-const std::string& stlplus::lm_unit_name::type(void) const\r
-{\r
-  return m_type;\r
-}\r
-\r
-void stlplus::lm_unit_name::set_type(const std::string& type)\r
-{\r
-  m_type = type;\r
-}\r
-\r
-bool stlplus::lm_unit_name::write(std::ostream& context) const\r
-{\r
-  context << m_name << " " << m_type;\r
-  return !context.fail();\r
-}\r
-\r
-bool stlplus::lm_unit_name::read(std::istream& context)\r
-{\r
-  context >> m_name >> m_type;\r
-  return !context.fail();\r
-}\r
-\r
-std::string stlplus::lm_unit_name::to_string(void) const\r
-{\r
-  return m_name + ":" + m_type;\r
-}\r
-\r
-bool stlplus::lm_unit_name::print(std::ostream& str) const\r
-{\r
-  str << to_string();\r
-  return !str.fail();\r
-}\r
-\r
-std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit_name& name)\r
-{\r
-  name.print(str);\r
-  return str;\r
-}\r
-\r
-bool stlplus::operator == (const stlplus::lm_unit_name& l, const stlplus::lm_unit_name& r)\r
-{\r
-  return l.name() == r.name() && l.type() == r.type();\r
-}\r
-\r
-bool stlplus::operator < (const stlplus::lm_unit_name& l, const stlplus::lm_unit_name& r)\r
-{\r
-  // sort by name then type\r
-  return (l.name() != r.name()) ? l.name() < r.name() : l.type() < r.type();\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// dependencies\r
-\r
-// file dependencies\r
-\r
-stlplus::lm_file_dependency::lm_file_dependency(void) : m_line(0), m_column(0)\r
-{\r
-}\r
-\r
-stlplus::lm_file_dependency::lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line, unsigned column)\r
-{\r
-  set_path(library_path, path);\r
-  set_line(line);\r
-  set_column(column);\r
-}\r
-\r
-stlplus::lm_file_dependency::~lm_file_dependency(void)\r
-{\r
-}\r
-\r
-const std::string& stlplus::lm_file_dependency::path(void) const\r
-{\r
-  return m_path;\r
-}\r
-\r
-std::string stlplus::lm_file_dependency::path_full(const std::string& library_path) const\r
-{\r
-  return filespec_to_path(library_path, m_path);\r
-}\r
-\r
-void stlplus::lm_file_dependency::set_path(const std::string& library_path, const std::string& path)\r
-{\r
-  m_path = filespec_to_relative_path(library_path, path);\r
-}\r
-\r
-unsigned stlplus::lm_file_dependency::line(void) const\r
-{\r
-  return m_line;\r
-}\r
-\r
-void stlplus::lm_file_dependency::set_line(unsigned line)\r
-{\r
-  m_line = line;\r
-}\r
-\r
-unsigned stlplus::lm_file_dependency::column(void) const\r
-{\r
-  return m_column;\r
-}\r
-\r
-void stlplus::lm_file_dependency::set_column(unsigned column)\r
-{\r
-  m_column = column;\r
-}\r
-\r
-bool stlplus::lm_file_dependency::write(std::ostream& context) const\r
-{\r
-  context << m_path << " " << m_line << " " << m_column;\r
-  return !context.fail();\r
-}\r
-\r
-bool stlplus::lm_file_dependency::read(std::istream& context)\r
-{\r
-  context >> m_path >> m_line >> m_column;\r
-  return !context.fail();\r
-}\r
-\r
-bool stlplus::lm_file_dependency::print(std::ostream& str) const\r
-{\r
-  str << "file: " << m_path;\r
-  if (m_line != 0)\r
-    str << ":" << m_line << ":" << m_column;\r
-  return !str.fail();\r
-}\r
-\r
-std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_file_dependency& dependency)\r
-{\r
-  dependency.print(str);\r
-  return str;\r
-}\r
-\r
-// unit dependency\r
-\r
-stlplus::lm_unit_dependency::lm_unit_dependency(void)\r
-{\r
-}\r
-\r
-stlplus::lm_unit_dependency::lm_unit_dependency(const std::string& library, const lm_unit_name& name) : \r
-  m_library(library), m_name(name)\r
-{\r
-}\r
-\r
-stlplus::lm_unit_dependency::~lm_unit_dependency(void)\r
-{\r
-}\r
-\r
-const std::string& stlplus::lm_unit_dependency::library(void) const\r
-{\r
-  return m_library;\r
-}\r
-\r
-void stlplus::lm_unit_dependency::set_library(const std::string& library)\r
-{\r
-  m_library = library;\r
-}\r
-\r
-const stlplus::lm_unit_name& stlplus::lm_unit_dependency::unit_name(void) const\r
-{\r
-  return m_name;\r
-}\r
-\r
-void stlplus::lm_unit_dependency::set_unit_name(const lm_unit_name& unit_name)\r
-{\r
-  m_name = unit_name;\r
-}\r
-\r
-const std::string& stlplus::lm_unit_dependency::name(void) const\r
-{\r
-  return m_name.name();\r
-}\r
-\r
-void stlplus::lm_unit_dependency::set_name(const std::string& name)\r
-{\r
-  m_name.set_name(name);\r
-}\r
-\r
-const std::string& stlplus::lm_unit_dependency::type(void) const\r
-{\r
-  return m_name.type();\r
-}\r
-\r
-void stlplus::lm_unit_dependency::set_type(const std::string& type)\r
-{\r
-  m_name.set_type(type);\r
-}\r
-\r
-bool stlplus::lm_unit_dependency::write(std::ostream& context) const\r
-{\r
-  context << m_library;\r
-  m_name.write(context);\r
-  return !context.fail();\r
-}\r
-\r
-bool stlplus::lm_unit_dependency::read(std::istream& context)\r
-{\r
-  context >> m_library;\r
-  m_name.read(context);;\r
-  return !context.fail();\r
-}\r
-\r
-bool stlplus::lm_unit_dependency::print(std::ostream& str) const\r
-{\r
-  str << "unit: " << m_library << "." << m_name;\r
-  return !str.fail();\r
-}\r
-\r
-std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit_dependency& dependency)\r
-{\r
-  dependency.print(str);\r
-  return str;\r
-}\r
-\r
-// dependencies\r
-\r
-stlplus::lm_dependencies::lm_dependencies(void) : m_source(0)\r
-{\r
-}\r
-\r
-stlplus::lm_dependencies::lm_dependencies(const lm_dependencies& r) : m_source(0)\r
-{\r
-  *this = r;\r
-}\r
-\r
-stlplus::lm_dependencies& stlplus::lm_dependencies::operator=(const stlplus::lm_dependencies& r)\r
-{\r
-  if (m_source)\r
-    delete m_source;\r
-  m_source = 0;\r
-  if (r.m_source)\r
-    m_source = new lm_file_dependency(*r.m_source);\r
-  m_files = r.m_files;\r
-  m_units = r.m_units;\r
-  return *this;\r
-}\r
-\r
-stlplus::lm_dependencies::~lm_dependencies(void)\r
-{\r
-  if (m_source)\r
-    delete m_source;\r
-}\r
-\r
-void stlplus::lm_dependencies::set_source_file(const lm_file_dependency& source)\r
-{\r
-  if (m_source)\r
-    delete m_source;\r
-  m_source = new lm_file_dependency(source);\r
-}\r
-\r
-bool stlplus::lm_dependencies::source_file_present(void) const\r
-{\r
-  return (m_source != 0);\r
-}\r
-\r
-const stlplus::lm_file_dependency& stlplus::lm_dependencies::source_file(void) const\r
-{\r
-  return *m_source;\r
-}\r
-\r
-unsigned stlplus::lm_dependencies::file_add(const lm_file_dependency& dependency)\r
-{\r
-  m_files.push_back(dependency);\r
-  return m_files.size()-1;\r
-}\r
-\r
-unsigned stlplus::lm_dependencies::file_size(void) const\r
-{\r
-  return m_files.size();\r
-}\r
-\r
-const stlplus::lm_file_dependency& stlplus::lm_dependencies::file_dependency(unsigned i) const\r
-{\r
-  return m_files[i];\r
-}\r
-\r
-void stlplus::lm_dependencies::file_erase(unsigned i)\r
-{\r
-  m_files.erase(m_files.begin()+i);\r
-}\r
-\r
-unsigned stlplus::lm_dependencies::unit_add(const lm_unit_dependency& dependency)\r
-{\r
-  m_units.push_back(dependency);\r
-  return m_units.size()-1;\r
-}\r
-\r
-unsigned stlplus::lm_dependencies::unit_size(void) const\r
-{\r
-  return m_units.size();\r
-}\r
-\r
-const stlplus::lm_unit_dependency& stlplus::lm_dependencies::unit_dependency(unsigned i) const\r
-{\r
-  return m_units[i];\r
-}\r
-\r
-void stlplus::lm_dependencies::unit_erase(unsigned i)\r
-{\r
-  m_units.erase(m_units.begin()+i);\r
-}\r
-\r
-void stlplus::lm_dependencies::clear(void)\r
-{\r
-  if (m_source)\r
-    delete m_source;\r
-  m_source = 0;\r
-  m_files.clear();\r
-  m_units.clear();\r
-}\r
-\r
-bool stlplus::lm_dependencies::empty(void) const\r
-{\r
-  return (m_source == 0) && m_files.empty() && m_units.empty();\r
-}\r
-\r
-bool stlplus::lm_dependencies::write(std::ostream& context) const\r
-{\r
-  context << (m_source ? true : false) << " ";\r
-  if (m_source) m_source->write(context);\r
-  context << std::endl;\r
-  context << m_files.size() << std::endl;\r
-  for (unsigned i = 0; i < m_files.size(); i++)\r
-  {\r
-    m_files[i].write(context);\r
-    context << std::endl;\r
-  }\r
-  context << m_units.size() << std::endl;\r
-  for (unsigned j = 0; j < m_units.size(); j++)\r
-  {\r
-    m_units[j].write(context);\r
-    context << std::endl;\r
-  }\r
-  return !context.fail();\r
-}\r
-\r
-bool stlplus::lm_dependencies::read(std::istream& context)\r
-{\r
-  clear();\r
-  bool source_present = false;\r
-  context >> source_present;\r
-  if (source_present)\r
-  {\r
-    m_source = new lm_file_dependency();\r
-    m_source->read(context);\r
-  }\r
-  unsigned files_size = 0;\r
-  context >> files_size;\r
-  for (unsigned i = 0; i < files_size; i++)\r
-  {\r
-    m_files.push_back(lm_file_dependency());\r
-    m_files.back().read(context);\r
-  }\r
-  unsigned units_size = 0;\r
-  context >> units_size;\r
-  for (unsigned j = 0; j < units_size; j++)\r
-  {\r
-    m_units.push_back(lm_unit_dependency());\r
-    m_units.back().read(context);\r
-  }\r
-  return !context.fail();\r
-}\r
-\r
-bool stlplus::lm_dependencies::print(std::ostream& str) const\r
-{\r
-  if (m_source)\r
-    str << "  source file: " << *m_source << std::endl;\r
-  for (unsigned i = 0; i < m_files.size(); i++)\r
-    str << "  " << m_files[i] << std::endl;\r
-  for (unsigned j = 0; j < m_units.size(); j++)\r
-    str << "  " << m_units[j] << std::endl;\r
-  return !str.fail();\r
-}\r
-\r
-std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_dependencies& dependencies)\r
-{\r
-  dependencies.print(str);\r
-  return str;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// lm_unit\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-stlplus::lm_unit::lm_unit(const lm_unit_name& name, lm_library* library) : \r
-  m_name(name), m_header_modified(false), m_loaded(false), m_marked(false), m_library(library), m_error(false)\r
-{\r
-  read_header();\r
-}\r
-\r
-stlplus::lm_unit::~lm_unit(void)\r
-{\r
-  write_header();\r
-}\r
-\r
-////////////////////////////////////////\r
-// Header data\r
-\r
-const stlplus::lm_unit_name& stlplus::lm_unit::unit_name(void) const\r
-{\r
-  return m_name;\r
-}\r
-\r
-const std::string& stlplus::lm_unit::name(void) const\r
-{\r
-  return m_name.name();\r
-}\r
-\r
-const std::string& stlplus::lm_unit::type(void) const\r
-{\r
-  return m_name.type();\r
-}\r
-\r
-// dependencies\r
-\r
-// source file dependency\r
-\r
-void stlplus::lm_unit::set_source_file(const lm_file_dependency& dependency)\r
-{\r
-  m_header_modified = true;\r
-  m_dependencies.set_source_file(dependency);\r
-}\r
-\r
-bool stlplus::lm_unit::source_file_present(void) const\r
-{\r
-  return m_dependencies.source_file_present();\r
-}\r
-\r
-const stlplus::lm_file_dependency& stlplus::lm_unit::source_file(void) const\r
-{\r
-  return m_dependencies.source_file();\r
-}\r
-\r
-// other file dependencies\r
-\r
-unsigned stlplus::lm_unit::file_add(const lm_file_dependency& dependency)\r
-{\r
-  m_header_modified = true;\r
-  return m_dependencies.file_add(dependency);\r
-}\r
-\r
-unsigned stlplus::lm_unit::file_size(void) const\r
-{\r
-  return m_dependencies.file_size();\r
-}\r
-\r
-const stlplus::lm_file_dependency& stlplus::lm_unit::file_dependency(unsigned i) const\r
-{\r
-  return m_dependencies.file_dependency(i);\r
-}\r
-\r
-void stlplus::lm_unit::file_erase(unsigned i)\r
-{\r
-  m_header_modified = true;\r
-  m_dependencies.file_erase(i);\r
-}\r
-\r
-// unit dependencies\r
-\r
-unsigned stlplus::lm_unit::unit_add(const lm_unit_dependency& dependency)\r
-{\r
-  m_header_modified = true;\r
-  return m_dependencies.unit_add(dependency);\r
-}\r
-\r
-unsigned stlplus::lm_unit::unit_size(void) const\r
-{\r
-  return m_dependencies.unit_size();\r
-}\r
-\r
-const stlplus::lm_unit_dependency& stlplus::lm_unit::unit_dependency(unsigned i) const\r
-{\r
-  return m_dependencies.unit_dependency(i);\r
-}\r
-\r
-void stlplus::lm_unit::unit_erase(unsigned i)\r
-{\r
-  m_header_modified = true;\r
-  m_dependencies.unit_erase(i);\r
-}\r
-\r
-const stlplus::lm_dependencies& stlplus::lm_unit::dependencies(void) const\r
-{\r
-  return m_dependencies;\r
-}\r
-\r
-void stlplus::lm_unit::set_dependencies(const lm_dependencies& dependencies)\r
-{\r
-  m_header_modified = true;\r
-  m_dependencies = dependencies;\r
-}\r
-\r
-void stlplus::lm_unit::clear_dependencies(void)\r
-{\r
-  m_header_modified = true;\r
-  m_dependencies.clear();\r
-}\r
-\r
-bool stlplus::lm_unit::empty_dependencies(void) const\r
-{\r
-  return m_dependencies.empty();\r
-}\r
-\r
-// dependency checking\r
-\r
-bool stlplus::lm_unit::out_of_date(void) const\r
-{\r
-  return m_library->out_of_date(m_name);\r
-}\r
-\r
-bool stlplus::lm_unit::up_to_date(void) const\r
-{\r
-  return m_library->up_to_date(m_name);\r
-}\r
-\r
-stlplus::lm_dependencies stlplus::lm_unit::out_of_date_reason(void) const\r
-{\r
-  return m_library->out_of_date_reason(m_name);\r
-}\r
-\r
-// supplementary data\r
-\r
-const std::string& stlplus::lm_unit::supplementary_data(void) const\r
-{\r
-  return m_supplement;\r
-}\r
-\r
-void stlplus::lm_unit::set_supplementary_data(const std::string& data)\r
-{\r
-  m_supplement = data;\r
-  m_header_modified = true;\r
-}\r
-\r
-////////////////////////////////////////\r
-// unit data management\r
-\r
-bool stlplus::lm_unit::load(void)\r
-{\r
-  if (out_of_date()) return false;\r
-  if (m_loaded) return true;\r
-  // get the user data for this type\r
-  lm_callback_map::iterator callback = m_library->m_manager->m_callbacks.find(type());\r
-  if (callback == m_library->m_manager->m_callbacks.end()) return false;\r
-  void* data = callback->second.m_type_data;\r
-  bool result = read(filename(), data);\r
-  m_loaded = true;\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_unit::save(void)\r
-{\r
-  if (!m_marked) return true;\r
-  if (!m_loaded) return false;\r
-  // get the user data for this type\r
-  lm_callback_map::iterator callback = m_library->m_manager->m_callbacks.find(type());\r
-  if (callback == m_library->m_manager->m_callbacks.end()) return false;\r
-  void* data = callback->second.m_type_data;\r
-  bool result = write(filename(), data);\r
-  if (result) m_marked = false;\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_unit::loaded(void) const\r
-{\r
-  return m_loaded;\r
-}\r
-\r
-void stlplus::lm_unit::mark(void)\r
-{\r
-  m_marked = true;\r
-}\r
-\r
-time_t stlplus::lm_unit::modified(void) const\r
-{\r
-  return file_modified(filename());\r
-}\r
-\r
-////////////////////////////////////////\r
-// containing library manager details\r
-\r
-const stlplus::lm_library* stlplus::lm_unit::library(void) const\r
-{\r
-  return m_library;\r
-}\r
-\r
-stlplus::lm_library* stlplus::lm_unit::library(void)\r
-{\r
-  return m_library;\r
-}\r
-\r
-const std::string& stlplus::lm_unit::library_name(void) const\r
-{\r
-  return m_library->name();\r
-}\r
-\r
-const std::string& stlplus::lm_unit::library_path(void) const\r
-{\r
-  return m_library->path();\r
-}\r
-\r
-// error handling - these apply to the last read/write operation\r
-\r
-bool stlplus::lm_unit::error(void) const\r
-{\r
-  return m_error;\r
-}\r
-\r
-// functions that customise subclasses of this superclass\r
-\r
-bool stlplus::lm_unit::read(const std::string& filespec, void* type_data)\r
-{\r
-  std::ifstream input(filespec.c_str());\r
-  bool result = read(input, type_data);\r
-  if (input.fail())\r
-  {\r
-    result = false;\r
-    m_error = true;\r
-  }\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_unit::read(std::istream&, void*)\r
-{\r
-  return false;\r
-}\r
-\r
-bool stlplus::lm_unit::write(const std::string& filespec, void* type_data)\r
-{\r
-  std::ofstream output(filespec.c_str());\r
-  bool result = write(output, type_data);\r
-  if (output.fail())\r
-  {\r
-    result = false;\r
-    m_error = true;\r
-  }\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_unit::write(std::ostream&, void*)\r
-{\r
-  return false;\r
-}\r
-\r
-bool stlplus::lm_unit::purge(void)\r
-{\r
-  return true;\r
-}\r
-\r
-stlplus::lm_unit* stlplus::lm_unit::clone(void) const\r
-{\r
-  return new lm_unit(*this);\r
-}\r
-\r
-bool stlplus::lm_unit::print(std::ostream& str) const\r
-{\r
-  str << m_name << " " << (m_loaded ? "loaded" : "") << " " << (m_marked ? "needs saving" : "");\r
-  return !str.fail();\r
-}\r
-\r
-bool stlplus::lm_unit::print_long(std::ostream& str) const\r
-{\r
-  str << "header:" << std::endl;\r
-  str << "  name: " << m_name.name() << std::endl;\r
-  str << "  type: " << library()->manager()->description(m_name.type()) << std::endl;\r
-  str << "  dependencies:" << std::endl;\r
-  // Note: I've inlined this rather than call the above-defined print for dependencies\r
-  // This is so that I can use the library manager to look up the descriptions of unit types\r
-  // I can also convert paths so that they are relative to the current directory rather than the library\r
-  // print the source file dependency if present\r
-  if (m_dependencies.source_file_present())\r
-  {\r
-    str << "  source file: ";\r
-    str << filespec_to_relative_path(m_dependencies.source_file().path_full(library()->path()));\r
-    if (m_dependencies.source_file().line() != 0)\r
-      str << ":" << m_dependencies.source_file().line() << ":" << m_dependencies.source_file().column();\r
-    str << std::endl;\r
-  }\r
-  // now print other file dependencies\r
-  // convert these to relative paths too\r
-  for (unsigned f = 0; f < m_dependencies.file_size(); f++)\r
-  {\r
-    str << "  file: ";\r
-    str << filespec_to_relative_path(m_dependencies.file_dependency(f).path_full(library()->path()));\r
-    if (m_dependencies.file_dependency(f).line() != 0)\r
-      str << ":" << m_dependencies.file_dependency(f).line() << ":" << m_dependencies.file_dependency(f).column();\r
-    str << std::endl;\r
-  }\r
-  // now print unit dependencies\r
-  // convert unit types to their descriptive strings\r
-  for (unsigned u = 0; u < m_dependencies.unit_size(); u++)\r
-  {\r
-    str << "  " << library()->manager()->description(m_dependencies.unit_dependency(u).type()) << ": ";\r
-    str << m_dependencies.unit_dependency(u).library() << "." << m_dependencies.unit_dependency(u).name();\r
-    str << std::endl;\r
-  }\r
-  if (!m_supplement.empty())\r
-  {\r
-    str << "  supplementary data: " << m_supplement << std::endl;\r
-  }\r
-  return !str.fail();\r
-}\r
-\r
-// header file management\r
-\r
-std::string stlplus::lm_unit::filename(void) const\r
-{\r
-  return stlplus::create_filespec(library_path(), m_name.name(), m_name.type());\r
-}\r
-\r
-std::string stlplus::lm_unit::header_filename(void) const\r
-{\r
-  return stlplus::create_filespec(library_path(), m_name.name(), m_name.type() + std::string(HeaderExtension));\r
-}\r
-\r
-bool stlplus::lm_unit::read_header(void)\r
-{\r
-  if (file_exists(header_filename()))\r
-  {\r
-    std::ifstream input(header_filename().c_str());\r
-    m_dependencies.read(input);\r
-    input.get();\r
-    std::getline(input, m_supplement);\r
-  }\r
-  m_header_modified = false;\r
-  return true;\r
-}\r
-\r
-bool stlplus::lm_unit::write_header(void)\r
-{\r
-  if (!m_header_modified) return true;\r
-  std::ofstream output(header_filename().c_str());\r
-  m_dependencies.write(output);\r
-  output << m_supplement << std::endl;\r
-  m_header_modified = false;\r
-  return true;\r
-}\r
-\r
-// print diagnostics\r
-\r
-std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_unit& u)\r
-{\r
-  u.print(str);\r
-  return str;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// lm_library\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// constructors/destructors\r
-// copy operations only legal on unopened libraries\r
-\r
-stlplus::lm_library::lm_library(library_manager* manager) : m_writable(false), m_manager(manager)\r
-{\r
-}\r
-\r
-stlplus::lm_library::lm_library(const lm_library& library) : m_writable(library.m_writable), m_manager(library.m_manager)\r
-{\r
-}\r
-\r
-stlplus::lm_library& stlplus::lm_library::operator = (const stlplus::lm_library& library)\r
-{\r
-  m_writable = library.m_writable;\r
-  m_manager = library.m_manager;\r
-  return *this;\r
-}\r
-\r
-stlplus::lm_library::~lm_library(void)\r
-{\r
-  close();\r
-}\r
-\r
-const stlplus::library_manager* stlplus::lm_library::manager(void) const\r
-{\r
-  return m_manager;\r
-}\r
-\r
-stlplus::library_manager* stlplus::lm_library::manager(void)\r
-{\r
-  return m_manager;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// initialisers\r
-\r
-bool stlplus::lm_library::create(const std::string& name, const std::string& path, bool writable)\r
-{\r
-  close();\r
-  if (!create_library(path, m_manager->m_owner, name, writable)) return false;\r
-  return open(path);\r
-}\r
-\r
-bool stlplus::lm_library::open(const std::string& path)\r
-{\r
-  close();\r
-  if (!read_context(path, m_manager->m_owner, m_name, m_writable)) return false;\r
-  // convert path to full path on load\r
-  m_path = folder_to_path(path);\r
-  return load_types();\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// management of types\r
-\r
-bool stlplus::lm_library::load_type(const std::string& type)\r
-{\r
-  lm_callback_map::iterator callback = m_manager->m_callbacks.find(type);\r
-  if (callback == m_manager->m_callbacks.end()) return false;\r
-  // a null callback means create a dummy unit from the baseclass only\r
-  lm_create_callback fn = callback->second.m_callback;\r
-  void* data = callback->second.m_type_data;\r
-  // for each file in the library folder that matches the type of the create callback, create an unloaded unit\r
-  std::vector<std::string> files = folder_wildcard(m_path, stlplus::create_filename("*", type), false, true);\r
-  for (unsigned i = 0; i < files.size(); i++)\r
-  {\r
-    // key by unit name - lowercase name if case-insensitive\r
-    lm_unit_name uname(basename_part(files[i]),type);\r
-    if (!m_manager->m_unit_case) uname.lowercase();\r
-    lm_unit_ptr unit;\r
-    // if there's a callback, use it to create the subclass, else create the\r
-    // superclass which only contains header information\r
-    if (fn)\r
-      unit.set(fn(uname,this,data));\r
-    else\r
-      unit.set(new lm_unit(uname,this));\r
-    m_units[uname] = unit;\r
-  }\r
-  return true;\r
-}\r
-\r
-bool stlplus::lm_library::load_types(void)\r
-{\r
-  bool result = true;\r
-  for (lm_callback_map::const_iterator i = m_manager->m_callbacks.begin(); i != m_manager->m_callbacks.end(); i++)\r
-    result &= load_type(i->first);\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_library::remove_type(const std::string& type)\r
-{\r
-  bool result = true;\r
-  std::vector<std::string> units = names(type);\r
-  for (std::vector<std::string>::iterator i = units.begin(); i != units.end(); i++)\r
-  {\r
-    lm_unit_name name(*i, type);\r
-    std::map<lm_unit_name,lm_unit_ptr>::iterator ni = local_find(name);\r
-    if (ni != m_units.end())\r
-      m_units.erase(ni);\r
-  }\r
-  return result;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// whole library operations\r
-\r
-bool stlplus::lm_library::load(void)\r
-{\r
-  bool result = true;\r
-  for (std::map<lm_unit_name,lm_unit_ptr>::iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    result &= i->second->load();\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_library::save(void)\r
-{\r
-  bool result = true;\r
-  for (std::map<lm_unit_name,lm_unit_ptr>::iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    result &= i->second->save();\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_library::purge(void)\r
-{\r
-  bool result = true;\r
-  for (std::map<lm_unit_name,lm_unit_ptr>::iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    result &= i->second->purge();\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_library::close(void)\r
-{\r
-  bool result = save();\r
-  m_units.clear();\r
-  m_path = "";\r
-  m_writable = false;\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_library::erase(void)\r
-{\r
-  // preserve the path because close destroys it\r
-  std::string path = m_path;\r
-  return close() && erase_library(path, m_manager->m_owner);\r
-}\r
-\r
-const std::string& stlplus::lm_library::name(void) const\r
-{\r
-  return m_name;\r
-}\r
-\r
-const std::string& stlplus::lm_library::path(void) const\r
-{\r
-  return m_path;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// managing read/write status\r
-\r
-bool stlplus::lm_library::set_read_write(bool writable)\r
-{\r
-  if (m_writable == writable) return true;\r
-  if (os_read_only()) return false;\r
-  m_writable = writable;\r
-  if (!write_context(m_path, m_manager->m_owner, m_name, m_writable))\r
-    read_context(m_path, m_manager->m_owner, m_name, m_writable);\r
-  return m_writable == writable;\r
-}\r
-\r
-bool stlplus::lm_library::set_writable(void)\r
-{\r
-  return set_read_write(true);\r
-}\r
-\r
-bool stlplus::lm_library::set_read_only(void)\r
-{\r
-  return set_read_write(false);\r
-}\r
-\r
-bool stlplus::lm_library::writable(void) const\r
-{\r
-  return os_writable() && lm_writable();\r
-}\r
-\r
-bool stlplus::lm_library::read_only(void) const\r
-{\r
-  return os_read_only() || lm_read_only();\r
-}\r
-\r
-bool stlplus::lm_library::os_writable(void) const\r
-{\r
-  return folder_writable(path());\r
-}\r
-\r
-bool stlplus::lm_library::os_read_only(void) const\r
-{\r
-  return !folder_writable(path());\r
-}\r
-\r
-bool stlplus::lm_library::lm_writable(void) const\r
-{\r
-  return m_writable;\r
-}\r
-\r
-bool stlplus::lm_library::lm_read_only(void) const\r
-{\r
-  return !m_writable;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// unit management\r
-\r
-std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::iterator stlplus::lm_library::local_find(const lm_unit_name& name)\r
-{\r
-  // implement the case-sensitivity\r
-  lm_unit_name local = name;\r
-  if (!m_manager->m_unit_case) local.lowercase();\r
-  return m_units.find(local);\r
-}\r
-\r
-std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator stlplus::lm_library::local_find(const lm_unit_name& name) const\r
-{\r
-  // implement the case-sensitivity\r
-  lm_unit_name local = name;\r
-  if (!m_manager->m_unit_case) local.set_name(lowercase(local.name()));\r
-  return m_units.find(local);\r
-}\r
-\r
-bool stlplus::lm_library::exists(const lm_unit_name& name) const\r
-{\r
-  return find(name).present();\r
-}\r
-\r
-stlplus::lm_unit_ptr stlplus::lm_library::create(const stlplus::lm_unit_name& name)\r
-{\r
-  if (read_only()) return lm_unit_ptr();\r
-  // preserve the unit's name, but use a lowercase key in case-insensitive mode\r
-  lm_unit_name uname = name;\r
-  if (!m_manager->m_unit_case) uname.lowercase();\r
-  // remove any existing unit with the same name\r
-  erase(uname);\r
-  // use the callbacks to create a new unit\r
-  lm_callback_map::iterator callback = m_manager->m_callbacks.find(name.type());\r
-  if (callback == m_manager->m_callbacks.end()) return lm_unit_ptr();\r
-  lm_unit_ptr new_unit;\r
-  new_unit.set(callback->second.m_callback(name,this,callback->second.m_type_data));\r
-  new_unit->m_loaded = true;\r
-  // add it to the library manager\r
-  m_units[uname] = new_unit;\r
-  return m_units[uname];\r
-}\r
-\r
-bool stlplus::lm_library::loaded(const lm_unit_name& name) const\r
-{\r
-  lm_unit_ptr unit = find(name);\r
-  return unit && unit->loaded();\r
-}\r
-\r
-bool stlplus::lm_library::load(const lm_unit_name& name)\r
-{\r
-  lm_unit_ptr unit = find(name);\r
-  if (!unit) return false;\r
-  return unit->load();\r
-}\r
-\r
-bool stlplus::lm_library::purge(const lm_unit_name& name)\r
-{\r
-  lm_unit_ptr unit = find(name);\r
-  if (!unit) return false;\r
-  bool result = save(name);\r
-  result &= unit->purge();\r
-  unit->m_loaded = false;\r
-  return result;\r
-}\r
-\r
-bool stlplus::lm_library::save(const lm_unit_name& name)\r
-{\r
-  if (read_only()) return false;\r
-  lm_unit_ptr unit = find(name);\r
-  if (!unit) return false;\r
-  return unit->save();\r
-}\r
-\r
-bool stlplus::lm_library::erase(const lm_unit_name& name)\r
-{\r
-  if (read_only()) return false;\r
-  std::map<lm_unit_name,lm_unit_ptr>::iterator i = local_find(name);\r
-  if (i == m_units.end()) return false;\r
-  std::string spec = i->second->filename();\r
-  std::string header_spec = i->second->header_filename();\r
-  m_units.erase(i);\r
-  file_delete(spec);\r
-  file_delete(header_spec);\r
-  return true;\r
-}\r
-\r
-bool stlplus::lm_library::mark(const lm_unit_name& name)\r
-{\r
-  if (read_only()) return false;\r
-  lm_unit_ptr unit = find(name);\r
-  if (!unit) return false;\r
-  unit->mark();\r
-  return true;\r
-}\r
-\r
-time_t stlplus::lm_library::modified(const lm_unit_name& name) const\r
-{\r
-  lm_unit_ptr unit = find(name);\r
-  return unit ? unit->modified() : 0;\r
-}\r
-\r
-bool stlplus::lm_library::erase_by_source(const std::string& source_file)\r
-{\r
-  if (read_only()) return false;\r
-  if (source_file.empty()) return false;\r
-  bool result = false;\r
-  std::string source_file_full = filespec_to_path(source_file);\r
-  // erase by unit name so that I don't have to deal with an iterator to a changing map\r
-  std::vector<lm_unit_name> units = names();\r
-  for (std::vector<lm_unit_name>::iterator i = units.begin(); i != units.end(); i++)\r
-  {\r
-    lm_unit_ptr unit = find(*i);\r
-    if (unit && unit->source_file_present())\r
-    {\r
-      std::string file_full = unit->source_file().path_full(unit->library_path());\r
-      if (file_full == source_file_full)\r
-      {\r
-        erase(*i);\r
-        result = true;\r
-      }\r
-    }\r
-  }\r
-  return result;\r
-}\r
-\r
-const stlplus::lm_unit_ptr stlplus::lm_library::find(const stlplus::lm_unit_name& name) const\r
-{\r
-  std::map<lm_unit_name,lm_unit_ptr>::const_iterator i = local_find(name);\r
-  if (i == m_units.end()) return lm_unit_ptr();\r
-  return i->second;\r
-}\r
-\r
-stlplus::lm_unit_ptr stlplus::lm_library::find(const stlplus::lm_unit_name& name)\r
-{\r
-  std::map<lm_unit_name,lm_unit_ptr>::iterator i = local_find(name);\r
-  if (i == m_units.end()) return lm_unit_ptr();\r
-  return i->second;\r
-}\r
-\r
-std::vector<stlplus::lm_unit_name> stlplus::lm_library::names(void) const\r
-{\r
-  std::vector<stlplus::lm_unit_name> result;\r
-  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    result.push_back(i->second->unit_name());\r
-  return result;\r
-}\r
-\r
-std::vector<std::string> stlplus::lm_library::names(const std::string& type) const\r
-{\r
-  std::vector<std::string> result;\r
-  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    if (i->first.type() == type)\r
-      result.push_back(i->second->name());\r
-  return result;\r
-}\r
-\r
-std::vector<stlplus::lm_unit_ptr> stlplus::lm_library::handles(void) const\r
-{\r
-  std::vector<stlplus::lm_unit_ptr> result;\r
-  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    result.push_back(i->second);\r
-  return result;\r
-}\r
-\r
-std::vector<stlplus::lm_unit_ptr> stlplus::lm_library::handles(const std::string& type) const\r
-{\r
-  std::vector<stlplus::lm_unit_ptr> result;\r
-  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    if (i->first.type() == type)\r
-      result.push_back(i->second);\r
-  return result;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// dependency checking\r
-\r
-bool stlplus::lm_library::out_of_date(const stlplus::lm_unit_name& name) const\r
-{\r
-  return m_manager->out_of_date(m_name, name);\r
-}\r
-\r
-bool stlplus::lm_library::up_to_date(const stlplus::lm_unit_name& name) const\r
-{\r
-  return m_manager->up_to_date(m_name, name);\r
-}\r
-\r
-stlplus::lm_dependencies stlplus::lm_library::out_of_date_reason(const stlplus::lm_unit_name& unit) const\r
-{\r
-  return m_manager->out_of_date_reason(m_name, unit);\r
-}\r
-\r
-std::pair<bool,unsigned> stlplus::lm_library::tidy(void)\r
-{\r
-  std::pair<bool,unsigned> result = std::make_pair(true,0);\r
-  // erase every unit that is out of date\r
-  // this will potentially make other units out of date, so keep erasing until\r
-  // everything is up to date or an error occurs\r
-  for (;;)\r
-  {\r
-    std::vector<stlplus::lm_unit_name> units = names();\r
-    unsigned initial_count = result.second;\r
-    for (std::vector<stlplus::lm_unit_name>::iterator i = units.begin(); i != units.end(); i++)\r
-    {\r
-      if (out_of_date(*i))\r
-      {\r
-        if (!erase(*i))\r
-          result.first = false;\r
-        else\r
-          result.second++;\r
-      }\r
-    }\r
-    if (!result.first) break;\r
-    if (result.second == initial_count) break;\r
-  }\r
-  return result;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// do-everything print routine!\r
-\r
-bool stlplus::lm_library::pretty_print(std::ostream& str,\r
-                                       bool print_units,\r
-                                       const std::string& type) const\r
-{\r
-  // print the library information\r
-  if (this == m_manager->work())\r
-    str << "->> ";\r
-  else\r
-    str << "    ";\r
-  str << name() << " in directory " << folder_to_relative_path(path());\r
-  if (read_only()) str << " (locked)";\r
-  str << std::endl;\r
-  // select the units\r
-  if (print_units)\r
-  {\r
-    // separate into a block per unit kind\r
-    for (lm_callback_map::const_iterator j = m_manager->m_callbacks.begin(); j != m_manager->m_callbacks.end(); j++)\r
-    {\r
-      // select the requested unit kind\r
-      if (type.empty() || type == j->first)\r
-      {\r
-        // get all the units of this kind\r
-        std::vector<std::string> unit_names = names(j->first);\r
-        if (!unit_names.empty())\r
-        {\r
-          str << "    " << j->second.m_description << std::endl;\r
-          for (unsigned k = 0; k < unit_names.size(); k++)\r
-          {\r
-            lm_dependencies reason = out_of_date_reason(stlplus::lm_unit_name(unit_names[k],j->first));\r
-            str << "    - " << unit_names[k];\r
-            if (!reason.empty()) str << " (out of date)";\r
-            str << std::endl;\r
-            if (!reason.empty())\r
-            {\r
-              if (reason.source_file_present())\r
-              {\r
-                const lm_file_dependency& file = reason.source_file();\r
-                str << "    * source file " << filespec_to_relative_path(file.path_full(path())) << " has changed" << std::endl;\r
-              }\r
-              for (unsigned i1 = 0; i1 < reason.file_size(); i1++)\r
-              {\r
-                const lm_file_dependency& file = reason.file_dependency(i1);\r
-                str << "    * file " << filespec_to_relative_path(file.path_full(path())) << " has changed" << std::endl;\r
-              }\r
-              for (unsigned i2 = 0; i2 < reason.unit_size(); i2++)\r
-              {\r
-                const lm_unit_dependency& file = reason.unit_dependency(i2);\r
-                lm_callback_map::const_iterator entry = m_manager->m_callbacks.find(file.type());\r
-                str << "    * " << entry->second.m_description << " " << file.library() << "." << file.name() << " has changed" << std::endl;\r
-              }\r
-            }\r
-          }\r
-        }\r
-      }\r
-    }\r
-  }\r
-  return true;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// diagnostic print routines\r
-\r
-bool stlplus::lm_library::print(std::ostream& str) const\r
-{\r
-  str << name() << " in " << path() << " " << (writable() ? "writable" : "read-only") << std::endl;\r
-  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    i->second->print(str);\r
-  return !str.fail();\r
-}\r
-\r
-bool stlplus::lm_library::print_long(std::ostream& str) const\r
-{\r
-  str << name() << " in " << path() << " " << (writable() ? "writable" : "read-only") << std::endl;\r
-  for (std::map<stlplus::lm_unit_name,stlplus::lm_unit_ptr>::const_iterator i = m_units.begin(); i != m_units.end(); i++)\r
-    i->second->print_long(str);\r
-  return !str.fail();\r
-}\r
-\r
-std::ostream& stlplus::operator << (std::ostream& str, const stlplus::lm_library& lib)\r
-{\r
-  lib.print(str);\r
-  return str;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// library manager\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-// static functions allow you to test whether a directory is a library before opening it\r
-// you can also find the library's name without opening it\r
-\r
-bool stlplus::library_manager::is_library(const std::string& path, const std::string& owner)\r
-{\r
-  std::string spec = stlplus::create_filespec(path, owner, LibraryNameExtension);\r
-  return file_exists(spec);\r
-}\r
-\r
-std::string stlplus::library_manager::library_name(const std::string& path, const std::string& owner)\r
-{\r
-  std::string name;\r
-  bool writable = false;\r
-  if (!read_context(path, owner, name, writable))\r
-    return std::string();\r
-  return name;\r
-}\r
-\r
-bool stlplus::library_manager::is_library(const std::string& path)\r
-{\r
-  return is_library(path, m_owner);\r
-}\r
-\r
-std::string stlplus::library_manager::library_name(const std::string& path)\r
-{\r
-  return library_name(path, m_owner);\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// tructors\r
-\r
-stlplus::library_manager::library_manager(const std::string& owner, bool library_case, bool unit_case) :\r
-  m_owner(owner), m_ini_files(0), m_library_case(library_case), m_unit_case(unit_case)\r
-{\r
-}\r
-\r
-stlplus::library_manager::~library_manager(void)\r
-{\r
-  close();\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// case sensitivity\r
-\r
-bool stlplus::library_manager::library_case(void) const\r
-{\r
-  return m_library_case;\r
-}\r
-\r
-void stlplus::library_manager::set_library_case(bool library_case)\r
-{\r
-  m_library_case = library_case;\r
-}\r
-\r
-bool stlplus::library_manager::unit_case(void) const\r
-{\r
-  return m_unit_case;\r
-}\r
-\r
-void stlplus::library_manager::set_unit_case(bool unit_case)\r
-{\r
-  m_unit_case = unit_case;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// type handling\r
-\r
-bool stlplus::library_manager::add_type(const std::string& type,\r
-                                        const std::string& description,\r
-                                        lm_create_callback fn,\r
-                                        void* type_data)\r
-{\r
-  bool result = true;\r
-  m_callbacks[type] = lm_callback_entry(fn, description, type_data);\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result &= i->load_type(type);\r
-  return result;\r
-}\r
-\r
-bool stlplus::library_manager::remove_type(const std::string& type)\r
-{\r
-  bool result = true;\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result &= i->remove_type(type);\r
-  m_callbacks.erase(type);\r
-  return result;\r
-}\r
-\r
-std::vector<std::string> stlplus::library_manager::types(void) const\r
-{\r
-  std::vector<std::string> result;\r
-  for (lm_callback_map::const_iterator i = m_callbacks.begin(); i != m_callbacks.end(); i++)\r
-    result.push_back(i->first);\r
-  return result;\r
-}\r
-\r
-std::string stlplus::library_manager::description(const std::string& type) const\r
-{\r
-  lm_callback_map::const_iterator found = m_callbacks.find(type);\r
-  if (found == m_callbacks.end()) return std::string();\r
-  return found->second.m_description;\r
-}\r
-\r
-stlplus::lm_create_callback stlplus::library_manager::callback(const std::string& type) const\r
-{\r
-  lm_callback_map::const_iterator found = m_callbacks.find(type);\r
-  if (found == m_callbacks.end()) return 0;\r
-  return found->second.m_callback;\r
-}\r
-\r
-void* stlplus::library_manager::type_data(const std::string& type) const\r
-{\r
-  lm_callback_map::const_iterator found = m_callbacks.find(type);\r
-  if (found == m_callbacks.end()) return 0;\r
-  return found->second.m_type_data;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// mapping file handling\r
-\r
-void stlplus::library_manager::set_mapping_file(const std::string& mapping_file)\r
-{\r
-  m_mapping_file = mapping_file;\r
-}\r
-\r
-bool stlplus::library_manager::load_mappings(const std::string& mapping_file)\r
-{\r
-  m_mapping_file = mapping_file;\r
-  if (!file_exists(mapping_file))\r
-  {\r
-    return false;\r
-  }\r
-  std::ifstream input(mapping_file.c_str());\r
-  if (input.fail())\r
-    return false;\r
-  // each line of the map file is a path to a library\r
-  // the first line is the work library - may be empty\r
-  // mappings are saved as paths relative to the mapping file and converted to full paths on load\r
-  bool result = true;\r
-  unsigned line = 1;\r
-  for (std::string path = ""; std::getline(input,path); line++)\r
-  {\r
-    if (path.empty()) continue;\r
-    std::string full_path = folder_to_path(folder_part(m_mapping_file), path);\r
-    if (!is_library(full_path))\r
-    {\r
-      result = false;\r
-    }\r
-    else\r
-    {\r
-      lm_library* lib = open(full_path);\r
-      if (!lib)\r
-        result = false;\r
-      else if (line == 1)\r
-        setwork(lib->name());\r
-    }\r
-  }\r
-  return result;\r
-}\r
-\r
-std::string stlplus::library_manager::mapping_file()\r
-{\r
-  return m_mapping_file;\r
-}\r
-\r
-bool stlplus::library_manager::set_ini_manager(ini_manager* ini_files, const std::string& library_section, const std::string& work_name)\r
-{\r
-  if (!ini_files) return false;\r
-  bool result = true;\r
-  m_ini_files = ini_files;\r
-  m_ini_section = library_section;\r
-  m_ini_work = work_name;\r
-  // now load the existing library mappings if present - in any case create the sections\r
-  // Note: a library mapping is saved as a path relative to the ini file - on load convert it to a path relative to the current directory\r
-  if (m_ini_files->section_exists(m_ini_section))\r
-  {\r
-    std::vector<std::string> library_names = m_ini_files->variable_names(m_ini_section);\r
-    std::string work_name;\r
-    for (unsigned i = 0; i < library_names.size(); i++)\r
-    {\r
-      std::string library_name = library_names[i];\r
-      // if the variable name is the work name, then this is a mapping to an existing library name\r
-      // if it is null, then it is masking a global library definition so ignore it\r
-      // otherwise it is a mapping to a directory containing the library\r
-      if (library_name.empty())\r
-      {\r
-      }\r
-      else if (library_name == m_ini_work)\r
-      {\r
-        work_name = m_ini_files->variable_value(m_ini_section, library_name);\r
-      }\r
-      else\r
-      {\r
-        std::string value = m_ini_files->variable_value(m_ini_section, library_name);\r
-        std::string filename = m_ini_files->variable_filename(m_ini_section, library_name);\r
-        // get the path to the ini file defining this library, strip off the ini filename to get the folder\r
-        // then combine this with the library path from that ini file to the library to get a full path to the library\r
-        // whew!\r
-        std::string full_path = folder_to_path(folder_part(filename),value);\r
-        if (!is_library(full_path))\r
-          result = false;\r
-        else\r
-        {\r
-          lm_library* lib = open(full_path);\r
-          if (!lib)\r
-            result = false;\r
-        }\r
-      }\r
-    }\r
-    // work must be set after all the libraries have been opened because it is\r
-    // illegal to set work to a library that doesn't already exist in the\r
-    // library manager\r
-    if (work_name.empty())\r
-      unsetwork();\r
-    else\r
-      result &= setwork(work_name);\r
-  }\r
-  return result;\r
-}\r
-\r
-stlplus::ini_manager* stlplus::library_manager::get_ini_manager(void) const\r
-{\r
-  return m_ini_files;\r
-}\r
-\r
-bool stlplus::library_manager::save_mappings (void)\r
-{\r
-  bool result = true;\r
-  // save to mapping file or ini manager or both\r
-  if (!m_mapping_file.empty())\r
-  {\r
-    if (m_libraries.size() == 0)\r
-    {\r
-      // if the file would be empty, delete it\r
-      if (!file_delete(m_mapping_file))\r
-        result = false;\r
-    }\r
-    else\r
-    {\r
-      std::ofstream output(m_mapping_file.c_str());\r
-      if (output.fail())\r
-      {\r
-        result = false;\r
-      }\r
-      else\r
-      {\r
-        // each line of the map file is a path to a library\r
-        // the first line is the work library\r
-        // mappings are saved as relative paths to the mapping file and converted to full paths on load\r
-        if (!work_name().empty())\r
-          output << folder_to_relative_path(folder_part(m_mapping_file), path(work_name()));\r
-        output << std::endl;\r
-        std::vector<std::string> libraries = names();\r
-        for (unsigned i = 0; i < libraries.size(); ++i)\r
-        {\r
-          if (libraries[i] != work_name())\r
-            output << folder_to_relative_path(folder_part(m_mapping_file), path(libraries[i])) << std::endl;\r
-        }\r
-        if (output.fail())\r
-          result = false;\r
-      }\r
-    }\r
-  }\r
-  if (m_ini_files)\r
-  {\r
-    // this is somewhat tricky!\r
-    // first remove all local mappings\r
-    // then need to compare the surviving library mappings with the contents of the library manager\r
-    // if there's a library in the ini files not in the library manager, mask it with an empty local declaration\r
-    // if there's a library in the ini files with the same mapping as the library manager, do nothing\r
-    // if there's a library in the ini files with a different mapping write that library mapping\r
-    // if there's a mapping missing from the ini files, write it\r
-    // finally write the work mapping if there is one\r
-    // clear all local mappings\r
-    // TODO - rework this so that the ini files only change if the mappings change\r
-    m_ini_files->clear_section(m_ini_section);\r
-    m_ini_files->add_comment(m_ini_section, "generated automatically by the library manager");\r
-    // look for globally defined library mappings that need to be overridden in the local ini file\r
-    std::vector<std::string> ini_names = m_ini_files->variable_names(m_ini_section);\r
-    for (unsigned i = 0; i < ini_names.size(); i++)\r
-    {\r
-      std::string ini_name = ini_names[i];\r
-      // check for a global library that needs to be locally masked\r
-      if (!exists(ini_name))\r
-        m_ini_files->add_variable(m_ini_section, ini_name, "");\r
-      else\r
-      {\r
-        // check for a library that is locally remapped\r
-        std::string value = m_ini_files->variable_value(m_ini_section, ini_name);\r
-        std::string filename = m_ini_files->variable_filename(m_ini_section, ini_name);\r
-        std::string full_ini_path = folder_to_path(folder_part(filename), value);\r
-        std::string full_lib_path = folder_to_path(path(ini_name));\r
-        if (full_ini_path != full_lib_path)\r
-        {\r
-          // write the path relative to the ini file\r
-          std::string relative_path = folder_to_relative_path(folder_part(filename), full_lib_path);\r
-          m_ini_files->add_variable(m_ini_section, ini_name, relative_path);\r
-        }\r
-      }\r
-    }\r
-    // now scan the library for mappings that aren't yet in the ini file\r
-    std::vector<std::string> lib_names = names();\r
-    for (unsigned j = 0; j < lib_names.size(); j++)\r
-    {\r
-      std::string lib_name = lib_names[j];\r
-      if (std::find(ini_names.begin(), ini_names.end(), lib_name) == ini_names.end())\r
-      {\r
-        // write the path relative to the ini file\r
-        std::string full_lib_path = folder_to_path(path(lib_name));\r
-        std::string filename = m_ini_files->variable_filename(m_ini_section, lib_name);\r
-        std::string relative_path = folder_to_relative_path(folder_part(filename), full_lib_path);\r
-        m_ini_files->add_variable(m_ini_section, lib_name, relative_path);\r
-      }\r
-    }\r
-    // write the work library - also write a blank value if work is not set but is defined in another library\r
-    if (!work_name().empty())\r
-      m_ini_files->add_variable(m_ini_section, m_ini_work, work_name());\r
-    else if (m_ini_files->variable_exists(m_ini_section, m_ini_work))\r
-      m_ini_files->add_variable(m_ini_section, m_ini_work, "");\r
-    m_ini_files->add_blank(m_ini_section);\r
-    // remove the section from the ini file manager if there's nothing in it\r
-    if (m_ini_files->empty_section(m_ini_section))\r
-      m_ini_files->erase_section(m_ini_section);\r
-    if (!m_ini_files->save())\r
-      result = false;\r
-  }\r
-  return result;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// library management\r
-\r
-bool stlplus::library_manager::exists(const std::string& name) const\r
-{\r
-  return find(name) != 0;\r
-}\r
-\r
-stlplus::lm_library* stlplus::library_manager::create(const std::string& name, const std::string& path, bool writable)\r
-{\r
-  if (!create_library(path, m_owner, name, writable)) return 0;\r
-  return open(path);\r
-}\r
-\r
-stlplus::lm_library* stlplus::library_manager::open(const std::string& path)\r
-{\r
-  std::string name;\r
-  bool writable = false;\r
-  if (!read_context(path, m_owner, name, writable)) return 0;\r
-  // remove any pre-existing library with the same name\r
-  close(name);\r
-  // add the library to the manager and open it\r
-  m_libraries.push_back(lm_library(this));\r
-  if (!m_libraries.back().open(folder_to_path(path)))\r
-  {\r
-    // remove the library in the event of an error\r
-    m_libraries.erase(--m_libraries.end());\r
-    return 0;\r
-  }\r
-  return &m_libraries.back();\r
-}\r
-\r
-bool stlplus::library_manager::load(const std::string& name)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->load();\r
-}\r
-\r
-bool stlplus::library_manager::save(const std::string& name)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->save();\r
-}\r
-\r
-bool stlplus::library_manager::purge(const std::string& name)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->purge();\r
-}\r
-\r
-bool stlplus::library_manager::close(const std::string& name)\r
-{\r
-  bool result= true;\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  result &= found->close();\r
-  m_libraries.erase(found);\r
-  if (name == m_work) m_work = "";\r
-  return result;\r
-}\r
-\r
-bool stlplus::library_manager::erase(const std::string& name)\r
-{\r
-  bool result= true;\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  result &= found->erase();\r
-  m_libraries.erase(found);\r
-  if (name == m_work) m_work = "";\r
-  return result;\r
-}\r
-\r
-// operations on all libraries - as above but applied to all the libraries in the manager\r
-\r
-bool stlplus::library_manager::load(void)\r
-{\r
-  bool result = true;\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result &= i->load();\r
-  return result;\r
-}\r
-\r
-bool stlplus::library_manager::save(void)\r
-{\r
-  bool result = true;\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result &= i->save();\r
-  return result;\r
-}\r
-\r
-bool stlplus::library_manager::purge(void)\r
-{\r
-  bool result = true;\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result &= i->purge();\r
-  return result;\r
-}\r
-\r
-bool stlplus::library_manager::close(void)\r
-{\r
-  bool result = true;\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); )\r
-  {\r
-    std::list<lm_library>::iterator next = i;\r
-    next++;\r
-    result &= i->close();\r
-    m_libraries.erase(i);\r
-    i = next;\r
-  }\r
-  return result;\r
-}\r
-\r
-bool stlplus::library_manager::erase(void)\r
-{\r
-  bool result = true;\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); )\r
-  {\r
-    std::list<lm_library>::iterator next = i;\r
-    next++;\r
-    result &= i->erase();\r
-    m_libraries.erase(i);\r
-    i = next;\r
-  }\r
-  return result;\r
-}\r
-\r
-// get name and path of a library - name can differ in case if the library manager is case-insensitive\r
-\r
-std::string stlplus::library_manager::name(const std::string& name) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return std::string();\r
-  return found->name();\r
-}\r
-\r
-std::string stlplus::library_manager::path(const std::string& name) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return std::string();\r
-  return found->path();\r
-}\r
-\r
-// control and test read/write status\r
-\r
-bool stlplus::library_manager::set_writable(const std::string& name)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->set_writable();\r
-}\r
-\r
-bool stlplus::library_manager::set_read_only(const std::string& name)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->set_read_only();\r
-}\r
-\r
-bool stlplus::library_manager::writable(const std::string& name) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->writable();\r
-}\r
-\r
-bool stlplus::library_manager::read_only(const std::string& name) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->read_only();\r
-}\r
-\r
-bool stlplus::library_manager::os_writable(const std::string& library) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(library);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->os_writable();\r
-}\r
-\r
-bool stlplus::library_manager::os_read_only(const std::string& library) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(library);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->os_read_only();\r
-}\r
-\r
-bool stlplus::library_manager::lm_writable(const std::string& library) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(library);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->lm_writable();\r
-}\r
-\r
-bool stlplus::library_manager::lm_read_only(const std::string& library) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(library);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->lm_read_only();\r
-}\r
-\r
-// find a library in the manager - returns null if not found\r
-\r
-stlplus::lm_library* stlplus::library_manager::find(const std::string& name)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return 0;\r
-  return &(*found);\r
-}\r
-\r
-const stlplus::lm_library* stlplus::library_manager::find(const std::string& name) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return 0;\r
-  return &(*found);\r
-}\r
-\r
-// get the set of all library names\r
-\r
-std::vector<std::string> stlplus::library_manager::names(void) const\r
-{\r
-  std::vector<std::string> result;\r
-  for (std::list<lm_library>::const_iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result.push_back(i->name());\r
-  return result;\r
-}\r
-\r
-// get the set of all libraries\r
-\r
-std::vector<const stlplus::lm_library*> stlplus::library_manager::handles(void) const\r
-{\r
-  std::vector<const lm_library*> result;\r
-  for (std::list<lm_library>::const_iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result.push_back(&(*i));\r
-  return result;\r
-}\r
-\r
-std::vector<stlplus::lm_library*> stlplus::library_manager::handles(void)\r
-{\r
-  std::vector<stlplus::lm_library*> result;\r
-  for (std::list<stlplus::lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    result.push_back(&(*i));\r
-  return result;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// current library management\r
-\r
-bool stlplus::library_manager::setwork(const std::string& name)\r
-{\r
-  unsetwork();\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  m_work = found->name();\r
-  return true;\r
-}\r
-\r
-bool stlplus::library_manager::unsetwork(void)\r
-{\r
-  m_work = "";\r
-  return true;\r
-}\r
-\r
-const stlplus::lm_library* stlplus::library_manager::work(void) const\r
-{\r
-  if (m_work.empty()) return 0;\r
-  return find(m_work);\r
-}\r
-\r
-stlplus::lm_library* stlplus::library_manager::work(void)\r
-{\r
-  if (m_work.empty()) return 0;\r
-  return find(m_work);\r
-}\r
-\r
-std::string stlplus::library_manager::work_name(void) const\r
-{\r
-  return m_work;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// unit management within a library\r
-\r
-bool stlplus::library_manager::exists(const std::string& name, const stlplus::lm_unit_name& unit) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->exists(unit);\r
-}\r
-\r
-stlplus::lm_unit_ptr stlplus::library_manager::create(const std::string& name, const stlplus::lm_unit_name& unit)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
-  return found->create(unit);\r
-}\r
-\r
-bool stlplus::library_manager::loaded(const std::string& name, const stlplus::lm_unit_name& unit) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
-  return found->loaded(unit);\r
-}\r
-\r
-bool stlplus::library_manager::load(const std::string& name, const stlplus::lm_unit_name& unit)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
-  return found->load(unit);\r
-}\r
-\r
-bool stlplus::library_manager::purge(const std::string& name, const stlplus::lm_unit_name& unit)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->purge(unit);\r
-}\r
-\r
-bool stlplus::library_manager::save(const std::string& name, const stlplus::lm_unit_name& unit)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->save(unit);\r
-}\r
-\r
-bool stlplus::library_manager::erase(const std::string& name, const stlplus::lm_unit_name& unit)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->erase(unit);\r
-}\r
-\r
-bool stlplus::library_manager::mark(const std::string& name, const stlplus::lm_unit_name& unit)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return false;\r
-  return found->mark(unit);\r
-}\r
-\r
-time_t stlplus::library_manager::modified(const std::string& name, const stlplus::lm_unit_name& unit) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return 0;\r
-  return found->modified(unit);\r
-}\r
-\r
-bool stlplus::library_manager::erase_by_source(const std::string& source_file)\r
-{\r
-  bool result = true;\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-    if (i->writable())\r
-      result &= i->erase_by_source(source_file);\r
-  return result;\r
-}\r
-\r
-const stlplus::lm_unit_ptr stlplus::library_manager::find(const std::string& name, const stlplus::lm_unit_name& unit) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end())\r
-    return stlplus::lm_unit_ptr();\r
-  return found->find(unit);\r
-}\r
-\r
-stlplus::lm_unit_ptr stlplus::library_manager::find(const std::string& name, const stlplus::lm_unit_name& unit)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return stlplus::lm_unit_ptr();\r
-  return found->find(unit);\r
-}\r
-\r
-std::vector<stlplus::lm_unit_name> stlplus::library_manager::names(const std::string& name) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return std::vector<stlplus::lm_unit_name>();\r
-  return found->names();\r
-}\r
-\r
-std::vector<std::string> stlplus::library_manager::names(const std::string& name, const std::string& type) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return std::vector<std::string>();\r
-  return found->names(type);\r
-}\r
-\r
-std::vector<stlplus::lm_unit_ptr> stlplus::library_manager::handles(const std::string& name) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return std::vector<stlplus::lm_unit_ptr>();\r
-  return found->handles();\r
-}\r
-\r
-std::vector<stlplus::lm_unit_ptr> stlplus::library_manager::handles(const std::string& name, const std::string& type) const\r
-{\r
-  std::list<lm_library>::const_iterator found = local_find(name);\r
-  if (found == m_libraries.end()) return std::vector<stlplus::lm_unit_ptr>();\r
-  return found->handles(type);\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// dependency checking\r
-// done at the top level because a global view of the libraries is required\r
-\r
-bool stlplus::library_manager::out_of_date(const std::string& library, const stlplus::lm_unit_name& name) const\r
-{\r
-  return !up_to_date(library, name);\r
-}\r
-\r
-bool stlplus::library_manager::up_to_date(const std::string& library, const stlplus::lm_unit_name& name) const\r
-{\r
-  lm_dependencies reason = out_of_date_reason(library, name);\r
-  return reason.empty();\r
-}\r
-\r
-stlplus::lm_dependencies stlplus::library_manager::out_of_date_reason(const std::string& library, const stlplus::lm_unit_name& name) const\r
-{\r
-  std::map<std::pair<std::string,stlplus::lm_unit_name>,lm_dependencies> visited;\r
-  return out_of_date_check(visited, this, library, name);\r
-}\r
-\r
-std::pair<bool,unsigned> stlplus::library_manager::tidy(const std::string& library)\r
-{\r
-  std::list<lm_library>::iterator found = local_find(library);\r
-  if (found == m_libraries.end()) return std::make_pair(false,0);\r
-  return found->tidy();\r
-}\r
-\r
-std::pair<bool,unsigned> stlplus::library_manager::tidy(void)\r
-{\r
-  std::pair<bool,unsigned> result = std::make_pair(true,0);\r
-  for (std::list<lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-  {\r
-    if (i->writable())\r
-    {\r
-      std::pair<bool,unsigned> library_result = i->tidy();\r
-      result.second += library_result.second;\r
-      result.first &= library_result.first;\r
-    }\r
-  }\r
-  return result;\r
-}\r
-\r
-//////////////////////////////////////////////////////////////////////////////\r
-// do-everything print routine!\r
-\r
-bool stlplus::library_manager::pretty_print(std::ostream& str,\r
-                                            bool print_units,\r
-                                            const std::string& lib,\r
-                                            const std::string& type) const\r
-{\r
-  bool library_found = false;\r
-  for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)\r
-  {\r
-    // select the library\r
-    if (lib.empty() || lib == l->name())\r
-    {\r
-      l->pretty_print(str, print_units, type);\r
-      library_found = true;\r
-    }\r
-  }\r
-  if (!library_found)\r
-  {\r
-    if (lib.empty())\r
-      str << "there are no libraries in the library list" << std::endl;\r
-    else\r
-      str << "there is no library called " << lib << " in the library list" << std::endl;\r
-    return false;\r
-  }\r
-  return true;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// diagnostic print routines\r
-\r
-bool stlplus::library_manager::print(std::ostream& str) const\r
-{\r
-  for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)\r
-    l->print(str);\r
-  return str;\r
-}\r
-\r
-bool stlplus::library_manager::print_long(std::ostream& str) const\r
-{\r
-  for (std::list<lm_library>::const_iterator l = m_libraries.begin(); l != m_libraries.end(); l++)\r
-    l->print_long(str);\r
-  return str;\r
-}\r
-\r
-// find a library by name\r
-\r
-std::list<stlplus::lm_library>::iterator stlplus::library_manager::local_find(const std::string& name)\r
-{\r
-  for (std::list<stlplus::lm_library>::iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-  {\r
-    if (m_library_case)\r
-    {\r
-      if (i->name() == name) return i;\r
-    }\r
-    else\r
-    {\r
-      if (lowercase(i->name()) == lowercase(name)) return i;\r
-    }\r
-  }\r
-  return m_libraries.end();\r
-}\r
-\r
-std::list<stlplus::lm_library>::const_iterator stlplus::library_manager::local_find(const std::string& name) const\r
-{\r
-  for (std::list<stlplus::lm_library>::const_iterator i = m_libraries.begin(); i != m_libraries.end(); i++)\r
-  {\r
-    if (m_library_case)\r
-    {\r
-      if (i->name() == name) return i;\r
-    }\r
-    else\r
-    {\r
-      if (lowercase(i->name()) == lowercase(name)) return i;\r
-    }\r
-  }\r
-  return m_libraries.end();\r
-}\r
-\r
-std::ostream& stlplus::operator << (std::ostream& str, const stlplus::library_manager& manager)\r
-{\r
-  manager.print(str);\r
-  return str;\r
-}\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
diff --git a/src/stlplus/subsystems/library_manager.hpp b/src/stlplus/subsystems/library_manager.hpp
deleted file mode 100644 (file)
index 96e1afd..0000000
+++ /dev/null
@@ -1,708 +0,0 @@
-#ifndef STLPLUS_LIBRARY_MANAGER\r
-#define STLPLUS_LIBRARY_MANAGER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Generalised library manager.\r
-\r
-//   Manages library units in a set of library directories. A unit is both a file\r
-//   on-disk and a data-structure in memory. To use the library manager, you need\r
-//   to:\r
-\r
-//     - design a type based on lm_unit with serialising functions read/write \r
-//     - decide on a file extension for the type\r
-//     - decide on a description of the type\r
-//     - write a create callback for this type\r
-//     - register the file extension, description and callback with the library manager\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "subsystems_fixes.hpp"\r
-#include "ini_manager.hpp"\r
-#include "smart_ptr.hpp"\r
-#include <iostream>\r
-#include <string>\r
-#include <vector>\r
-#include <list>\r
-#include <map>\r
-#include <time.h>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Internals\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class lm_library;\r
-  class library_manager;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // unit names\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class lm_unit_name\r
-  {\r
-  public:\r
-    lm_unit_name(const std::string& name = std::string(), const std::string& type = std::string());\r
-    ~lm_unit_name(void);\r
-\r
-    const std::string& name(void) const;\r
-    void set_name(const std::string& name);\r
-    void lowercase(void);\r
-\r
-    const std::string& type(void) const;\r
-    void set_type(const std::string& type);\r
-\r
-    bool write(std::ostream& context) const;\r
-    bool read(std::istream& context);\r
-\r
-    std::string to_string(void) const;\r
-    bool print(std::ostream&) const;\r
-\r
-  private:\r
-    std::string m_name;\r
-    std::string m_type;\r
-  };\r
-\r
-  std::ostream& operator << (std::ostream&, const lm_unit_name&);\r
-  bool operator == (const lm_unit_name& l, const lm_unit_name& r);\r
-  bool operator < (const lm_unit_name& l, const lm_unit_name& r);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // dependencies\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // dependencies on external files\r
-\r
-  class lm_file_dependency\r
-  {\r
-  public:\r
-    lm_file_dependency(void);\r
-    lm_file_dependency(const std::string& library_path, const std::string& path, unsigned line = 0, unsigned column = 0);\r
-    ~lm_file_dependency(void);\r
-\r
-    // a path can be retrieved as either a relative path to the library or as a\r
-    // full path by providing the library path as an argument\r
-    const std::string& path(void) const;\r
-    std::string path_full(const std::string& library_path) const;\r
-    void set_path(const std::string& library_path, const std::string& path);\r
-\r
-    unsigned line(void) const;\r
-    void set_line(unsigned line = 0);\r
-\r
-    unsigned column(void) const;\r
-    void set_column(unsigned column = 0);\r
-\r
-    bool write(std::ostream& context) const;\r
-    bool read(std::istream& context);\r
-\r
-    bool print(std::ostream&) const;\r
-\r
-  private:\r
-    std::string m_path; // file dependencies are stored as paths relative to the containing library\r
-    unsigned m_line;    // line - starts at 1, 0 means no line/column information\r
-    unsigned m_column;  // column - starts at 0\r
-  };\r
-\r
-  std::ostream& operator <<(std::ostream&, const lm_file_dependency&);\r
-\r
-  // dependencies on other units\r
-\r
-  class lm_unit_dependency\r
-  {\r
-  public:\r
-    lm_unit_dependency(void);\r
-    lm_unit_dependency(const std::string& library, const lm_unit_name& name);\r
-    ~lm_unit_dependency(void);\r
-\r
-    const std::string& library(void) const;\r
-    void set_library(const std::string& library);\r
-\r
-    const lm_unit_name& unit_name(void) const;\r
-    void set_unit_name(const lm_unit_name& unit_name);\r
-\r
-    const std::string& name(void) const;\r
-    void set_name(const std::string& name);\r
-\r
-    const std::string& type(void) const;\r
-    void set_type(const std::string& type);\r
-\r
-    bool write(std::ostream& context) const;\r
-    bool read(std::istream& context);\r
-\r
-    bool print(std::ostream&) const;\r
-\r
-  private:\r
-    std::string m_library;\r
-    lm_unit_name m_name;\r
-  };\r
-\r
-  std::ostream& operator<<(std::ostream&, const lm_unit_dependency&);\r
-\r
-  // the set of all dependencies\r
-\r
-  class lm_dependencies\r
-  {\r
-  public:\r
-    lm_dependencies(void);\r
-    lm_dependencies(const lm_dependencies&);\r
-    lm_dependencies& operator=(const lm_dependencies&);\r
-    ~lm_dependencies(void);\r
-\r
-    // source file dependency\r
-    void set_source_file(const lm_file_dependency&);\r
-    bool source_file_present(void) const;\r
-    const lm_file_dependency& source_file(void) const;\r
-\r
-    // other file dependencies\r
-    unsigned file_add(const lm_file_dependency& dependency);\r
-    unsigned file_size(void) const;\r
-    const lm_file_dependency& file_dependency(unsigned) const;\r
-    void file_erase(unsigned);\r
-\r
-    // unit dependencies\r
-    unsigned unit_add(const lm_unit_dependency& dependency);\r
-    unsigned unit_size(void) const;\r
-    const lm_unit_dependency& unit_dependency(unsigned) const;\r
-    void unit_erase(unsigned);\r
-\r
-    void clear(void);\r
-    bool empty(void) const;\r
-\r
-    bool write(std::ostream& context) const;\r
-    bool read(std::istream& context);\r
-\r
-    bool print(std::ostream&) const;\r
-\r
-  private:\r
-    lm_file_dependency* m_source;            // source file dependency (optional)\r
-    std::vector<lm_file_dependency> m_files; // other file dependencies\r
-    std::vector<lm_unit_dependency> m_units; // unit dependencies\r
-  };\r
-\r
-  std::ostream& operator << (std::ostream&, const lm_dependencies&);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // library unit superclass\r
-  // user's units must be derivatives of lm_unit and overload all the virtuals\r
-\r
-  class lm_unit\r
-  {\r
-    friend class lm_library;\r
-  public:\r
-    ////////////////////////////////////////\r
-    // constructor/destructor\r
-\r
-    lm_unit(const lm_unit_name& name, lm_library* library);\r
-    virtual ~lm_unit(void);\r
-\r
-    ////////////////////////////////////////\r
-    // Header data\r
-\r
-    // unit name\r
-    const lm_unit_name& unit_name(void) const;\r
-    const std::string& name(void) const;\r
-    const std::string& type(void) const;\r
-\r
-    // dependencies\r
-    // all file dependencies are converted for internal use to a path relative to the library\r
-    // they can be retrieved either in this form or as a full path\r
-\r
-    // source file dependency\r
-    void set_source_file(const lm_file_dependency&);\r
-    bool source_file_present(void) const;\r
-    const lm_file_dependency& source_file(void) const;\r
-\r
-    // other file dependencies\r
-    unsigned file_add(const lm_file_dependency& dependency);\r
-    unsigned file_size(void) const;\r
-    const lm_file_dependency& file_dependency(unsigned) const;\r
-    void file_erase(unsigned);\r
-\r
-    // unit dependencies\r
-    unsigned unit_add(const lm_unit_dependency& dependency);\r
-    unsigned unit_size(void) const;\r
-    const lm_unit_dependency& unit_dependency(unsigned) const;\r
-    void unit_erase(unsigned);\r
-\r
-    const lm_dependencies& dependencies(void) const;\r
-    void set_dependencies(const lm_dependencies&);\r
-    void clear_dependencies(void);\r
-    bool empty_dependencies(void) const;\r
-\r
-    // dependency checking\r
-\r
-    bool out_of_date(void) const;\r
-    bool up_to_date(void) const;\r
-    lm_dependencies out_of_date_reason(void) const;\r
-\r
-    // supplementary data\r
-\r
-    const std::string& supplementary_data(void) const;\r
-    void set_supplementary_data(const std::string& data);\r
-\r
-    ////////////////////////////////////////\r
-    // unit data management\r
-\r
-    bool load(void);\r
-    bool save(void);\r
-    bool loaded(void) const;\r
-    void mark(void);\r
-\r
-    // file modified time - only changes after a save\r
-\r
-    time_t modified(void) const;\r
-\r
-    ////////////////////////////////////////\r
-    // containing library manager details\r
-\r
-    // get the owning library\r
-    const lm_library* library(void) const;\r
-    lm_library* library(void);\r
-\r
-    // owning library name and path\r
-    const std::string& library_name(void) const;\r
-    const std::string& library_path(void) const;\r
-\r
-    ////////////////////////////////////////\r
-    // error handling - these apply to the last read/write operation\r
-\r
-    bool error(void) const;\r
-\r
-    ////////////////////////////////////////\r
-    // functions that customise subclasses of this superclass\r
-    // You MUST provide at least:\r
-    //   - read - either read operation can be overloaded\r
-    //   - write - either write operation can be overloaded\r
-    //   - clone\r
-\r
-    // read(filename) is the one actually called to read your data\r
-    // the default read(filename) simply calls read(istream) to actually read the file\r
-    // the default read(istream) does nothing but fail by returning false so you must overload one or other\r
-\r
-    // you can just overload read(istream) if you want to use IOstream, or you\r
-    // can overload read(filename) to use any I/O system\r
-\r
-    virtual bool read(const std::string& filename, void* type_data);\r
-    virtual bool read(std::istream& file, void* type_data);\r
-\r
-    // as above, but for writing the data type\r
-\r
-    // write(filename) is the one actually called to write your data\r
-    // the default write(filename) simply calls write(ostream) to actually write the file\r
-    // the default write(ostream) does nothing but fail by returning false so you must overload one or other\r
-\r
-    // you can just overload write(ostream) if you want to use IOstream, or you\r
-    // can overload write(filename) to use any I/O system\r
-\r
-    virtual bool write(const std::string& filename, void* type_data);\r
-    virtual bool write(std::ostream& file, void* type_data);\r
-\r
-    // purge clears any memory associated with the unit - makes the unit unloaded\r
-    // the default does nothing\r
-    virtual bool purge(void);\r
-\r
-    // the clone function creates a new-ed copy of the subclass\r
-    virtual lm_unit* clone(void) const;\r
-\r
-    // the default print routines print header-only information\r
-    // you can overload these to provide a debug printout of the data structure\r
-    virtual bool print(std::ostream&) const;\r
-    virtual bool print_long(std::ostream&) const;\r
-\r
-  protected:\r
-    // header file management\r
-    std::string filename(void) const;\r
-    std::string header_filename(void) const;\r
-    bool write_header(void);\r
-    bool read_header(void);\r
-\r
-  private:\r
-    // header fields\r
-    lm_unit_name m_name;            // name\r
-    lm_dependencies m_dependencies; // file and unit dependencies\r
-    std::string m_supplement;       // supplementary data\r
-    bool m_header_modified;         // header modified\r
-\r
-    // internal fields\r
-    bool m_loaded;                  // loaded flag\r
-    bool m_marked;                  // mark - determines whether the unit needs saving\r
-\r
-    // library manager fields\r
-    lm_library* m_library;          // parent library\r
-\r
-    // error handling fields\r
-    bool m_error;                    // error flag if load or save fails - from IOstream\r
-  };\r
-\r
-  // Iostream print calls the short print method\r
-  std::ostream& operator << (std::ostream& str, const lm_unit& u);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // other types used in the library manager\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // user types\r
-\r
-  typedef smart_ptr_nocopy<lm_unit> lm_unit_ptr;\r
-  typedef lm_unit* (*lm_create_callback)(const lm_unit_name& unit_name, lm_library* parent_library, void* type_data);\r
-\r
-  // internal types used in the library manager but made global because they are shared\r
-\r
-  struct lm_callback_entry\r
-  {\r
-    lm_create_callback m_callback;\r
-    std::string m_description;\r
-    void* m_type_data;\r
-\r
-    lm_callback_entry(lm_create_callback callback = 0, const std::string& description = std::string(), void* type_data = 0) :\r
-      m_callback(callback), m_description(description), m_type_data(type_data) {}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Library\r
-  // Must be contained in a library_manager\r
-  // Manages objects of class lm_unit and its subclasses\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class lm_library\r
-  {\r
-  public:\r
-    friend class library_manager;\r
-    friend class lm_unit;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // constructors/destructor - lm_library should only ever be constructed by library_manager\r
-\r
-    lm_library(library_manager* manager);\r
-    lm_library(const lm_library&);\r
-    lm_library& operator = (const lm_library&);\r
-    ~lm_library(void);\r
-\r
-  public:\r
-\r
-    const library_manager* manager(void) const;\r
-    library_manager* manager(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // initialisers\r
-\r
-    bool create(const std::string& name, const std::string& path, bool writable);\r
-    bool open(const std::string& path);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // management of types\r
-\r
-    bool load_type(const std::string& type);\r
-    bool load_types(void);\r
-    bool remove_type(const std::string& type);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // whole library operations\r
-\r
-    bool load(void);\r
-    bool save(void);\r
-    bool purge(void);\r
-    bool close(void);\r
-    bool erase(void);\r
-\r
-    const std::string& name(void) const;\r
-    const std::string& path(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // managing read/write status\r
-\r
-    bool set_read_write(bool writable);\r
-    bool set_writable(void);\r
-    bool set_read_only(void);\r
-    bool writable(void) const;\r
-    bool read_only(void) const;\r
-    bool os_writable(void) const;\r
-    bool os_read_only(void) const;\r
-    bool lm_writable(void) const;\r
-    bool lm_read_only(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // unit management\r
-\r
-    bool exists(const lm_unit_name& name) const;\r
-    lm_unit_ptr create(const lm_unit_name&);\r
-    bool loaded(const lm_unit_name& name) const;\r
-    bool load(const lm_unit_name& unit);\r
-    bool purge(const lm_unit_name& unit);\r
-    bool save(const lm_unit_name& unit);\r
-    bool erase(const lm_unit_name& name);\r
-    bool mark(const lm_unit_name& name);\r
-    time_t modified(const lm_unit_name& name) const;\r
-\r
-    bool erase_by_source(const std::string& source_file);\r
-\r
-    const lm_unit_ptr find(const lm_unit_name& name) const;\r
-    lm_unit_ptr find(const lm_unit_name& name);\r
-\r
-    std::vector<lm_unit_name> names(void) const;\r
-    std::vector<std::string> names(const std::string& type) const;\r
-    std::vector<lm_unit_ptr> handles(void) const;\r
-    std::vector<lm_unit_ptr> handles(const std::string& type) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // dependency checking\r
-\r
-    bool out_of_date(const lm_unit_name& name) const;\r
-    bool up_to_date(const lm_unit_name& name) const;\r
-    lm_dependencies out_of_date_reason(const lm_unit_name& name) const;\r
-\r
-    std::pair<bool,unsigned> tidy(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // do-everything print function\r
-\r
-    bool pretty_print(std::ostream& str,\r
-                      bool print_units = false,                       // print the unit names not just the library names\r
-                      const std::string& type = std::string()) const; // print just this type ("" means all)\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // diagnostic print routines\r
-\r
-    bool print(std::ostream& str) const;\r
-    bool print_long(std::ostream& str) const;\r
-\r
-  private:\r
-\r
-    std::map<lm_unit_name,lm_unit_ptr>::iterator local_find(const lm_unit_name& name);\r
-    std::map<lm_unit_name,lm_unit_ptr>::const_iterator local_find(const lm_unit_name& name) const;\r
-\r
-    std::string m_name;                         // name\r
-    std::string m_path;                         // path\r
-    bool m_writable;                            // writable\r
-    std::map<lm_unit_name,lm_unit_ptr> m_units; // units\r
-    library_manager* m_manager;                 // parent library manager\r
-  };\r
-\r
-  std::ostream& operator << (std::ostream& str, const lm_library& lib);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Library Manager\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class library_manager\r
-  {\r
-  public:\r
-    friend class lm_library;\r
-    friend class lm_unit;\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // static functions allow you to test whether a directory is a library before opening it\r
-    // you can also find the library's name without opening it\r
-\r
-    static bool is_library(const std::string& path, const std::string& owner);\r
-    static std::string library_name(const std::string& path, const std::string& owner);\r
-\r
-    // non-static forms test for libraries with the same owner as the library manager\r
-\r
-    bool is_library(const std::string& path);\r
-    std::string library_name(const std::string& path);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // tructors\r
-\r
-    explicit library_manager(const std::string& owner, bool library_case = false, bool unit_case = false);\r
-    ~library_manager(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // case sensitivity\r
-\r
-    bool library_case(void) const;\r
-    void set_library_case(bool library_case);\r
-\r
-    bool unit_case(void) const;\r
-    void set_unit_case(bool library_case);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // type handling\r
-    // only units of types added in this way will be recognised\r
-\r
-    bool add_type(const std::string& type,\r
-                  const std::string& description,\r
-                  lm_create_callback fn = 0,\r
-                  void* type_data = 0);\r
-    bool remove_type(const std::string& type);\r
-    std::vector<std::string> types(void) const;\r
-\r
-    std::string description(const std::string& type) const;\r
-    lm_create_callback callback(const std::string& type) const;\r
-    void* type_data(const std::string& type) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // Library mappings\r
-    // The library manager implements two different styles of library mappings\r
-    //   - mapping file\r
-    //   - ini file\r
-    // mapping file handling uses a simple text file to store the mappings in an internally-defined format\r
-    // ini file handling stores library mappings using the ini_manager component\r
-    // These modes are switched on by simply specifying a mapping file or an ini file to hold the mappings\r
-\r
-    // mapping file methods\r
-\r
-    // set but do not load - use this when you want to create a new mapping file\r
-    void set_mapping_file(const std::string& mapping_file);\r
-    // set and load - use this with an existing mapping file\r
-    bool load_mappings (const std::string& mapping_file);\r
-    // return the mapping file string\r
-    std::string mapping_file();\r
-\r
-    // ini file methods - the ini manager must be pre-loaded with the list of ini files to manage\r
-\r
-    // set and load - this will create the relevant sections in the local ini file if not present already\r
-    bool set_ini_manager(ini_manager* ini_files, const std::string& library_section, const std::string& work_section);\r
-    ini_manager* get_ini_manager(void) const;\r
-\r
-    // save to the library mapping handler, whichever kind it is\r
-    bool save_mappings (void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // library management\r
-\r
-    // operations on a single library\r
-    // test whether a named library exists\r
-    bool exists(const std::string& name) const;\r
-    // create a new libarry in the specified directory\r
-    lm_library* create(const std::string& name, const std::string& path, bool writable = true);\r
-    // open an existing library\r
-    lm_library* open(const std::string& path);\r
-    // load all units in the library\r
-    bool load(const std::string& name);\r
-    // save all marked units in the library\r
-    bool save(const std::string& name);\r
-    // purge all loaded units in the library\r
-    bool purge(const std::string& name);\r
-    // close the library - remove it from the manager but leave on disk\r
-    bool close(const std::string& name);\r
-    // erase the library - delete the directory and remove the library from the manager\r
-    bool erase(const std::string& name);\r
-\r
-    // operations on all libraries - as above but applied to all the libraries in the manager\r
-    bool load(void);\r
-    bool save(void);\r
-    bool purge(void);\r
-    bool close(void);\r
-    bool erase(void);\r
-\r
-    // get name and path of a library - name can differ in case if the library manager is case-insensitive\r
-    std::string name(const std::string& library) const;\r
-    std::string path(const std::string& library) const;\r
-\r
-    // control and test read/write status\r
-    bool set_writable(const std::string& library);\r
-    bool set_read_only(const std::string& library);\r
-    bool writable(const std::string& library) const;\r
-    bool read_only(const std::string& library) const;\r
-    bool os_writable(const std::string& library) const;\r
-    bool os_read_only(const std::string& library) const;\r
-    bool lm_writable(const std::string& library) const;\r
-    bool lm_read_only(const std::string& library) const;\r
-\r
-    // find a library in the manager - returns null if not found\r
-    lm_library* find(const std::string& name);\r
-    const lm_library* find(const std::string& name) const;\r
-\r
-    // get the set of all library names\r
-    std::vector<std::string> names(void) const;\r
-    // get the set of all libraries\r
-    std::vector<const lm_library*> handles(void) const;\r
-    std::vector<lm_library*> handles(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // current library management\r
-\r
-    bool setwork(const std::string& library);\r
-    bool unsetwork(void);\r
-    const lm_library* work(void) const;\r
-    lm_library* work(void);\r
-    std::string work_name(void) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // unit management within a library\r
-    // Note: you can also manipulate the library class through a handle returned by find() or handles()\r
-\r
-    bool exists(const std::string& library, const lm_unit_name& name) const;\r
-    lm_unit_ptr create(const std::string& library, const lm_unit_name& name);\r
-    bool loaded(const std::string& library, const lm_unit_name& name) const;\r
-    bool load(const std::string& library, const lm_unit_name& name);\r
-    bool purge(const std::string& library, const lm_unit_name& name);\r
-    bool save(const std::string& library, const lm_unit_name& name);\r
-    bool erase(const std::string& library, const lm_unit_name& name);\r
-    bool mark(const std::string& library, const lm_unit_name& name);\r
-    time_t modified(const std::string& library, const lm_unit_name& name) const;\r
-\r
-    bool erase_by_source(const std::string& source_file);\r
-\r
-    const lm_unit_ptr find(const std::string& library, const lm_unit_name& name) const;\r
-    lm_unit_ptr find(const std::string& library, const lm_unit_name& name);\r
-\r
-    std::vector<lm_unit_name> names(const std::string& library) const;\r
-    std::vector<std::string> names(const std::string& library, const std::string& type) const;\r
-    std::vector<lm_unit_ptr> handles(const std::string& library) const;\r
-    std::vector<lm_unit_ptr> handles(const std::string& library, const std::string& type) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // dependency checking\r
-\r
-    bool out_of_date(const std::string& library, const lm_unit_name& name) const;\r
-    bool up_to_date(const std::string& library, const lm_unit_name& name) const;\r
-    lm_dependencies out_of_date_reason(const std::string& library, const lm_unit_name& name) const;\r
-\r
-    // delete out of date units from a library or all libraries\r
-    // return the number of units tidied and a flag to say whether all units were successfully tidied\r
-    std::pair<bool,unsigned> tidy(const std::string& library);\r
-    std::pair<bool,unsigned> tidy(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // do-everything print routine!\r
-\r
-    bool pretty_print(std::ostream& str,\r
-                      bool print_units = false,                       // print the unit names not just the library names\r
-                      const std::string& library = std::string(),     // print just the specified library ("" means all)\r
-                      const std::string& type = std::string()) const; // print just this type ("" means all)\r
-\r
-    ////////////////////////////////////////////////////////////////////////////////\r
-    // diagnostic print routines\r
-\r
-    bool print(std::ostream& str) const;\r
-    bool print_long(std::ostream& str) const;\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // internals\r
-\r
-  private:\r
-    // NOT a copyable object\r
-    library_manager(const library_manager&);\r
-    library_manager& operator = (const library_manager&);\r
-\r
-  protected:\r
-    std::list<lm_library>::iterator local_find(const std::string& name);\r
-    std::list<lm_library>::const_iterator local_find(const std::string& name) const;\r
-\r
-    std::string m_owner;                               // owner application name\r
-    std::string m_mapping_file;                        // mapping file method of library management\r
-    ini_manager* m_ini_files;                          // ini manager method of library management\r
-    std::string m_ini_section;                         // ini manager method of library management\r
-    std::string m_ini_work;                            // ini manager method of library management\r
-    std::list<lm_library> m_libraries;                 // libraries\r
-    std::string m_work;                                // work library\r
-    std::map<std::string,lm_callback_entry> m_callbacks; // callbacks\r
-    bool m_library_case;                               // case sensitivity for library names\r
-    bool m_unit_case;                                  // case sensitivity for unit names\r
-  };\r
-\r
-  std::ostream& operator << (std::ostream& str, const library_manager& libraries);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/subsystems/message_handler.cpp b/src/stlplus/subsystems/message_handler.cpp
deleted file mode 100644 (file)
index fd1d2e8..0000000
+++ /dev/null
@@ -1,2014 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "message_handler.hpp"\r
-#include "dprintf.hpp"\r
-#include <fstream>\r
-#include <map>\r
-#include <list>\r
-#include <ctype.h>\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Utilities\r
-\r
-  static std::ostream& operator<< (std::ostream& device, const std::vector<std::string>& data)\r
-  {\r
-    for (unsigned i = 0; i < data.size(); i++)\r
-      device << data[i] << std::endl;\r
-    device.flush();\r
-    return device;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  static const char* information_id = "INFORMATION";\r
-  static const char* context_id = "CONTEXT";\r
-  static const char* supplement_id = "SUPPLEMENT";\r
-  static const char* warning_id = "WARNING";\r
-  static const char* error_id = "ERROR";\r
-  static const char* fatal_id = "FATAL";\r
-  static const char* position_id = "POSITION";\r
-\r
-  static const char* default_information_format = "@0";\r
-  static const char* default_context_format = "context: @0";\r
-  static const char* default_supplement_format = "supplement: @0";\r
-  static const char* default_warning_format = "warning: @0";\r
-  static const char* default_error_format = "error: @0";\r
-  static const char* default_fatal_format = "FATAL: @0";\r
-  static const char* default_position_format = "\"@1\" (@2,@3) : @0";\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // position class\r
-\r
-  message_position::message_position(void) :\r
-    m_filename(std::string()), m_line(0), m_column(0) \r
-  {\r
-  }\r
-\r
-  message_position::message_position(const std::string& filename, unsigned line, unsigned column) :\r
-    m_filename(filename), m_line(line), m_column(column)\r
-  {\r
-  }\r
-\r
-  message_position::~message_position(void)\r
-  {\r
-  }\r
-\r
-  const std::string& message_position::filename(void) const\r
-  {\r
-    return m_filename;\r
-  }\r
-\r
-  unsigned message_position::line(void) const\r
-  {\r
-    return m_line;\r
-  }\r
-\r
-  unsigned message_position::column(void) const\r
-  {\r
-    return m_column;\r
-  }\r
-\r
-  message_position message_position::operator + (unsigned offset) const\r
-  {\r
-    message_position result(*this);\r
-    result += offset;\r
-    return result;\r
-  }\r
-\r
-  message_position& message_position::operator += (unsigned offset)\r
-  {\r
-    m_column += offset;\r
-    return *this;\r
-  }\r
-\r
-  bool message_position::empty(void) const\r
-  {\r
-    return m_filename.empty();\r
-  }\r
-\r
-  bool message_position::valid(void) const\r
-  {\r
-    return !empty();\r
-  }\r
-\r
-  std::vector<std::string> message_position::show(void) const\r
-  {\r
-    std::vector<std::string> result;\r
-    if (valid())\r
-    {\r
-      // skip row-1 lines of the file and print out the resultant line\r
-      std::ifstream source(filename().c_str());\r
-      std::string current_line;\r
-      for (unsigned i = 0; i < line(); i++)\r
-      {\r
-        if (!source.good())\r
-          return result;\r
-        std::getline(source,current_line);\r
-      }\r
-      result.push_back(current_line);\r
-      // now put an up-arrow at the appropriate column\r
-      // preserve any tabs in the original line\r
-      result.push_back(std::string());\r
-      for (unsigned j = 0; j < column(); j++)\r
-      {\r
-        if (j < current_line.size() && current_line[j] == '\t')\r
-          result.back() += '\t';\r
-        else\r
-          result.back() += ' ';\r
-      }\r
-      result.back() += '^';\r
-    }\r
-    return result;\r
-  }\r
-\r
-  std::string to_string(const message_position& where)\r
-  {\r
-    return dformat("{%s:%u:%u}", where.filename().c_str(), where.line(), where.column());\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // context subclass\r
-\r
-  class message_context_body\r
-  {\r
-  private:\r
-    unsigned m_depth;\r
-    message_handler_base* m_base;\r
-\r
-  public:\r
-    message_context_body(message_handler_base& handler) :\r
-      m_depth(0), m_base(0)\r
-      {\r
-        set(handler);\r
-      }\r
-\r
-    ~message_context_body(void)\r
-      {\r
-        pop();\r
-      }\r
-\r
-    void set(message_handler_base& handler)\r
-      {\r
-        m_base = &handler;\r
-        m_depth = m_base->context_depth();\r
-      }\r
-\r
-    void pop(void)\r
-      {\r
-        if (m_base)\r
-          m_base->pop_context(m_depth);\r
-      }\r
-  private:\r
-    message_context_body(const message_context_body&);\r
-    message_context_body& operator=(const message_context_body&);\r
-  };\r
-\r
-  // exported context class\r
-\r
-  message_context::message_context(message_handler_base& handler) : m_body(new message_context_body(handler))\r
-  {\r
-  }\r
-\r
-  void message_context::set(message_handler_base& handler)\r
-  {\r
-    m_body->set(handler);\r
-  }\r
-\r
-  void message_context::pop(void)\r
-  {\r
-    m_body->pop();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // exceptions\r
-\r
-  // read_error\r
-\r
-  message_handler_read_error::message_handler_read_error(const message_position& position, const std::string& reason) :\r
-    std::runtime_error(to_string(position) + std::string(": Message handler read error - ") + reason), \r
-    m_position(position)\r
-  {\r
-  }\r
-\r
-  message_handler_read_error::~message_handler_read_error(void) throw()\r
-  {\r
-  }\r
-\r
-  const message_position& message_handler_read_error::where(void) const\r
-  {\r
-    return m_position;\r
-  }\r
-\r
-  // format error\r
-\r
-  message_handler_format_error::message_handler_format_error(const std::string& format, unsigned offset) :\r
-    std::runtime_error(std::string("Message handler formatting error in \"") + format + std::string("\"")),\r
-    m_position("",0,0), m_format(format), m_offset(offset)\r
-  {\r
-  }\r
-\r
-  message_handler_format_error::message_handler_format_error(const message_position& pos, const std::string& format, unsigned offset) : \r
-    std::runtime_error(to_string(pos) + std::string(": Message handler formatting error in \"") + format + std::string("\"")), \r
-    m_position(pos), m_format(format), m_offset(offset)\r
-  {\r
-  }\r
-\r
-  message_handler_format_error::~message_handler_format_error(void) throw()\r
-  {\r
-  }\r
-\r
-  const message_position& message_handler_format_error::where(void) const\r
-  {\r
-    return m_position;\r
-  }\r
-\r
-  const std::string& message_handler_format_error::format(void) const\r
-  {\r
-    return m_format;\r
-  }\r
-\r
-  unsigned message_handler_format_error::offset(void) const\r
-  {\r
-    return m_offset;\r
-  }\r
-\r
-  // id_error\r
-\r
-  message_handler_id_error::message_handler_id_error(const std::string& id) :\r
-    std::runtime_error(std::string("Message handler message ID not found: ") + id), m_id(id)\r
-  {\r
-  }\r
-\r
-  message_handler_id_error::~message_handler_id_error(void) throw()\r
-  {\r
-  }\r
-\r
-  const std::string& message_handler_id_error::id(void) const\r
-  {\r
-    return m_id;\r
-  }\r
-\r
-  // limit_error\r
-\r
-  message_handler_limit_error::message_handler_limit_error(unsigned limit) : \r
-    std::runtime_error(std::string("Message handler limit error: ") + dformat("%u",limit) + std::string(" reached")),\r
-    m_limit(limit)\r
-  {\r
-  }\r
-\r
-  message_handler_limit_error::~message_handler_limit_error(void) throw()\r
-  {\r
-  }\r
-\r
-  unsigned message_handler_limit_error::limit(void) const\r
-  {\r
-    return m_limit;\r
-  }\r
-\r
-  // fatal_error\r
-\r
-  message_handler_fatal_error::message_handler_fatal_error(const std::string& id) : \r
-    std::runtime_error(std::string("Message Handler Fatal error: ") + id),\r
-    m_id(id)\r
-  {\r
-  }\r
-\r
-  message_handler_fatal_error::~message_handler_fatal_error(void) throw()\r
-  {\r
-  }\r
-\r
-  const std::string& message_handler_fatal_error::id(void) const\r
-  {\r
-    return m_id;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class message\r
-  {\r
-  private:\r
-    unsigned m_index;    // index into message files\r
-    unsigned m_line;     // line\r
-    unsigned m_column;   // column\r
-    std::string m_text;  // text\r
-\r
-  public:\r
-    message(unsigned index = (unsigned)-1,\r
-            unsigned line = 0,\r
-            unsigned column = 0,\r
-            const std::string& text = "") :\r
-      m_index(index),m_line(line),m_column(column),m_text(text)\r
-      {\r
-      }\r
-    message(const std::string& text) :\r
-      m_index((unsigned)-1),m_line(0),m_column(0),m_text(text)\r
-      {\r
-      }\r
-\r
-    ~message(void)\r
-      {\r
-      }\r
-\r
-    unsigned index(void) const\r
-      {\r
-        return m_index;\r
-      }\r
-\r
-    unsigned line(void) const\r
-      {\r
-        return m_line;\r
-      }\r
-\r
-    unsigned column(void) const\r
-      {\r
-        return m_column;\r
-      }\r
-\r
-    const std::string& text(void) const\r
-      {\r
-        return m_text;\r
-      }\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class pending_message\r
-  {\r
-  private:\r
-    message_position m_position;\r
-    std::string m_id;\r
-    std::vector<std::string> m_args;\r
-  public:\r
-    pending_message(const message_position& position, const std::string& id, const std::vector<std::string>& args) :\r
-      m_position(position), m_id(id), m_args(args) {}\r
-    pending_message(const std::string& id, const std::vector<std::string>& args) :\r
-      m_position(message_position()), m_id(id), m_args(args) {}\r
-    ~pending_message(void) {}\r
-\r
-    const message_position& position(void) const {return m_position;}\r
-    const std::string& id(void) const {return m_id;}\r
-    const std::vector<std::string>& args(void) const {return m_args;}\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class message_handler_base_body\r
-  {\r
-  public:\r
-    std::vector<std::string> m_files;          // message files in the order they were added\r
-    std::map<std::string,message> m_messages;  // messages stored as id:message pairs\r
-    bool m_show;                               // show source\r
-    std::list<pending_message> m_context;      // context message stack\r
-    std::list<pending_message> m_supplement;   // supplementary message stack\r
-\r
-  public:\r
-    message_handler_base_body(void) :\r
-      m_show(false)\r
-      {\r
-        // preload with default formats\r
-        add_message(information_id,default_information_format);\r
-        add_message(warning_id,default_warning_format);\r
-        add_message(error_id,default_error_format);\r
-        add_message(fatal_id,default_fatal_format);\r
-        add_message(position_id,default_position_format);\r
-        add_message(context_id,default_context_format);\r
-        add_message(supplement_id,default_supplement_format);\r
-      }\r
-\r
-    ~message_handler_base_body(void)\r
-      {\r
-      }\r
-\r
-    void set_show(bool show)\r
-      {\r
-        m_show = show;\r
-      }\r
-\r
-    void add_message_file(const std::string& file)\r
-      throw(message_handler_read_error)\r
-      {\r
-        m_files.push_back(file);\r
-        std::ifstream input(file.c_str());\r
-        if (!input.good()) \r
-          throw message_handler_read_error(message_position(file,0,0), std::string("file not found: ") + file);\r
-        std::string line;\r
-        unsigned l = 0;\r
-        while(input.good())\r
-        {\r
-          std::getline(input,line);\r
-          l++;\r
-          if (line.size() > 0 && isalpha(line[0]))\r
-          {\r
-            // Get the id field which starts with an alphabetic and contains alphanumerics and underscore\r
-            std::string id;\r
-            unsigned i = 0;\r
-            for (; i < line.size(); i++)\r
-            {\r
-              if (isalnum(line[i]) || line[i] == '_')\r
-                id += line[i];\r
-              else\r
-                break;\r
-            }\r
-            // check this ID is unique within the files - however it is legal to override a hard-coded message\r
-            std::map<std::string,message>::iterator found = m_messages.find(id);\r
-            if (found != m_messages.end() && found->second.index() != (unsigned)-1)\r
-              throw message_handler_read_error(message_position(file,l,i), std::string("repeated ID ") + id);\r
-            // skip whitespace\r
-            for (; i < line.size(); i++)\r
-            {\r
-              if (!isspace(line[i]))\r
-                break;\r
-            }\r
-            // now get the text part and add the message to the message map\r
-            std::string text = line.substr(i, line.size()-i);\r
-            m_messages[id] = message(m_files.size()-1, l, i, text);\r
-          }\r
-        }\r
-      }\r
-\r
-    void add_message(const std::string& id, const std::string& text)\r
-      throw()\r
-      {\r
-        m_messages[id] = message((unsigned)-1, 0, 0, text);\r
-      }\r
-\r
-    bool message_present(const std::string& id) const\r
-      throw()\r
-      {\r
-        return m_messages.find(id) != m_messages.end();\r
-      }\r
-\r
-    void push_supplement(const message_position& position,\r
-                         const std::string& message_id,\r
-                         const std::vector<std::string>& args)\r
-      {\r
-        m_supplement.push_back(pending_message(position,message_id,args));\r
-      }\r
-\r
-    void push_context(const message_position& position,\r
-                      const std::string& message_id,\r
-                      const std::vector<std::string>& args)\r
-      {\r
-        m_context.push_back(pending_message(position,message_id,args));\r
-      }\r
-\r
-    void pop_context(unsigned depth)\r
-      {\r
-        while (depth < m_context.size())\r
-          m_context.pop_back();\r
-      }\r
-\r
-    unsigned context_depth(void) const\r
-      {\r
-        return m_context.size();\r
-      }\r
-\r
-    std::vector<std::string> format_report(const message_position& position,\r
-                                           const std::string& message_id,\r
-                                           const std::string& status_id,\r
-                                           const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error)\r
-      {\r
-        // gathers everything together into a full multi-line report\r
-        std::vector<std::string> result;\r
-        // the first part of the report is the status message (info/warning/error/fatal)\r
-        result.push_back(format_id(position, message_id, status_id, args));\r
-        // now append any supplemental messages that have been stacked\r
-        // these are printed in FIFO order i.e. the order that they were added to the handler\r
-        for (std::list<pending_message>::iterator j = m_supplement.begin(); j != m_supplement.end(); j++)\r
-          result.push_back(format_id(j->position(),j->id(),supplement_id,j->args()));\r
-        // now discard any supplementary messages because they only persist until they are printed once\r
-        m_supplement.clear();\r
-        // now append any context messages that have been stacked\r
-        // these are printed in LIFO order i.e. closest context first\r
-        for (std::list<pending_message>::reverse_iterator i = m_context.rbegin(); i != m_context.rend(); i++)\r
-          result.push_back(format_id(i->position(),i->id(),context_id,i->args()));\r
-        return result;\r
-      }\r
-\r
-    std::string format_id(const message_position& position,\r
-                          const std::string& message_id,\r
-                          const std::string& status_id,\r
-                          const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error)\r
-      {\r
-        // This function creates a fully-formatted single-line message from a\r
-        // combination of the position format and the status format plus the message\r
-        // ID and its arguments. There are up to three levels of substitution\r
-        // required to do this.\r
-\r
-        // get the status format from the status_id\r
-        std::map<std::string,message>::iterator status_found = m_messages.find(status_id);\r
-        if (status_found == m_messages.end()) throw message_handler_id_error(status_id);\r
-\r
-        // similarly get the message format\r
-        std::map<std::string,message>::iterator message_found = m_messages.find(message_id);\r
-        if (message_found == m_messages.end()) throw message_handler_id_error(message_id);\r
-\r
-        // format the message contents\r
-        std::string message_text = format_message(message_found->second, args);\r
-\r
-        // now format the message in the status string (informational, warning etc).\r
-        std::vector<std::string> status_args;\r
-        status_args.push_back(message_text);\r
-        std::string result = format_message(status_found->second, status_args);\r
-\r
-        // finally, if the message is positional, format the status message in the positional string\r
-        if (position.valid())\r
-        {\r
-          // get the position format from the message set\r
-          std::map<std::string,message>::iterator position_found = m_messages.find(position_id);\r
-          if (position_found == m_messages.end()) throw message_handler_id_error(position_id);\r
-\r
-          // now format the message\r
-          std::vector<std::string> position_args;\r
-          position_args.push_back(result);\r
-          position_args.push_back(position.filename());\r
-          position_args.push_back(dformat("%u",position.line()));\r
-          position_args.push_back(dformat("%u",position.column()));\r
-          result = format_message(position_found->second, position_args);\r
-          // add the source file text and position if that option is on\r
-\r
-          if (m_show)\r
-          {\r
-            std::vector<std::string> show = position.show();\r
-            for (unsigned i = 0; i < show.size(); i++)\r
-            {\r
-              result += std::string("\n");\r
-              result += show[i];\r
-            }\r
-          }\r
-        }\r
-        return result;\r
-      }\r
-\r
-    std::string format_message(const message& mess,\r
-                               const std::vector<std::string>& args) \r
-      throw(message_handler_format_error)\r
-      {\r
-        // this function creates a formatted string from the stored message text and\r
-        // the arguments. Most of the work is done in format_string. However, if a\r
-        // formatting error is found, this function uses extra information stored in\r
-        // the message data structure to improve the reporting of the error\r
-        try\r
-        {\r
-          // This is the basic string formatter which performs parameter substitution\r
-          // into a message. Parameter placeholders are in the form @0, @1 etc, where\r
-          // the number is the index of the argument in the args vector. At present,\r
-          // no field codes are supported as in printf formats Algorithm: scan the\r
-          // input string and transfer it into the result. When an @nnn appears,\r
-          // substitute the relevant argument from the args vector. Throw an exception\r
-          // if its out of range. Also convert C-style escaped characters of the form\r
-          // \n.\r
-          std::string format = mess.text();\r
-          std::string result;\r
-          for (unsigned i = 0; i < format.size(); )\r
-          {\r
-            if (format[i] == '@')\r
-            {\r
-              // an argument substitution has been found - now find the argument number\r
-              if (i+1 == format.size()) throw message_handler_format_error(format, i);\r
-              i++;\r
-              // check for @@ which is an escaped form of '@'\r
-              if (format[i] == '@')\r
-              {\r
-                result += '@';\r
-                i++;\r
-              }\r
-              else\r
-              {\r
-                // there must be at least one digit in the substitution number\r
-                if (!isdigit(format[i])) throw message_handler_format_error(format,i);\r
-                unsigned a = 0;\r
-                for (; i < format.size() && isdigit(format[i]); i++)\r
-                {\r
-                  a *= 10;\r
-                  a += (format[i] - '0');\r
-                }\r
-                // check for an argument request out of the range of the set of arguments\r
-                if (a >= args.size()) throw message_handler_format_error(format,i-1);\r
-                result += args[a];\r
-              }\r
-            }\r
-            else if (format[i] == '\\')\r
-            {\r
-              // an escaped character has been found\r
-              if (i+1 == format.size()) throw message_handler_format_error(format, i);\r
-              i++;\r
-              // do the special ones first, then all the others just strip off the \ and leave the following characters\r
-              switch(format[i])\r
-              {\r
-              case '\\':\r
-                result += '\\';\r
-                break;\r
-              case 't':\r
-                result += '\t';\r
-                break;\r
-              case 'n':\r
-                result += '\n';\r
-                break;\r
-              case 'r':\r
-                result += '\r';\r
-                break;\r
-              case 'a':\r
-                result += '\a';\r
-                break;\r
-              default:\r
-                result += format[i];\r
-                break;\r
-              }\r
-              i++;\r
-            }\r
-            else\r
-            {\r
-              // plain text found - just append to the result\r
-              result += format[i++];\r
-            }\r
-          }\r
-          return result;\r
-        }\r
-        catch(message_handler_format_error& exception)\r
-        {\r
-          // if the message came from a message file, improve the error reporting by adding file positional information\r
-          // Also adjust the position from the start of the text (stored in the message field) to the column of the error\r
-          if (mess.index() != (unsigned)-1)\r
-            throw message_handler_format_error(\r
-              message_position(m_files[mess.index()], mess.line(), mess.column()+exception.offset()),\r
-              exception.format(),\r
-              exception.offset());\r
-          else\r
-            throw exception;\r
-        }\r
-      }\r
-\r
-  private:\r
-    message_handler_base_body(message_handler_base_body&);\r
-    message_handler_base_body& operator=(message_handler_base_body&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  message_handler_base::message_handler_base(bool show)\r
-    throw() :\r
-    m_base_body(new message_handler_base_body)\r
-  {\r
-    m_base_body->set_show(show);\r
-  }\r
-\r
-  message_handler_base::message_handler_base(const std::string& file, bool show)\r
-    throw(message_handler_read_error) :\r
-    m_base_body(new message_handler_base_body)\r
-  {\r
-    m_base_body->set_show(show);\r
-    add_message_file(file);\r
-  }\r
-\r
-  message_handler_base::message_handler_base(const std::vector<std::string>& files, bool show)\r
-    throw(message_handler_read_error) :\r
-    m_base_body(new message_handler_base_body)\r
-  {\r
-    m_base_body->set_show(show);\r
-    add_message_files(files);\r
-  }\r
-\r
-  message_handler_base::~message_handler_base(void)\r
-    throw()\r
-  {\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void message_handler_base::add_message_file(const std::string& file)\r
-    throw(message_handler_read_error)\r
-  {\r
-    m_base_body->add_message_file(file);\r
-  }\r
-\r
-  void message_handler_base::add_message_files(const std::vector<std::string>& files)\r
-    throw(message_handler_read_error)\r
-  {\r
-    for (unsigned i = 0; i < files.size(); i++)\r
-      add_message_file(files[i]);\r
-  }\r
-\r
-  void message_handler_base::add_message(const std::string& id, const std::string& text)\r
-    throw()\r
-  {\r
-    m_base_body->add_message(id,text);\r
-  }\r
-\r
-  bool message_handler_base::message_present(const std::string& id) const\r
-    throw()\r
-  {\r
-    return m_base_body->message_present(id);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void message_handler_base::set_information_format(const std::string& format) throw()\r
-  {\r
-    add_message(information_id, format);\r
-  }\r
-\r
-  void message_handler_base::set_warning_format(const std::string& format) throw()\r
-  {\r
-    add_message(warning_id, format);\r
-  }\r
-\r
-  void message_handler_base::set_error_format(const std::string& format) throw()\r
-  {\r
-    add_message(error_id, format);\r
-  }\r
-\r
-  void message_handler_base::set_fatal_format(const std::string& format) throw()\r
-  {\r
-    add_message(fatal_id, format);\r
-  }\r
-\r
-  void message_handler_base::set_position_format(const std::string& format) throw()\r
-  {\r
-    add_message(position_id, format);\r
-  }\r
-\r
-  void message_handler_base::set_context_format(const std::string& format) throw()\r
-  {\r
-    add_message(context_id, format);\r
-  }\r
-\r
-  void message_handler_base::set_supplement_format(const std::string& format) throw()\r
-  {\r
-    add_message(supplement_id, format);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  void message_handler_base::show_position(void)\r
-    throw()\r
-  {\r
-    m_base_body->set_show(true);\r
-  }\r
-\r
-  void message_handler_base::hide_position(void)\r
-    throw()\r
-  {\r
-    m_base_body->set_show(false);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // information messages\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const std::string& id,\r
-                                                                     const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return information_message(message_position(), id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return information_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const std::string& id,\r
-                                                                     const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return information_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const std::string& id,\r
-                                                                     const std::string& arg1,\r
-                                                                     const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return information_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const std::string& id,\r
-                                                                     const std::string& arg1,\r
-                                                                     const std::string& arg2,\r
-                                                                     const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return information_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const message_position& position,\r
-                                                                     const std::string& id,\r
-                                                                     const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return m_base_body->format_report(position, id, information_id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const message_position& position,\r
-                                                                     const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return information_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const message_position& position,\r
-                                                                     const std::string& id,\r
-                                                                     const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return information_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const message_position& position,\r
-                                                                     const std::string& id,\r
-                                                                     const std::string& arg1,\r
-                                                                     const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return information_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::information_message(const message_position& position,\r
-                                                                     const std::string& id,\r
-                                                                     const std::string& arg1,\r
-                                                                     const std::string& arg2,\r
-                                                                     const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return information_message(position, id, args);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // warning messages\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const std::string& id,\r
-                                                                 const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return warning_message(message_position(), id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return warning_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const std::string& id,\r
-                                                                 const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return warning_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const std::string& id,\r
-                                                                 const std::string& arg1,\r
-                                                                 const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return warning_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const std::string& id,\r
-                                                                 const std::string& arg1,\r
-                                                                 const std::string& arg2,\r
-                                                                 const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return warning_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const message_position& position,\r
-                                                                 const std::string& id,\r
-                                                                 const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return m_base_body->format_report(position, id, warning_id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const message_position& position,\r
-                                                                 const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return warning_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const message_position& position,\r
-                                                                 const std::string& id,\r
-                                                                 const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return warning_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const message_position& position,\r
-                                                                 const std::string& id,\r
-                                                                 const std::string& arg1,\r
-                                                                 const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return warning_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::warning_message(const message_position& position,\r
-                                                                 const std::string& id,\r
-                                                                 const std::string& arg1,\r
-                                                                 const std::string& arg2,\r
-                                                                 const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return warning_message(position, id, args);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // error messages\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const std::string& id,\r
-                                                               const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return error_message(message_position(), id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return error_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const std::string& id,\r
-                                                               const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return error_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return error_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2,\r
-                                                               const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return error_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return m_base_body->format_report(position, id, error_id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const message_position& position,\r
-                                                               const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return error_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return error_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return error_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::error_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2,\r
-                                                               const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return error_message(position, id, args);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // fatal messages\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const std::string& id,\r
-                                                               const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return fatal_message(message_position(), id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return fatal_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const std::string& id,\r
-                                                               const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return fatal_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return fatal_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2,\r
-                                                               const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return fatal_message(id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return m_base_body->format_report(position, id, fatal_id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const message_position& position,\r
-                                                               const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return fatal_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return fatal_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return fatal_message(position, id, args);\r
-  }\r
-\r
-  std::vector<std::string> message_handler_base::fatal_message(const message_position& position,\r
-                                                               const std::string& id,\r
-                                                               const std::string& arg1,\r
-                                                               const std::string& arg2,\r
-                                                               const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return fatal_message(position, id, args);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // supplemental messages\r
-\r
-  void message_handler_base::push_supplement(const std::string& id,\r
-                                             const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    push_supplement(message_position(), id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    push_supplement(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const std::string& id,\r
-                                             const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    push_supplement(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    push_supplement(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2,\r
-                                             const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    push_supplement(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const message_position& position,\r
-                                             const std::string& id,\r
-                                             const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    m_base_body->push_supplement(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const message_position& position,\r
-                                             const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    push_supplement(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const message_position& position,\r
-                                             const std::string& id,\r
-                                             const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    push_supplement(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const message_position& position,\r
-                                             const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    push_supplement(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_supplement(const message_position& position,\r
-                                             const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2,\r
-                                             const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    push_supplement(position, id, args);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // context\r
-\r
-  void message_handler_base::push_context (const std::string& id,\r
-                                           const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    push_context(message_position(), id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    push_context(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const std::string& id,\r
-                                           const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    push_context(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    push_context(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2,\r
-                                           const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    push_context(id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const message_position& position,\r
-                                           const std::string& id,\r
-                                           const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    m_base_body->push_context(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const message_position& position,\r
-                                           const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    push_context(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const message_position& position,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    push_context(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const message_position& position,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    push_context(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::push_context (const message_position& position,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2,\r
-                                           const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    push_context(position, id, args);\r
-  }\r
-\r
-  void message_handler_base::pop_context(void) throw()\r
-  {\r
-    m_base_body->pop_context(m_base_body->context_depth()-1);\r
-  }\r
-\r
-  void message_handler_base::pop_context(unsigned depth) throw()\r
-  {\r
-    m_base_body->pop_context(depth);\r
-  }\r
-\r
-  unsigned message_handler_base::context_depth(void) const\r
-    throw()\r
-  {\r
-    return m_base_body->context_depth();\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const std::string& id, const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    return auto_push_context(message_position(), id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const std::string& id)                                                 \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return auto_push_context(id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const std::string& id,\r
-                                                          const std::string& arg1)                         \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return auto_push_context(id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context (const std::string& id,\r
-                                                           const std::string& arg1,\r
-                                                           const std::string& arg2) \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return auto_push_context(id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const std::string& id,\r
-                                                          const std::string& arg1,\r
-                                                          const std::string& arg2,\r
-                                                          const std::string& arg3) \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return auto_push_context(id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const message_position& position,\r
-                                                          const std::string& id,\r
-                                                          const std::vector<std::string>& args)            \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    message_context result(*this);\r
-    m_base_body->push_context(position, id, args);\r
-    return result;\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const message_position& position,\r
-                                                          const std::string& id)             \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    return auto_push_context(position, id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const message_position& position,\r
-                                                          const std::string& id,\r
-                                                          const std::string& arg1)                         \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    return auto_push_context(position, id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const message_position& position,\r
-                                                          const std::string& id,\r
-                                                          const std::string& arg1,\r
-                                                          const std::string& arg2) \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    return auto_push_context(position, id, args);\r
-  }\r
-\r
-  message_context message_handler_base::auto_push_context(const message_position& position,\r
-                                                          const std::string& id,\r
-                                                          const std::string& arg1,\r
-                                                          const std::string& arg2,\r
-                                                          const std::string& arg3) \r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    std::vector<std::string> args;\r
-    args.push_back(arg1);\r
-    args.push_back(arg2);\r
-    args.push_back(arg3);\r
-    return auto_push_context(position, id, args);\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // iostream-based derivative uses the above base class to generate messages then uses iostream to print them\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class message_handler_body\r
-  {\r
-  private:\r
-    std::ostream* m_device;                        // TextIO output device\r
-    unsigned m_limit;                              // error limit\r
-    unsigned m_errors;                             // error count\r
-\r
-  public:\r
-    message_handler_body(std::ostream& device, unsigned limit) :\r
-      m_device(&device), m_limit(limit), m_errors(0)\r
-      {\r
-      }\r
-\r
-    ~message_handler_body(void)\r
-      {\r
-        device().flush();\r
-      }\r
-\r
-    std::ostream& device(void)\r
-      {\r
-        return *m_device;\r
-      }\r
-\r
-    unsigned limit(void) const\r
-      {\r
-        return m_limit;\r
-      }\r
-\r
-    void set_limit(unsigned limit)\r
-      {\r
-        m_limit = limit;\r
-      }\r
-\r
-    unsigned count(void) const\r
-      {\r
-        return m_errors;\r
-      }\r
-\r
-    void set_count(unsigned count)\r
-      {\r
-        m_errors = count;\r
-      }\r
-\r
-    void error_increment(void)\r
-      {\r
-        ++m_errors;\r
-      }\r
-\r
-    bool limit_reached(void) const\r
-      {\r
-        return m_limit > 0 && m_errors >= m_limit;\r
-      }\r
-\r
-  private:\r
-    message_handler_body(const message_handler_body&);\r
-    message_handler_body& operator=(const message_handler_body&);\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  message_handler::message_handler(std::ostream& device, unsigned limit, bool show)\r
-    throw() :\r
-    message_handler_base(show), m_body(new message_handler_body(device, limit))\r
-  {\r
-  }\r
-\r
-  message_handler::message_handler(std::ostream& device,\r
-                                   const std::string& message_file, unsigned limit, bool show) \r
-    throw(message_handler_read_error) :\r
-    message_handler_base(message_file,show), m_body(new message_handler_body(device, limit))\r
-  {\r
-  }\r
-\r
-  message_handler::message_handler(std::ostream& device, const std::vector<std::string>& message_files, unsigned limit, bool show) \r
-    throw(message_handler_read_error) :\r
-    message_handler_base(message_files,show), m_body(new message_handler_body(device, limit))\r
-  {\r
-  }\r
-\r
-  message_handler::~message_handler(void)\r
-    throw()\r
-  {\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // error count\r
-\r
-  void message_handler::set_error_limit(unsigned error_limit)\r
-    throw()\r
-  {\r
-    m_body->set_limit(error_limit);\r
-  }\r
-\r
-  unsigned message_handler::error_limit(void) const\r
-    throw()\r
-  {\r
-    return m_body->limit();\r
-  }\r
-\r
-  void message_handler::reset_error_count(void)\r
-    throw()\r
-  {\r
-    m_body->set_count(0);\r
-  }\r
-\r
-  unsigned message_handler::error_count(void) const\r
-    throw()\r
-  {\r
-    return m_body->count();\r
-  }\r
-\r
-  std::ostream& message_handler::device(void)\r
-  {\r
-    return m_body->device();\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // information messages\r
-\r
-  bool message_handler::information(const std::string& id,\r
-                                    const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(id, args);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(id);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const std::string& id,\r
-                                    const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(id, arg1);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const std::string& id,\r
-                                    const std::string& arg1,\r
-                                    const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(id, arg1, arg2);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const std::string& id,\r
-                                    const std::string& arg1,\r
-                                    const std::string& arg2,\r
-                                    const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(id, arg1, arg2, arg3);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const message_position& position,\r
-                                    const std::string& id,\r
-                                    const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(position, id, args);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const message_position& position,\r
-                                    const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(position, id);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const message_position& position,\r
-                                    const std::string& id,\r
-                                    const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(position, id, arg1);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const message_position& position,\r
-                                    const std::string& id,\r
-                                    const std::string& arg1,\r
-                                    const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(position, id, arg1, arg2);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::information(const message_position& position,\r
-                                    const std::string& id,\r
-                                    const std::string& arg1,\r
-                                    const std::string& arg2,\r
-                                    const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << information_message(position, id, arg1, arg2, arg3);\r
-    return true;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // warning messages\r
-\r
-  bool message_handler::warning(const std::string& id,\r
-                                const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(id, args);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(id);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const std::string& id,\r
-                                const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(id, arg1);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const std::string& id,\r
-                                const std::string& arg1,\r
-                                const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(id, arg1, arg2);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const std::string& id,\r
-                                const std::string& arg1,\r
-                                const std::string& arg2,\r
-                                const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(id, arg1, arg2, arg3);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const message_position& position,\r
-                                const std::string& id,\r
-                                const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(position, id, args);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const message_position& position,\r
-                                const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(position, id);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const message_position& position,\r
-                                const std::string& id,\r
-                                const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(position, id, arg1);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const message_position& position,\r
-                                const std::string& id,\r
-                                const std::string& arg1,\r
-                                const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(position, id, arg1, arg2);\r
-    return true;\r
-  }\r
-\r
-  bool message_handler::warning(const message_position& position,\r
-                                const std::string& id,\r
-                                const std::string& arg1,\r
-                                const std::string& arg2,\r
-                                const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error)\r
-  {\r
-    device() << warning_message(position, id, arg1, arg2, arg3);\r
-    return true;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // error messages\r
-\r
-  bool message_handler::error(const std::string& id,\r
-                              const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(id, args);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(id);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const std::string& id,\r
-                              const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(id, arg1);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(id, arg1, arg2);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2,\r
-                              const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(id, arg1, arg2, arg3);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(position, id, args);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const message_position& position,\r
-                              const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(position, id);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(position, id, arg1);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(position, id, arg1, arg2);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  bool message_handler::error(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2,\r
-                              const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error)\r
-  {\r
-    device() << error_message(position, id, arg1, arg2, arg3);\r
-    m_body->error_increment();\r
-    if (m_body->limit_reached()) throw message_handler_limit_error(m_body->limit());\r
-    return false;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // fatal messages\r
-\r
-  bool message_handler::fatal(const std::string& id,\r
-                              const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(id, args);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(id);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const std::string& id,\r
-                              const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(id, arg1);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(id, arg1, arg2);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2,\r
-                              const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(id, arg1, arg2, arg3);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::vector<std::string>& args)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(position, id, args);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const message_position& position,\r
-                              const std::string& id)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(position, id);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::string& arg1)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(position, id, arg1);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(position, id, arg1, arg2);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  bool message_handler::fatal(const message_position& position,\r
-                              const std::string& id,\r
-                              const std::string& arg1,\r
-                              const std::string& arg2,\r
-                              const std::string& arg3)\r
-    throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error)\r
-  {\r
-    device() << fatal_message(position, id, arg1, arg2, arg3);\r
-    throw message_handler_fatal_error(id);\r
-  }\r
-\r
-  ///////////////////////////////////////////////////////////////////////////////\r
-  // plain text\r
-\r
-  bool message_handler::plaintext(const std::string& text)\r
-  {\r
-    device() << text << std::endl;\r
-    return true;\r
-  }\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/subsystems/message_handler.hpp b/src/stlplus/subsystems/message_handler.hpp
deleted file mode 100644 (file)
index 26b8ed6..0000000
+++ /dev/null
@@ -1,1015 +0,0 @@
-#ifndef STLPLUS_MESSAGE_HANDLER\r
-#define STLPLUS_MESSAGE_HANDLER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A general-purpose message handler using a message file as the source of all text\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "subsystems_fixes.hpp"\r
-#include "smart_ptr.hpp"\r
-#include <iostream>\r
-#include <string>\r
-#include <vector>\r
-#include <stdexcept>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // Internals\r
-\r
-  class message_handler_base;\r
-  class message_handler_base_body;\r
-\r
-  class message_handler;\r
-  class message_handler_body;\r
-\r
-  class message_context_body;\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // an object representing a file position\r
-  // used for example when reporting errors when parsing a text file\r
-\r
-  class message_position\r
-  {\r
-  public:\r
-    message_position(void);\r
-    message_position(const std::string& filename, unsigned line, unsigned column);\r
-    ~message_position(void);\r
-\r
-    // access the elements of the position\r
-    const std::string& filename(void) const;\r
-    // line number in the range 1..n\r
-    // so line 0 means uninitialised\r
-    unsigned line(void) const;\r
-    // column number in the range 0..m-1\r
-    unsigned column(void) const;\r
-\r
-    // add a column offset to a position\r
-    message_position operator + (unsigned) const;\r
-    message_position& operator += (unsigned);\r
-\r
-    // tests for valid position\r
-    bool empty(void) const;\r
-    bool valid(void) const;\r
-\r
-    // vector of two strings\r
-    // - the first reproducing the source line\r
-    // - the second an arrow pointing to the correct column\r
-    // the vector will be empty if the position can't be found\r
-    std::vector<std::string> show(void) const;\r
-\r
-  private:\r
-    std::string m_filename;\r
-    unsigned m_line;\r
-    unsigned m_column;\r
-  };\r
-\r
-  std::string to_string(const message_position& where);\r
-\r
-  //////////////////////////////////////////////////////////////////////////////\r
-  // an object representing an message context\r
-  // used to control the context stack\r
-  // on initialisation, the message_context stores the state of the context stack\r
-  // on destruction it restores the state by popping any context that has been pushed since creation\r
-\r
-  class message_context\r
-  {\r
-  public:\r
-    message_context(message_handler_base& handler);\r
-\r
-    void set(message_handler_base& handler);\r
-    void pop(void);\r
-\r
-  private:\r
-    friend class message_context_body;\r
-    friend class message_handler_base;\r
-    smart_ptr_nocopy<message_context_body> m_body;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // exception classes which can be thrown by the message handler\r
-\r
-  // read_error is thrown if the message file read fails\r
-  class message_handler_read_error : public std::runtime_error\r
-  {\r
-  public:\r
-    message_handler_read_error(const message_position& position, const std::string& reason);\r
-    ~message_handler_read_error(void) throw();\r
-\r
-    const message_position& where(void) const;\r
-\r
-  private:\r
-    message_position m_position;\r
-  };\r
-\r
-  // format_error is thrown if a formatting error occurs trying to create the text for the message\r
-\r
-  class message_handler_format_error : public std::runtime_error\r
-  {\r
-  public:\r
-    message_handler_format_error(const std::string& format, unsigned offset);\r
-    message_handler_format_error(const message_position& pos, const std::string& format, unsigned offset);\r
-    ~message_handler_format_error(void) throw();\r
-\r
-    const message_position& where(void) const;\r
-    const std::string& format(void) const;\r
-    unsigned offset(void) const;\r
-\r
-  private:\r
-    message_position m_position;\r
-    std::string m_format;\r
-    unsigned m_offset;\r
-  };\r
-\r
-  // id_error is thrown if an error id is requested that could not be found in the message file\r
-\r
-  class message_handler_id_error : public std::runtime_error\r
-  {\r
-  public:\r
-    message_handler_id_error(const std::string& id);\r
-    ~message_handler_id_error(void) throw();\r
-\r
-    const std::string& id(void) const;\r
-\r
-  private:\r
-    std::string m_id;\r
-  };\r
-\r
-  // limit_error is thrown when the number of errors reaches the error limit\r
-\r
-  class message_handler_limit_error : public std::runtime_error\r
-  {\r
-  public:\r
-    message_handler_limit_error(unsigned limit);\r
-    ~message_handler_limit_error(void) throw();\r
-\r
-    unsigned limit(void) const;\r
-\r
-  private:\r
-    unsigned m_limit;   // the limit that was exceeded\r
-  };\r
-\r
-  // fatal_error is thrown when a fatal error is reported\r
-\r
-  class message_handler_fatal_error : public std::runtime_error\r
-  {\r
-  public:\r
-    message_handler_fatal_error(const std::string& id);\r
-    ~message_handler_fatal_error(void) throw();\r
-\r
-    const std::string& id(void) const;\r
-\r
-  private:\r
-    std::string m_id;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // base version returns message objects as vectors of strings\r
-  // - it is then up to the user to decide what to do with them\r
-  // - suitable for use in a GUI for example where the message is displayed in a dialog\r
-\r
-  class message_handler_base\r
-  {\r
-  public:\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // constructor\r
-\r
-    // The first form sets the show flag but doesn't load any message files.\r
-    // The second and third forms also read message file(s) by calling\r
-    // add_message_file and therefore can throw exceptions. The first form\r
-    // defers file reading to explicit calls of add_message_file so does not\r
-    // throw any exceptions.\r
-\r
-    // show determines whether the source file line containing the source of a problem should also be shown\r
-\r
-    message_handler_base(bool show = true)\r
-      throw();\r
-\r
-    message_handler_base(const std::string& message_file, bool show = true)\r
-      throw(message_handler_read_error);\r
-\r
-    message_handler_base(const std::vector<std::string>& message_files, bool show = true)\r
-      throw(message_handler_read_error);\r
-\r
-    virtual ~message_handler_base(void)\r
-      throw();\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // message file handling\r
-\r
-    // The message file format contains lines of the form:\r
-    //\r
-    // <id> <spaces> <text>\r
-    //\r
-    // In <id> is a unique mnemonic for the message. It starts with an\r
-    // alphabetic character and may contain alphanumerics and underscores only.\r
-    // The <spaces> can be one or more space or tab characters. The <text> is the\r
-    // remainder of the line and is plain text (not a quoted string). All lines\r
-    // starting with a non-alphabetic character are assumed to be comments and are\r
-    // ignored\r
-\r
-    // If the message file is missing the function throws read_error with no line\r
-    // number. If formatting errors were found in the file,then it throws a\r
-    // read_error with valid line information.\r
-\r
-    // Any number of message files can be added and they accumulate\r
-\r
-    void add_message_file(const std::string& message_file)\r
-      throw(message_handler_read_error);\r
-\r
-    void add_message_files(const std::vector<std::string>& message_files)\r
-      throw(message_handler_read_error);\r
-\r
-    void add_message(const std::string& id, const std::string& text)\r
-      throw();\r
-\r
-    bool message_present(const std::string& id) const\r
-      throw();\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // format control\r
-\r
-    // The status formats - that is, information/warning/error/fatal/context/supplement\r
-    // formats take a single argument which is the formatted message\r
-    // For example: "warning: @0"\r
-    //\r
-    // Messages may be printed as either simple or positional\r
-    //   simple:     just a text message, such as a progress report\r
-    //   positional: a message relating to a source file line\r
-    // The formatted message text is generated directly for simple messages\r
-    // However, for positional messages, this text is further substituted\r
-    // into a positional format string.\r
-    // The positional format string takes up to 4 arguments:\r
-    //   @0: simple message text\r
-    //   @1: filename\r
-    //   @2: line number\r
-    //   @3: column number\r
-    // You can miss out a part of this (e.g. the column number)\r
-    // by simply not including the argument number in the format string\r
-    // For example: "file: @1, line: @2: @0"\r
-    //\r
-    // The default formats are:\r
-    //   information: "@0"\r
-    //   warning:     "warning: @0"\r
-    //   error:       "error: @0"\r
-    //   fatal:       "FATAL: @0"\r
-    //   context:     "context: @0"\r
-    //   supplement:  "supplement: @0"\r
-    //\r
-    //   positional:  "\"@1\" (@2,@3) : @0"\r
-\r
-    void set_information_format(const std::string& format)\r
-      throw();\r
-\r
-    void set_warning_format(const std::string& format)\r
-      throw();\r
-\r
-    void set_error_format(const std::string& format)\r
-      throw();\r
-\r
-    void set_fatal_format(const std::string& format)\r
-      throw();\r
-\r
-    void set_context_format(const std::string& format)\r
-      throw();\r
-\r
-    void set_supplement_format(const std::string& format)\r
-      throw();\r
-\r
-    void set_position_format(const std::string& format)\r
-      throw();\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // source file position display control\r
-    // show_position indicates that the source file line containing the error\r
-    //   should be shown with the message on subsequent lines\r
-    // hide_position indicates that the source file line should not be shown\r
-\r
-    void show_position(void)\r
-      throw();\r
-\r
-    void hide_position(void)\r
-      throw();\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // Message formatting functions\r
-    // These functions return a vector of strings containing the completed message\r
-\r
-    // There are 6 classes of message: information, context, supplement, warning, error, fatal\r
-    // The 4 main classes are:\r
-    //   - information: progress messages, status messages etc.\r
-    //   - warning: a problem has been found but there is a sensible way of proceeding\r
-    //   - error: a problem has been found and the operation will fail\r
-    //            processing may continue but only to find further errors\r
-    //   - fatal: an internal (programming) error has been found and the operation is stopping NOW\r
-    // The remaining two always follow one of the above\r
-    //   - context: give stack-like information of the error context \r
-    //              e.g. if processing include files, the sequence of includes forms a stack\r
-    //   - supplement: give extra information of the error context\r
-    //              e.g. give the set of possible solutions to the problem\r
-\r
-    // There are 2 kinds of message: simple, positional\r
-    //   - simple: just a text message\r
-    //   - positional: a message relating to a source file and a specific position in that file\r
-    // This gives 8 variants. \r
-    // Note: a positional message with an empty position is treated as a simple message\r
-\r
-    // Messages can have arguments.\r
-    // All arguments are strings.\r
-    // For each variant there are 5 functions relating to different numbers of arguments.\r
-    //   - general form: takes any number of arguments as a vector of strings\r
-    //   - 0 arguments: takes no arguments\r
-    //   - 1 argument: allows a single argument\r
-    //   - 2 arguments: allows two arguments\r
-    //   - 3 arguments: allows three arguments\r
-    // For more than 3 arguments, use the general form\r
-\r
-    // information messages\r
-\r
-    // simple messages\r
-    std::vector<std::string> information_message(const std::string& id,\r
-                                                 const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const std::string& id,\r
-                                                 const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const std::string& id,\r
-                                                 const std::string& arg1,\r
-                                                 const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const std::string& id,\r
-                                                 const std::string& arg1,\r
-                                                 const std::string& arg2,\r
-                                                 const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional messages\r
-    std::vector<std::string> information_message(const message_position&,\r
-                                                 const std::string& id,\r
-                                                 const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const message_position&,\r
-                                                 const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const message_position&,\r
-                                                 const std::string& id,\r
-                                                 const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const message_position&,\r
-                                                 const std::string& id,\r
-                                                 const std::string& arg1,\r
-                                                 const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> information_message(const message_position&,\r
-                                                 const std::string& id,\r
-                                                 const std::string& arg1,\r
-                                                 const std::string& arg2,\r
-                                                 const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // warning messages\r
-\r
-    // simple messages\r
-    std::vector<std::string> warning_message(const std::string& id,\r
-                                             const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const std::string& id,\r
-                                             const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2,\r
-                                             const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional messages\r
-    std::vector<std::string> warning_message(const message_position&,\r
-                                             const std::string& id,\r
-                                             const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const message_position&,\r
-                                             const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const message_position&,\r
-                                             const std::string& id,\r
-                                             const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const message_position&,\r
-                                             const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> warning_message(const message_position&,\r
-                                             const std::string& id,\r
-                                             const std::string& arg1,\r
-                                             const std::string& arg2,\r
-                                             const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // error messages\r
-\r
-    // simple messages\r
-    std::vector<std::string> error_message(const std::string& id,\r
-                                           const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const std::string& id,\r
-                                           const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2,\r
-                                           const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional messages\r
-    std::vector<std::string> error_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const message_position&,\r
-                                           const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> error_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2,\r
-                                           const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // fatal messages\r
-    // Note that these do not throw the fatal_error exception because that would prevent the message being reported\r
-    // the caller should throw the exception after reporting the message\r
-\r
-    // simple messages\r
-    std::vector<std::string> fatal_message(const std::string& id,\r
-                                           const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const std::string& id,\r
-                                           const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2,\r
-                                           const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional messages\r
-    std::vector<std::string> fatal_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const message_position&,\r
-                                           const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    std::vector<std::string> fatal_message(const message_position&,\r
-                                           const std::string& id,\r
-                                           const std::string& arg1,\r
-                                           const std::string& arg2,\r
-                                           const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // supplement messages - these must be pushed *before* the message that they apply to\r
-\r
-    // simple messages\r
-    void push_supplement(const std::string& id,\r
-                         const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const std::string& id,\r
-                         const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const std::string& id,\r
-                         const std::string& arg1,\r
-                         const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const std::string& id,\r
-                         const std::string& arg1,\r
-                         const std::string& arg2,\r
-                         const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional messages\r
-    void push_supplement(const message_position&,\r
-                         const std::string& id,\r
-                         const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const message_position&,\r
-                         const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const message_position&,\r
-                         const std::string& id,\r
-                         const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const message_position&,\r
-                         const std::string& id,\r
-                         const std::string& arg1,\r
-                         const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_supplement(const message_position&,\r
-                         const std::string& id,\r
-                         const std::string& arg1,\r
-                         const std::string& arg2,\r
-                         const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // context stack - allows supplementary messages to be printed after each message showing where it came from\r
-    // for example, an message whilst inlining a function could be followed by a "function called from..." message\r
-\r
-    // simple context messages\r
-    void push_context(const std::string& id,\r
-                      const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const std::string& id,\r
-                      const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const std::string& id,\r
-                      const std::string& arg1,\r
-                      const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const std::string& id,\r
-                      const std::string& arg1,\r
-                      const std::string& arg2,\r
-                      const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional context messages\r
-    void push_context(const message_position&,\r
-                      const std::string& id,\r
-                      const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const message_position&,\r
-                      const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const message_position&,\r
-                      const std::string& id,\r
-                      const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const message_position&,\r
-                      const std::string& id,\r
-                      const std::string& arg1,\r
-                      const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    void push_context(const message_position&,\r
-                      const std::string& id,\r
-                      const std::string& arg1,\r
-                      const std::string& arg2,\r
-                      const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    unsigned context_depth(void) const\r
-      throw();\r
-\r
-    // remove the last level of context if there is one\r
-    void pop_context(void)\r
-      throw();\r
-    // remove context messages to the specified depth\r
-    void pop_context(unsigned)\r
-      throw();\r
-\r
-    // push the context and save it in the message_context handle. When the\r
-    // message_context handle goes out of scope, the context is popped\r
-    // automatically\r
-\r
-    // simple context messages\r
-    message_context auto_push_context(const std::string& id,\r
-                                      const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const std::string& id,\r
-                                      const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const std::string& id,\r
-                                      const std::string& arg1,\r
-                                      const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const std::string& id,\r
-                                      const std::string& arg1,\r
-                                      const std::string& arg2,\r
-                                      const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional context messages\r
-    message_context auto_push_context(const message_position&,\r
-                                      const std::string& id,\r
-                                      const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const message_position&,\r
-                                      const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const message_position&,\r
-                                      const std::string& id,\r
-                                      const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const message_position&,\r
-                                      const std::string& id,\r
-                                      const std::string& arg1,\r
-                                      const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    message_context auto_push_context(const message_position&,\r
-                                      const std::string& id,\r
-                                      const std::string& arg1,\r
-                                      const std::string& arg2,\r
-                                      const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-  private:\r
-    friend class message_handler_base_body;\r
-    smart_ptr_nocopy<message_handler_base_body> m_base_body;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-  // iostream-based derivative uses the above base class to generate messages then uses iostream to print them\r
-  // Note: since this is a public derivative, all message_handler_base operations are also available\r
-\r
-  class message_handler : public message_handler_base\r
-  {\r
-  public:\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // constructor\r
-\r
-    // The device is the output on which to print the error. For command-line tools\r
-    // it will be either std::cout (standard output) or std::cerr (standard error) from\r
-    // <iostream>.\r
-\r
-    // The second and third form also reads a message file by calling\r
-    // add_message_file and therefore can throw exceptions. The first form\r
-    // defers file reading to explicit calls of add_message_file so does not\r
-    // throw any exceptions.\r
-\r
-    // limit sets the error limit - zero disables this feature\r
-    // show determines whether the source file line containing the error should also be shown\r
-\r
-    message_handler(std::ostream& device,unsigned limit = 0,bool show = true) \r
-      throw();\r
-\r
-    message_handler(std::ostream& device,\r
-                    const std::string& message_file,unsigned limit = 0,bool show = true) \r
-      throw(message_handler_read_error);\r
-\r
-    message_handler(std::ostream& device,\r
-                    const std::vector<std::string>& message_files,unsigned limit = 0,bool show = true) \r
-      throw(message_handler_read_error);\r
-\r
-    ~message_handler(void)\r
-      throw();\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // error count and error limits\r
-\r
-    void set_error_limit(unsigned error_limit)\r
-      throw();\r
-\r
-    unsigned error_limit(void) const\r
-      throw();\r
-\r
-    void reset_error_count(void)\r
-      throw();\r
-\r
-    unsigned error_count(void) const\r
-      throw();\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // access the output device for whatever reason (for example, to ensure that\r
-    // text output goes wherever the messages go)\r
-\r
-    std::ostream& device(void);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // Message reporting functions\r
-    // These are based on the error formatting functions in the baseclass\r
-\r
-    // information messages\r
-\r
-    // simple messages\r
-    bool information(const std::string& id,\r
-                     const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const std::string& id,\r
-                     const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const std::string& id,\r
-                     const std::string& arg1,\r
-                     const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const std::string& id,\r
-                     const std::string& arg1,\r
-                     const std::string& arg2,\r
-                     const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional messages\r
-    bool information(const message_position&,\r
-                     const std::string& id,\r
-                     const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const message_position&,\r
-                     const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const message_position&,\r
-                     const std::string& id,\r
-                     const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const message_position&,\r
-                     const std::string& id,\r
-                     const std::string& arg1,\r
-                     const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool information(const message_position&,\r
-                     const std::string& id,\r
-                     const std::string& arg1,\r
-                     const std::string& arg2,\r
-                     const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // warning messages\r
-\r
-    // simple messages\r
-    bool warning(const std::string& id,\r
-                 const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const std::string& id,\r
-                 const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const std::string& id,\r
-                 const std::string& arg1,\r
-                 const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const std::string& id,\r
-                 const std::string& arg1,\r
-                 const std::string& arg2,\r
-                 const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // positional messages\r
-    bool warning(const message_position&,\r
-                 const std::string& id,\r
-                 const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const message_position&,\r
-                 const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const message_position&,\r
-                 const std::string& id,\r
-                 const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const message_position&,\r
-                 const std::string& id,\r
-                 const std::string& arg1,\r
-                 const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    bool warning(const message_position&,\r
-                 const std::string& id,\r
-                 const std::string& arg1,\r
-                 const std::string& arg2,\r
-                 const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error);\r
-\r
-    // error messages\r
-\r
-    // simple messages\r
-    bool error(const std::string& id,\r
-               const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const std::string& id,\r
-               const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2,\r
-               const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    // positional messages\r
-    bool error(const message_position&,\r
-               const std::string& id,\r
-               const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const message_position&,\r
-               const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const message_position&,\r
-               const std::string& id,\r
-               const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const message_position&,\r
-               const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    bool error(const message_position&,\r
-               const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2,\r
-               const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_limit_error);\r
-\r
-    // fatal messages\r
-    // These report the error and then always throw the fatal_error exception\r
-\r
-    // simple messages\r
-    bool fatal(const std::string& id,\r
-               const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const std::string& id,\r
-               const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2,\r
-               const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    // positional messages\r
-    bool fatal(const message_position&,\r
-               const std::string& id,\r
-               const std::vector<std::string>& args)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const message_position&,\r
-               const std::string& id)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const message_position&,\r
-               const std::string& id,\r
-               const std::string& arg1)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const message_position&,\r
-               const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    bool fatal(const message_position&,\r
-               const std::string& id,\r
-               const std::string& arg1,\r
-               const std::string& arg2,\r
-               const std::string& arg3)\r
-      throw(message_handler_id_error,message_handler_format_error,message_handler_fatal_error);\r
-\r
-    //////////////////////////////////////////////////////////////////////////////\r
-    // plain text output\r
-    // provides a simple way of outputting text from the program to the same device as the messages\r
-    // Each call of plaintext is treated as a line of text and has a newline appended\r
-\r
-    bool plaintext (const std::string& text);\r
-\r
-  private:\r
-    friend class message_handler_body;\r
-    smart_ptr_nocopy<message_handler_body> m_body;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
diff --git a/src/stlplus/subsystems/subsystems.hpp b/src/stlplus/subsystems/subsystems.hpp
deleted file mode 100644 (file)
index 2bc41b5..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef STLPLUS_SUBSYSTEMS\r
-#define STLPLUS_SUBSYSTEMS\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Allows all the STLplus subsystems to be included in one go\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#include "cli_parser.hpp"\r
-#include "ini_manager.hpp"\r
-#include "library_manager.hpp"\r
-#include "message_handler.hpp"\r
-#include "timer.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/subsystems/subsystems_fixes.hpp b/src/stlplus/subsystems/subsystems_fixes.hpp
deleted file mode 100644 (file)
index 8fd9f91..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef STLPLUS_SUBSYSTEMS_FIXES\r
-#define STLPLUS_SUBSYSTEMS_FIXES\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   Contains work arounds for OS or Compiler specific problems\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-// Unnecessary compiler warnings\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-#ifdef _MSC_VER\r
-// Microsoft Visual Studio\r
-// shut up the following irritating warnings\r
-//   4786 - VC6, identifier string exceeded maximum allowable length and was truncated (only affects debugger)\r
-//   4305 - VC6, identifier type was converted to a smaller type\r
-//   4503 - VC6, decorated name was longer than the maximum the compiler allows (only affects debugger)\r
-//   4309 - VC6, type conversion operation caused a constant to exceeded the space allocated for it\r
-//   4290 - VC6, C++ exception specification ignored\r
-//   4800 - VC6, forcing value to bool 'true' or 'false' (performance warning)\r
-//   4675 - VC7.1, "change" in function overload resolution _might_ have altered program\r
-//   4996 - VC8, 'xxxx' was declared deprecated\r
-#pragma warning(disable: 4786 4305 4503 4309 4290 4800 4675 4996)\r
-#endif\r
-\r
-#ifdef __BORLANDC__\r
-// Borland\r
-// Shut up the following irritating warnings\r
-//   8026 - Functions with exception specifications are not expanded inline\r
-//   8027 - Functions with xxx are not expanded inline\r
-#pragma warn -8026\r
-#pragma warn -8027\r
-#endif\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#endif\r
diff --git a/src/stlplus/subsystems/timer.cpp b/src/stlplus/subsystems/timer.cpp
deleted file mode 100644 (file)
index 9faac0f..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "timer.hpp"\r
-#include "dprintf.hpp"\r
-#include "time.hpp"\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-namespace stlplus\r
-{\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-  timer::timer(void)\r
-  {\r
-    reset();\r
-  }\r
-\r
-  timer::~timer(void)\r
-  {\r
-  }\r
-\r
-  void timer::reset(void)\r
-  {\r
-    m_clock = clock();\r
-    m_time = time(0);\r
-  }\r
-\r
-  float timer::cpu(void) const\r
-  {\r
-    return ((float)(clock() - m_clock)) / ((float)CLOCKS_PER_SEC);\r
-  }\r
-\r
-  float timer::elapsed(void) const\r
-  {\r
-    return ((float)(time(0) - m_time));\r
-  }\r
-\r
-  std::string timer::text(void) const\r
-  {\r
-    return dformat("%4.2fs CPU, %s elapsed", cpu(), delaytime_string(time(0)-m_time).c_str());\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-  std::ostream& operator << (std::ostream& str, const timer& t)\r
-  {\r
-    return str << t.text();\r
-  }\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
diff --git a/src/stlplus/subsystems/timer.hpp b/src/stlplus/subsystems/timer.hpp
deleted file mode 100644 (file)
index a3ad38d..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef STLPLUS_TIMER\r
-#define STLPLUS_TIMER\r
-////////////////////////////////////////////////////////////////////////////////\r
-\r
-//   Author:    Andy Rushton\r
-//   Copyright: (c) Southampton University 1999-2004\r
-//              (c) Andy Rushton           2004-2009\r
-//   License:   BSD License, see ../docs/license.html\r
-\r
-//   A CPU timer encapsulated as a class. Measures the CPU time used since its\r
-//   construction and allows this cumulative time to be reported at any time.\r
-\r
-////////////////////////////////////////////////////////////////////////////////\r
-#include "subsystems_fixes.hpp"\r
-#include <time.h>\r
-#include <string>\r
-#include <iostream>\r
-\r
-namespace stlplus\r
-{\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  class timer\r
-  {\r
-  private:\r
-    clock_t m_clock;\r
-    time_t m_time;\r
-\r
-  public:\r
-    // constructor resets the timer to zero\r
-    timer(void);\r
-    ~timer(void);\r
-\r
-    // reset the timer to zero without destroying it\r
-    void reset(void);\r
-\r
-    // get the elapsed time in seconds, expressed as a float\r
-    float elapsed(void) const;\r
-    // get the CPU time in seconds, expressed as a float\r
-    float cpu(void) const;\r
-\r
-    // get a printable string representing the elapsed time and CPU time\r
-    std::string text(void) const;\r
-  };\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-  // print the elapsed time and CPU time using the same representation as the text method\r
-  std::ostream& operator << (std::ostream&, const timer&);\r
-\r
-  ////////////////////////////////////////////////////////////////////////////////\r
-\r
-} // end namespace stlplus\r
-\r
-#endif\r
This page took 2.213036 seconds and 4 git commands to generate.