aboutsummaryrefslogtreecommitdiff
path: root/0.8.0/paludis/util
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-10-11 20:56:59 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-10-11 20:56:59 +0000
commite3b86134db7baada7b3a1e779e7d6d046ab53a1a (patch)
tree6acb3c0de68e1b95dbba8f0e00f770b8f31e4bac /0.8.0/paludis/util
parentab9cdb1150d97449e857cd55fe706377c9ab2422 (diff)
downloadpaludis-0.8.0.tar.gz
paludis-0.8.0.tar.xz
Tag release 0.8.00.8.0
Diffstat (limited to '0.8.0/paludis/util')
-rw-r--r--0.8.0/paludis/util/Makefile.am.m464
-rw-r--r--0.8.0/paludis/util/attributes.hh.in63
-rw-r--r--0.8.0/paludis/util/collection.hh343
-rw-r--r--0.8.0/paludis/util/collection_concrete.hh280
-rw-r--r--0.8.0/paludis/util/compare.hh160
-rw-r--r--0.8.0/paludis/util/comparison_policy.hh517
-rw-r--r--0.8.0/paludis/util/counted_ptr.hh447
-rw-r--r--0.8.0/paludis/util/counted_ptr_TEST.cc373
-rw-r--r--0.8.0/paludis/util/destringify.cc34
-rw-r--r--0.8.0/paludis/util/destringify.hh152
-rw-r--r--0.8.0/paludis/util/destringify_TEST.cc113
-rw-r--r--0.8.0/paludis/util/dir_iterator.cc171
-rw-r--r--0.8.0/paludis/util/dir_iterator.hh117
-rw-r--r--0.8.0/paludis/util/dir_iterator_TEST.cc97
-rwxr-xr-x0.8.0/paludis/util/dir_iterator_TEST_cleanup.sh9
-rwxr-xr-x0.8.0/paludis/util/dir_iterator_TEST_setup.sh6
-rw-r--r--0.8.0/paludis/util/exception.cc127
-rw-r--r--0.8.0/paludis/util/exception.hh214
-rw-r--r--0.8.0/paludis/util/fast_unique_copy.hh84
-rw-r--r--0.8.0/paludis/util/fast_unique_copy_TEST.cc121
-rw-r--r--0.8.0/paludis/util/fd_holder.hh60
-rw-r--r--0.8.0/paludis/util/fd_output_stream.hh117
-rw-r--r--0.8.0/paludis/util/files.m443
-rw-r--r--0.8.0/paludis/util/fs_entry.cc439
-rw-r--r--0.8.0/paludis/util/fs_entry.hh332
-rw-r--r--0.8.0/paludis/util/fs_entry_TEST.cc368
-rwxr-xr-x0.8.0/paludis/util/fs_entry_TEST_cleanup.sh9
-rwxr-xr-x0.8.0/paludis/util/fs_entry_TEST_setup.sh17
-rw-r--r--0.8.0/paludis/util/instantiation_policy.hh291
-rw-r--r--0.8.0/paludis/util/instantiation_policy_TEST.cc191
-rw-r--r--0.8.0/paludis/util/is_file_with_extension.cc56
-rw-r--r--0.8.0/paludis/util/is_file_with_extension.hh67
-rw-r--r--0.8.0/paludis/util/is_file_with_extension_TEST.cc94
-rwxr-xr-x0.8.0/paludis/util/is_file_with_extension_TEST_cleanup.sh9
-rwxr-xr-x0.8.0/paludis/util/is_file_with_extension_TEST_setup.sh6
-rw-r--r--0.8.0/paludis/util/iterator.hh502
-rw-r--r--0.8.0/paludis/util/iterator_TEST.cc361
-rw-r--r--0.8.0/paludis/util/join.hh67
-rw-r--r--0.8.0/paludis/util/join_TEST.cc102
-rw-r--r--0.8.0/paludis/util/log.cc156
-rw-r--r--0.8.0/paludis/util/log.hh119
-rw-r--r--0.8.0/paludis/util/log_TEST.cc74
-rw-r--r--0.8.0/paludis/util/pipe.cc37
-rw-r--r--0.8.0/paludis/util/pipe.hh72
-rw-r--r--0.8.0/paludis/util/private_implementation_pattern.hh70
-rw-r--r--0.8.0/paludis/util/pstream.cc141
-rw-r--r--0.8.0/paludis/util/pstream.hh228
-rw-r--r--0.8.0/paludis/util/pstream_TEST.cc111
-rw-r--r--0.8.0/paludis/util/random.cc43
-rw-r--r--0.8.0/paludis/util/random.hh71
-rw-r--r--0.8.0/paludis/util/random_TEST.cc121
-rw-r--r--0.8.0/paludis/util/save.hh83
-rw-r--r--0.8.0/paludis/util/save_TEST.cc68
-rw-r--r--0.8.0/paludis/util/sr.hh45
-rw-r--r--0.8.0/paludis/util/stringify.hh168
-rw-r--r--0.8.0/paludis/util/stringify_TEST.cc129
-rw-r--r--0.8.0/paludis/util/strip.cc100
-rw-r--r--0.8.0/paludis/util/strip.hh130
-rw-r--r--0.8.0/paludis/util/strip_TEST.cc123
-rw-r--r--0.8.0/paludis/util/system.cc230
-rw-r--r--0.8.0/paludis/util/system.hh168
-rw-r--r--0.8.0/paludis/util/system_TEST.cc184
-rwxr-xr-x0.8.0/paludis/util/system_TEST_cleanup.sh9
-rwxr-xr-x0.8.0/paludis/util/system_TEST_setup.sh5
-rw-r--r--0.8.0/paludis/util/test_extras.cc73
-rw-r--r--0.8.0/paludis/util/tokeniser.cc28
-rw-r--r--0.8.0/paludis/util/tokeniser.hh245
-rw-r--r--0.8.0/paludis/util/tokeniser_TEST.cc139
-rw-r--r--0.8.0/paludis/util/util.hh.m442
-rw-r--r--0.8.0/paludis/util/validated.hh124
-rw-r--r--0.8.0/paludis/util/validated_TEST.cc126
-rw-r--r--0.8.0/paludis/util/virtual_constructor.hh243
-rw-r--r--0.8.0/paludis/util/virtual_constructor_TEST.cc190
-rw-r--r--0.8.0/paludis/util/visitor.hh359
-rw-r--r--0.8.0/paludis/util/visitor_TEST.cc190
75 files changed, 11067 insertions, 0 deletions
diff --git a/0.8.0/paludis/util/Makefile.am.m4 b/0.8.0/paludis/util/Makefile.am.m4
new file mode 100644
index 000000000..1adce6b3e
--- /dev/null
+++ b/0.8.0/paludis/util/Makefile.am.m4
@@ -0,0 +1,64 @@
+ifdef(`__gnu__',`',`errprint(`This is not GNU m4...
+')m4exit(1)') include(`misc/generated-file.txt')
+
+dnl vim: set ft=m4 noet :
+
+define(`filelist', `')dnl
+define(`headerlist', `')dnl
+define(`testlist', `')dnl
+define(`testscriptlist', `')dnl
+define(`addtest', `define(`testlist', testlist `$1_TEST')dnl
+$1_TEST_SOURCES = $1_TEST.cc
+$1_TEST_LDADD = test_extras.o $(top_builddir)/test/libtest.a libpaludisutil.la
+$1_TEST_CXXFLAGS = -I$(top_srcdir)
+')dnl
+define(`addtestscript', `define(`testscriptlist', testscriptlist `$1_TEST_setup.sh $1_TEST_cleanup.sh')')dnl
+define(`addhh', `define(`filelist', filelist `$1.hh')define(`headerlist', headerlist `$1.hh')')dnl
+define(`addhhx', `define(`filelist', filelist `$1.hh')')dnl
+define(`addcc', `define(`filelist', filelist `$1.cc')')dnl
+define(`addimpl', `define(`filelist', filelist `$1-impl.hh')')dnl
+define(`addthis', `dnl
+ifelse(`$2', `hh', `addhh(`$1')', `')dnl
+ifelse(`$2', `hhx', `addhhx(`$1')', `')dnl
+ifelse(`$2', `cc', `addcc(`$1')', `')dnl
+ifelse(`$2', `impl', `addimpl(`$1')', `')dnl
+ifelse(`$2', `test', `addtest(`$1')', `')dnl
+ifelse(`$2', `testscript', `addtestscript(`$1')', `')')dnl
+define(`add', `addthis(`$1',`$2')addthis(`$1',`$3')addthis(`$1',`$4')dnl
+addthis(`$1',`$5')addthis(`$1',`$6')')dnl
+
+include(`paludis/util/files.m4')
+
+CLEANFILES = *~ gmon.out *.gcov *.gcno *.gcda
+MAINTAINERCLEANFILES = Makefile.in Makefile.am paludis.hh \
+ hashed_containers.hh util.hh attributes.hh
+AM_CXXFLAGS = -I$(top_srcdir) @PALUDIS_CXXFLAGS@ @PALUDIS_CXXFLAGS_VISIBILITY@
+DEFS=\
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\"
+EXTRA_DIST = util.hh.m4 Makefile.am.m4 files.m4 \
+ testscriptlist test_extras.cc attributes.hh.in
+SUBDIRS = .
+
+libpaludisutil_la_SOURCES = filelist
+libpaludisutil_la_LDFLAGS = -version-info @VERSION_LIB_CURRENT@:@VERSION_LIB_REVISION@:0
+
+TESTS = testlist
+
+TESTS_ENVIRONMENT = env \
+ PALUDIS_EBUILD_DIR="$(srcdir)/ebuild/" \
+ TEST_SCRIPT_DIR="$(srcdir)/" \
+ bash $(top_srcdir)/test/run_test.sh
+
+check_PROGRAMS = $(TESTS)
+check_SCRIPTS = testscriptlist
+lib_LTLIBRARIES = libpaludisutil.la
+paludis_util_includedir = $(includedir)/paludis/util/
+paludis_util_include_HEADERS = headerlist
+
+Makefile.am : Makefile.am.m4 files.m4
+ $(top_srcdir)/misc/do_m4.bash Makefile.am
+
+util.hh : util.hh.m4 files.m4
+ $(top_srcdir)/misc/do_m4.bash util.hh
+
diff --git a/0.8.0/paludis/util/attributes.hh.in b/0.8.0/paludis/util/attributes.hh.in
new file mode 100644
index 000000000..f5f83b53b
--- /dev/null
+++ b/0.8.0/paludis/util/attributes.hh.in
@@ -0,0 +1,63 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_ATTRIBUTES_HH
+#define PALUDIS_GUARD_PALUDIS_ATTRIBUTES_HH 1
+
+/** \file
+ * Declare the PALUDIS_ATTRIBUTE macro.
+ *
+ * \ingroup grplibpaludisutil
+ */
+
+/** \def PALUDIS_ATTRIBUTE
+ * If we're using a recent GCC or ICC, expands to __attribute__, otherwise
+ * discards its arguments.
+ *
+ * \ingroup grplibpaludisutil
+ */
+
+/** \def PALUDIS_CAN_USE_ATTRIBUTE
+ * Defined if we can rely upon PALUDIS_ATTRIBUTE working (for example, for
+ * weak).
+ *
+ * \ingroup grplibpaludisutil
+ */
+
+#if (defined(__GNUC__) || defined(DOXYGEN))
+# if ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || defined(DOXYGEN))
+# define PALUDIS_ATTRIBUTE(x) __attribute__(x)
+# define PALUDIS_CAN_USE_ATTRIBUTE 1
+# else
+# define PALUDIS_ATTRIBUTE(x)
+# endif
+#else
+# define PALUDIS_ATTRIBUTE(x)
+#endif
+
+#define PALUDIS_ENABLE_VISIBILITY @PALUDIS_ENABLE_VISIBILITY@
+#if PALUDIS_ENABLE_VISIBILITY
+# define PALUDIS_VISIBLE PALUDIS_ATTRIBUTE((visibility("default")))
+# define PALUDIS_HIDDEN PALUDIS_ATTRIBUTE((visibility("hidden")))
+#else
+# define PALUDIS_VISIBLE
+# define PALUDIS_HIDDEN
+#endif
+
+#endif
diff --git a/0.8.0/paludis/util/collection.hh b/0.8.0/paludis/util/collection.hh
new file mode 100644
index 000000000..920bece1c
--- /dev/null
+++ b/0.8.0/paludis/util/collection.hh
@@ -0,0 +1,343 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_SEQUENTIAL_COLLECTION_HH
+#define PALUDIS_GUARD_PALUDIS_SEQUENTIAL_COLLECTION_HH 1
+
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <libwrapiter/libwrapiter.hh>
+#include <iterator>
+
+/** \file
+ * Various wrappers around collections of items, for convenience and
+ * avoiding passing around huge containers.
+ *
+ * \ingroup grpcollections
+ */
+
+namespace paludis
+{
+ /**
+ * Wrapper around a std::list of a particular item. Multiple items
+ * with the same value are disallowed.
+ *
+ * This item cannot be constructed. Use SequentialCollection::Concrete,
+ * which requires including paludis/util/collection_concrete.hh .
+ *
+ * \ingroup grpcollections
+ */
+ template <typename T_>
+ class PALUDIS_VISIBLE SequentialCollection :
+ private InstantiationPolicy<SequentialCollection<T_>, instantiation_method::NonCopyableTag>,
+ public InternalCounted<SequentialCollection<T_> >,
+ public std::iterator<typename std::iterator_traits<
+ typename libwrapiter::ForwardIterator<SequentialCollection<T_>, const T_> >::iterator_category, T_>
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ SequentialCollection()
+ {
+ }
+
+ ///\}
+
+ public:
+ class Concrete;
+
+ /**
+ * Issue with g++ 3.4.6: const_reference isn't defined via our std::iterator
+ * inherit, but it is needed by many standard algorithms.
+ */
+ typedef const T_ & const_reference;
+
+ ///\name Basic operations
+ ///\{
+
+ virtual ~SequentialCollection()
+ {
+ }
+
+ ///\}
+
+ ///\name Iterate over our items
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<SequentialCollection<T_>, const T_> Iterator;
+
+ virtual Iterator begin() const = 0;
+
+ virtual Iterator end() const = 0;
+
+ virtual Iterator last() const = 0;
+
+ ///\}
+
+ ///\name Finding items
+ ///\{
+
+ /**
+ * Return an Iterator to an item, or end() if there's no match.
+ */
+ virtual Iterator find(const T_ & v) const = 0;
+
+ ///\}
+
+ ///\name Adding and modifying items
+ ///\{
+
+ /**
+ * Append an item, return whether we succeeded.
+ */
+ virtual bool append(T_ v) = 0;
+
+ /**
+ * Append an item.
+ */
+ virtual void push_back(const T_ & v) = 0;
+
+ ///\}
+
+ ///\name Queries
+ ///\{
+
+ /**
+ * Are we empty?
+ */
+ virtual bool empty() const = 0;
+
+ ///\}
+ };
+
+ /**
+ * Wrapper around a std::set of a particular item.
+ *
+ * This item cannot be constructed. Use SortedCollection::Concrete,
+ * which requires including paludis/util/collection_concrete.hh .
+ *
+ * \ingroup grpcollections
+ */
+ template <typename T_, typename C_ = std::less<T_> >
+ class PALUDIS_VISIBLE SortedCollection :
+ private InstantiationPolicy<SortedCollection<T_, C_>, instantiation_method::NonCopyableTag>,
+ public InternalCounted<SortedCollection<T_, C_> >,
+ public std::iterator<typename std::iterator_traits<
+ typename libwrapiter::ForwardIterator<SortedCollection<T_, C_>, const T_> >::iterator_category, T_>
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ SortedCollection()
+ {
+ }
+
+ ///\}
+
+ public:
+ class Concrete;
+
+ ///\name Basic operations
+ ///\{
+
+ virtual ~SortedCollection()
+ {
+ }
+
+ ///\}
+
+ ///\name Iterate over our items
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<SortedCollection<T_, C_>, const T_> Iterator;
+
+ virtual Iterator begin() const = 0;
+
+ virtual Iterator end() const = 0;
+
+ struct ReverseTag;
+ typedef libwrapiter::ForwardIterator<ReverseTag, const T_> ReverseIterator;
+
+ virtual ReverseIterator rbegin() const = 0;
+
+ virtual ReverseIterator rend() const = 0;
+
+ virtual Iterator last() const = 0;
+
+ ///\}
+
+ ///\name Finding items
+ ///\{
+
+ virtual Iterator find(const T_ & v) const = 0;
+
+ virtual int count(const T_ & v) const = 0;
+
+ ///\}
+
+ ///\name Adding, removing and modifying items
+ ///\{
+
+ /**
+ * Insert an item, return whether we succeeded.
+ */
+ virtual bool insert(const T_ & v) = 0;
+
+ /**
+ * Insert a range of items, return whether we inserted everything.
+ */
+ template <typename I_>
+ bool insert(I_ b, const I_ & e)
+ {
+ bool result(false);
+ for ( ; b != e ; ++b)
+ result |= insert(*b);
+ return result;
+ }
+
+ /**
+ * Erase an item, return whether we succeeded.
+ */
+ virtual bool erase(const T_ & v) = 0;
+
+ /**
+ * Insert all items from another container.
+ */
+ virtual bool merge(typename SortedCollection<T_, C_>::ConstPointer o) = 0;
+
+ /**
+ * Our insert iterator type.
+ */
+ typedef libwrapiter::OutputIterator<SortedCollection<T_, C_>, T_> Inserter;
+
+ /**
+ * Fetch an inserter.
+ */
+ virtual Inserter inserter() = 0;
+
+ ///\}
+
+ ///\name Queries
+ ///\{
+
+ /**
+ * Are we empty?
+ */
+ virtual bool empty() const = 0;
+
+ /**
+ * How big are we?
+ */
+ virtual unsigned size() const = 0;
+
+ ///\}
+ };
+
+ /**
+ * Wrapper around a std::map of a particular item.
+ *
+ * This item cannot be constructed. Use AssociativeCollection::Concrete,
+ * which requires including paludis/util/collection_concrete.hh .
+ *
+ * \ingroup grpcollections
+ */
+ template <typename K_, typename V_>
+ class PALUDIS_VISIBLE AssociativeCollection :
+ private InstantiationPolicy<AssociativeCollection<K_, V_>, instantiation_method::NonCopyableTag>,
+ public InternalCounted<AssociativeCollection<K_, V_> >,
+ public std::iterator<typename std::iterator_traits<
+ typename libwrapiter::ForwardIterator<AssociativeCollection<K_, V_>,
+ const std::pair<const K_, V_> > >::iterator_category, const std::pair<const K_, V_> >
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ AssociativeCollection()
+ {
+ }
+
+ ///\}
+
+ public:
+ class Concrete;
+
+ ///\name Basic operations
+ ///\{
+
+ virtual ~AssociativeCollection()
+ {
+ }
+
+ ///\}
+
+ ///\name Iterate over our items
+ ///\{
+
+ typedef libwrapiter::ForwardIterator<AssociativeCollection<K_, V_>,
+ const std::pair<const K_, V_> > Iterator;
+
+ virtual Iterator begin() const = 0;
+
+ virtual Iterator end() const = 0;
+
+ ///\}
+
+ ///\name Finding items
+ ///\{
+
+ virtual Iterator find(const K_ & v) const = 0;
+
+ ///\}
+
+ ///\name Adding, removing and modifying items
+ ///\{
+
+ /**
+ * Insert an item, return whether we succeeded.
+ */
+ virtual bool insert(const K_ & k, const V_ & v) = 0;
+
+ /**
+ * Erase an item, return whether we succeeded.
+ */
+ virtual bool erase(const K_ & k) = 0;
+
+ /**
+ * Erase an item, return whether we succeeded.
+ */
+ virtual bool erase(const Iterator & i) = 0;
+
+ ///\}
+
+ ///\name Queries
+ ///\{
+
+ /**
+ * Are we empty?
+ */
+ virtual bool empty() const = 0;
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/collection_concrete.hh b/0.8.0/paludis/util/collection_concrete.hh
new file mode 100644
index 000000000..af2031a5b
--- /dev/null
+++ b/0.8.0/paludis/util/collection_concrete.hh
@@ -0,0 +1,280 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_COLLECTION_CONCRETE_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_COLLECTION_CONCRETE_HH 1
+
+#include <paludis/util/collection.hh>
+#include <list>
+#include <set>
+#include <map>
+#include <algorithm>
+
+/** \file
+ * Concrete implementations for the collection classes.
+ *
+ * Do not include this file in other headers if possible. It pulls in big
+ * STL things, slowing down compilation.
+ *
+ * \ingroup grpcollections
+ */
+
+namespace paludis
+{
+ /**
+ * Concrete implementation for a SequentialCollection.
+ *
+ * \see SequentialCollection
+ * \ingroup grpcollections
+ */
+ template <typename T_>
+ class PALUDIS_VISIBLE SequentialCollection<T_>::Concrete :
+ public SequentialCollection<T_>
+ {
+ private:
+ std::list<T_> _items;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ Concrete() :
+ SequentialCollection()
+ {
+ }
+
+ virtual ~Concrete()
+ {
+ }
+
+ ///\}
+
+ virtual Iterator begin() const
+ {
+ return Iterator(_items.begin());
+ }
+
+ virtual Iterator end() const
+ {
+ return Iterator(_items.end());
+ }
+
+ virtual Iterator last() const
+ {
+ return Iterator(_items.begin() == _items.end() ? _items.end() : --(_items.end()));
+ }
+
+ virtual Iterator find(const T_ & v) const
+ {
+ return Iterator(std::find(_items.begin(), _items.end(), v));
+ }
+
+ virtual bool append(T_ v)
+ {
+ if (end() != find(v))
+ return false;
+
+ _items.push_back(v);
+ return true;
+ }
+
+ void push_back(const T_ & v)
+ {
+ if (end() == find(v))
+ _items.push_back(v);
+ }
+
+ virtual bool empty() const
+ {
+ return _items.empty();
+ }
+ };
+
+ /**
+ * Concrete implementation for a SortedCollection.
+ *
+ * \see SortedCollection
+ * \ingroup grpcollections
+ */
+ template <typename T_, typename C_ = std::less<T_> >
+ class PALUDIS_VISIBLE SortedCollection<T_, C_>::Concrete :
+ public SortedCollection<T_, C_>
+ {
+ private:
+ std::set<T_, C_> _items;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ Concrete()
+ {
+ }
+
+ virtual ~Concrete()
+ {
+ }
+
+ ///\}
+
+ virtual Iterator begin() const
+ {
+ return Iterator(_items.begin());
+ }
+
+ virtual Iterator end() const
+ {
+ return Iterator(_items.end());
+ }
+
+ virtual ReverseIterator rbegin() const
+ {
+ return ReverseIterator(_items.rbegin());
+ }
+
+ virtual ReverseIterator rend() const
+ {
+ return ReverseIterator(_items.rend());
+ }
+
+ virtual Iterator last() const
+ {
+ typename std::set<T_, C_>::const_iterator result(_items.end());
+ if (result != _items.begin())
+ --result;
+ return Iterator(result);
+ }
+
+ virtual Iterator find(const T_ & v) const
+ {
+ return Iterator(_items.find(v));
+ }
+
+ virtual int count(const T_ & v) const
+ {
+ return _items.count(v);
+ }
+
+ virtual bool insert(const T_ & v)
+ {
+ return _items.insert(v).second;
+ }
+
+ virtual bool erase(const T_ & v)
+ {
+ return 0 != _items.erase(v);
+ }
+
+ virtual bool merge(typename SortedCollection<T_, C_>::ConstPointer o)
+ {
+ bool result(true);
+ Iterator o_begin(o->begin()), o_end(o->end());
+ for ( ; o_begin != o_end ; ++o_begin)
+ result &= insert(*o_begin);
+ return result;
+ }
+
+ virtual Inserter inserter()
+ {
+ return Inserter(std::inserter(_items, _items.begin()));
+ }
+
+ virtual bool empty() const
+ {
+ return _items.empty();
+ }
+
+ virtual unsigned size() const
+ {
+ return _items.size();
+ }
+ };
+
+ /**
+ * Concrete implementation for an AssociativeCollection.
+ *
+ * \see AssociativeCollection
+ * \ingroup grpcollections
+ */
+ template <typename K_, typename V_>
+ class PALUDIS_VISIBLE AssociativeCollection<K_, V_>::Concrete :
+ public AssociativeCollection<K_, V_>
+ {
+ private:
+ std::map<K_, V_> _items;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ Concrete()
+ {
+ }
+
+ template <typename I_>
+ Concrete(const I_ & b, const I_ & b_end) :
+ _items(b, b_end)
+ {
+ }
+
+ virtual ~Concrete()
+ {
+ }
+
+ ///\}
+
+ virtual Iterator begin() const
+ {
+ return Iterator(_items.begin());
+ }
+
+ virtual Iterator end() const
+ {
+ return Iterator(_items.end());
+ }
+
+ virtual Iterator find(const K_ & v) const
+ {
+ return Iterator(_items.find(v));
+ }
+
+ virtual bool insert(const K_ & k, const V_ & v)
+ {
+ return _items.insert(std::make_pair(k, v)).second;
+ }
+
+ virtual bool erase(const K_ & k)
+ {
+ return 0 != _items.erase(k);
+ }
+
+ virtual bool erase(const Iterator & i)
+ {
+ _items.erase(i->first);
+ return true;
+ }
+
+ virtual bool empty() const
+ {
+ return _items.empty();
+ }
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/compare.hh b/0.8.0/paludis/util/compare.hh
new file mode 100644
index 000000000..87011fc7f
--- /dev/null
+++ b/0.8.0/paludis/util/compare.hh
@@ -0,0 +1,160 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_COMPARE_HH
+#define PALUDIS_GUARD_PALUDIS_COMPARE_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <paludis/util/validated.hh>
+#include <string>
+
+/** \file
+ * Declarations for the compare functions.
+ *
+ * \ingroup grpcompare
+ */
+
+namespace paludis
+{
+ /**
+ * Compare t1 and t2.
+ *
+ * \retval -1 if t1 < t2, 1 if t1 > t2, 0 otherwise.
+ *
+ * \ingroup grpcompare
+ */
+ inline int compare(int t1, int t2)
+ {
+ if (t1 < t2)
+ return -1;
+ else if (t1 > t2)
+ return 1;
+ else
+ return 0;
+ }
+
+ /**
+ * Compare t1 and t2.
+ *
+ * \retval -1 if t1 < t2, 1 if t1 > t2, 0 otherwise.
+ *
+ * \ingroup grpcompare
+ */
+ inline int compare(unsigned t1, unsigned t2)
+ {
+ if (t1 < t2)
+ return -1;
+ else if (t1 > t2)
+ return 1;
+ else
+ return 0;
+ }
+
+ /**
+ * Compare t1 and t2.
+ *
+ * \retval -1 if t1 < t2, 1 if t1 > t2, 0 otherwise.
+ *
+ * \ingroup grpcompare
+ */
+ inline int long compare(unsigned long t1, unsigned long t2)
+ {
+ if (t1 < t2)
+ return -1;
+ else if (t1 > t2)
+ return 1;
+ else
+ return 0;
+ }
+
+ /**
+ * Compare t1 and t2.
+ *
+ * \retval -1 if t1 < t2, 1 if t1 > t2, 0 otherwise.
+ *
+ * \ingroup grpcompare
+ */
+ inline int compare(long t1, long t2)
+ {
+ if (t1 < t2)
+ return -1;
+ else if (t1 > t2)
+ return 1;
+ else
+ return 0;
+ }
+
+ /**
+ * Compare t1 and t2.
+ *
+ * \retval -1 if t1 < t2, 1 if t1 > t2, 0 otherwise.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename T_>
+ inline int compare(
+ const std::basic_string<T_> & t1,
+ const std::basic_string<T_> & t2)
+ {
+ register int r(t1.compare(t2));
+ if (r < 0)
+ return -1;
+ else if (r > 0)
+ return 1;
+ else
+ return 0;
+ }
+
+ /**
+ * Compare t1 and t2.
+ *
+ * \retval -1 if t1 < t2, 1 if t1 > t2, 0 otherwise.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename T_, typename U_>
+ inline int compare(
+ const Validated<T_, U_> & t1,
+ const Validated<T_, U_> & t2)
+ {
+ return compare(t1.data(), t2.data());
+ }
+
+ /**
+ * Compare t1 and t2.
+ *
+ * \retval -1 if t1 < t2, 1 if t1 > t2, 0 otherwise.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename T_>
+ int compare(
+ const T_ & t1,
+ const T_ & t2)
+ {
+ if (t1 < t2)
+ return -1;
+ else if (t1 > t2)
+ return 1;
+ else
+ return 0;
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/comparison_policy.hh b/0.8.0/paludis/util/comparison_policy.hh
new file mode 100644
index 000000000..73adf1d1d
--- /dev/null
+++ b/0.8.0/paludis/util/comparison_policy.hh
@@ -0,0 +1,517 @@
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_COMPARISON_POLICY_HH
+#define PALUDIS_GUARD_PALUDIS_COMPARISON_POLICY_HH 1
+
+/** \file
+ * Declarations for the ComparisonPolicy class.
+ *
+ * \ingroup grpcompare
+ */
+
+namespace paludis
+{
+ /**
+ * Comparison modes for paludis::ComparisonPolicy.
+ *
+ * \ingroup grpcompare
+ */
+ namespace comparison_mode
+ {
+ /**
+ * No comparisons can be made.
+ *
+ * \ingroup grpcompare
+ */
+ struct NoComparisonTag
+ {
+ };
+
+ /**
+ * Comparisons can be made via operator== and operator!=.
+ *
+ * \ingroup grpcompare
+ */
+ struct EqualityComparisonTag
+ {
+ };
+
+ /**
+ * The full range of comparison operators is available.
+ *
+ * \ingroup grpcompare
+ */
+ struct FullComparisonTag
+ {
+ };
+ }
+
+ /**
+ * Comparison methods for paludis::ComparisonPolicy.
+ *
+ * \ingroup grpcompare
+ */
+ namespace comparison_method
+ {
+ /**
+ * Comparisons are done via a member of type MemberType_.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename MemberType_>
+ struct CompareByMemberTag
+ {
+ };
+
+ /**
+ * Comparisons are done by a member function that returns an integer
+ * less than zero (less than), equal to zero (equal to) or greater than
+ * zero (greater than).
+ *
+ * \ingroup grpcompare
+ */
+ struct CompareByMemberComparisonFunctionTag
+ {
+ };
+
+
+ /**
+ * Comparisons are done via a member function that returns an item of
+ * type MemberType_.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename MemberType_>
+ struct CompareByMemberFetchFunctionTag
+ {
+ };
+ }
+
+#ifdef DOXYGEN
+ /**
+ * ComparisonPolicy specifies the availabillity of comparison methods and
+ * the strategy used to do comparisons.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_, typename ComparisonModeTag_, typename ComparisonMethodTag_>
+ struct ComparisonPolicy
+ {
+ };
+#else
+ template <typename OurType_, typename ComparisonModeTag_, typename ComparisonMethodTag_>
+ struct ComparisonPolicy;
+#endif
+
+ /**
+ * ComparisonPolicy: specialisation for NoComparisonTag.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_, typename ComparisonMethodTag_>
+ class ComparisonPolicy<OurType_, comparison_mode::NoComparisonTag, ComparisonMethodTag_>
+ {
+ public:
+ ///\name Comparison policy tags
+ ///\{
+
+ /// Our comparison mode.
+ typedef comparison_mode::NoComparisonTag ComparisonPolicyModeTag;
+
+ /// Our comparison method.
+ typedef ComparisonMethodTag_ ComparisonPolicyMethodTag;
+
+ /// Our comparison policy.
+ typedef ComparisonPolicy<OurType_, ComparisonPolicyModeTag, ComparisonPolicyMethodTag> ComparisonPolicyType;
+
+ ///\}
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for EqualityComparisonTag +
+ * CompareByMemberTag.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberTag<MemberType_> >
+ {
+ private:
+ const MemberType_ OurType_::* const _v;
+
+ public:
+ ///\name Comparison policy tags
+ ///\{
+
+ /// Our comparison mode.
+ typedef comparison_mode::EqualityComparisonTag ComparisonPolicyModeTag;
+
+ /// Our comparison method.
+ typedef comparison_method::CompareByMemberTag<MemberType_> ComparisonPolicyMethodTag;
+
+ /// Our comparison policy.
+ typedef ComparisonPolicy<OurType_, ComparisonPolicyModeTag, ComparisonPolicyMethodTag> ComparisonPolicyType;
+
+ ///\}
+
+ ///\name Basic operations
+ ///\{
+
+ ComparisonPolicy(const MemberType_ OurType_::* const v) :
+ _v(v)
+ {
+ }
+
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+ ///\}
+
+ ///\name Comparison operators
+ ///\{
+
+#undef PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR
+#define PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(op) \
+ bool operator op (const OurType_ & other) const \
+ { \
+ return static_cast<const OurType_ *>(this)->*_v op other.*( \
+ (static_cast<const ComparisonPolicyType *>(&other))->_v); \
+ }
+
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(==)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(!=)
+
+ ///\}
+
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for EqualityComparisonTag +
+ * CompareByMemberComparisonFunctionTag.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_>
+ class ComparisonPolicy<OurType_, comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberComparisonFunctionTag>
+ {
+ private:
+ bool (OurType_::* const _v)(const OurType_ &) const;
+
+ public:
+ ///\name Comparison policy tags
+ ///\{
+
+ /// Our comparison mode.
+ typedef comparison_mode::EqualityComparisonTag ComparisonPolicyModeTag;
+
+ /// Our comparison method.
+ typedef comparison_method::CompareByMemberComparisonFunctionTag ComparisonPolicyMethodTag;
+
+ /// Our comparison policy.
+ typedef ComparisonPolicy<OurType_, ComparisonPolicyModeTag, ComparisonPolicyMethodTag> ComparisonPolicyType;
+
+ ///\}
+
+ ///\name Basic operations
+ ///\{
+
+ ComparisonPolicy(bool (OurType_::* const v)(const OurType_ &) const) :
+ _v(v)
+ {
+ }
+
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+ ///\}
+
+ ///\name Comparison operators
+ ///\{
+
+ bool operator== (const OurType_ & other) const
+ {
+ return (static_cast<const OurType_ *>(this)->*_v)(other);
+ }
+
+ bool operator!= (const OurType_ & other) const
+ {
+ return ! (static_cast<const OurType_ *>(this)->*_v)(other);
+ }
+
+ ///\}
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for FullComparisonTag +
+ * CompareByMemberTag.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<MemberType_> >
+ {
+ private:
+ const MemberType_ OurType_::* const _v;
+
+ public:
+ ///\name Comparison policy tags
+ ///\{
+
+ /// Our comparison mode.
+ typedef comparison_mode::FullComparisonTag ComparisonPolicyModeTag;
+
+ /// Our comparison method.
+ typedef comparison_method::CompareByMemberTag<MemberType_> ComparisonPolicyMethodTag;
+
+ /// Our comparison policy.
+ typedef ComparisonPolicy<OurType_, ComparisonPolicyModeTag, ComparisonPolicyMethodTag> ComparisonPolicyType;
+
+ ///\}
+
+ ///\name Basic operations
+ ///\{
+
+ ComparisonPolicy(const MemberType_ OurType_::* const v) :
+ _v(v)
+ {
+ }
+
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+ ///\}
+
+ ///\name Comparison operators
+ ///\{
+
+#undef PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR
+#define PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(op) \
+ bool operator op (const OurType_ & other) const \
+ { \
+ return static_cast<const OurType_ *>(this)->*_v op other.*( \
+ (static_cast<const ComparisonPolicyType *>(&other))->_v); \
+ }
+
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(==)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(!=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(<=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(>=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(<)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(>)
+
+ ///\}
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for FullComparisonTag +
+ * CompareByMemberComparisonFunctionTag.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_>
+ class ComparisonPolicy<OurType_, comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberComparisonFunctionTag>
+ {
+ private:
+ int (OurType_::* const _v)(const OurType_ &) const;
+
+ public:
+ ///\name Comparison policy tags
+ //\{
+
+ /// Our comparison mode.
+ typedef comparison_mode::FullComparisonTag ComparisonPolicyModeTag;
+
+ /// Our comparison method.
+ typedef comparison_method::CompareByMemberComparisonFunctionTag ComparisonPolicyMethodTag;
+
+ /// Our comparison policy.
+ typedef ComparisonPolicy<OurType_, ComparisonPolicyModeTag, ComparisonPolicyMethodTag> ComparisonPolicyType;
+
+ ///\}
+
+ ///\name Basic operations
+ ///\{
+
+ ComparisonPolicy(int (OurType_::* v)(const OurType_ &) const) :
+ _v(v)
+ {
+ }
+
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+ ///\}
+
+ ///\name Comparison operators
+ ///\{
+
+#undef PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR
+#define PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(op) \
+ bool operator op (const OurType_ & other) const \
+ { \
+ return (static_cast<const OurType_ *>(this)->*_v)(other) op 0; \
+ }
+
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(==)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(!=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(<=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(>=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(<)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(>)
+
+ ///\}
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for EqualityComparisonTag +
+ * CompareByMemberFetchFunctionTag.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberFetchFunctionTag<MemberType_> >
+ {
+ private:
+ MemberType_ (OurType_::* const _v)() const;
+
+ public:
+ ///\name Comparison policy tags
+ ///\{
+
+ /// Our comparison mode.
+ typedef comparison_mode::EqualityComparisonTag ComparisonPolicyModeTag;
+
+ /// Our comparison method.
+ typedef comparison_method::CompareByMemberFetchFunctionTag<MemberType_> ComparisonPolicyMethodTag;
+
+ /// Our comparison policy.
+ typedef ComparisonPolicy<OurType_, ComparisonPolicyModeTag, ComparisonPolicyMethodTag> ComparisonPolicyType;
+
+ ///\}
+
+ ///\name Basic operations
+ ///\{
+
+ ComparisonPolicy(MemberType_ (OurType_::* const v)() const) :
+ _v(v)
+ {
+ }
+
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+ ///\}
+
+ ///\name Comparison operators
+ ///\{
+
+#undef PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR
+#define PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(op) \
+ bool operator op (const OurType_ & other) const \
+ { \
+ return (static_cast<const OurType_ *>(this)->*_v)() op (other.*other._v)(); \
+ }
+
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(==)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(!=)
+
+ ///\}
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for FullComparisonTag +
+ * CompareByMemberFetchFunctionTag.
+ *
+ * \ingroup grpcompare
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberFetchFunctionTag<MemberType_> >
+ {
+ private:
+ MemberType_ (OurType_::* const _v)() const;
+
+ public:
+ ///\name Comparison policy tags
+ ///\{
+
+ /// Our comparison mode.
+ typedef comparison_mode::FullComparisonTag ComparisonPolicyModeTag;
+
+ /// Our comparison method.
+ typedef comparison_method::CompareByMemberFetchFunctionTag<MemberType_> ComparisonPolicyMethodTag;
+
+ /// Our comparison policy.
+ typedef ComparisonPolicy<OurType_, ComparisonPolicyModeTag, ComparisonPolicyMethodTag> ComparisonPolicyType;
+
+ ///\}
+
+ ///\name Basic operations
+ ///\{
+
+ ComparisonPolicy(MemberType_ (OurType_::* const v)() const) :
+ _v(v)
+ {
+ }
+
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+ ///\}
+
+ ///\name Comparison operators
+ ///\{
+
+#undef PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR
+#define PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(op) \
+ bool operator op (const OurType_ & other) const \
+ { \
+ return ((static_cast<const OurType_ *>(this)->*_v)()) op \
+ ((other.*(static_cast<const OurType_ *>(&other)->_v))()); \
+ }
+
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(==)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(!=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(<=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(>=)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(<)
+ PALUDIS_COMPARISON_POLICY_MAKE_OPERATOR(>)
+
+ ///\}
+ };
+}
+
+#endif
+
diff --git a/0.8.0/paludis/util/counted_ptr.hh b/0.8.0/paludis/util/counted_ptr.hh
new file mode 100644
index 000000000..f00575d8b
--- /dev/null
+++ b/0.8.0/paludis/util/counted_ptr.hh
@@ -0,0 +1,447 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_COUNTED_PTR_HH
+#define PALUDIS_GUARD_PALUDIS_COUNTED_PTR_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <paludis/util/comparison_policy.hh>
+#include <paludis/util/exception.hh>
+
+/** \file
+ * Declaration for the CountedPtr template class.
+ *
+ * \ingroup grppointers
+ */
+
+namespace paludis
+{
+ /**
+ * Contains CountedPtr count policies.
+ *
+ * \ingroup grppointers
+ */
+ namespace count_policy
+ {
+ /**
+ * CountedPtr policy: reference counts are stored separately.
+ *
+ * \ingroup grppointers
+ */
+ struct ExternalCountTag
+ {
+ };
+
+ /**
+ * CountedPtr policy: reference counts are stored by the class via the
+ * Counted subclass.
+ *
+ * \ingroup grppointers
+ */
+ struct InternalCountTag
+ {
+ };
+ }
+
+ /**
+ * CountedPtr internals.
+ *
+ * \ingroup grppointers
+ */
+ namespace counted_ptr_internals
+ {
+ /**
+ * Base class for CountedPtr.
+ *
+ * \ingroup grppointers
+ */
+ template <typename T_>
+ class CountedPtrBase :
+ public ComparisonPolicy<CountedPtrBase<T_>,
+ comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberTag<T_ *> >
+ {
+ private:
+ CountedPtrBase(const CountedPtrBase & other);
+
+ const CountedPtrBase & operator= (const CountedPtrBase & other);
+
+ protected:
+ /**
+ * Pointer to our data.
+ */
+ T_ * _ptr;
+
+ ///\name Basic operations
+ ///\{
+
+ CountedPtrBase(T_ * ptr) :
+ ComparisonPolicy<CountedPtrBase<T_>,
+ comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberTag<T_ *> >(
+ &CountedPtrBase::_ptr),
+ _ptr(ptr)
+ {
+ }
+
+ virtual ~CountedPtrBase()
+ {
+ }
+
+ ///\}
+
+ public:
+ ///\name Dereference operators
+ ///\{
+
+ inline const T_ & operator* () const;
+ inline const T_ * operator-> () const;
+ T_ & operator* ();
+ T_ * operator-> ();
+
+ /**
+ * Fetch our raw pointer.
+ */
+ T_ * raw_pointer() const
+ {
+ return _ptr;
+ }
+
+ ///\}
+
+ /**
+ * Return whether we are null. We use const void * rather than bool
+ * here to avoid bool -> int conversion weirdness. See \ref
+ * TCppPL 21.3.3.
+ */
+ operator const void * () const
+ {
+ return _ptr;
+ }
+ };
+
+ template <typename T_>
+ const T_ & CountedPtrBase<T_>::operator* () const
+ {
+ return *_ptr;
+ }
+
+ template <typename T_>
+ const T_ * CountedPtrBase<T_>::operator-> () const
+ {
+ return _ptr;
+ }
+
+ template <typename T_>
+ T_ & CountedPtrBase<T_>::operator* ()
+ {
+ return *_ptr;
+ }
+
+ template <typename T_>
+ T_ * CountedPtrBase<T_>::operator-> ()
+ {
+ return _ptr;
+ }
+ }
+
+ /**
+ * Reference counted pointer class.
+ *
+ * \ingroup grppointers
+ */
+ template <typename T_, typename CountPolicy_ = count_policy::InternalCountTag>
+ class CountedPtr;
+
+ /**
+ * Base for an internal counted class.
+ *
+ * \ingroup grppointers
+ */
+ template <typename T_>
+ class InternalCounted;
+
+ /**
+ * Reference counted pointer class (specialisation for ExternalCountTag).
+ *
+ * \ingroup grppointers
+ */
+ template <typename T_>
+ class CountedPtr<T_, count_policy::ExternalCountTag> :
+ public counted_ptr_internals::CountedPtrBase<T_>
+ {
+ private:
+ unsigned * _ref_count;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ explicit CountedPtr(T_ * const ptr) :
+ counted_ptr_internals::CountedPtrBase<T_>(ptr),
+ _ref_count(new unsigned(1))
+ {
+ }
+
+ CountedPtr(const CountedPtr & other) :
+ counted_ptr_internals::CountedPtrBase<T_>(other.raw_pointer()),
+ _ref_count(other._ref_count)
+ {
+ ++*_ref_count;
+ }
+
+ /**
+ * Constructor, from another CountedPtr of a descendent of our
+ * data's class.
+ */
+ template <typename O_>
+ CountedPtr(const CountedPtr<O_, count_policy::ExternalCountTag> & other) :
+ counted_ptr_internals::CountedPtrBase<T_>(other._ptr),
+ _ref_count(other.reference_count_pointer())
+ {
+ ++*_ref_count;
+ }
+
+ ~CountedPtr()
+ {
+ if (0 == --(*_ref_count))
+ {
+ delete this->_ptr;
+ delete _ref_count;
+ }
+ }
+
+ /**
+ * Assignment, from another CountedPtr.
+ */
+ const CountedPtr & operator= (const CountedPtr & other)
+ {
+ if (other._ptr != this->_ptr)
+ {
+ if (0 == --*_ref_count)
+ {
+ delete this->_ptr;
+ delete _ref_count;
+ }
+
+ this->_ptr = other._ptr;
+ _ref_count = other._ref_count;
+ ++*_ref_count;
+ }
+ return *this;
+ }
+
+ /**
+ * Explicit assignment, from a raw pointer.
+ */
+ const CountedPtr & assign(T_ * const other)
+ {
+ return operator= (CountedPtr<T_, count_policy::ExternalCountTag>(other));
+ }
+
+ /**
+ * Explicit assignment to zero.
+ */
+ const CountedPtr & zero()
+ {
+ return operator= (CountedPtr<T_, count_policy::ExternalCountTag>(0));
+ }
+
+ ///\}
+
+ ///\name Pointer operations
+ ///\{
+
+ /**
+ * Fetch our reference count pointer.
+ */
+ unsigned * reference_count_pointer() const
+ {
+ return _ref_count;
+ }
+
+ ///\}
+ };
+
+ /**
+ * Reference counted pointer class (specialisation for InternalCountTag).
+ *
+ * \ingroup grppointers
+ */
+ template <typename T_>
+ class CountedPtr<T_, count_policy::InternalCountTag> :
+ public counted_ptr_internals::CountedPtrBase<T_>
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ explicit CountedPtr(T_ * const ptr) :
+ counted_ptr_internals::CountedPtrBase<T_>(ptr)
+ {
+ if (0 != this->_ptr)
+ ++*this->_ptr->reference_count_pointer();
+ }
+
+ CountedPtr(const CountedPtr & other) :
+ counted_ptr_internals::CountedPtrBase<T_>(other._ptr)
+ {
+ if (0 != this->_ptr)
+ ++*this->_ptr->reference_count_pointer();
+ }
+
+ /**
+ * Constructor, from another CountedPtr of a descendent of our
+ * data's class.
+ */
+ template <typename O_>
+ CountedPtr(const CountedPtr<O_, count_policy::InternalCountTag> & other) :
+ counted_ptr_internals::CountedPtrBase<T_>(
+ static_cast<T_ *>(other.raw_pointer()))
+ {
+ if (0 != this->_ptr)
+ ++*this->_ptr->reference_count_pointer();
+ }
+
+ ~CountedPtr();
+
+ const CountedPtr & operator= (const CountedPtr & other)
+ {
+ if (other._ptr != this->_ptr)
+ {
+ if (0 != this->_ptr)
+ if (0 == --(*this->_ptr->reference_count_pointer()))
+ delete this->_ptr;
+
+ this->_ptr = other._ptr;
+ if (0 != this->_ptr)
+ ++*this->_ptr->reference_count_pointer();
+ }
+ return *this;
+ }
+
+ /**
+ * Explicit assignment, from a raw pointer.
+ */
+ const CountedPtr & assign(T_ * const other)
+ {
+ return operator= (CountedPtr<T_, count_policy::InternalCountTag>(other));
+ }
+
+ /**
+ * Explicit assignment to zero.
+ */
+ const CountedPtr & zero()
+ {
+ return operator= (CountedPtr<T_, count_policy::InternalCountTag>(0));
+ }
+
+ ///\}
+
+ ///\name Pointer operations
+ ///\{
+
+ /**
+ * Fetch our reference count pointer.
+ */
+ unsigned * reference_count_pointer() const
+ {
+ if (0 != this->_ptr)
+ return this->_ptr->reference_count_pointer();
+ else
+ return 0;
+ }
+
+ ///\}
+ };
+
+ template <typename T_>
+ CountedPtr<T_, count_policy::InternalCountTag>::~CountedPtr()
+ {
+ if (0 != this->_ptr)
+ if (0 == --(*this->_ptr->reference_count_pointer()))
+ delete this->_ptr;
+ }
+}
+
+#include <paludis/util/instantiation_policy.hh>
+
+namespace paludis
+{
+ /**
+ * Base class for an internally counted class.
+ *
+ * \ingroup grppointers
+ */
+ template <typename T_>
+ class InternalCounted :
+ private InstantiationPolicy<InternalCounted<T_>,
+ instantiation_method::NonCopyableTag>
+ {
+ private:
+ mutable unsigned _ref_count;
+
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ InternalCounted() :
+ _ref_count(0)
+ {
+ }
+
+ ~InternalCounted()
+ {
+ }
+
+ ///\}
+
+ public:
+ ///\name Pointer types
+ ///\{
+
+ /**
+ * A CountedPtr to us.
+ */
+ typedef CountedPtr<T_, count_policy::InternalCountTag> Pointer;
+
+ /**
+ * A CountedPtr to us (const).
+ */
+ typedef CountedPtr<const T_, count_policy::InternalCountTag> ConstPointer;
+
+ ///\}
+
+ ///\name Pointer operations
+ ///\{
+
+ /**
+ * Fetch a pointer to our reference count (may be zero).
+ */
+ unsigned * reference_count_pointer() const
+ {
+ return & _ref_count;
+ }
+
+ ///\}
+ };
+}
+
+#endif
+
diff --git a/0.8.0/paludis/util/counted_ptr_TEST.cc b/0.8.0/paludis/util/counted_ptr_TEST.cc
new file mode 100644
index 000000000..5faaab78e
--- /dev/null
+++ b/0.8.0/paludis/util/counted_ptr_TEST.cc
@@ -0,0 +1,373 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/counted_ptr.hh>
+#include <string>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for counted_ptr.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+namespace
+{
+ /**
+ * Test InternalCounted class.
+ *
+ * \ingroup grptestcases
+ */
+ class MyClass :
+ public InternalCounted<MyClass>
+ {
+ private:
+ int _v;
+
+ public:
+ MyClass(const int v) :
+ _v(v)
+ {
+ }
+
+ MyClass(const MyClass & other) :
+ InternalCounted<MyClass>(),
+ _v(other._v)
+ {
+ }
+
+ const MyClass & operator= (const MyClass & other)
+ {
+ _v = other._v;
+ return *this;
+ }
+
+ bool operator== (const MyClass & other) const
+ {
+ return _v == other._v;
+ }
+
+ int value() const
+ {
+ return _v;
+ }
+ };
+}
+
+/**
+ * Test InternalCounted class is stringifiable.
+ *
+ * \ingroup grptestcases
+ */
+std::ostream & operator<< (std::ostream & s, const MyClass & c)
+{
+ s << c.value();
+ return s;
+}
+
+namespace test_cases
+{
+ /**
+ * \test CountedPtr creation tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrCreationTests : TestCase
+ {
+ CountedPtrCreationTests() : TestCase("CountedPtr creation tests") { }
+
+ void run()
+ {
+ CountedPtr<int, count_policy::ExternalCountTag> i(new int(10));
+ CountedPtr<std::string, count_policy::ExternalCountTag> j(new std::string("moo"));
+ }
+ } test_counted_ptr_creation;
+
+ /**
+ * \test CountedPtr dereference tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrDereferenceTests : TestCase
+ {
+ CountedPtrDereferenceTests() : TestCase("CountedPtr dereference tests") { }
+
+ void run()
+ {
+ CountedPtr<int, count_policy::ExternalCountTag> i(new int(10));
+ TEST_CHECK_EQUAL(*i, 10);
+
+ CountedPtr<std::string, count_policy::ExternalCountTag> j(new std::string("moo"));
+ TEST_CHECK_EQUAL(*j, "moo");
+ TEST_CHECK_EQUAL(j->length(), 3);
+ }
+ } test_counted_ptr_dereference;
+
+ /**
+ * \test CountedPtr copy tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrCopyTests : TestCase
+ {
+ CountedPtrCopyTests() : TestCase("CountedPtr copy tests") { }
+
+ void run()
+ {
+ CountedPtr<int, count_policy::ExternalCountTag> i(new int(10));
+ TEST_CHECK_EQUAL(*i, 10);
+
+ CountedPtr<int, count_policy::ExternalCountTag> i2(i);
+ TEST_CHECK_EQUAL(*i, 10);
+ TEST_CHECK_EQUAL(*i2, 10);
+ }
+ } test_counted_ptr_copy;
+
+ /**
+ * \test CountedPtr dereference-assign tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrDereferenceAssignTests : TestCase
+ {
+ CountedPtrDereferenceAssignTests() : TestCase("CountedPtr dereference assign tests") { }
+
+ void run()
+ {
+ CountedPtr<int, count_policy::ExternalCountTag> i(new int(10));
+ TEST_CHECK_EQUAL(*i, 10);
+ *i = 20;
+ TEST_CHECK_EQUAL(*i, 20);
+
+ CountedPtr<int, count_policy::ExternalCountTag> i2(i);
+ TEST_CHECK_EQUAL(*i, 20);
+ TEST_CHECK_EQUAL(*i2, 20);
+
+ *i = 30;
+ TEST_CHECK_EQUAL(*i, 30);
+ TEST_CHECK_EQUAL(*i2, 30);
+
+ *i2 = 40;
+ TEST_CHECK_EQUAL(*i, 40);
+ TEST_CHECK_EQUAL(*i2, 40);
+ }
+ } test_counted_ptr_dereference_assign;
+
+ /**
+ * \test CountedPtr assign value tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrAssignValueTests : TestCase
+ {
+ CountedPtrAssignValueTests() : TestCase("CountedPtr assign value tests") { }
+
+ void run()
+ {
+ CountedPtr<int, count_policy::ExternalCountTag> i(new int(10));
+ TEST_CHECK_EQUAL(*i, 10);
+ CountedPtr<int, count_policy::ExternalCountTag> i2(i);
+ TEST_CHECK_EQUAL(*i, 10);
+ TEST_CHECK_EQUAL(*i2, 10);
+
+ i = CountedPtr<int, count_policy::ExternalCountTag>(new int(20));
+ TEST_CHECK_EQUAL(*i, 20);
+ TEST_CHECK_EQUAL(*i2, 10);
+ }
+ } test_counted_ptr_assign_value;
+
+ /**
+ * \test CountedPtr assign pointer tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrAssignPointerTests : TestCase
+ {
+ CountedPtrAssignPointerTests() : TestCase("CountedPtr assign pointer tests") { }
+
+ void run()
+ {
+ CountedPtr<int, count_policy::ExternalCountTag> i(new int(10));
+ TEST_CHECK_EQUAL(*i, 10);
+ CountedPtr<int, count_policy::ExternalCountTag> i2(i);
+ TEST_CHECK_EQUAL(*i, 10);
+ TEST_CHECK_EQUAL(*i2, 10);
+
+ CountedPtr<int, count_policy::ExternalCountTag> i3(new int(30));
+
+ i = i3;
+ TEST_CHECK_EQUAL(*i, 30);
+ TEST_CHECK_EQUAL(*i2, 10);
+ TEST_CHECK_EQUAL(*i3, 30);
+
+ i.assign(new int(50));
+ TEST_CHECK_EQUAL(*i, 50);
+
+ i.zero();
+ TEST_CHECK(! i);
+ }
+ } test_counted_ptr_assign_pointer;
+
+ /**
+ * \test CountedPtr internal creation tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrInternalCreationTests : TestCase
+ {
+ CountedPtrInternalCreationTests() : TestCase("CountedPtr internal creation tests") { }
+
+ void run()
+ {
+ MyClass::Pointer i(new MyClass(10));
+ }
+ } test_counted_ptr_internal_creation;
+
+ /**
+ * \test CountedPtr internal dereference tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrInternalDereferenceTests : TestCase
+ {
+ CountedPtrInternalDereferenceTests() : TestCase("CountedPtr internal dereference tests") { }
+
+ void run()
+ {
+ MyClass::Pointer i(new MyClass(10));
+ TEST_CHECK_EQUAL(*i, 10);
+
+ MyClass::Pointer j(new MyClass(20));
+ TEST_CHECK_EQUAL(*j, 20);
+ }
+ } test_counted_ptr_internal_dereference;
+
+ /**
+ * \test CountedPtr internal copy tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrInternalCopyTests : TestCase
+ {
+ CountedPtrInternalCopyTests() : TestCase("CountedPtr internal copy tests") { }
+
+ void run()
+ {
+ MyClass::Pointer i(new MyClass(10));
+ TEST_CHECK_EQUAL(*i, 10);
+
+ MyClass::Pointer i2(i);
+ TEST_CHECK_EQUAL(*i, 10);
+ TEST_CHECK_EQUAL(*i2, 10);
+ }
+ } test_counted_ptr_internal_copy;
+
+ /**
+ * \test CountedPtr internal dereference-assign tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrInternalDereferenceAssignTests : TestCase
+ {
+ CountedPtrInternalDereferenceAssignTests() :
+ TestCase("CountedPtr internal dereference assign tests") { }
+
+ void run()
+ {
+ MyClass::Pointer i(new MyClass(10));
+ TEST_CHECK_EQUAL(*i, 10);
+ *i = 20;
+ TEST_CHECK_EQUAL(*i, 20);
+
+ MyClass::Pointer i2(i);
+ TEST_CHECK_EQUAL(*i, 20);
+ TEST_CHECK_EQUAL(*i2, 20);
+
+ *i = 30;
+ TEST_CHECK_EQUAL(*i, 30);
+ TEST_CHECK_EQUAL(*i2, 30);
+
+ *i2 = 40;
+ TEST_CHECK_EQUAL(*i, 40);
+ TEST_CHECK_EQUAL(*i2, 40);
+ }
+ } test_counted_ptr_internal_dereference_assign;
+
+ /**
+ * \test CountedPtr internal assign value tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrInternalAssignValueTests : TestCase
+ {
+ CountedPtrInternalAssignValueTests() :
+ TestCase("CountedPtr internal assign value tests") { }
+
+ void run()
+ {
+ MyClass::Pointer i(new MyClass(10));
+ TEST_CHECK_EQUAL(*i, 10);
+ MyClass::Pointer i2(i);
+ TEST_CHECK_EQUAL(*i, 10);
+ TEST_CHECK_EQUAL(*i2, 10);
+
+ i = MyClass::Pointer(new MyClass(20));
+ TEST_CHECK_EQUAL(*i, 20);
+ TEST_CHECK_EQUAL(*i2, 10);
+ }
+ } test_counted_ptr_internal_assign_value;
+
+ /**
+ * \test CountedPtr internal assign pointer tests.
+ *
+ * \ingroup grptestcases
+ */
+ struct CountedPtrInternalAssignPointerTests : TestCase
+ {
+ CountedPtrInternalAssignPointerTests() :
+ TestCase("CountedPtr internal assign pointer tests") { }
+
+ void run()
+ {
+ MyClass::Pointer i(new MyClass(10));
+ TEST_CHECK_EQUAL(*i, 10);
+ MyClass::Pointer i2(i);
+ TEST_CHECK_EQUAL(*i, 10);
+ TEST_CHECK_EQUAL(*i2, 10);
+
+ MyClass::Pointer i3(new MyClass(30));
+
+ i = i3;
+ TEST_CHECK_EQUAL(*i, 30);
+ TEST_CHECK_EQUAL(*i2, 10);
+ TEST_CHECK_EQUAL(*i3, 30);
+
+ i.assign(new MyClass(50));
+ TEST_CHECK_EQUAL(*i, 50);
+
+ i.zero();
+ TEST_CHECK(! i);
+ }
+ } test_counted_ptr_internal_assign_pointer;
+}
+
diff --git a/0.8.0/paludis/util/destringify.cc b/0.8.0/paludis/util/destringify.cc
new file mode 100644
index 000000000..f60126140
--- /dev/null
+++ b/0.8.0/paludis/util/destringify.cc
@@ -0,0 +1,34 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <paludis/util/destringify.hh>
+
+/** \file
+ * Implementation for DestringifyError.
+ *
+ * \ingroup grpdestringify
+ */
+
+using namespace paludis;
+
+DestringifyError::DestringifyError(const std::string & str) throw () :
+ Exception("Couldn't destringify '" + str + "'." )
+{
+}
diff --git a/0.8.0/paludis/util/destringify.hh b/0.8.0/paludis/util/destringify.hh
new file mode 100644
index 000000000..c272d2919
--- /dev/null
+++ b/0.8.0/paludis/util/destringify.hh
@@ -0,0 +1,152 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DESTRINGIFY_HH
+#define PALUDIS_GUARD_PALUDIS_DESTRINGIFY_HH 1
+
+#include <paludis/util/exception.hh>
+#include <sstream>
+#include <string>
+
+/** \file
+ * Destringify functions.
+ *
+ * \ingroup grpdestringify
+ */
+
+namespace paludis
+{
+ /**
+ * Default exception type thrown by destringify when it fails.
+ *
+ * \ingroup grpdestringify
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE DestringifyError :
+ public Exception
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ DestringifyError(const std::string & str) throw ();
+
+ ///\}
+ };
+
+ /**
+ * For internal use by destringify.
+ *
+ * \ingroup grpdestringify
+ */
+ namespace destringify_internals
+ {
+ /**
+ * Basic destringifier.
+ *
+ * \ingroup grpdestringify
+ */
+ template <typename Type_, typename Exception_>
+ struct Destringifier
+ {
+ /**
+ * Do the destringification.
+ */
+ static Type_ do_destringify(const std::string & s)
+ {
+ std::istringstream ss(s);
+ Type_ t;
+ ss >> t;
+ if (!ss.eof() || ss.bad())
+ throw Exception_(s);
+ return t;
+ }
+ };
+
+ /**
+ * Specialised destringify for std::string.
+ *
+ * \ingroup grpdestringify
+ */
+ template <typename Exception_>
+ struct Destringifier<std::string, Exception_>
+ {
+ /**
+ * Do the destringification.
+ */
+ static std::string do_destringify(const std::string & s)
+ {
+ return s;
+ }
+ };
+
+ /**
+ * Specialised destringify for bool.
+ *
+ * \ingroup grpdestringify
+ */
+ template <typename Exception_>
+ struct Destringifier<bool, Exception_>
+ {
+ /**
+ * Do the destringification.
+ */
+ static bool do_destringify(const std::string & s)
+ {
+ int i;
+ try
+ {
+ i = Destringifier<int, Exception_>::do_destringify(s);
+ return i > 0;
+ }
+ catch (const DestringifyError &)
+ {
+ bool b;
+ std::istringstream ss(s);
+ ss >> std::boolalpha >> b;
+ if (! ss.eof() || ss.bad())
+ throw Exception_(s);
+ return b;
+ }
+ }
+ };
+ }
+
+ /**
+ * Extract a value of some type from a string.
+ *
+ * \ingroup grpdestringify
+ */
+ template <typename Type_, typename Exception_>
+ Type_ destringify(const std::string & s)
+ {
+ if (s == "")
+ throw Exception_("");
+
+ return destringify_internals::Destringifier<Type_, Exception_>::do_destringify(s);
+ }
+
+ template <typename Type_>
+ Type_ destringify(const std::string & s)
+ {
+ return destringify<Type_, DestringifyError>(s);
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/destringify_TEST.cc b/0.8.0/paludis/util/destringify_TEST.cc
new file mode 100644
index 000000000..8ea4cd647
--- /dev/null
+++ b/0.8.0/paludis/util/destringify_TEST.cc
@@ -0,0 +1,113 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Stephen Bennett <spb@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/destringify.hh>
+#include <string>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for destringify.hh
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /** \test
+ * Test destringify for integers.
+ *
+ * \ingroup grptestcases
+ */
+ struct DestringifyIntTests : TestCase
+ {
+ DestringifyIntTests() : TestCase("destringify int") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(destringify<int>("0"), 0);
+ TEST_CHECK_EQUAL(destringify<int>("1"), 1);
+ TEST_CHECK_EQUAL(destringify<int>("99"), 99);
+ TEST_CHECK_EQUAL(destringify<int>("-99"), -99);
+ TEST_CHECK_EQUAL(destringify<int>(" 12345"), 12345);
+ TEST_CHECK_THROWS(destringify<int>(""), DestringifyError);
+ }
+ } test_case_destringify_int;
+
+ /** \test
+ * Test destringify for floats.
+ *
+ * \ingroup grptestcases
+ */
+ struct DestringifyFloatTests : TestCase
+ {
+ DestringifyFloatTests() : TestCase("destringify float") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(destringify<float>("0"), 0.f);
+ TEST_CHECK_EQUAL(destringify<float>("0.0"), 0.f);
+ TEST_CHECK_EQUAL(destringify<float>("0.1"), 0.1f);
+ TEST_CHECK_EQUAL(destringify<float>("-1.54"), -1.54f);
+ TEST_CHECK_THROWS(destringify<float>("I am a fish"), DestringifyError);
+ }
+ } test_case_destringify_float;
+
+ /** \test
+ * Test destringify for strings.
+ *
+ * \ingroup grptestcases
+ */
+ struct DestringifyStringTests : TestCase
+ {
+ DestringifyStringTests() : TestCase("destringify string") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(destringify<std::string>("asdf"), "asdf");
+ TEST_CHECK_EQUAL(destringify<std::string>(" a f e b "), " a f e b ");
+ }
+ } test_case_destringify_string;
+
+ /** \test
+ * Test destringify for bool.
+ *
+ * \ingroup grptestcases
+ */
+ struct DestringifyBoolTests : TestCase
+ {
+ DestringifyBoolTests() : TestCase("destringify bool") { }
+
+ void run()
+ {
+ TEST_CHECK( destringify<bool>("true"));
+ TEST_CHECK( destringify<bool>("1"));
+ TEST_CHECK( destringify<bool>("5"));
+ TEST_CHECK(!destringify<bool>("false"));
+ TEST_CHECK(!destringify<bool>("0"));
+ TEST_CHECK(!destringify<bool>("-1"));
+ TEST_CHECK_THROWS(destringify<bool>("flase"), DestringifyError);
+ TEST_CHECK_THROWS(destringify<bool>("432.2413"), DestringifyError);
+ }
+ } test_case_destringify_bool;
+}
+
diff --git a/0.8.0/paludis/util/dir_iterator.cc b/0.8.0/paludis/util/dir_iterator.cc
new file mode 100644
index 000000000..7281f4de4
--- /dev/null
+++ b/0.8.0/paludis/util/dir_iterator.cc
@@ -0,0 +1,171 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <dirent.h>
+#include <errno.h>
+#include <paludis/util/dir_iterator.hh>
+#include <paludis/util/stringify.hh>
+#include <sys/types.h>
+#include <set>
+
+/** \file
+ * Implementation of paludis::DirIterator.
+ *
+ * \ingroup grpfilesystem
+ */
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for DirIterator.
+ *
+ * \ingroup grpfilesystem
+ */
+ template<>
+ struct Implementation<DirIterator> :
+ InternalCounted<Implementation<DirIterator> >
+ {
+ FSEntry base;
+ bool ignore_dotfiles;
+ CountedPtr<std::set<FSEntry>, count_policy::ExternalCountTag> items;
+ std::set<FSEntry>::iterator iter;
+
+ Implementation(const FSEntry & b, bool i, CountedPtr<std::set<FSEntry>,
+ count_policy::ExternalCountTag> ii) :
+ base(b),
+ ignore_dotfiles(i),
+ items(ii)
+ {
+ }
+ };
+}
+
+DirOpenError::DirOpenError(const FSEntry & location, const int errno_value) throw () :
+ FSError("Error opening directory '" + stringify(location) + "': " + strerror(errno_value))
+{
+}
+
+DirIterator::DirIterator(const FSEntry & base, bool ignore_dotfiles) :
+ PrivateImplementationPattern<DirIterator>(new Implementation<DirIterator>(
+ base, ignore_dotfiles, CountedPtr<std::set<FSEntry>,
+ count_policy::ExternalCountTag>(new std::set<FSEntry>)))
+{
+ DIR * d(opendir(stringify(_imp->base).c_str()));
+ if (0 == d)
+ throw DirOpenError(_imp->base, errno);
+
+ struct dirent * de;
+ while (0 != ((de = readdir(d))))
+ if (_imp->ignore_dotfiles)
+ {
+ if ('.' != de->d_name[0])
+ _imp->items->insert(_imp->base / std::string(de->d_name));
+ }
+ else if (! (de->d_name[0] == '.' &&
+ (de->d_name[1] == '\0' || (de->d_name[1] == '.' && de->d_name[2] == '\0'))))
+ _imp->items->insert(_imp->base / std::string(de->d_name));
+
+ _imp->iter = _imp->items->begin();
+
+ closedir(d);
+}
+
+DirIterator::DirIterator(const DirIterator & other) :
+ PrivateImplementationPattern<DirIterator>(new Implementation<DirIterator>(
+ other._imp->base, other._imp->ignore_dotfiles, other._imp->items))
+{
+ _imp->iter = other._imp->iter;
+}
+
+DirIterator::DirIterator() :
+ PrivateImplementationPattern<DirIterator>(new Implementation<DirIterator>(
+ FSEntry(""), true, CountedPtr<std::set<FSEntry>,
+ count_policy::ExternalCountTag>(new std::set<FSEntry>)))
+{
+ _imp->iter = _imp->items->end();
+}
+
+DirIterator::~DirIterator()
+{
+}
+
+const DirIterator &
+DirIterator::operator= (const DirIterator & other)
+{
+ if (this != &other)
+ {
+ _imp->base = other._imp->base;
+ _imp->items = other._imp->items;
+ _imp->iter = other._imp->iter;
+ _imp->ignore_dotfiles = other._imp->ignore_dotfiles;
+ }
+ return *this;
+}
+
+const FSEntry &
+DirIterator::operator* () const
+{
+ return *_imp->iter;
+}
+
+const FSEntry *
+DirIterator::operator-> () const
+{
+ return &*_imp->iter;
+}
+
+DirIterator &
+DirIterator::operator++ ()
+{
+ ++_imp->iter;
+ return *this;
+}
+
+DirIterator
+DirIterator::operator++ (int)
+{
+ DirIterator c(*this);
+ _imp->iter++;
+ return c;
+}
+
+bool
+DirIterator::operator== (const DirIterator & other) const
+{
+ if (other._imp->iter == other._imp->items->end())
+ return _imp->iter == _imp->items->end();
+
+ if (_imp->iter == _imp->items->end())
+ return other._imp->iter == other._imp->items->end();
+
+ if (other._imp->items != _imp->items)
+ throw InternalError(PALUDIS_HERE,
+ "comparing two different DirIterators.");
+
+ return other._imp->iter == _imp->iter;
+}
+
+bool
+DirIterator::operator!= (const DirIterator & other) const
+{
+ return ! operator== (other);
+}
+
diff --git a/0.8.0/paludis/util/dir_iterator.hh b/0.8.0/paludis/util/dir_iterator.hh
new file mode 100644
index 000000000..3892ae401
--- /dev/null
+++ b/0.8.0/paludis/util/dir_iterator.hh
@@ -0,0 +1,117 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DIR_ITERATOR_HH
+#define PALUDIS_GUARD_PALUDIS_DIR_ITERATOR_HH 1
+
+#include <iterator>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+
+/** \file
+ * Declarations for paludis::DirIterator.
+ *
+ * \ingroup grpfilesystem
+ */
+
+namespace paludis
+{
+ /**
+ * Raised when a directory open fails.
+ *
+ * \ingroup grpfilesystem
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE DirOpenError :
+ public FSError
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ DirOpenError(const FSEntry & location, const int errno_value) throw ();
+
+ ///\}
+ };
+
+ /**
+ * An iterator that iterates over the contents of a directory. At present,
+ * we read in all the entries at creation time and maintain a CountedPtr
+ * to an ordered set of FSEntry instances. This may change at some point,
+ * if it turns out that it's quicker to use opendir and seekdir for each
+ * instance.
+ *
+ * \ingroup grpfilesystem
+ */
+ class PALUDIS_VISIBLE DirIterator :
+ public std::iterator<std::forward_iterator_tag, FSEntry>,
+ private PrivateImplementationPattern<DirIterator>
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ /**
+ * Constructor, to an FSEntry which must be a directory, with an
+ * option to not ignore dotfiles.
+ */
+ explicit DirIterator(const FSEntry & base, bool ignore_dotfiles = true);
+
+ DirIterator(const DirIterator & other);
+
+ /**
+ * Constructor, creates an end() iterator.
+ */
+ DirIterator();
+
+ ~DirIterator();
+
+ const DirIterator & operator= (const DirIterator & other);
+
+ ///\}
+
+ ///\name Dereference operators
+ ///\{
+
+ const FSEntry & operator* () const;
+
+ const FSEntry * operator-> () const;
+
+ ///\}
+
+ ///\name Increment, decrement operators
+ ///\{
+
+ DirIterator & operator++ ();
+ DirIterator operator++ (int);
+
+ ///\}
+
+ ///\name Comparison operators
+ ///\{
+
+ bool operator== (const DirIterator & other) const;
+ bool operator!= (const DirIterator & other) const;
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/dir_iterator_TEST.cc b/0.8.0/paludis/util/dir_iterator_TEST.cc
new file mode 100644
index 000000000..217f48a4e
--- /dev/null
+++ b/0.8.0/paludis/util/dir_iterator_TEST.cc
@@ -0,0 +1,97 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Mark Loeser <halcy0n@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/dir_iterator.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for dir_iterator.hh.
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test DirIterator construction and manipulation.
+ *
+ * \ingroup grptestcases
+ */
+ struct DirIteratorManipulationTest : TestCase
+ {
+ DirIteratorManipulationTest() : TestCase("construction and manipulation") { }
+
+ void run()
+ {
+ TEST_CHECK_THROWS(DirIterator(FSEntry("/i/dont/exist/")), DirOpenError);
+
+ DirIterator iter(FSEntry("dir_iterator_TEST_dir"));
+ DirIterator iter1(iter);
+ TEST_CHECK(iter == iter1);
+ TEST_CHECK(!(iter != iter1));
+ }
+ } test_dir_iterator_manipulation;
+
+ /**
+ * \test Test DirIterator iterating abilities
+ *
+ * \ingroup grptestcases
+ */
+ struct DirIteratorIterateTest : TestCase
+ {
+ DirIteratorIterateTest() : TestCase("iterate") {}
+
+ void run()
+ {
+ DirIterator iter(FSEntry("dir_iterator_TEST_dir"));
+ DirIterator iter1(FSEntry("dir_iterator_TEST_dir"));
+ DirIterator iter2(FSEntry("dir_iterator_TEST_dir"), false);
+
+ TEST_CHECK(iter != DirIterator());
+ TEST_CHECK(DirIterator() != iter);
+
+ TEST_CHECK_EQUAL(iter->basename(), "file1");
+ TEST_CHECK(++iter != DirIterator());
+ TEST_CHECK_EQUAL(iter->basename(), "file2");
+ TEST_CHECK(++iter == DirIterator());
+ TEST_CHECK(DirIterator() == iter);
+
+ while (iter1 != DirIterator())
+ ++iter1;
+ TEST_CHECK(iter1 == DirIterator());
+ TEST_CHECK(iter == iter1);
+
+ TEST_CHECK_EQUAL(iter2->basename(), ".file3");
+ TEST_CHECK(++iter2 != DirIterator());
+ TEST_CHECK_EQUAL(iter2->basename(), "file1");
+ TEST_CHECK(++iter2 != DirIterator());
+ TEST_CHECK_EQUAL(iter2->basename(), "file2");
+ TEST_CHECK(++iter2 == DirIterator());
+ TEST_CHECK(DirIterator() == iter2);
+ TEST_CHECK(iter2 == DirIterator());
+
+ TEST_CHECK(iter1 == iter2);
+ TEST_CHECK(iter2 == iter1);
+ }
+ } test_dir_iterator_iterate;
+}
diff --git a/0.8.0/paludis/util/dir_iterator_TEST_cleanup.sh b/0.8.0/paludis/util/dir_iterator_TEST_cleanup.sh
new file mode 100755
index 000000000..17378f3c1
--- /dev/null
+++ b/0.8.0/paludis/util/dir_iterator_TEST_cleanup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d dir_iterator_TEST_dir ] ; then
+ rm -fr dir_iterator_TEST_dir
+else
+ true
+fi
+
diff --git a/0.8.0/paludis/util/dir_iterator_TEST_setup.sh b/0.8.0/paludis/util/dir_iterator_TEST_setup.sh
new file mode 100755
index 000000000..930f2f5a7
--- /dev/null
+++ b/0.8.0/paludis/util/dir_iterator_TEST_setup.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir dir_iterator_TEST_dir || exit 2
+cd dir_iterator_TEST_dir || exit 3
+touch file1 file2 .file3 || exit 4
diff --git a/0.8.0/paludis/util/exception.cc b/0.8.0/paludis/util/exception.cc
new file mode 100644
index 000000000..f9c754893
--- /dev/null
+++ b/0.8.0/paludis/util/exception.cc
@@ -0,0 +1,127 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/exception.hh>
+#include <libebt/libebt.hh>
+
+/** \file
+ * Exception class implementations.
+ *
+ * \ingroup grpexceptions
+ */
+
+using namespace paludis;
+
+namespace
+{
+ struct ContextTag;
+}
+
+struct Context::ContextData
+{
+ libebt::BacktraceContext<ContextTag> context;
+
+ ContextData(const std::string & s) :
+ context(s)
+ {
+ }
+};
+
+Context::Context(const std::string & s) :
+ _context_data(new ContextData(s))
+{
+}
+
+Context::~Context()
+{
+ delete _context_data;
+}
+
+std::string
+Context::backtrace(const std::string & delim)
+{
+ return libebt::BacktraceContext<ContextTag>::backtrace(delim);
+}
+
+struct Exception::ContextData :
+ public libebt::Backtraceable<ContextTag>
+{
+};
+
+Exception::Exception(const std::string & our_message) throw () :
+ _message(our_message),
+ _context_data(new ContextData)
+{
+}
+
+Exception::Exception(const Exception & other) :
+ std::exception(other),
+ _message(other._message),
+ _context_data(new ContextData(*other._context_data))
+{
+}
+
+Exception::~Exception() throw ()
+{
+ delete _context_data;
+}
+
+bool
+Exception::empty() const
+{
+ return _context_data->empty();
+}
+
+const std::string &
+Exception::message() const throw ()
+{
+ return _message;
+}
+
+std::string
+Exception::backtrace(const std::string & delim) const
+{
+ return _context_data->backtrace(delim);
+}
+
+NotAvailableError::NotAvailableError(const std::string & msg) throw () :
+ Exception("Error: Not available: " + msg)
+{
+}
+
+InternalError::InternalError(const std::string & where, const std::string & our_message) throw () :
+ Exception("Eek! Internal error at " + where + ": " + our_message)
+{
+}
+
+InternalError::InternalError(const std::string & where) throw () :
+ Exception("Eek! Internal error at " + where)
+{
+}
+
+NameError::NameError(const std::string & name, const std::string & role) throw () :
+ Exception("Name '" + name + "' is not a valid " + role)
+{
+}
+
+ConfigurationError::ConfigurationError(const std::string & msg) throw () :
+ Exception(msg)
+{
+}
+
diff --git a/0.8.0/paludis/util/exception.hh b/0.8.0/paludis/util/exception.hh
new file mode 100644
index 000000000..4b0ce0d96
--- /dev/null
+++ b/0.8.0/paludis/util/exception.hh
@@ -0,0 +1,214 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_EXCEPTION_HH
+#define PALUDIS_GUARD_PALUDIS_EXCEPTION_HH 1
+
+#include <paludis/util/attributes.hh>
+#include <libwrapiter/libwrapiter_forward_iterator.hh>
+#include <string>
+#include <exception>
+
+
+/** \file
+ * Declaration for the Exception base class, the InternalError exception
+ * class, the NameError class and related utilities.
+ *
+ * \ingroup grpexceptions
+ */
+
+namespace paludis
+{
+ /**
+ * Backtrace context class.
+ *
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE Context
+ {
+ private:
+ Context(const Context &);
+ const Context & operator= (const Context &);
+
+ struct ContextData;
+ ContextData * const _context_data;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ Context(const std::string &);
+
+ ~Context();
+
+ ///\}
+
+ /**
+ * Current context (forwards to libebt).
+ */
+ static std::string backtrace(const std::string & delim);
+ };
+
+ /**
+ * Base exception class.
+ *
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE Exception :
+ public std::exception
+ {
+ private:
+ const std::string _message;
+ struct ContextData;
+ ContextData * const _context_data;
+
+ const Exception & operator= (const Exception &);
+
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ Exception(const std::string & message) throw ();
+
+ Exception(const Exception &);
+
+ ///\}
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ virtual ~Exception() throw () PALUDIS_ATTRIBUTE((nothrow));
+
+ ///\}
+
+ /**
+ * Return our descriptive error message.
+ */
+ const std::string & message() const throw () PALUDIS_ATTRIBUTE((nothrow));
+
+ /**
+ * Make a backtrace.
+ */
+ std::string backtrace(const std::string & delim) const;
+
+ /**
+ * Is our backtrace empty?
+ */
+ bool empty() const;
+ };
+
+ /**
+ * An InternalError is an Exception that is thrown if something that is
+ * never supposed to happen happens.
+ *
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE InternalError :
+ public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ *
+ * \param where Should be set to the PALUDIS_HERE macro.
+ *
+ * \param message A short message.
+ */
+ InternalError(const std::string & where, const std::string & message) throw ();
+
+ /**
+ * Constructor, with no message (deprecated).
+ *
+ * \param where Should be set to the PALUDIS_HERE macro.
+ *
+ * \deprecated Use paludis::InternalError::InternalError(const char * const,
+ * const std::string &) instead.
+ */
+ InternalError(const std::string & where) throw () PALUDIS_ATTRIBUTE((deprecated));
+ };
+
+ /**
+ * A NotAvailableError is an Exception that is thrown if something that is
+ * not available (for example due to compile time configure options or platform
+ * limitations) is used.
+ *
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE NotAvailableError :
+ public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NotAvailableError(const std::string & message) throw ();
+ };
+
+ /**
+ * A NameError is an Exception that is thrown when some kind of invalid
+ * name is encountered.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpnames
+ */
+ class PALUDIS_VISIBLE NameError :
+ public Exception
+ {
+ protected:
+ /**
+ * Constructor.
+ *
+ * \param name The invalid name encountered.
+ * \param role The role for the name, for example "package name".
+ */
+ NameError(const std::string & name, const std::string & role) throw ();
+ };
+
+ /**
+ * A ConfigurationError is thrown when an invalid configuration occurs.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpconfigfile
+ */
+ class PALUDIS_VISIBLE ConfigurationError :
+ public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ ConfigurationError(const std::string & msg) throw ();
+ };
+
+ template <typename T_>
+ std::string
+ stringify(const T_ & item);
+
+ /** \def PALUDIS_HERE
+ * Expands to the current function name, file and line, for use with
+ * paludis::InternalError.
+ *
+ * \ingroup grpexceptions
+ */
+#define PALUDIS_HERE (std::string(__PRETTY_FUNCTION__) + " at " + \
+ std::string(__FILE__) + ":" + paludis::stringify(__LINE__))
+}
+
+#endif
diff --git a/0.8.0/paludis/util/fast_unique_copy.hh b/0.8.0/paludis/util/fast_unique_copy.hh
new file mode 100644
index 000000000..28b0a9f49
--- /dev/null
+++ b/0.8.0/paludis/util/fast_unique_copy.hh
@@ -0,0 +1,84 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_REPOSITORIES_VIRTUALS_FAST_UNIQUE_COPY_HH
+#define PALUDIS_GUARD_PALUDIS_REPOSITORIES_VIRTUALS_FAST_UNIQUE_COPY_HH 1
+
+#include <paludis/util/iterator.hh>
+#include <functional>
+
+namespace paludis
+{
+ /**
+ * For use by fast_unique_copy only.
+ */
+ namespace fast_unique_copy_internals
+ {
+ /**
+ * For use by fast_unique_copy only.
+ */
+ template <typename I_, typename O_, typename C_>
+ void
+ real_fast_unique_copy(const I_ & start, const I_ & end, const I_ & full_end, O_ out,
+ const C_ & comp, const I_ & mbgt)
+ {
+ if (start != end)
+ {
+ // if our final item is less than or equal to mbgt, there're no
+ // matches in this block
+ if ((mbgt != full_end) && ((comp(*previous(end), *mbgt)) || (! comp(*mbgt, *previous(end)))))
+ return;
+
+ // if our first item is equal to our last item, we have exactly
+ // one unique item in this sequence
+ if ((! comp(*start, *previous(end))) && (! comp(*previous(end), *start)))
+ *out++ = *start;
+ else
+ {
+ I_ mid = start + (std::distance(start, end) >> 1);
+ real_fast_unique_copy(start, mid, full_end, out, comp, mbgt);
+ real_fast_unique_copy(mid, end, full_end, out, comp, previous(mid));
+ }
+ }
+ }
+ }
+
+ /**
+ * Extract unique elements from a sorted range of random access iterators.
+ */
+ template <typename I_, typename O_>
+ void
+ fast_unique_copy(const I_ & start, const I_ & end, O_ out)
+ {
+ fast_unique_copy_internals::real_fast_unique_copy(start, end, end, out,
+ std::less<typename std::iterator_traits<I_>::value_type>(), end);
+ }
+
+ /**
+ * Extract unique elements from a sorted range of random access iterators.
+ */
+ template <typename I_, typename O_, typename C_>
+ void
+ fast_unique_copy(const I_ & start, const I_ & end, O_ out, const C_ & comp)
+ {
+ fast_unique_copy_internals::real_fast_unique_copy(start, end, end, out, comp, end);
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/fast_unique_copy_TEST.cc b/0.8.0/paludis/util/fast_unique_copy_TEST.cc
new file mode 100644
index 000000000..6e7611d9b
--- /dev/null
+++ b/0.8.0/paludis/util/fast_unique_copy_TEST.cc
@@ -0,0 +1,121 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "fast_unique_copy.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <paludis/util/join.hh>
+#include <vector>
+
+using namespace test;
+using namespace paludis;
+
+namespace test_cases
+{
+ struct FastUniqueCopySimpleSequenceTest : TestCase
+ {
+ FastUniqueCopySimpleSequenceTest() : TestCase("fast_unique_copy simple sequence") { }
+
+ void run()
+ {
+ for (unsigned sz = 0 ; sz < 20 ; ++sz)
+ {
+ TestMessageSuffix s("sz=" + stringify(sz));
+ std::vector<unsigned> v;
+ for (unsigned x = 0 ; x < sz ; ++x)
+ v.push_back(x);
+
+ std::vector<unsigned> r;
+ fast_unique_copy(v.begin(), v.end(), std::back_inserter(r), std::less<int>());
+
+ TestMessageSuffix vs("v=" + join(v.begin(), v.end(), ","));
+ TestMessageSuffix rs("r=" + join(r.begin(), r.end(), ","));
+
+ TEST_CHECK_EQUAL(r.size(), sz);
+ for (unsigned x = 0 ; x < sz ; ++x)
+ TEST_CHECK_EQUAL(r[x], x);
+ }
+ }
+
+ } test_fast_unique_copy_simple_sequence;
+
+ struct FastUniqueCopyRepeatedElementTest : TestCase
+ {
+ FastUniqueCopyRepeatedElementTest() : TestCase("fast_unique_copy single repeated element") { }
+
+ void run()
+ {
+ for (unsigned sz = 0 ; sz < 20 ; ++sz)
+ {
+ TestMessageSuffix s("sz=" + stringify(sz));
+ std::vector<unsigned> v;
+ for (unsigned x = 0 ; x < sz ; ++x)
+ v.push_back(42);
+
+ std::vector<unsigned> r;
+ fast_unique_copy(v.begin(), v.end(), std::back_inserter(r));
+
+ TestMessageSuffix vs("v=" + join(v.begin(), v.end(), ","));
+ TestMessageSuffix rs("r=" + join(r.begin(), r.end(), ","));
+
+ if (sz == 0)
+ TEST_CHECK_EQUAL(r.size(), 0);
+ else
+ {
+ TEST_CHECK_EQUAL(r.size(), 1);
+ TEST_CHECK_EQUAL(r[0], 42);
+ }
+ }
+ }
+
+ } test_fast_unique_copy_repeated_element;
+
+ struct FastUniqueCopyNxNTest : TestCase
+ {
+ FastUniqueCopyNxNTest() : TestCase("fast_unique_copy nxn") { }
+
+ void run()
+ {
+ for (unsigned sz = 0 ; sz < 20 ; ++sz)
+ {
+ TestMessageSuffix s("sz=" + stringify(sz));
+ std::vector<unsigned> v;
+ for (unsigned x = 0 ; x < sz ; ++x)
+ for (unsigned y = 0 ; y < x ; ++y)
+ v.push_back(x);
+
+ std::vector<unsigned> r;
+ fast_unique_copy(v.begin(), v.end(), std::back_inserter(r));
+
+ TestMessageSuffix vs("v=" + join(v.begin(), v.end(), ","));
+ TestMessageSuffix rs("r=" + join(r.begin(), r.end(), ","));
+ if (sz == 0)
+ TEST_CHECK_EQUAL(r.size(), 0);
+ else
+ {
+ TEST_CHECK_EQUAL(r.size(), sz - 1);
+ for (unsigned x = 0 ; x < sz - 1 ; ++x)
+ TEST_CHECK_EQUAL(r[x], x + 1);
+ }
+ }
+ }
+
+ } test_fast_unique_copy_nxn;
+}
+
diff --git a/0.8.0/paludis/util/fd_holder.hh b/0.8.0/paludis/util/fd_holder.hh
new file mode 100644
index 000000000..2798fd9e9
--- /dev/null
+++ b/0.8.0/paludis/util/fd_holder.hh
@@ -0,0 +1,60 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_FD_HOLDER_HH
+#define PALUDIS_GUARD_PALUDIS_FD_HOLDER_HH 1
+
+#include <unistd.h>
+
+namespace paludis
+{
+ /**
+ * RAII holder for a file descriptor.
+ */
+ class PALUDIS_VISIBLE FDHolder
+ {
+ private:
+ const int _fd;
+ const bool _sync;
+
+ public:
+ FDHolder(const int fd, bool sync = true) :
+ _fd(fd),
+ _sync(sync)
+ {
+ }
+
+ ~FDHolder()
+ {
+ if (-1 != _fd)
+ {
+ if (_sync)
+ ::fsync(_fd);
+ ::close(_fd);
+ }
+ }
+
+ operator int () const
+ {
+ return _fd;
+ }
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/fd_output_stream.hh b/0.8.0/paludis/util/fd_output_stream.hh
new file mode 100644
index 000000000..84ee6edb9
--- /dev/null
+++ b/0.8.0/paludis/util/fd_output_stream.hh
@@ -0,0 +1,117 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_FD_OUTPUT_STREAM_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_FD_OUTPUT_STREAM_HH 1
+
+#include <ostream>
+#include <unistd.h>
+
+namespace paludis
+{
+ /**
+ * Output stream buffer class that's opened via an FD.
+ *
+ * See \ref TCppSL Ch. 13.13 for what we're doing here. The buffer code is
+ * based upon the "io/outbuf2.hpp" example in section 13.13.3.
+ *
+ * \ingroup grpfdotputstream
+ */
+ class PALUDIS_VISIBLE FDOutputStreamBuf :
+ public std::streambuf
+ {
+ protected:
+ int fd;
+
+ virtual int_type
+ overflow(int_type c)
+ {
+ if (c != EOF)
+ {
+ char z = c;
+ if (1 != write(fd, &z, 1))
+ return EOF;
+ }
+ return c;
+ }
+
+ virtual std::streamsize
+ xsputn(const char * s, std::streamsize num)
+ {
+ return write(fd, s, num);
+ }
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ FDOutputStreamBuf(const int f) :
+ fd(f)
+ {
+ }
+
+ ///\}
+ };
+
+ /**
+ * Member from base initialisation for FDOutputStream.
+ *
+ * \ingroup grpfdotputstream
+ */
+ class PALUDIS_VISIBLE FDOutputStreamBase
+ {
+ protected:
+ FDOutputStreamBuf buf;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ FDOutputStreamBase(const int fd) :
+ buf(fd)
+ {
+ }
+
+ ///\}
+ };
+
+ /**
+ * Output stream buffer class that's opened via an FD.
+ *
+ * \ingroup grpfdotputstream
+ */
+ class PALUDIS_VISIBLE FDOutputStream :
+ protected FDOutputStreamBase,
+ public std::ostream
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ FDOutputStream(const int fd) :
+ FDOutputStreamBase(fd),
+ std::ostream(&buf)
+ {
+ }
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/files.m4 b/0.8.0/paludis/util/files.m4
new file mode 100644
index 000000000..e8ffdbadb
--- /dev/null
+++ b/0.8.0/paludis/util/files.m4
@@ -0,0 +1,43 @@
+dnl vim: set ft=m4 et :
+dnl This file is used by Makefile.am.m4. You should use the provided
+dnl autogen.bash script to do all the hard work.
+dnl
+dnl This file is used to avoid having to make lots of repetitive changes in
+dnl Makefile.am every time we add a source or test file. The first parameter is
+dnl the base filename with no extension; later parameters can be `hh', `cc',
+dnl `test', `impl', `testscript'. Note that there isn't much error checking done
+dnl on this file at present...
+
+add(`attributes', `hh')
+add(`collection', `hh')
+add(`collection_concrete', `hhx')
+add(`compare', `hh')
+add(`comparison_policy', `hh')
+add(`counted_ptr', `hh', `test')
+add(`destringify', `hh', `cc', `test')
+add(`dir_iterator', `hh', `cc', `test', `testscript')
+add(`exception', `hh', `cc')
+add(`fast_unique_copy', `hh', `test')
+add(`fd_output_stream', `hh')
+add(`fs_entry', `hh', `cc', `test', `testscript')
+add(`fd_holder', `hh')
+add(`iterator', `hh', `test')
+add(`instantiation_policy', `hh', `test')
+add(`is_file_with_extension', `hh', `cc', `test', `testscript')
+add(`join', `hh', `test')
+add(`log', `hh', `cc', `test')
+add(`pipe', `hh', `cc')
+add(`private_implementation_pattern', `hh')
+add(`pstream', `hh', `cc', `test')
+add(`random', `hh', `cc', `test')
+add(`save', `hh', `test')
+add(`sr', `hh')
+add(`stringify', `hh', `test')
+add(`strip', `hh', `cc', `test')
+add(`system', `hh', `cc', `test', `testscript')
+add(`tokeniser', `hh', `cc', `test')
+add(`util', `hh')
+add(`validated', `hh', `test')
+add(`virtual_constructor', `hh', `test')
+add(`visitor', `hh', `test')
+
diff --git a/0.8.0/paludis/util/fs_entry.cc b/0.8.0/paludis/util/fs_entry.cc
new file mode 100644
index 000000000..117bddb20
--- /dev/null
+++ b/0.8.0/paludis/util/fs_entry.cc
@@ -0,0 +1,439 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2006 Mark Loeser <halcy0n@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/exception.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/stringify.hh>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+#include <cstring>
+#include <cstdlib>
+
+/** \file
+ * Implementation of paludis::FSEntry.
+ *
+ * \ingroup grpfilesystem
+ */
+
+using namespace paludis;
+
+FSError::FSError(const std::string & our_message) throw () :
+ Exception(our_message)
+{
+}
+
+FSEntry::FSEntry(const std::string & path) :
+ ComparisonPolicyType(&FSEntry::_path),
+ _path(path),
+ _stat_info(0),
+ _exists(false),
+ _checked(false)
+{
+ _normalise();
+}
+
+FSEntry::FSEntry(const FSEntry & other) :
+ ComparisonPolicyType(&FSEntry::_path),
+ _path(other._path),
+ _stat_info(other._stat_info),
+ _exists(other._exists),
+ _checked(other._checked)
+{
+}
+
+FSEntry::~FSEntry()
+{
+}
+
+const FSEntry &
+FSEntry::operator= (const FSEntry & other)
+{
+ _path = other._path;
+ _stat_info = other._stat_info;
+ _exists = other._exists;
+ _checked = other._checked;
+
+ return *this;
+}
+
+FSEntry
+FSEntry::operator/ (const FSEntry & rhs) const
+{
+ return FSEntry(_path + "/" + rhs._path);
+}
+
+FSEntry
+FSEntry::operator/ (const std::string & rhs) const
+{
+ return operator/ (FSEntry(rhs));
+}
+
+const FSEntry &
+FSEntry::operator/= (const FSEntry & rhs)
+{
+ _path.append("/");
+ _path.append(rhs._path);
+ _normalise();
+
+ _checked = false;
+ _exists = false;
+ _stat_info = CountedPtr<struct ::stat, count_policy::ExternalCountTag>(0);
+
+ return *this;
+}
+
+bool
+FSEntry::exists() const
+{
+ _stat();
+
+ return _exists;
+}
+
+bool
+FSEntry::is_directory() const
+{
+ _stat();
+
+ if (_exists)
+ return S_ISDIR((*_stat_info).st_mode);
+
+ return false;
+}
+
+bool
+FSEntry::is_regular_file() const
+{
+ _stat();
+
+ if (_exists)
+ return S_ISREG((*_stat_info).st_mode);
+
+ return false;
+}
+
+bool
+FSEntry::is_symbolic_link() const
+{
+ _stat();
+
+ if (_exists)
+ return S_ISLNK((*_stat_info).st_mode);
+
+ return false;
+}
+
+
+bool
+FSEntry::has_permission(const FSUserGroup & user_group, const FSPermission & fs_perm) const
+{
+ _stat();
+
+ if (! _exists)
+ throw FSError("Filesystem entry '" + _path + "' does not exist");
+
+ switch (user_group)
+ {
+ case fs_ug_owner:
+ {
+ switch (fs_perm)
+ {
+ case fs_perm_read:
+ return (*_stat_info).st_mode & S_IRUSR;
+ case fs_perm_write:
+ return (*_stat_info).st_mode & S_IWUSR;
+ case fs_perm_execute:
+ return (*_stat_info).st_mode & S_IXUSR;
+ }
+ throw InternalError(PALUDIS_HERE, "Unhandled FSPermission");
+ }
+ case fs_ug_group:
+ {
+ switch (fs_perm)
+ {
+ case fs_perm_read:
+ return (*_stat_info).st_mode & S_IRGRP;
+ case fs_perm_write:
+ return (*_stat_info).st_mode & S_IWGRP;
+ case fs_perm_execute:
+ return (*_stat_info).st_mode & S_IXGRP;
+ }
+ throw InternalError(PALUDIS_HERE, "Unhandled FSPermission");
+ }
+ case fs_ug_others:
+ {
+ switch (fs_perm)
+ {
+ case fs_perm_read:
+ return (*_stat_info).st_mode & S_IROTH;
+ case fs_perm_write:
+ return (*_stat_info).st_mode & S_IWOTH;
+ case fs_perm_execute:
+ return (*_stat_info).st_mode & S_IXOTH;
+ }
+ throw InternalError(PALUDIS_HERE, "Unhandled FSPermission");
+ }
+ }
+
+ throw InternalError(PALUDIS_HERE, "Unhandled FSUserGroup");
+}
+
+mode_t
+FSEntry::permissions() const
+{
+ _stat();
+
+ if (! _exists)
+ throw FSError("Filesystem entry '" + _path + "' does not exist");
+
+ return _stat_info->st_mode;
+}
+
+void
+FSEntry::_normalise()
+{
+ try
+ {
+ std::string new_path;
+ std::string::size_type p(0);
+ while (p < _path.length())
+ {
+ if ('/' == _path[p])
+ {
+ new_path += '/';
+ while (++p < _path.length())
+ if ('/' != _path[p])
+ break;
+ }
+ else
+ new_path += _path[p++];
+ }
+ _path = new_path;
+
+ if (! _path.empty())
+ if ('/' == _path.at(_path.length() - 1))
+ _path.erase(_path.length() - 1);
+ if (_path.empty())
+ _path = "/";
+ }
+ catch (const std::exception & e)
+ {
+ Context c("When normalising FSEntry path '" + _path + "':");
+ throw InternalError(PALUDIS_HERE,
+ "caught std::exception '" + stringify(e.what()) + "'");
+ }
+}
+
+void
+FSEntry::_stat() const
+{
+ if (_checked)
+ return;
+
+ _stat_info = CountedPtr<struct stat, count_policy::ExternalCountTag>(new struct stat);
+ if (0 != lstat(_path.c_str(), _stat_info.raw_pointer()))
+ {
+ if (errno != ENOENT)
+ throw FSError("Error running stat() on '" + stringify(_path) + "': "
+ + strerror(errno));
+
+ _exists = false;
+ _stat_info = CountedPtr<struct stat, count_policy::ExternalCountTag>(0);
+ }
+ else
+ _exists = true;
+
+ _checked = true;
+}
+
+std::string
+FSEntry::basename() const
+{
+ if (_path == "/")
+ return _path;
+
+ return _path.substr(_path.rfind('/') + 1);
+}
+
+FSEntry
+FSEntry::dirname() const
+{
+ if (_path == "/")
+ return FSEntry(_path);
+
+ return FSEntry(_path.substr(0, _path.rfind('/')));
+}
+
+FSEntry
+FSEntry::realpath() const
+{
+ char r[PATH_MAX + 1];
+ std::memset(r, 0, PATH_MAX + 1);
+ if (! ::realpath(_path.c_str(), r))
+ throw FSError("Could not resolve path '" + _path + "'");
+ return FSEntry(r);
+}
+
+FSEntry
+FSEntry::cwd()
+{
+ char r[PATH_MAX + 1];
+ std::memset(r, 0, PATH_MAX + 1);
+ if (! ::getcwd(r, PATH_MAX))
+ throw FSError("Could not get current working directory");
+ return FSEntry(r);
+}
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const FSEntry & f)
+{
+ s << f._path;
+ return s;
+}
+
+time_t
+FSEntry::ctime() const
+{
+ _stat();
+
+ if (! _exists)
+ throw FSError("Filesystem entry '" + _path + "' does not exist");
+
+ return (*_stat_info).st_ctime;
+}
+
+time_t
+FSEntry::mtime() const
+{
+ _stat();
+
+ if (! _exists)
+ throw FSError("Filesystem entry '" + _path + "' does not exist");
+
+ return (*_stat_info).st_mtime;
+}
+
+off_t
+FSEntry::file_size() const
+{
+ _stat();
+
+ if (! _exists)
+ throw FSError("Filesystem entry '" + _path + "' does not exist");
+
+ if (! is_regular_file())
+ throw FSError("file_size called on non-regular file '" + _path + "'");
+
+ return _stat_info->st_size;
+}
+
+bool
+FSEntry::mkdir(mode_t mode)
+{
+ if (0 == ::mkdir(_path.c_str(), mode))
+ return true;
+
+ int e(errno);
+ if (e == EEXIST)
+ {
+ if (is_directory())
+ return false;
+ throw FSError("mkdir '" + _path + "' failed: target exists and is not a directory");
+ }
+ else
+ throw FSError("mkdir '" + _path + "' failed: " + ::strerror(e));
+}
+
+bool
+FSEntry::unlink()
+{
+ if (0 == ::unlink(_path.c_str()))
+ return true;
+
+ int e(errno);
+ if (e == ENOENT)
+ return false;
+ else
+ throw FSError("unlink '" + _path + "' failed: " + ::strerror(e));
+}
+
+bool
+FSEntry::rmdir()
+{
+ if (0 == ::rmdir(_path.c_str()))
+ return true;
+
+ int e(errno);
+ if (e == ENOENT)
+ return false;
+ else
+ throw FSError("rmdir '" + _path + "' failed: " + ::strerror(e));
+}
+
+std::string
+FSEntry::readlink() const
+{
+ char buf[PATH_MAX + 1];
+ std::memset(buf, 0, PATH_MAX + 1);
+ if (-1 == ::readlink(_path.c_str(), buf, PATH_MAX))
+ throw FSError("readlink '" + _path + "' failed: " + ::strerror(errno));
+ return buf;
+}
+
+void
+FSEntry::chown(const uid_t new_owner, const gid_t new_group)
+{
+ if (0 != ::chown(_path.c_str(), new_owner, new_group))
+ throw FSError("chown '" + _path + "' failed: " + ::strerror(errno));
+}
+
+void
+FSEntry::chmod(const mode_t mode)
+{
+ if (0 != ::chmod(_path.c_str(), mode))
+ throw FSError("chmod '" + _path + "' failed: " + ::strerror(errno));
+}
+
+uid_t
+FSEntry::owner() const
+{
+ _stat();
+
+ if (! _exists)
+ throw FSError("Filesystem entry '" + _path + "' does not exist");
+
+ return _stat_info->st_uid;
+}
+
+gid_t
+FSEntry::group() const
+{
+ _stat();
+
+ if (! _exists)
+ throw FSError("Filesystem entry '" + _path + "' does not exist");
+
+ return _stat_info->st_gid;
+}
+
diff --git a/0.8.0/paludis/util/fs_entry.hh b/0.8.0/paludis/util/fs_entry.hh
new file mode 100644
index 000000000..946222964
--- /dev/null
+++ b/0.8.0/paludis/util/fs_entry.hh
@@ -0,0 +1,332 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2006 Mark Loeser <halcy0n@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_FS_ENTRY_HH
+#define PALUDIS_GUARD_PALUDIS_FS_ENTRY_HH 1
+
+#include <paludis/util/comparison_policy.hh>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/exception.hh>
+#include <string>
+#include <iosfwd>
+
+/** \file
+ * Declarations for paludis::Filesystem.
+ *
+ * \ingroup grpfilesystem
+ */
+
+struct stat;
+
+namespace paludis
+{
+ /**
+ * Generic filesystem error class.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpfilesystem
+ */
+ class PALUDIS_VISIBLE FSError :
+ public Exception
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ FSError(const std::string & message) throw ();
+
+ ///\}
+ };
+
+ /**
+ * File permissions used by FSEntry.
+ *
+ * \ingroup grpfilesystem
+ */
+ enum FSPermission
+ {
+ fs_perm_read, ///< read permission on file
+ fs_perm_write, ///< write permission on file
+ fs_perm_execute ///< execute permission on file
+ };
+
+ /**
+ * User classes used by FSEntry.
+ *
+ * \ingroup grpfilesystem
+ */
+ enum FSUserGroup
+ {
+ fs_ug_owner, ///< owner permission
+ fs_ug_group, ///< group permission
+ fs_ug_others ///< others permission
+ };
+
+ /**
+ * Represents an entry (which may or may not exist) in the filesystem.
+ *
+ * \ingroup grpfilesystem
+ */
+ class PALUDIS_VISIBLE FSEntry :
+ public ComparisonPolicy<
+ FSEntry,
+ comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<std::string> >
+ {
+ friend std::ostream & operator<< (std::ostream & s, const FSEntry & f);
+
+ private:
+ std::string _path;
+
+ mutable CountedPtr<struct ::stat, count_policy::ExternalCountTag> _stat_info;
+
+ mutable bool _exists;
+
+ /**
+ * Whether or not we have run _stat() on this location yet
+ */
+ mutable bool _checked;
+
+ void _normalise();
+
+ /**
+ * Runs lstat() on the current path if we have not done so already
+ * Note: lstat() will give information on the symlink itself, and not what
+ * the link points to, which is how stat() works.
+ */
+ void _stat() const;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ FSEntry(const std::string & path);
+
+ FSEntry(const FSEntry & other);
+
+ ~FSEntry();
+
+ const FSEntry & operator= (const FSEntry & other);
+
+ ///\}
+
+ ///\name Modification operations
+ ///\{
+
+ /**
+ * Join with another FSEntry.
+ */
+ FSEntry operator/ (const FSEntry & rhs) const;
+
+ /**
+ * Append another FSEntry.
+ */
+ const FSEntry & operator/= (const FSEntry & rhs);
+
+ /**
+ * Join with another path.
+ */
+ FSEntry operator/ (const std::string & rhs) const;
+
+ /**
+ * Append another path.
+ */
+ const FSEntry & operator/= (const std::string & rhs)
+ {
+ return operator/= (FSEntry(rhs));
+ }
+
+ /**
+ * Return the last part of our path (eg '/foo/bar' => 'bar').
+ */
+ std::string basename() const;
+
+ /**
+ * Return the first part of our path (eg '/foo/bar' => '/foo').
+ */
+ FSEntry dirname() const;
+
+
+ ///\}
+
+ ///\name Filesystem queries
+ ///\{
+
+ /**
+ * Does a filesystem entry exist at our location?
+ */
+ bool exists() const;
+
+ /**
+ * Does a filesystem entry exist at our location, and if it does,
+ * is it a directory?
+ */
+ bool is_directory() const;
+
+ /**
+ * Does a filesystem entry exist at our location, and if it does,
+ * is it a regular file?
+ */
+ bool is_regular_file() const;
+
+ /**
+ * Does a filesystem entry exist at our location, and if it does,
+ * is it a symbolic link?
+ */
+ bool is_symbolic_link() const;
+
+ /**
+ * Check if filesystem entry has `perm` for `user_group`.
+ *
+ * \exception FSError if there was a problem accessing the filesystem entry
+ */
+ bool has_permission(const FSUserGroup & user_group, const FSPermission & fs_perm) const;
+
+ /**
+ * Return the permissions for our item.
+ *
+ * \exception FSError if there was a problem accessing the filesystem entry
+ */
+ mode_t permissions() const;
+
+ /**
+ * Return the canonicalised version of our path.
+ */
+ FSEntry realpath() const;
+
+ /**
+ * Return our destination, if we are a symlink.
+ *
+ * \exception FSError if we are not a symlink, or if the system call
+ * fails.
+ */
+ std::string readlink() const;
+
+ /**
+ * Return the time the filesystem entry was created
+ * \exception FSError if there was a problem accessing the filesystem entry
+ */
+ time_t ctime() const;
+
+ /**
+ * Return the time the filesystem entry was last modified
+ * \exception FSError if there was a problem accessing the filesystem entry
+ */
+ time_t mtime() const;
+
+ /**
+ * Return the size of our file, in bytes.
+ *
+ * \exception FSError if we don't have a size.
+ */
+ off_t file_size() const;
+
+ /**
+ * Fetch our owner.
+ *
+ * \exception FSError If we don't exist or the stat call fails.
+ */
+ uid_t owner() const;
+
+ /**
+ * Fetch our group.
+ *
+ * \exception FSError If we don't exist or the stat call fails.
+ */
+ gid_t group() const;
+
+ /**
+ * Return the current working directory
+ */
+ static FSEntry cwd();
+
+ ///\}
+
+ ///\name Filesystem operations
+ ///\{
+
+ /**
+ * Try to make a directory.
+ *
+ * \return True, if we succeeded, and false if the directory
+ * already exists and is a directory.
+ *
+ * \exception FSError If an error other than the directory already
+ * existing occurs.
+ */
+ bool mkdir(const mode_t mode = 0755);
+
+ /**
+ * Try to unlink.
+ *
+ * \return True, if we succeeded, and false if we don't exist
+ * already.
+ *
+ * \exception FSError If an error other than us already not
+ * existing occurs.
+ */
+ bool unlink();
+
+ /**
+ * Try to rmdir.
+ *
+ * \return True, if we succeeded, and false if we don't exist
+ * already.
+ *
+ * \exception FSError If an error other than us already not
+ * existing occurs.
+ */
+ bool rmdir();
+
+ /**
+ * Change our permissions.
+ *
+ * \exception FSError If the chown failed.
+ */
+ void chown(const uid_t owner, const gid_t group = -1);
+
+ /**
+ * Change our permissions.
+ *
+ * \exception FSError If the chmod failed.
+ */
+ void chmod(const mode_t mode);
+
+ ///\}
+ };
+
+ /**
+ * An FSEntry can be written to an ostream.
+ *
+ * \ingroup grpfilesystem
+ */
+ std::ostream & operator<< (std::ostream & s, const FSEntry & f) PALUDIS_VISIBLE;
+
+ template <typename T_> class SequentialCollection;
+
+ /**
+ * An ordered group of FSEntry instances.
+ *
+ * \ingroup grpfilesystem
+ */
+ typedef SequentialCollection<FSEntry> FSEntryCollection;
+}
+
+#endif
diff --git a/0.8.0/paludis/util/fs_entry_TEST.cc b/0.8.0/paludis/util/fs_entry_TEST.cc
new file mode 100644
index 000000000..21717c3ca
--- /dev/null
+++ b/0.8.0/paludis/util/fs_entry_TEST.cc
@@ -0,0 +1,368 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ * Copyright (c) 2006 Mark Loeser <halcy0n@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <ctime>
+#include <paludis/util/fs_entry.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for fs_entry.hh.
+ *
+ * \todo this is nowhere near complete.
+ *
+ * \ingroup grpfilesystem
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test FSEntry construction and manipulation.
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryManipulationTest : TestCase
+ {
+ FSEntryManipulationTest() : TestCase("construction and manipulation") { }
+
+ void run()
+ {
+ FSEntry f("/foo/bar");
+ FSEntry c(f);
+ TEST_CHECK_EQUAL(f, FSEntry("/foo/bar"));
+ TEST_CHECK_EQUAL(c, FSEntry("/foo/bar"));
+ f = FSEntry("/baz");
+ TEST_CHECK_EQUAL(f, FSEntry("/baz"));
+ TEST_CHECK_EQUAL(c, FSEntry("/foo/bar"));
+ c /= "moo";
+ TEST_CHECK_EQUAL(f, FSEntry("/baz"));
+ TEST_CHECK_EQUAL(c, FSEntry("/foo/bar/moo"));
+ f = c / f;
+ TEST_CHECK_EQUAL(f, FSEntry("/foo/bar/moo/baz"));
+ TEST_CHECK_EQUAL(c, FSEntry("/foo/bar/moo"));
+
+ f = FSEntry::cwd();
+ }
+ } test_fs_entry_manipulation;
+
+ /**
+ * \test Test FSEntry behavior.
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryRealpathTest : TestCase
+ {
+ FSEntryRealpathTest() : TestCase("behavior") { }
+
+ bool repeatable() const
+ {
+ return false;
+ }
+
+ void run()
+ {
+ FSEntry d("fs_entry_TEST_dir");
+ TEST_CHECK(d.is_directory());
+
+ d /= "all_perms";
+ TEST_CHECK(d.is_regular_file());
+
+ FSEntry e("fs_entry_TEST_dir/nosuchfile");
+ TEST_CHECK(! e.is_regular_file());
+ d = e;
+ TEST_CHECK(! d.is_regular_file());
+ TEST_CHECK(! d.exists());
+ TEST_CHECK_THROWS(e.readlink(), FSError);
+
+ d = FSEntry("fs_entry_TEST_dir/all_perms");
+ TEST_CHECK(! e.is_regular_file());
+ TEST_CHECK(d.is_regular_file());
+ TEST_CHECK(d.exists());
+
+ d = FSEntry("fs_entry_TEST_dir/symlink_to_dir_a");
+ TEST_CHECK(d.is_symbolic_link());
+ TEST_CHECK(! d.is_directory());
+ TEST_CHECK(! d.is_regular_file());
+
+ FSEntry f("fs_entry_TEST_dir/symlink_to_dir_a/file_in_a");
+ TEST_CHECK(f.is_regular_file());
+ TEST_CHECK(! f.is_symbolic_link());
+ FSEntry r(f.realpath());
+ TEST_CHECK(r.is_regular_file());
+ std::string g("fs_entry_TEST_dir/dir_a/file_in_a");
+ TEST_CHECK_EQUAL(stringify(r).substr(stringify(r).length() - g.length()), g);
+
+ FSEntry h("fs_entry_TEST_dir/symlink_to_file_in_a");
+ TEST_CHECK(h.is_symbolic_link());
+ TEST_CHECK(! h.is_regular_file());
+ TEST_CHECK_EQUAL(h.readlink(), "dir_a/file_in_a");
+
+ FSEntry i("fs_entry_TEST_dir/dir_to_make");
+ TEST_CHECK(i.mkdir());
+ TEST_CHECK(! i.mkdir());
+ TEST_CHECK(i.rmdir());
+ FSEntry j("fs_entry_TEST_dir/dir_to_make");
+ TEST_CHECK(! j.exists());
+ TEST_CHECK(! j.is_directory());
+
+ FSEntry k("fs_entry_TEST_dir/dir_a/file_in_a");
+ TEST_CHECK_THROWS(k.mkdir(), FSError);
+ }
+ } test_fs_entry_behaviour;
+
+ /**
+ * \test Test FSEntry has_permission methods.
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryHasPermission: TestCase
+ {
+ FSEntryHasPermission() : TestCase("has_permission") {}
+
+ void run()
+ {
+ FSEntry a("fs_entry_TEST_dir/all_perms");
+ FSEntry b("fs_entry_TEST_dir/no_perms");
+ FSEntry c("fs_entry_TEST_dir/no_such_file");
+
+ TEST_CHECK(a.has_permission(fs_ug_owner, fs_perm_read));
+ TEST_CHECK(a.has_permission(fs_ug_owner, fs_perm_write));
+ TEST_CHECK(a.has_permission(fs_ug_owner, fs_perm_execute));
+ TEST_CHECK(a.has_permission(fs_ug_group, fs_perm_read));
+ TEST_CHECK(a.has_permission(fs_ug_group, fs_perm_write));
+ TEST_CHECK(a.has_permission(fs_ug_group, fs_perm_execute));
+ TEST_CHECK(a.has_permission(fs_ug_others, fs_perm_read));
+ TEST_CHECK(a.has_permission(fs_ug_others, fs_perm_write));
+ TEST_CHECK(a.has_permission(fs_ug_others, fs_perm_execute));
+
+ TEST_CHECK(!b.has_permission(fs_ug_owner, fs_perm_read));
+ TEST_CHECK(!b.has_permission(fs_ug_owner, fs_perm_write));
+ TEST_CHECK(!b.has_permission(fs_ug_owner, fs_perm_execute));
+ TEST_CHECK(!b.has_permission(fs_ug_group, fs_perm_read));
+ TEST_CHECK(!b.has_permission(fs_ug_group, fs_perm_write));
+ TEST_CHECK(!b.has_permission(fs_ug_group, fs_perm_execute));
+ TEST_CHECK(!b.has_permission(fs_ug_others, fs_perm_read));
+ TEST_CHECK(!b.has_permission(fs_ug_others, fs_perm_write));
+ TEST_CHECK(!b.has_permission(fs_ug_others, fs_perm_execute));
+
+ TEST_CHECK_THROWS(c.has_permission(fs_ug_owner, fs_perm_read), FSError);
+ }
+ } test_fs_entry_permission;
+
+ /**
+ * \test Test FSEntry ctime and mtime methods
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryTime : TestCase
+ {
+ FSEntryTime() : TestCase("ctime and mtime") {}
+
+ void run()
+ {
+ FSEntry a("fs_entry_TEST_dir");
+ FSEntry b("fs_entry_TEST_dir/no_perms");
+ FSEntry c("fs_entry_TEST_dir/no_such_file");
+
+ TEST_CHECK(a.ctime() <= std::time(NULL));
+ TEST_CHECK((a.mtime() >= a.ctime()) && (a.mtime() <= std::time(NULL)));
+ TEST_CHECK(b.ctime() <= std::time(NULL));
+ TEST_CHECK((b.mtime() >= b.ctime()) && (b.mtime() <= std::time(NULL)));
+
+ TEST_CHECK_THROWS(c.ctime(), FSError);
+ TEST_CHECK_THROWS(c.mtime(), FSError);
+ }
+ } test_fs_entry_time;
+
+ /**
+ * \test Test FSEntry file_size
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryFileSize : TestCase
+ {
+ FSEntryFileSize() : TestCase("file size") {}
+
+ void run()
+ {
+ FSEntry f("fs_entry_TEST_dir/ten_bytes");
+ FSEntry d("fs_entry_TEST_dir/dir_a");
+ FSEntry e("fs_entry_TEST_dir/no_such_file");
+
+ TEST_CHECK_EQUAL(f.file_size(), 10);
+ TEST_CHECK_THROWS(d.file_size(), FSError);
+ TEST_CHECK_THROWS(e.file_size(), FSError);
+ }
+ } test_fs_entry_size;
+
+ /**
+ * \test Test FSEntry basename and dirname methods
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryBaseDirName : TestCase
+ {
+ FSEntryBaseDirName() : TestCase("basename and dirname") {}
+
+ void run()
+ {
+ FSEntry a("/foo/bar");
+ FSEntry b("/moo/went/the/cow");
+ FSEntry c("/");
+ FSEntry d(".");
+ FSEntry e("..");
+
+ TEST_CHECK(a.basename() == "bar");
+ TEST_CHECK(stringify(a.dirname()) == "/foo");
+ TEST_CHECK(b.basename() == "cow");
+ TEST_CHECK(stringify(b.dirname()) == "/moo/went/the");
+ TEST_CHECK(c.basename() == "/");
+ TEST_CHECK(stringify(c.dirname()) == "/");
+ TEST_CHECK(d.basename() == ".");
+ TEST_CHECK(stringify(d.dirname()) == ".");
+ TEST_CHECK(e.basename() == "..");
+ TEST_CHECK(stringify(e.dirname()) == "..");
+ }
+ } test_fs_entry_dir_base_name;
+
+ /**
+ * \test Test FSEntry chmod, chown and permissions methods
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryChangePerms : TestCase
+ {
+ FSEntryChangePerms() : TestCase("chmod, chown and permissions") {}
+
+ void run()
+ {
+ FSEntry a("fs_entry_TEST_dir/no_perms");
+
+ uid_t my_uid = geteuid();
+ a.chown(my_uid);
+ TEST_CHECK_EQUAL(a.owner(), my_uid);
+
+ mode_t all_perms(S_IRUSR | S_IWUSR | S_IXUSR |
+ S_IRGRP | S_IWGRP | S_IXGRP |
+ S_IROTH | S_IWOTH | S_IXOTH);
+ a.chmod(all_perms);
+
+ FSEntry b("fs_entry_TEST_dir/no_perms");
+
+ TEST_CHECK_EQUAL(static_cast<mode_t>(b.permissions() & 0xFFF), all_perms);
+
+ mode_t no_perms(0);
+ b.chmod(no_perms);
+
+ FSEntry c("fs_entry_TEST_dir/no_perms");
+ TEST_CHECK_EQUAL(static_cast<mode_t>(c.permissions() & 0xFFF), no_perms);
+
+ FSEntry d("fs_entry_TEST_dir/i_dont_exist");
+
+ TEST_CHECK_THROWS(d.permissions(), FSError);
+ TEST_CHECK_THROWS(d.chmod(all_perms), FSError);
+ TEST_CHECK_THROWS(d.chown(static_cast<uid_t>(-1)), FSError);
+ TEST_CHECK_THROWS(d.owner(), FSError);
+ TEST_CHECK_THROWS(d.group(), FSError);
+
+ if (0 == my_uid)
+ {
+ struct passwd *pw = getpwent();
+
+ if (! pw)
+ throw InternalError(PALUDIS_HERE, "getpwent returned NULL");
+
+ std::string my_file("fs_entry_TEST_dir/all_perms");
+ FSEntry e(my_file);
+
+ uid_t my_owner = e.owner();
+ gid_t my_group = e.group();
+
+ if (pw->pw_uid == my_owner)
+ {
+ pw = getpwent();
+
+ if (! pw)
+ throw InternalError(PALUDIS_HERE, "getpwent returned NULL");
+ }
+
+ uid_t new_owner(pw->pw_uid);
+
+ e.chown(new_owner);
+
+ TEST_CHECK_EQUAL(FSEntry(my_file).owner(), new_owner);
+ TEST_CHECK_EQUAL(FSEntry(my_file).group(), my_group);
+
+ gid_t new_group(pw->pw_gid);
+
+ endpwent();
+
+ e.chown(static_cast<uid_t>(-1), new_group);
+
+ TEST_CHECK_EQUAL(FSEntry(my_file).owner(), new_owner);
+ TEST_CHECK_EQUAL(FSEntry(my_file).group(), new_group);
+
+ e.chown(static_cast<uid_t>(-1));
+
+ TEST_CHECK_EQUAL(FSEntry(my_file).owner(), new_owner);
+ TEST_CHECK_EQUAL(FSEntry(my_file).group(), new_group);
+
+ e.chown(my_owner, my_group);
+
+ TEST_CHECK_EQUAL(FSEntry(my_file).owner(), my_owner);
+ TEST_CHECK_EQUAL(FSEntry(my_file).group(), my_group);
+ }
+ else
+ {
+ FSEntry e("fs_entry_TEST_dir/all_perms");
+
+ TEST_CHECK_THROWS(e.chown(0, 0), FSError);
+ }
+ }
+ } test_fs_entry_change_perms;
+
+ /**
+ * \test Test operator<<
+ *
+ * \ingroup grpfilesystem
+ */
+ struct FSEntryToOstreamOperator : TestCase
+ {
+ FSEntryToOstreamOperator() : TestCase("operator<<") {}
+
+ void run()
+ {
+ std::string name("fs_entry_TEST_dir/no_perms");
+ std::ostringstream s;
+ FSEntry a(name);
+
+ s << a;
+
+ TEST_CHECK_EQUAL(s.str(), name);
+ }
+ } test_fs_entry_to_ostream_operator;
+}
+
diff --git a/0.8.0/paludis/util/fs_entry_TEST_cleanup.sh b/0.8.0/paludis/util/fs_entry_TEST_cleanup.sh
new file mode 100755
index 000000000..662b2bb36
--- /dev/null
+++ b/0.8.0/paludis/util/fs_entry_TEST_cleanup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d fs_entry_TEST_dir ] ; then
+ rm -fr fs_entry_TEST_dir
+else
+ true
+fi
+
diff --git a/0.8.0/paludis/util/fs_entry_TEST_setup.sh b/0.8.0/paludis/util/fs_entry_TEST_setup.sh
new file mode 100755
index 000000000..7d7796bf7
--- /dev/null
+++ b/0.8.0/paludis/util/fs_entry_TEST_setup.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir fs_entry_TEST_dir || exit 2
+cd fs_entry_TEST_dir || exit 3
+mkdir dir_a || exit 4
+ln -s dir_a symlink_to_dir_a || exit 5
+touch dir_a/file_in_a || exit 6
+
+touch all_perms || exit 7
+chmod 777 all_perms || exit 8
+touch no_perms || exit 9
+sleep 1
+echo > no_perms
+chmod 000 no_perms || exit 10
+echo -n '0123456789' > ten_bytes || exit 11
+ln -s dir_a/file_in_a symlink_to_file_in_a || exit 12
diff --git a/0.8.0/paludis/util/instantiation_policy.hh b/0.8.0/paludis/util/instantiation_policy.hh
new file mode 100644
index 000000000..65625ba94
--- /dev/null
+++ b/0.8.0/paludis/util/instantiation_policy.hh
@@ -0,0 +1,291 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_INSTANTIATION_POLICY_HH
+#define PALUDIS_GUARD_PALUDIS_INSTANTIATION_POLICY_HH 1
+
+#include <paludis/util/attributes.hh>
+
+/** \file
+ * InstantiationPolicy patterns.
+ *
+ * \ingroup grpinstance
+ */
+
+namespace paludis
+{
+ /**
+ * Instantiation policies for paludis::InstantiationPolicy.
+ *
+ * \ingroup grpinstance
+ */
+ namespace instantiation_method
+ {
+ /**
+ * Cannot be copied or assigned to.
+ *
+ * \ingroup grpinstance
+ */
+ struct NonCopyableTag
+ {
+ };
+
+ /**
+ * Cannot be instantiated
+ *
+ * \ingroup grpinstance
+ */
+ struct NonInstantiableTag
+ {
+ };
+
+ /**
+ * Single instance created at startup.
+ *
+ * \ingroup grpinstance
+ */
+ struct SingletonAtStartupTag
+ {
+ };
+
+ /**
+ * Single instance created when needed.
+ *
+ * \ingroup grpinstance
+ */
+ struct SingletonAsNeededTag
+ {
+ };
+ }
+
+ /**
+ * InstantiationPolicy is used to specify behaviour of classes that have
+ * something other than the default C++ instantiation behaviour.
+ *
+ * \ingroup grpinstance
+ */
+ template <typename OurType_, typename InstantiationMethodTag_>
+ struct InstantiationPolicy;
+
+ /**
+ * InstantiationPolicy: specialisation for classes that cannot be copied
+ * or assigned to.
+ *
+ * \ingroup grpinstance
+ */
+ template<typename OurType_>
+ class PALUDIS_VISIBLE InstantiationPolicy<OurType_, instantiation_method::NonCopyableTag>
+ {
+ private:
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ ~InstantiationPolicy()
+ {
+ }
+
+ InstantiationPolicy()
+ {
+ }
+
+ ///\}
+ };
+
+ /**
+ * InstantiationPolicy: specialisation for classes that cannot be created.
+ *
+ * \ingroup grpinstance
+ */
+ template<typename OurType_>
+ class InstantiationPolicy<OurType_, instantiation_method::NonInstantiableTag>
+ {
+ private:
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ InstantiationPolicy();
+
+ ~InstantiationPolicy()
+ {
+ }
+
+ ///\}
+ };
+}
+
+#include <paludis/util/counted_ptr.hh>
+
+namespace paludis
+{
+ /**
+ * InstantiationPolicy: specialisation for singleton classes that are
+ * created at startup.
+ *
+ * \ingroup grpinstance
+ */
+ template<typename OurType_>
+ class PALUDIS_VISIBLE InstantiationPolicy<OurType_, instantiation_method::SingletonAtStartupTag>
+ {
+ private:
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ static CountedPtr<OurType_, count_policy::ExternalCountTag> _instance;
+
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ InstantiationPolicy()
+ {
+ }
+
+ ///\}
+
+ public:
+ ///\name Singleton operations
+ ///\{
+
+ /**
+ * Fetch our instance.
+ */
+ static OurType_ * get_instance()
+ {
+ return _instance.raw_pointer();
+ }
+
+ ///\}
+ };
+
+ template <typename OurType_>
+ CountedPtr<OurType_, count_policy::ExternalCountTag>
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAtStartupTag>::_instance(
+ new OurType_);
+
+ /**
+ * InstantiationPolicy: specialisation for singleton classes that are
+ * created as needed.
+ *
+ * \ingroup grpinstance
+ */
+ template<typename OurType_>
+ class PALUDIS_VISIBLE InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>
+ {
+ private:
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ static OurType_ * * _get_instance_ptr();
+
+ class DeleteOnDestruction;
+ friend class DeleteOnDestruction;
+
+ static void _delete(OurType_ * const p)
+ {
+ delete p;
+ }
+
+ class PALUDIS_VISIBLE DeleteOnDestruction
+ {
+ private:
+ OurType_ * * const _ptr;
+
+ public:
+ DeleteOnDestruction(OurType_ * * const p) :
+ _ptr(p)
+ {
+ }
+
+ ~DeleteOnDestruction()
+ {
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::_delete(* _ptr);
+ * _ptr = 0;
+ }
+ };
+
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ InstantiationPolicy()
+ {
+ }
+
+ ///\}
+
+ public:
+ ///\name Singleton operations
+ ///\{
+
+ /**
+ * Fetch our instance.
+ */
+ static OurType_ * get_instance();
+
+ /**
+ * Destroy our instance.
+ */
+ static void destroy_instance();
+
+ ///\}
+ };
+
+ template<typename OurType_>
+ OurType_ * *
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::_get_instance_ptr()
+ {
+ static OurType_ * instance(0);
+ static DeleteOnDestruction delete_instance(&instance);
+
+ return &instance;
+ }
+
+ template<typename OurType_>
+ OurType_ *
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::get_instance()
+ {
+ OurType_ * * i(_get_instance_ptr());
+ if (0 == *i)
+ *i = new OurType_;
+ return *i;
+ }
+
+ template<typename OurType_>
+ void
+ InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>::destroy_instance()
+ {
+ OurType_ * * i(_get_instance_ptr());
+ delete *i;
+ *i = 0;
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/instantiation_policy_TEST.cc b/0.8.0/paludis/util/instantiation_policy_TEST.cc
new file mode 100644
index 000000000..6c8aa34eb
--- /dev/null
+++ b/0.8.0/paludis/util/instantiation_policy_TEST.cc
@@ -0,0 +1,191 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/instantiation_policy.hh>
+#include <string>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for instantiation_policy.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+namespace
+{
+ /**
+ * Test class for InstantiationPolicy.
+ *
+ * \ingroup grptestcases
+ */
+ class MyClass :
+ public InstantiationPolicy<MyClass, instantiation_method::SingletonAsNeededTag>
+ {
+ friend class InstantiationPolicy<MyClass, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ MyClass()
+ {
+ ++instances;
+ }
+
+ public:
+ std::string s;
+
+ static int instances;
+ };
+
+ int MyClass::instances = 0;
+
+ class MyClassTwo :
+ public InstantiationPolicy<MyClassTwo, instantiation_method::SingletonAsNeededTag>
+ {
+ friend class InstantiationPolicy<MyClassTwo, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ MyClassTwo()
+ {
+ ++instances;
+ }
+
+ ~MyClassTwo()
+ {
+ --instances;
+ }
+
+ public:
+ std::string s;
+
+ static int instances;
+ };
+
+ int MyClassTwo::instances = 0;
+
+ struct MyLoadAtStartupClass :
+ public InstantiationPolicy<MyLoadAtStartupClass, instantiation_method::SingletonAtStartupTag>
+ {
+ friend class InstantiationPolicy<MyLoadAtStartupClass, instantiation_method::SingletonAtStartupTag>;
+
+ private:
+ MyLoadAtStartupClass()
+ {
+ ++instances;
+ }
+
+ public:
+ std::string s;
+
+ static int instances;
+ };
+
+ int MyLoadAtStartupClass::instances = 0;
+}
+
+namespace test_cases
+{
+ /**
+ * \test Test singleton behaviour.
+ *
+ * \ingroup grptestcases
+ */
+ struct SingletonPatternTest : TestCase
+ {
+ SingletonPatternTest() : TestCase("singleton test") { }
+
+ bool repeatable() const
+ {
+ return false;
+ }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(MyClass::instances, 0);
+ TEST_CHECK(0 != MyClass::get_instance());
+ TEST_CHECK_EQUAL(MyClass::instances, 1);
+ TEST_CHECK(MyClass::get_instance() == MyClass::get_instance());
+ TEST_CHECK(MyClass::get_instance()->s.empty());
+ MyClass::get_instance()->s = "foo";
+ TEST_CHECK_EQUAL(MyClass::get_instance()->s, "foo");
+ }
+ } test_singleton_pattern;
+
+ /**
+ * \test Test singleton behaviour.
+ *
+ * \ingroup grptestcases
+ */
+ struct SingletonPatternDeleteTest : TestCase
+ {
+ SingletonPatternDeleteTest() : TestCase("singleton delete test") { }
+
+ bool repeatable() const
+ {
+ return false;
+ }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 0);
+ TEST_CHECK(0 != MyClassTwo::get_instance());
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 1);
+ TEST_CHECK(MyClassTwo::get_instance() == MyClassTwo::get_instance());
+ TEST_CHECK(MyClassTwo::get_instance()->s.empty());
+ MyClassTwo::get_instance()->s = "foo";
+ TEST_CHECK_EQUAL(MyClassTwo::get_instance()->s, "foo");
+ MyClassTwo::destroy_instance();
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 0);
+ TEST_CHECK(0 != MyClassTwo::get_instance());
+ TEST_CHECK_EQUAL(MyClassTwo::instances, 1);
+ TEST_CHECK(MyClassTwo::get_instance()->s.empty());
+ }
+ } test_singleton_pattern_delete;
+
+ /**
+ * \test Test singleton create at startup behaviour.
+ *
+ * \ingroup grptestcases
+ */
+ struct SingletonPatternCreateAtStartupTest : TestCase
+ {
+ SingletonPatternCreateAtStartupTest() : TestCase("singleton create at startup test") { }
+
+ bool repeatable() const
+ {
+ return false;
+ }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(MyLoadAtStartupClass::instances, 1);
+ TEST_CHECK(0 != MyLoadAtStartupClass::get_instance());
+ TEST_CHECK_EQUAL(MyLoadAtStartupClass::instances, 1);
+ TEST_CHECK(MyLoadAtStartupClass::get_instance() == MyLoadAtStartupClass::get_instance());
+ TEST_CHECK(MyLoadAtStartupClass::get_instance()->s.empty());
+ MyLoadAtStartupClass::get_instance()->s = "foo";
+ TEST_CHECK_EQUAL(MyLoadAtStartupClass::get_instance()->s, "foo");
+ }
+ } test_singleton_pattern_create_at_startup;
+}
+
+
+
diff --git a/0.8.0/paludis/util/is_file_with_extension.cc b/0.8.0/paludis/util/is_file_with_extension.cc
new file mode 100644
index 000000000..9655b5e4b
--- /dev/null
+++ b/0.8.0/paludis/util/is_file_with_extension.cc
@@ -0,0 +1,56 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/is_file_with_extension.hh>
+
+using namespace paludis;
+
+/** \file
+ * Implementation of IsFileWithExtension.
+ *
+ * \ingroup grpfilesystem
+ */
+
+IsFileWithExtension::IsFileWithExtension(const std::string & ext) :
+ _prefix(""),
+ _ext(ext)
+{
+}
+
+IsFileWithExtension::IsFileWithExtension(const std::string & prefix, const std::string & ext) :
+ _prefix(prefix),
+ _ext(ext)
+{
+}
+
+bool
+IsFileWithExtension::operator() (const FSEntry & f) const
+{
+ const std::string filename(f.basename());
+
+ if (filename.length() < _ext.length() + _prefix.length())
+ return false;
+ if (0 != filename.compare(filename.length() - _ext.length(),
+ _ext.length(), _ext))
+ return false;
+ if (0 != filename.compare(0, _prefix.length(), _prefix))
+ return false;
+ return f.is_regular_file() || (f.exists() && f.realpath().is_regular_file());
+}
+
diff --git a/0.8.0/paludis/util/is_file_with_extension.hh b/0.8.0/paludis/util/is_file_with_extension.hh
new file mode 100644
index 000000000..a96d29092
--- /dev/null
+++ b/0.8.0/paludis/util/is_file_with_extension.hh
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_IS_FILE_WITH_EXTENSION_HH
+#define PALUDIS_GUARD_PALUDIS_IS_FILE_WITH_EXTENSION_HH 1
+
+#include <functional>
+#include <paludis/util/fs_entry.hh>
+#include <string>
+
+/** \file
+ * Declarations for the IsFileWithExtension class.
+ *
+ * \ingroup grpfilesystem
+ */
+
+namespace paludis
+{
+ /**
+ * The IsFileWithExtension class is a functor that determines whether an
+ * FSEntry instance is a file with a given extension and (optionally) a
+ * given filename prefix.
+ *
+ * \ingroup grpfilesystem
+ */
+ class PALUDIS_VISIBLE IsFileWithExtension :
+ public std::unary_function<bool, FSEntry>
+ {
+ private:
+ const std::string _prefix;
+ const std::string _ext;
+
+ public:
+ /**
+ * Constructor.
+ */
+ IsFileWithExtension(const std::string & ext);
+
+ /**
+ * Constructor.
+ */
+ IsFileWithExtension(const std::string & prefix, const std::string & ext);
+
+ /**
+ * Operator.
+ */
+ bool operator() (const FSEntry & f) const;
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/is_file_with_extension_TEST.cc b/0.8.0/paludis/util/is_file_with_extension_TEST.cc
new file mode 100644
index 000000000..a60c2243c
--- /dev/null
+++ b/0.8.0/paludis/util/is_file_with_extension_TEST.cc
@@ -0,0 +1,94 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Mark Loeser <halcy0n@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+#include <paludis/util/is_file_with_extension.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+
+/** \file
+ * Test cases for IsFileWithExtension.
+ *
+ * \ingroup grptestcases
+ */
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ /**
+ * \test Test IsFileWithExtension.
+ *
+ * \ingroup grptestcases
+ */
+ struct IsFileWithExtensionTest : TestCase
+ {
+ IsFileWithExtensionTest() : TestCase("is file with extension") { }
+
+ void run()
+ {
+ IsFileWithExtension a("foo");
+ IsFileWithExtension b("goat");
+
+ FSEntry c("teh.foo");
+ FSEntry d("is_file_with_extension_TEST_file.goat");
+
+ TEST_CHECK(d.exists());
+
+ TEST_CHECK( !a(c) );
+ TEST_CHECK( !a(d) );
+ TEST_CHECK( !b(c) );
+ TEST_CHECK( b(d) );
+
+ }
+ } test_is_file_with_extension;
+
+ /**
+ * \test Test IsFileWithExtension with a prefix.
+ *
+ * \ingroup grptestcases
+ */
+ struct IsFileWithExtensionPrefixTest : TestCase
+ {
+ IsFileWithExtensionPrefixTest() : TestCase("is file with extension (with prefix)") { }
+
+ void run()
+ {
+ IsFileWithExtension a("teh","foo");
+ IsFileWithExtension b("is", "goat");
+ IsFileWithExtension c("with", "goat");
+
+ FSEntry d("teh.foo");
+ FSEntry e("is_file_with_extension_TEST_file.goat");
+
+ TEST_CHECK(e.exists());
+
+ TEST_CHECK( !a(d) );
+ TEST_CHECK( !a(e) );
+ TEST_CHECK( !b(d) );
+ TEST_CHECK( b(e) );
+ TEST_CHECK( !c(e) );
+ }
+ } test_is_file_with_extension_prefix;
+
+
+}
+
diff --git a/0.8.0/paludis/util/is_file_with_extension_TEST_cleanup.sh b/0.8.0/paludis/util/is_file_with_extension_TEST_cleanup.sh
new file mode 100755
index 000000000..986933aae
--- /dev/null
+++ b/0.8.0/paludis/util/is_file_with_extension_TEST_cleanup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -f "is_file_with_extension_TEST_file.goat" ] ; then
+ rm -f "is_file_with_extension_TEST_file.goat"
+else
+ true
+fi
+
diff --git a/0.8.0/paludis/util/is_file_with_extension_TEST_setup.sh b/0.8.0/paludis/util/is_file_with_extension_TEST_setup.sh
new file mode 100755
index 000000000..bdfacbf64
--- /dev/null
+++ b/0.8.0/paludis/util/is_file_with_extension_TEST_setup.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+touch is_file_with_extension_TEST_file.goat || exit 2
+
+
diff --git a/0.8.0/paludis/util/iterator.hh b/0.8.0/paludis/util/iterator.hh
new file mode 100644
index 000000000..bb83cd31a
--- /dev/null
+++ b/0.8.0/paludis/util/iterator.hh
@@ -0,0 +1,502 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_INDIRECT_ITERATOR_HH
+#define PALUDIS_GUARD_PALUDIS_INDIRECT_ITERATOR_HH 1
+
+#include <iterator>
+#include <paludis/util/comparison_policy.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declarations for various iterator helpers.
+ *
+ * \ingroup grpiterators
+ */
+
+namespace paludis
+{
+ /**
+ * Return a new iterator pointing to the item after i.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename T_>
+ T_ next(const T_ & i)
+ {
+ T_ result(i);
+ return ++result;
+ }
+
+ /**
+ * Return a new iterator pointing to the item before i.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename T_>
+ T_ previous(const T_ & i)
+ {
+ T_ result(i);
+ return --result;
+ }
+
+ template <typename Iter_, typename Value_>
+ class IndirectIterator;
+
+ namespace
+ {
+ /**
+ * Determine the comparison class to use for IndirectIterator.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename IterCategory_, typename Iter_, typename Value_>
+ struct Comparisons
+ {
+ /**
+ * Default to providing == and !=.
+ */
+ typedef ComparisonPolicy<IndirectIterator<Iter_, Value_>,
+ comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberTag<Iter_> > Type;
+ };
+
+ /**
+ * Determine the comparison class to use for IndirectIterator
+ * (specialisation for random access iterators).
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Iter_, typename Value_>
+ struct Comparisons<std::random_access_iterator_tag, Iter_, Value_>
+ {
+ /**
+ * Provide the full range of comparison operators.
+ */
+ typedef ComparisonPolicy<IndirectIterator<Iter_, Value_>,
+ comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<Iter_> > Type;
+ };
+ }
+
+ /**
+ * An IndirectIterator is an iterator adapter that does one additional level
+ * of dereferencing.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Iter_, typename Value_>
+ class IndirectIterator : public std::iterator<typename std::iterator_traits<Iter_>::iterator_category, Value_>,
+ public Comparisons<typename std::iterator_traits<Iter_>::iterator_category,
+ Iter_, Value_>::Type
+ {
+ private:
+ Iter_ _i;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ IndirectIterator(const Iter_ & i) :
+ Comparisons<typename std::iterator_traits<Iter_>::iterator_category, Iter_, Value_>::Type(
+ &IndirectIterator<Iter_, Value_>::_i),
+ _i(i)
+ {
+ }
+
+ IndirectIterator(const IndirectIterator & other) :
+ Comparisons<typename std::iterator_traits<Iter_>::iterator_category, Iter_, Value_>::Type(
+ &IndirectIterator<Iter_, Value_>::_i),
+ _i(other._i)
+ {
+ }
+
+ const IndirectIterator & operator= (const IndirectIterator & other)
+ {
+ _i = other._i;
+ return *this;
+ }
+
+ ///\}
+
+ ///\name Dereference operators
+ ///\{
+
+ Value_ & operator*()
+ {
+ return **_i;
+ }
+
+ Value_ * operator->()
+ {
+ return &**_i;
+ }
+
+ const Value_ & operator*() const
+ {
+ return **_i;
+ }
+
+ const Value_ * operator->() const
+ {
+ return &**_i;
+ }
+
+ ///\}
+
+ ///\name Increment, decrement operators
+ ///\{
+
+ IndirectIterator & operator++ ()
+ {
+ ++_i;
+ return *this;
+ }
+
+ IndirectIterator operator++ (int)
+ {
+ IndirectIterator tmp(*this);
+ ++_i;
+ return tmp;
+ }
+
+ ///\}
+ };
+
+ /**
+ * Convenience constructor for an IndirectIterator.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Value_, typename Iter_>
+ IndirectIterator<Iter_, Value_> indirect_iterator(const Iter_ & i)
+ {
+ return IndirectIterator<Iter_, Value_>(i);
+ }
+
+ /**
+ * A FilterInsertIterator is an insert iterator that only performs an insert
+ * if a particular predicate function returns true for the object to be
+ * inserted.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Iter_, typename Pred_>
+ class FilterInsertIterator :
+ public std::iterator<typename std::iterator_traits<Iter_>::iterator_category, void, void, void, void>
+ {
+ private:
+ Iter_ _i;
+ Pred_ _p;
+
+ public:
+ /**
+ * Fake a container_type for use with other iterator adapters.
+ */
+ typedef typename Iter_::container_type container_type;
+
+ ///\name Basic operations
+ ///\{
+
+ FilterInsertIterator(const Iter_ & i, const Pred_ & p) :
+ _i(i),
+ _p(p)
+ {
+ }
+
+ FilterInsertIterator(const FilterInsertIterator & other) :
+ _i(other._i),
+ _p(other._p)
+ {
+ }
+
+ template <typename T_>
+ const FilterInsertIterator & operator= (const T_ value)
+ {
+ if (_p(value))
+ *_i = value;
+ return *this;
+ }
+
+ ~FilterInsertIterator();
+
+ ///
+
+ ///\name Dereference operators
+ ///\{
+
+ FilterInsertIterator & operator* ()
+ {
+ return *this;
+ }
+
+ FilterInsertIterator * operator-> ()
+ {
+ return this;
+ }
+
+ ///\}
+
+ ///\name Increment, decrement operators
+ ///\{
+
+ FilterInsertIterator & operator++ ()
+ {
+ return *this;
+ }
+
+ FilterInsertIterator & operator++ (int)
+ {
+ return *this;
+ }
+
+ ///\}
+ };
+
+ template <typename Iter_, typename Pred_>
+ FilterInsertIterator<Iter_, Pred_>::~FilterInsertIterator()
+ {
+ }
+
+ /**
+ * Convenience function: make a FilterInsertIterator.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Iter_, typename Pred_>
+ FilterInsertIterator<Iter_, Pred_> filter_inserter(
+ const Iter_ & i, const Pred_ & p)
+ {
+ return FilterInsertIterator<Iter_, Pred_>(i, p);
+ }
+
+ /**
+ * A TransformInsertIterator is an insert iterator that calls some function
+ * upon an item before inserting it.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Iter_, typename Trans_>
+ class TransformInsertIterator :
+ public std::iterator<typename std::iterator_traits<Iter_>::iterator_category, void, void, void, void>
+ {
+ private:
+ Iter_ _i;
+ Trans_ _t;
+
+ public:
+ /**
+ * Fake a container_type entry to allow a TransformInsertIterator to
+ * work with other iterator adapters.
+ */
+ struct container_type
+ {
+ /// Our value type.
+ typedef typename Trans_::argument_type value_type;
+ };
+
+ ///\name Basic operations
+ ///\{
+ TransformInsertIterator(const Iter_ & i, const Trans_ & t = Trans_()) :
+ _i(i),
+ _t(t)
+ {
+ }
+
+ TransformInsertIterator(const TransformInsertIterator & other) :
+ _i(other._i),
+ _t(other._t)
+ {
+ }
+
+ template <typename T_>
+ const TransformInsertIterator & operator= (const T_ value)
+ {
+ *_i = _t(value);
+ return *this;
+ }
+
+ ///\}
+
+ ///\name Dereference operators
+ ///\{
+
+ TransformInsertIterator & operator* ()
+ {
+ return *this;
+ }
+
+ TransformInsertIterator * operator-> ()
+ {
+ return this;
+ }
+
+ ///\}
+
+ ///\name Increment, decrement operators
+ ///\{
+
+ TransformInsertIterator & operator++ ()
+ {
+ return *this;
+ }
+
+ TransformInsertIterator & operator++ (int)
+ {
+ return *this;
+ }
+
+ ///\}
+
+ };
+
+ /**
+ * Convenience function: make a TransformInsertIterator.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Iter_, typename Trans_>
+ TransformInsertIterator<Iter_, Trans_> transform_inserter(
+ const Iter_ & i, const Trans_ & t)
+ {
+ return TransformInsertIterator<Iter_, Trans_>(i, t);
+ }
+
+ /**
+ * Convenience class: select the first item of a pair.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename A_, typename B_>
+ struct SelectFirst :
+ std::unary_function<A_, std::pair<A_, B_> >
+ {
+ /// Carry out the selection.
+ A_ operator() (const std::pair<A_, B_> & p) const
+ {
+ return p.first;
+ }
+ };
+
+ /**
+ * Convenience class: select the second item of a pair.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename A_, typename B_>
+ struct SelectSecond :
+ std::unary_function<A_, std::pair<A_, B_> >
+ {
+ /// Carry out the selection.
+ A_ operator() (const std::pair<A_, B_> & p) const
+ {
+ return p.second;
+ }
+ };
+
+ /**
+ * A CreateInsertIterator is an insert iterator that creates an object of
+ * the specified type using the provided value.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Iter_, typename Type_>
+ class CreateInsertIterator :
+ public std::iterator<typename std::iterator_traits<Iter_>::iterator_category, void, void, void, void>
+ {
+ private:
+ Iter_ _i;
+
+ public:
+ /**
+ * Fake a container_type to allow us to work with other iterator
+ * adapters.
+ */
+ struct container_type
+ {
+ /// Our faked item type.
+ typedef Type_ value_type;
+ };
+
+ ///\name Basic operations
+ ///\{
+
+ CreateInsertIterator(const Iter_ & i) :
+ _i(i)
+ {
+ }
+
+ CreateInsertIterator(const CreateInsertIterator & other) :
+ _i(other._i)
+ {
+ }
+
+ template <typename T_>
+ const CreateInsertIterator & operator= (const T_ value)
+ {
+ *_i = Type_(value);
+ return *this;
+ }
+
+ ///\}
+
+ ///\name Dereference operators
+ ///\{
+
+ CreateInsertIterator & operator* ()
+ {
+ return *this;
+ }
+
+ CreateInsertIterator * operator-> ()
+ {
+ return this;
+ }
+
+ ///\}
+
+ ///\name Increment, decrement operators
+ ///\{
+
+ CreateInsertIterator & operator++ ()
+ {
+ return *this;
+ }
+
+ CreateInsertIterator & operator++ (int)
+ {
+ return *this;
+ }
+
+ ///\}
+ };
+
+ /**
+ * Convenience function: make a CreateInsertIterator.
+ *
+ * \ingroup grpiterators
+ */
+ template <typename Type_, typename Iter_>
+ CreateInsertIterator<Iter_, Type_> create_inserter(const Iter_ & i)
+ {
+ return CreateInsertIterator<Iter_, Type_>(i);
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/iterator_TEST.cc b/0.8.0/paludis/util/iterator_TEST.cc
new file mode 100644
index 000000000..83055d0ac
--- /dev/null
+++ b/0.8.0/paludis/util/iterator_TEST.cc
@@ -0,0 +1,361 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+#include <list>
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/iterator.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+#include <set>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for iterator utilities.
+ *
+ * \ingroup grptestcases
+ */
+
+namespace
+{
+ class Deleter
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ Deleter()
+ {
+ }
+
+ /**
+ * Delete an item.
+ */
+ template <typename T_>
+ void operator() (T_ t)
+ {
+ delete t;
+ }
+ };
+}
+
+namespace test_cases
+{
+ /**
+ * \test Test IndirectIterator over a vector of CountedPtr of int.
+ *
+ * \ingroup grptestcases
+ */
+ struct IndirectIteratorVecCPIntTest : TestCase
+ {
+ IndirectIteratorVecCPIntTest() : TestCase("vector<CountedPtr<int> >") { }
+
+ void run()
+ {
+ std::vector<CountedPtr<int, count_policy::ExternalCountTag> > v;
+ v.push_back(CountedPtr<int, count_policy::ExternalCountTag>(new int(5)));
+ v.push_back(CountedPtr<int, count_policy::ExternalCountTag>(new int(10)));
+ IndirectIterator<std::vector<CountedPtr<int,
+ count_policy::ExternalCountTag> >::iterator, int> vi(v.begin()), vi_end(v.end());
+ TEST_CHECK(vi != vi_end);
+ TEST_CHECK(vi < vi_end);
+ TEST_CHECK(! (vi > vi_end));
+ TEST_CHECK_EQUAL(*vi, 5);
+ TEST_CHECK(++vi != vi_end);
+ TEST_CHECK(vi < vi_end);
+ TEST_CHECK(! (vi > vi_end));
+ TEST_CHECK_EQUAL(*vi, 10);
+ TEST_CHECK(++vi == vi_end);
+ }
+ } test_indirect_iterator_vec_cp_int;
+
+ /**
+ * \test Test IndirectIterator over a list of CountedPtr of int.
+ *
+ * \ingroup grptestcases
+ */
+ struct IndirectIteratorListCPIntTest : TestCase
+ {
+ IndirectIteratorListCPIntTest() : TestCase("list<CountedPtr<int> >") { }
+
+ void run()
+ {
+ std::list<CountedPtr<int, count_policy::ExternalCountTag> > v;
+ v.push_back(CountedPtr<int, count_policy::ExternalCountTag>(new int(5)));
+ v.push_back(CountedPtr<int, count_policy::ExternalCountTag>(new int(10)));
+ IndirectIterator<std::list<CountedPtr<int,
+ count_policy::ExternalCountTag> >::iterator, int> vi(v.begin()), vi_end(v.end());
+ TEST_CHECK(vi != vi_end);
+ TEST_CHECK_EQUAL(*vi, 5);
+ TEST_CHECK(++vi != vi_end);
+ TEST_CHECK_EQUAL(*vi, 10);
+ TEST_CHECK(++vi == vi_end);
+ }
+ } test_indirect_iterator_list_cp_int;
+
+ /**
+ * \test Test IndirectIterator over a vector of int *.
+ *
+ * \ingroup grptestcases
+ */
+ struct IndirectIteratorVecPIntTest : TestCase
+ {
+ IndirectIteratorVecPIntTest() : TestCase("vector<int *>") { }
+
+ void run()
+ {
+ std::vector<int *> v;
+ v.push_back(new int(5));
+ v.push_back(new int(10));
+ IndirectIterator<std::vector<int *>::iterator, int> vi(v.begin()), vi_end(v.end());
+ TEST_CHECK(vi != vi_end);
+ TEST_CHECK(vi < vi_end);
+ TEST_CHECK(! (vi > vi_end));
+ TEST_CHECK_EQUAL(*vi, 5);
+ TEST_CHECK(++vi != vi_end);
+ TEST_CHECK(vi < vi_end);
+ TEST_CHECK(! (vi > vi_end));
+ TEST_CHECK_EQUAL(*vi, 10);
+ TEST_CHECK(++vi == vi_end);
+
+ std::for_each(v.begin(), v.end(), Deleter());
+ }
+ } test_indirect_iterator_vec_p_int;
+
+ /**
+ * \test Test IndirectIterator over a list of int *.
+ *
+ * \ingroup grptestcases
+ */
+ struct IndirectIteratorListPIntTest : TestCase
+ {
+ IndirectIteratorListPIntTest() : TestCase("list<CountedPtr<int *>") { }
+
+ void run()
+ {
+ std::list<int *> v;
+ v.push_back(new int(5));
+ v.push_back(new int(10));
+ IndirectIterator<std::list<int *>::iterator, int> vi(v.begin()), vi_end(v.end());
+ TEST_CHECK(vi != vi_end);
+ TEST_CHECK_EQUAL(*vi, 5);
+ TEST_CHECK(++vi != vi_end);
+ TEST_CHECK_EQUAL(*vi, 10);
+ TEST_CHECK(++vi == vi_end);
+
+ std::for_each(v.begin(), v.end(), Deleter());
+ }
+ } test_indirect_iterator_list_p_int;
+}
+
+#ifndef DOXYGEN
+struct Counter
+{
+ int n;
+
+ Counter() :
+ n(0)
+ {
+ }
+
+ int operator() ()
+ {
+ return n++;
+ }
+};
+
+int is_even(const int & v)
+{
+ return ! (v & 1);
+}
+#endif
+
+
+namespace test_cases
+{
+ /**
+ * \test Test FilterInsertIterator.
+ *
+ * \ingroup grptestcases
+ */
+ struct FilterInsertIteratorTest : TestCase
+ {
+ FilterInsertIteratorTest() : TestCase("filter insert iterator") { }
+
+ void run()
+ {
+ std::set<int> v;
+ std::generate_n(filter_inserter(std::inserter(v, v.begin()), std::ptr_fun(&is_even)),
+ 5, Counter());
+ TEST_CHECK_EQUAL(v.size(), 3);
+ for (int n = 0 ; n < 5 ; ++n)
+ {
+ TestMessageSuffix s("n=" + stringify(n));
+ if (is_even(n))
+ {
+ TEST_CHECK(v.end() != v.find(n));
+ TEST_CHECK_EQUAL(*v.find(n), n);
+ }
+ else
+ TEST_CHECK(v.end() == v.find(n));
+ }
+ }
+ } test_filter_insert_iterator;
+
+ /**
+ * \test Test iterator_utilities next()
+ *
+ * \ingroup grptestcases
+ */
+ struct IteratorNextTest : public TestCase
+ {
+ IteratorNextTest() : TestCase("iterator next()") { }
+
+ void run()
+ {
+ std::vector<int> v;
+ v.push_back(1);
+ v.push_back(2);
+ std::vector<int>::iterator iter(v.begin());
+
+ TEST_CHECK(*(next(iter)) == 2);
+ TEST_CHECK(next(next(iter)) == v.end());
+ iter = next(iter);
+ TEST_CHECK(++iter == v.end());
+ }
+ } test_iterator_next;
+
+ /**
+ * \test Test iterator_utilities previous()
+ *
+ * \ingroup grptestcases
+ */
+ struct IteratorpreviousTest : public TestCase
+ {
+ IteratorpreviousTest() : TestCase("iterator previous()") { }
+
+ void run()
+ {
+ std::vector<int> v;
+ v.push_back(1);
+ v.push_back(2);
+ std::vector<int>::iterator iter(v.end());
+
+ TEST_CHECK(*(previous(iter)) == 2);
+ TEST_CHECK(previous(previous(iter)) == v.begin());
+ iter = previous(iter);
+ TEST_CHECK(--iter == v.begin());
+ }
+ } test_iterator_previous;
+}
+
+#ifndef DOXYGEN
+int f(const int & v)
+{
+ return -v;
+}
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Test TransformInsertIterator.
+ *
+ * \ingroup grptestcases
+ */
+ struct TransformInsertIteratorTest : TestCase
+ {
+ TransformInsertIteratorTest() : TestCase("transform insert iterator") { }
+
+ void run()
+ {
+ std::vector<int> v;
+ std::generate_n(transform_inserter(std::back_inserter(v), std::ptr_fun(&f)),
+ 5, Counter());
+ TEST_CHECK_EQUAL(v.size(), 5);
+ for (int n = 0 ; n < 5 ; ++n)
+ {
+ TestMessageSuffix s("n=" + stringify(n));
+ TEST_CHECK_EQUAL(v.at(n), -n);
+ }
+ }
+ } test_transform_insert_iterator;
+
+ /**
+ * \test Test SelectFirst and SelectSecond.
+ *
+ * \ingroup grptestcases
+ */
+ struct SimpleSelectPairTest : TestCase
+ {
+ SimpleSelectPairTest() : TestCase("Simple SelectFirst and SelectSecond") {}
+
+ void run()
+ {
+ std::pair<int,int> p(1,2);
+ SelectFirst<int,int> f;
+ SelectSecond<int,int> s;
+
+ TEST_CHECK(f(p) == 1);
+ TEST_CHECK(s(p) == 2);
+ }
+ } test_select_pair;
+}
+
+#ifndef DOXYGEN
+struct C
+{
+ std::string s;
+
+ explicit C(const std::string & ss) :
+ s(ss)
+ {
+ }
+};
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Test create_inserter.
+ *
+ * \ingroup grptestcases
+ */
+ struct CreateInsertIteratorTest : TestCase
+ {
+ CreateInsertIteratorTest() : TestCase("create insert iterator") { }
+
+ void run()
+ {
+ std::vector<std::string> v;
+ v.push_back("one");
+ v.push_back("two");
+
+ std::vector<C> vv;
+ std::copy(v.begin(), v.end(), create_inserter<C>(std::back_inserter(vv)));
+
+ TEST_CHECK_EQUAL(vv.size(), 2);
+ TEST_CHECK_EQUAL(vv.at(0).s, "one");
+ TEST_CHECK_EQUAL(vv.at(1).s, "two");
+ }
+ } test_create_insert_iterator;
+}
diff --git a/0.8.0/paludis/util/join.hh b/0.8.0/paludis/util/join.hh
new file mode 100644
index 000000000..47d54dbb5
--- /dev/null
+++ b/0.8.0/paludis/util/join.hh
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_JOIN_HH
+#define PALUDIS_GUARD_PALUDIS_JOIN_HH 1
+
+#include <paludis/util/stringify.hh>
+#include <string>
+
+/** \file
+ * Declarations for the join function.
+ *
+ * \ingroup grpjoin
+ */
+
+namespace paludis
+{
+ /**
+ * Join together the items from i to end using joiner.
+ *
+ * \ingroup grpjoin
+ */
+ template <typename I_, typename T_>
+ T_ join(I_ i, I_ end, const T_ & joiner)
+ {
+ T_ result;
+ if (i != end)
+ while (true)
+ {
+ result += stringify(*i);
+ if (++i == end)
+ break;
+ result += joiner;
+ }
+ return result;
+ }
+
+ /**
+ * Convenience alternative join allowing a char * to be used for a
+ * string.
+ *
+ * \ingroup grpjoin
+ */
+ template <typename I_>
+ std::string join(I_ begin, const I_ end, const char * const t)
+ {
+ return join(begin, end, std::string(t));
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/join_TEST.cc b/0.8.0/paludis/util/join_TEST.cc
new file mode 100644
index 000000000..352c5cad9
--- /dev/null
+++ b/0.8.0/paludis/util/join_TEST.cc
@@ -0,0 +1,102 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <list>
+#include <paludis/util/join.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for join.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test join on a vector.
+ *
+ * \ingroup grptestcases
+ */
+ struct JoinVectorTest : TestCase
+ {
+ JoinVectorTest() : TestCase("join vector") { }
+
+ void run()
+ {
+ std::vector<std::string> v;
+ v.push_back("one");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "/"), "one");
+ v.push_back("two");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "/"), "one/two");
+ v.push_back("three");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "/"), "one/two/three");
+ }
+ } test_join_vector;
+
+ /**
+ * \test Test join on a list.
+ *
+ * \ingroup grptestcases
+ */
+ struct JoinListTest : TestCase
+ {
+ JoinListTest() : TestCase("join list") { }
+
+ void run()
+ {
+ std::list<std::string> v;
+ v.push_back("one");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "/"), "one");
+ v.push_back("two");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "/"), "one/two");
+ v.push_back("three");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "/"), "one/two/three");
+ }
+ } test_join_list;
+
+ /**
+ * \test Test join with empty things.
+ *
+ * \ingroup grptestcases
+ */
+ struct JoinEmptyTest : TestCase
+ {
+ JoinEmptyTest() : TestCase("join empty") { }
+
+ void run()
+ {
+ std::list<std::string> v;
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), ""), "");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "*"), "");
+ v.push_back("");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), ""), "");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "*"), "");
+ v.push_back("");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), ""), "");
+ TEST_CHECK_EQUAL(join(v.begin(), v.end(), "*"), "*");
+ }
+ } test_join_empty;
+}
+
diff --git a/0.8.0/paludis/util/log.cc b/0.8.0/paludis/util/log.cc
new file mode 100644
index 000000000..cbb445d11
--- /dev/null
+++ b/0.8.0/paludis/util/log.cc
@@ -0,0 +1,156 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <iostream>
+#include <paludis/util/log.hh>
+
+/** \file
+ * Implementation for Log.
+ *
+ * \ingroup grplog
+ */
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for Log.
+ *
+ * \ingroup grplog
+ */
+ template<>
+ struct Implementation<Log> :
+ InternalCounted<Implementation<Log> >
+ {
+ /// Current log level
+ LogLevel log_level;
+
+ /// Current output stream
+ std::ostream * stream;
+
+ /// Program name
+ std::string program_name;
+ };
+}
+
+Log::Log() :
+ PrivateImplementationPattern<Log>(new Implementation<Log>)
+{
+ _imp->log_level = initial_ll;
+ _imp->stream = &std::cerr;
+ _imp->program_name = "paludis";
+}
+
+Log::~Log()
+{
+}
+
+void
+Log::set_log_level(const LogLevel l)
+{
+ _imp->log_level = l;
+}
+
+LogLevel
+Log::log_level() const
+{
+ return _imp->log_level;
+}
+
+void
+Log::message(const LogLevel l, const LogContext c, const std::string & s)
+{
+ if (l >= _imp->log_level)
+ {
+ *_imp->stream << _imp->program_name << "@" << ::time(0) << ": ";
+ do
+ {
+ switch (l)
+ {
+ case ll_debug:
+ *_imp->stream << "[DEBUG] ";
+ continue;
+
+ case ll_qa:
+ *_imp->stream << "[QA] ";
+ continue;
+
+ case ll_warning:
+ *_imp->stream << "[WARNING] ";
+ continue;
+
+ case ll_silent:
+ throw InternalError(PALUDIS_HERE, "ll_silent used for a message");
+
+ case last_ll:
+ break;
+ }
+
+ throw InternalError(PALUDIS_HERE, "Bad value for log_level");
+
+ } while (false);
+
+ if (lc_context == c)
+ *_imp->stream << Context::backtrace("\n ... ") << s << std::endl;
+ else
+ *_imp->stream << s << std::endl;
+ }
+}
+
+void
+Log::set_log_stream(std::ostream * const s)
+{
+ _imp->stream = s;
+}
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const LogLevel & l)
+{
+ switch (l)
+ {
+ case ll_qa:
+ s << "qa";
+ return s;
+
+ case ll_warning:
+ s << "warning";
+ return s;
+
+ case ll_debug:
+ s << "debug";
+ return s;
+
+ case ll_silent:
+ s << "silent";
+ return s;
+
+ case last_ll:
+ ;
+ };
+
+ throw InternalError(PALUDIS_HERE, "Bad log level");
+}
+
+void
+Log::set_program_name(const std::string & s)
+{
+ _imp->program_name = s;
+}
+
diff --git a/0.8.0/paludis/util/log.hh b/0.8.0/paludis/util/log.hh
new file mode 100644
index 000000000..a1011050e
--- /dev/null
+++ b/0.8.0/paludis/util/log.hh
@@ -0,0 +1,119 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_LOG_HH
+#define PALUDIS_GUARD_PALUDIS_LOG_HH 1
+
+#include <iosfwd>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/private_implementation_pattern.hh>
+
+/** \file
+ * Declarations for Log and related classes.
+ *
+ * \ingroup grplog
+ */
+
+namespace paludis
+{
+ /**
+ * Specifies the level of a log message.
+ *
+ * Keep this in order. When deciding whether to display a message, Log
+ * uses message log level >= current log level, so it's important that
+ * least critical levels have lower numeric values.
+ *
+ * When modifying this, you will probably also want to take a look at
+ * ebuild/echo_functions.bash and the command_line source files.
+ *
+ * \ingroup grplog
+ */
+ enum LogLevel
+ {
+ ll_debug, ///< Debug message
+ ll_qa, ///< QA messages
+ ll_warning, ///< Warning message
+ ll_silent, ///< Silent (for set_log_level)
+ last_ll, ///< Number of items
+ initial_ll = ll_debug ///< Initial value
+ };
+
+ /**
+ * Specifies whether a log message has context.
+ *
+ * \ingroup grplog
+ */
+ enum LogContext
+ {
+ lc_no_context,
+ lc_context,
+ last_lc
+ };
+
+ /**
+ * Singleton class that handles log messages.
+ *
+ * \ingroup grplog
+ */
+ class PALUDIS_VISIBLE Log :
+ public InstantiationPolicy<Log, instantiation_method::SingletonAsNeededTag>,
+ private PrivateImplementationPattern<Log>
+ {
+ friend class InstantiationPolicy<Log, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ Log();
+
+ public:
+ /**
+ * Destructor, to be called only by our InstantiationPolicy.
+ */
+ ~Log();
+
+ /**
+ * Only display messages of at least this level.
+ */
+ void set_log_level(const LogLevel);
+
+ /**
+ * Fetch the current log level.
+ */
+ LogLevel log_level() const;
+
+ /**
+ * Log a message at the specified level.
+ */
+ void message(const LogLevel, const LogContext, const std::string &);
+
+ /**
+ * Change the log stream.
+ */
+ void set_log_stream(std::ostream * const);
+
+ /**
+ * Set our program name.
+ */
+ void set_program_name(const std::string &);
+ };
+
+ std::ostream &
+ operator<< (std::ostream &, const LogLevel &) PALUDIS_VISIBLE;
+}
+
+#endif
diff --git a/0.8.0/paludis/util/log_TEST.cc b/0.8.0/paludis/util/log_TEST.cc
new file mode 100644
index 000000000..608fa37f9
--- /dev/null
+++ b/0.8.0/paludis/util/log_TEST.cc
@@ -0,0 +1,74 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/log.hh>
+#include <sstream>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+/** \file
+ * Test cases for Log.
+ *
+ * \ingroup grptestcases
+ */
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ /**
+ * \test Test Log.
+ *
+ * \ingroup grptestcases
+ */
+ struct LogTest : TestCase
+ {
+ LogTest() : TestCase("log") { }
+
+ void run()
+ {
+ TEST_CHECK(Log::get_instance());
+ TEST_CHECK(Log::get_instance() == Log::get_instance());
+
+ std::stringstream s;
+ Log::get_instance()->set_log_stream(&s);
+ Log::get_instance()->set_log_level(ll_debug);
+
+ TEST_CHECK(s.str().empty());
+ Log::get_instance()->message(ll_debug, lc_no_context, "one");
+ TEST_CHECK(! s.str().empty());
+ TEST_CHECK(std::string::npos != s.str().find("one"));
+
+ std::stringstream t;
+ Log::get_instance()->set_log_stream(&t);
+ TEST_CHECK(t.str().empty());
+
+ Log::get_instance()->set_log_level(ll_warning);
+ Log::get_instance()->message(ll_debug, lc_no_context, "two");
+ TEST_CHECK(t.str().empty());
+ Log::get_instance()->message(ll_warning, lc_no_context, "three");
+ TEST_CHECK(! t.str().empty());
+ TEST_CHECK(std::string::npos == t.str().find("one"));
+ TEST_CHECK(std::string::npos == t.str().find("two"));
+ TEST_CHECK(std::string::npos != t.str().find("three"));
+ }
+ } test_log;
+}
+
diff --git a/0.8.0/paludis/util/pipe.cc b/0.8.0/paludis/util/pipe.cc
new file mode 100644
index 000000000..7cb714e97
--- /dev/null
+++ b/0.8.0/paludis/util/pipe.cc
@@ -0,0 +1,37 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "pipe.hh"
+#include <paludis/util/exception.hh>
+#include <unistd.h>
+
+using namespace paludis;
+
+Pipe::Pipe()
+{
+ if (-1 == pipe(_fds))
+ throw InternalError(PALUDIS_HERE, "pipe(2) failed");
+}
+
+Pipe::~Pipe()
+{
+ close(_fds[0]);
+ close(_fds[1]);
+}
+
diff --git a/0.8.0/paludis/util/pipe.hh b/0.8.0/paludis/util/pipe.hh
new file mode 100644
index 000000000..048f9fa89
--- /dev/null
+++ b/0.8.0/paludis/util/pipe.hh
@@ -0,0 +1,72 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_PIPE_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_PIPE_HH 1
+
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declaration for the Pipe class.
+ *
+ * \ingroup grppipe
+ */
+
+namespace paludis
+{
+ /**
+ * Wrapper around pipe file descriptors.
+ *
+ * \ingroup grppipe
+ */
+ class PALUDIS_VISIBLE Pipe :
+ InstantiationPolicy<Pipe, instantiation_method::NonCopyableTag>
+ {
+ private:
+ int _fds[2];
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ Pipe();
+
+ ~Pipe();
+
+ ///\}
+
+ ///\name File descriptors
+ ///\{
+
+ int read_fd() const
+ {
+ return _fds[0];
+ }
+
+ int write_fd() const
+ {
+ return _fds[1];
+ }
+
+ ///\}
+ };
+
+}
+
+#endif
diff --git a/0.8.0/paludis/util/private_implementation_pattern.hh b/0.8.0/paludis/util/private_implementation_pattern.hh
new file mode 100644
index 000000000..5546fae99
--- /dev/null
+++ b/0.8.0/paludis/util/private_implementation_pattern.hh
@@ -0,0 +1,70 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_PRIVATE_IMPLEMENTATION_PATTERN_HH
+#define PALUDIS_GUARD_PALUDIS_PRIVATE_IMPLEMENTATION_PATTERN_HH 1
+
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declarations for the PrivateImplementationPattern pattern.
+ *
+ * \ingroup grppimp
+ */
+
+namespace paludis
+{
+ /**
+ * Private implementation data, to be specialised for any class that
+ * uses PrivateImplementationPattern.
+ *
+ * \ingroup grppimp
+ */
+ template <typename C_>
+ struct Implementation;
+
+ /**
+ * A class descended from PrivateImplementationPattern has an associated
+ * Implementation instance.
+ *
+ * \ingroup grppimp
+ */
+ template <typename C_>
+ class PrivateImplementationPattern :
+ private InstantiationPolicy<PrivateImplementationPattern<C_>, instantiation_method::NonCopyableTag>
+ {
+ protected:
+ /**
+ * Pointer to our implementation data.
+ */
+ CountedPtr<Implementation<C_>, count_policy::InternalCountTag> _imp;
+
+ public:
+ /**
+ * Constructor.
+ */
+ explicit PrivateImplementationPattern(Implementation<C_> * i) :
+ _imp(i)
+ {
+ }
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/pstream.cc b/0.8.0/paludis/util/pstream.cc
new file mode 100644
index 000000000..8c4ef3a85
--- /dev/null
+++ b/0.8.0/paludis/util/pstream.cc
@@ -0,0 +1,141 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/log.hh>
+#include <paludis/util/pstream.hh>
+
+#include <cstring>
+#include <errno.h>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/** \file
+ * Implementation for PStream.
+ *
+ * \ingroup grpsystem
+ */
+
+using namespace paludis;
+
+PStreamError::PStreamError(const std::string & our_message) throw () :
+ Exception(our_message)
+{
+}
+
+PStreamInBuf::int_type
+PStreamInBuf::underflow()
+{
+ if (gptr() < egptr())
+ return *gptr();
+
+ int num_putback = gptr() - eback();
+ if (num_putback > putback_size)
+ num_putback = putback_size;
+ std::memmove(buffer + putback_size - num_putback,
+ gptr() - num_putback, num_putback);
+
+ ssize_t n = read(fd, buffer + putback_size, buffer_size - putback_size);
+ if (n <= 0)
+ return EOF;
+
+ setg(buffer + putback_size - num_putback, buffer + putback_size,
+ buffer + putback_size + n);
+
+ return *gptr();
+}
+
+PStreamInBuf::PStreamInBuf(const std::string & cmd) :
+ _command(cmd),
+ child(fork())
+{
+ if (0 == child)
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "dup2 " +
+ stringify(stdout_pipe.write_fd()) + " 1");
+ if (-1 == dup2(stdout_pipe.write_fd(), 1))
+ throw PStreamError("dup2 failed");
+ close(stdout_pipe.read_fd());
+
+ if (-1 != PStream::stderr_fd)
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "dup2 " +
+ stringify(PStream::stderr_fd) + " 2");
+
+ if (-1 == dup2(PStream::stderr_fd, 2))
+ throw PStreamError("dup2 failed");
+
+ if (-1 != PStream::stderr_close_fd)
+ close(PStream::stderr_close_fd);
+ }
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + cmd);
+ execl("/bin/sh", "sh", "-c", cmd.c_str(), static_cast<char *>(0));
+ throw PStreamError("execl /bin/sh -c '" + cmd + "' failed:"
+ + stringify(strerror(errno)));
+ }
+ else if (-1 == child)
+ throw PStreamError("fork failed: " + stringify(strerror(errno)));
+ else
+ {
+ close(stdout_pipe.write_fd());
+ fd = stdout_pipe.read_fd();
+ }
+
+ setg(buffer + putback_size, buffer + putback_size, buffer + putback_size);
+}
+
+PStreamInBuf::~PStreamInBuf()
+{
+ if (0 != fd)
+ {
+ int fdn(fd), x;
+ waitpid(child, &x, 0);
+ Log::get_instance()->message(ll_debug, lc_no_context,
+ "pclose " + stringify(fdn) + " -> " + stringify(x));
+ }
+}
+
+int
+PStreamInBuf::exit_status()
+{
+ if (0 != fd)
+ {
+ int fdn(fd);
+ waitpid(child, &_exit_status, 0);
+ fd = 0;
+ Log::get_instance()->message(ll_debug, lc_no_context,
+ "manual pclose " + stringify(fdn) + " -> " + stringify(_exit_status));
+ }
+ return _exit_status;
+}
+
+void
+PStream::set_stderr_fd(const int fd, const int fd2)
+{
+ _stderr_fd = fd;
+ _stderr_close_fd = fd2;
+}
+
+int PStream::_stderr_fd(-1);
+const int & PStream::stderr_fd(_stderr_fd);
+
+int PStream::_stderr_close_fd(-1);
+const int & PStream::stderr_close_fd(_stderr_close_fd);
+
diff --git a/0.8.0/paludis/util/pstream.hh b/0.8.0/paludis/util/pstream.hh
new file mode 100644
index 000000000..035eb189d
--- /dev/null
+++ b/0.8.0/paludis/util/pstream.hh
@@ -0,0 +1,228 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_PSTREAM_HH
+#define PALUDIS_GUARD_PALUDIS_PSTREAM_HH 1
+
+#include <cstdio>
+#include <istream>
+#include <limits>
+#include <paludis/util/exception.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/pipe.hh>
+#include <streambuf>
+#include <string>
+
+/** \file
+ * Declarations for the PStream and PStreamInBuf classes, and related
+ * utilities.
+ *
+ * \ingroup grpsystem
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if a PStream or PStreamInBuf encounters an error.
+ *
+ * \ingroup grpsystem
+ * \ingroup grpexceptions
+ */
+ class PALUDIS_VISIBLE PStreamError :
+ public Exception
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ PStreamError(const std::string & message) throw ();
+
+ ///\}
+ };
+
+ /**
+ * Input buffer class for a process, invoked using popen(3).
+ *
+ * Bidirectional I/O isn't supported since we haven't needed it yet, and
+ * because popen on Linux is unidirectional.
+ *
+ * See \ref TCppSL Ch. 13.13 for what we're doing here. The buffer code is
+ * based upon the "io/inbuf1.hpp" example in section 13.13.3.
+ *
+ * \ingroup grpsystem
+ */
+ class PALUDIS_VISIBLE PStreamInBuf :
+ public std::streambuf,
+ private InstantiationPolicy<PStreamInBuf, instantiation_method::NonCopyableTag>
+ {
+ private:
+ Pipe stdout_pipe;
+
+ const std::string _command;
+
+ int _exit_status;
+
+ pid_t child;
+
+ protected:
+ /**
+ * Our file descriptor.
+ */
+ int fd;
+
+ /**
+ * At most how many characters can we put back?
+ */
+ static const int putback_size = std::numeric_limits<unsigned>::digits >> 3;
+
+ /**
+ * How large is our internal buffer?
+ */
+ static const int buffer_size = 3 * putback_size;
+
+ /**
+ * Internal buffer.
+ */
+ char buffer[buffer_size];
+
+ /**
+ * Called when an underflow occurs.
+ */
+ virtual int_type underflow();
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ /**
+ * Constructor.
+ *
+ * \param command The command to run. See PStream for discussion.
+ */
+ PStreamInBuf(const std::string & command);
+
+ ~PStreamInBuf();
+
+ ///\}
+
+ /**
+ * What was our command?
+ */
+ const std::string & command() const
+ {
+ return _command;
+ }
+
+ /**
+ * What is our exit status?
+ */
+ int exit_status();
+ };
+
+ /**
+ * For internal use by PStream classes.
+ *
+ * \ingroup grpsystem
+ */
+ namespace pstream_internals
+ {
+ /**
+ * Avoid base from member issues for PStream.
+ *
+ * \ingroup grpsystem
+ */
+ struct PALUDIS_VISIBLE PStreamInBufBase :
+ private paludis::InstantiationPolicy<PStreamInBufBase, instantiation_method::NonCopyableTag>
+ {
+ /**
+ * Our buffer.
+ */
+ PStreamInBuf buf;
+
+ /**
+ * Constructor.
+ */
+ PStreamInBufBase(const std::string & command) :
+ buf(command)
+ {
+ }
+ };
+ }
+
+ /**
+ * A PStream class is a standard input stream class whose contents comes
+ * from the output of an executed command.
+ *
+ * \ingroup grpsystem
+ */
+ class PALUDIS_VISIBLE PStream :
+ private InstantiationPolicy<PStream, instantiation_method::NonCopyableTag>,
+ protected pstream_internals::PStreamInBufBase,
+ public std::istream
+ {
+ private:
+ static int _stderr_fd;
+ static int _stderr_close_fd;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ /**
+ * Constructor.
+ *
+ * \param command The command to execute. PATH is used, so there is
+ * usually no need to specify a full path. Arguments can be passed
+ * as part of the command.
+ */
+ PStream(const std::string & command) :
+ PStreamInBufBase(command),
+ std::istream(&buf)
+ {
+ }
+
+ ///\}
+
+ /**
+ * What is our exit status?
+ */
+ int exit_status()
+ {
+ return buf.exit_status();
+ }
+
+ /**
+ * Set a file descriptors to use for stderr and close on stderr
+ * (for all PStream instances).
+ */
+ static void set_stderr_fd(const int, const int);
+
+ /**
+ * File descriptor to use for stderr.
+ */
+ static const int & stderr_fd;
+
+ /**
+ * File descriptor to close for stderr.
+ */
+ static const int & stderr_close_fd;
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/pstream_TEST.cc b/0.8.0/paludis/util/pstream_TEST.cc
new file mode 100644
index 000000000..2f943cc00
--- /dev/null
+++ b/0.8.0/paludis/util/pstream_TEST.cc
@@ -0,0 +1,111 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/pstream.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Tests for PStream.
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test PStream on a normal command.
+ *
+ * \ingroup grptestcases
+ */
+ struct PStreamTest : TestCase
+ {
+ PStreamTest() : TestCase("pstream") { }
+
+ void run()
+ {
+ PStream * p;
+ TEST_CHECK((p = new PStream("echo hi")));
+ std::string line;
+ TEST_CHECK(std::getline(*p, line));
+ TEST_CHECK_EQUAL(line, "hi");
+ TEST_CHECK(! std::getline(*p, line));
+ TEST_CHECK_EQUAL(p->exit_status(), 0);
+ delete p;
+ }
+ } test_pstream;
+
+ /**
+ * \test Test PStream on a command that doesn't exist.
+ *
+ * \ingroup grptestcases
+ */
+ struct PStreamNoExistTest : TestCase
+ {
+ PStreamNoExistTest() : TestCase("pstream nonexistent command") { }
+
+ void run()
+ {
+ PStream p("thiscommanddoesnotexist 2>/dev/null");
+ TEST_CHECK(p.exit_status() != 0);
+ }
+ } test_pstream_no_exist;
+
+ /**
+ * \test Test PStream on a command that returns a failure with no output.
+ *
+ * \ingroup grptestcases
+ */
+ struct PStreamSilentFailTest : TestCase
+ {
+ PStreamSilentFailTest() : TestCase("pstream silent fail") { }
+
+ void run()
+ {
+ PStream p("test -e /doesnotexist");
+ TEST_CHECK(p.exit_status() != 0);
+ }
+ } test_pstream_silent_fail;
+
+ /**
+ * \test Test PStream on a command that fails with output.
+ *
+ * \ingroup grptestcases
+ */
+ struct PStreamFailTest : TestCase
+ {
+ PStreamFailTest() : TestCase("pstream fail") { }
+
+ void run()
+ {
+ PStream * p;
+ TEST_CHECK((p = new PStream("cat /doesnotexist 2>&1")));
+ std::string line;
+ TEST_CHECK(std::getline(*p, line));
+ TEST_CHECK(! line.empty());
+ TEST_CHECK(! std::getline(*p, line));
+ TEST_CHECK(p->exit_status() != 0);
+ delete p;
+ }
+ } test_pstream_fail;
+}
+
diff --git a/0.8.0/paludis/util/random.cc b/0.8.0/paludis/util/random.cc
new file mode 100644
index 000000000..5fbb8b0f9
--- /dev/null
+++ b/0.8.0/paludis/util/random.cc
@@ -0,0 +1,43 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "random.hh"
+#include <time.h>
+
+/** \file
+ * Implementation for random.hh.
+ *
+ * \ingroup grprandom
+ */
+
+using namespace paludis;
+
+uint32_t Random::global_seed(0xdeadbeef ^ ::time(0));
+
+Random::Random(uint32_t seed) :
+ local_seed(seed)
+{
+}
+
+Random::Random() :
+ local_seed(global_seed ^ ((::time(0) >> 16) | (::time(0) << 16)))
+{
+ global_seed += local_seed;
+}
+
diff --git a/0.8.0/paludis/util/random.hh b/0.8.0/paludis/util/random.hh
new file mode 100644
index 000000000..38a67f60e
--- /dev/null
+++ b/0.8.0/paludis/util/random.hh
@@ -0,0 +1,71 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_RANDOM_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_RANDOM_HH 1
+
+#include <cstdlib>
+#include <inttypes.h>
+#include <paludis/util/attributes.hh>
+
+namespace paludis
+{
+ /**
+ * A basic random number generator class, which is not suitable for
+ * cryptography but is fast and reasonably pseudorandom.
+ *
+ * See \ref TCppPL 22.7 for justification. See \ref TaoCP2 3.2.1 for the
+ * basic algorithm and \ref AppCrypt 16.1 for the choice of numbers.
+ *
+ * \ingroup grprandom
+ */
+ class PALUDIS_VISIBLE Random
+ {
+ private:
+ static uint32_t global_seed;
+ uint32_t local_seed;
+
+ static const uint32_t _a = 2416;
+ static const uint32_t _b = 374441;
+ static const uint32_t _m = 1771875;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ /// Constructor, with a seed.
+ Random(uint32_t seed);
+
+ /// Constructor, with a magic random seed.
+ Random();
+
+ ///\}
+
+ /// Fetch a random number in (0, max]
+ template <typename DiffType_>
+ DiffType_ operator() (DiffType_ max)
+ {
+ local_seed = (_a * local_seed + _b) % _m;
+ double t(static_cast<double>(local_seed) / static_cast<double>(_m));
+ return static_cast<DiffType_>(t * max);
+ }
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/random_TEST.cc b/0.8.0/paludis/util/random_TEST.cc
new file mode 100644
index 000000000..8188cbb84
--- /dev/null
+++ b/0.8.0/paludis/util/random_TEST.cc
@@ -0,0 +1,121 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "random.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+#include <algorithm>
+
+/** \file
+ * Test cases for paludis::Random.
+ *
+ * \ingroup grptestcases
+ */
+
+using namespace paludis;
+using namespace test;
+
+namespace
+{
+ struct RandomUpTo
+ {
+ Random random;
+ unsigned max;
+
+ RandomUpTo(const Random & r, const unsigned m) :
+ random(r),
+ max(m)
+ {
+ }
+
+ int operator() ()
+ {
+ return random(max);
+ }
+ };
+
+ inline double square(double v)
+ {
+ return v * v;
+ }
+}
+
+namespace test_cases
+{
+ /**
+ * \test Test Random distibutions using counts.
+ *
+ * \ingroup grptestcases
+ */
+ struct RandomDistributionCountsTest : TestCase
+ {
+ RandomDistributionCountsTest() : TestCase("distribution (counts)") { }
+
+ void run()
+ {
+ std::vector<int> v;
+ v.reserve(10000);
+ std::generate_n(std::back_inserter(v), 10000, RandomUpTo(Random(), 10));
+
+ TEST_CHECK_EQUAL(0, *std::min_element(v.begin(), v.end()));
+ TEST_CHECK_EQUAL(9, *std::max_element(v.begin(), v.end()));
+ for (int i(0) ; i < 10 ; ++i)
+ {
+ TEST_CHECK(std::count(v.begin(), v.end(), i) > 1);
+ TEST_CHECK(std::count(v.begin(), v.end(), i) < 3000);
+ }
+ }
+ } test_random_counts;
+
+ /**
+ * \test Test Random distibutions using chi square.
+ *
+ * This is a chi square test, so it could theoretically fail
+ * occasionally. See \ref TaoCP2 3.3.1 for details.
+ */
+ struct RandomDistributionChiSquaredTest : TestCase
+ {
+ RandomDistributionChiSquaredTest() : TestCase("distribution (chi square)") { }
+
+ void run()
+ {
+ int failures(0);
+
+ for (int attempts(0) ; attempts < 3 ; ++ attempts)
+ {
+ std::vector<int> v;
+ v.reserve(10000);
+ std::generate_n(std::back_inserter(v), 10000, RandomUpTo(Random(), 10));
+
+ double a(0);
+ for (int i(0) ; i <= 9 ; ++i)
+ a += (square(std::count(v.begin(), v.end(), i) - (10000 / 10)) / (10000 / 10));
+
+ TestMessageSuffix suffix("a=" + stringify(a), true);
+ TEST_CHECK(true);
+ if ((a < 2.088) || (a > 21.67))
+ ++failures;
+ }
+
+ TEST_CHECK(failures <= 1);
+ }
+ } test_random_chi_square;
+}
+
diff --git a/0.8.0/paludis/util/save.hh b/0.8.0/paludis/util/save.hh
new file mode 100644
index 000000000..d9005c7d7
--- /dev/null
+++ b/0.8.0/paludis/util/save.hh
@@ -0,0 +1,83 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_SAVE_HH
+#define PALUDIS_GUARD_PALUDIS_SAVE_HH 1
+
+#include <paludis/util/instantiation_policy.hh>
+
+/** \file
+ * Declarations for the Save class.
+ *
+ * \ingroup grpsave
+ */
+
+namespace paludis
+{
+ /**
+ * Save the value of a particular variable and assign it a new value for the
+ * duration of the Save instance's lifetime (RAII, see \ref EffCpp item 13 or
+ * \ref TCppPL section 14.4).
+ *
+ * \ingroup grpsave
+ */
+ template <typename T_>
+ class Save :
+ private InstantiationPolicy<Save<T_>, instantiation_method::NonCopyableTag>
+ {
+ private:
+ T_ * const _ptr;
+ const T_ _value;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ /**
+ * Constructor.
+ */
+ Save(T_ * const p) :
+ _ptr(p),
+ _value(*p)
+ {
+ }
+
+ /**
+ * Constructor, with convenience assignment to new_value.
+ */
+ Save(T_ * const p, const T_ & new_value) :
+ _ptr(p),
+ _value(*p)
+ {
+ *p = new_value;
+ }
+
+ /**
+ * Destructor.
+ */
+ ~Save()
+ {
+ *_ptr = _value;
+ }
+
+ ///\}
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/save_TEST.cc b/0.8.0/paludis/util/save_TEST.cc
new file mode 100644
index 000000000..362b671f0
--- /dev/null
+++ b/0.8.0/paludis/util/save_TEST.cc
@@ -0,0 +1,68 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/save.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for save.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test Save.
+ *
+ * \ingroup grptestcases
+ */
+ struct SaveTest : TestCase
+ {
+ SaveTest() : TestCase("save") { }
+
+ void run()
+ {
+ std::string s("one");
+ TEST_CHECK_EQUAL(s, "one");
+ {
+ Save<std::string> save_s(&s);
+ TEST_CHECK_EQUAL(s, "one");
+ s = "two";
+ TEST_CHECK_EQUAL(s, "two");
+ }
+ TEST_CHECK_EQUAL(s, "one");
+ {
+ Save<std::string> save_s(&s, "three");
+ TEST_CHECK_EQUAL(s, "three");
+ {
+ Save<std::string> save_s_2(&s, "four");
+ TEST_CHECK_EQUAL(s, "four");
+ }
+ TEST_CHECK_EQUAL(s, "three");
+ }
+ TEST_CHECK_EQUAL(s, "one");
+ }
+ } test_save;
+}
+
diff --git a/0.8.0/paludis/util/sr.hh b/0.8.0/paludis/util/sr.hh
new file mode 100644
index 000000000..7f41fb6ce
--- /dev/null
+++ b/0.8.0/paludis/util/sr.hh
@@ -0,0 +1,45 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_SR_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_SR_HH 1
+
+namespace paludis
+{
+ struct Empty
+ {
+ };
+
+ template <bool value_, typename IfTrue_, typename IfFalse_>
+ struct Select;
+
+ template <typename IfTrue_, typename IfFalse_>
+ struct Select<true, IfTrue_, IfFalse_>
+ {
+ typedef IfTrue_ Type;
+ };
+
+ template <typename IfTrue_, typename IfFalse_>
+ struct Select<false, IfTrue_, IfFalse_>
+ {
+ typedef IfFalse_ Type;
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/stringify.hh b/0.8.0/paludis/util/stringify.hh
new file mode 100644
index 000000000..807a0ac0b
--- /dev/null
+++ b/0.8.0/paludis/util/stringify.hh
@@ -0,0 +1,168 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_STRINGIFY_HH
+#define PALUDIS_GUARD_PALUDIS_STRINGIFY_HH 1
+
+#include <sstream>
+#include <string>
+#include <paludis/util/attributes.hh>
+
+/** \file
+ * Stringify functions.
+ *
+ * \ingroup grpstringify
+ */
+
+namespace paludis
+{
+ template <typename T_, typename U_>
+ class CountedPtr;
+
+ /**
+ * For use by stringify.
+ *
+ * \ingroup grpstringify
+ */
+ namespace stringify_internals
+ {
+ /**
+ * Check that T_ is a sane type to be stringified.
+ *
+ * \ingroup grpstringify
+ */
+ template <typename T_>
+ struct CheckType
+ {
+ /// Yes, we are a sane type.
+ enum { value = 0 } Value;
+ };
+
+ /**
+ * Check that T_ is a sane type to be stringified, which it isn't
+ * if it's a pointer unless it's a char * pointer.
+ *
+ * \ingroup grpstringify
+ */
+ template <typename T_>
+ struct CheckType<T_ *>
+ {
+ };
+
+ /**
+ * Check that T_ is a sane type to be stringified, which it isn't
+ * if it's a CountedPtr.
+ *
+ * \ingroup grpstringify
+ */
+ template <typename T_, typename U_>
+ struct CheckType<CountedPtr<T_, U_> >
+ {
+ };
+
+ /**
+ * Check that T_ is a sane type to be stringified, which it isn't
+ * if it's a pointer unless it's a char * pointer.
+ *
+ * \ingroup grpstringify
+ */
+ template <>
+ struct CheckType<char *>
+ {
+ /// Yes, we are a sane type.
+ enum { value = 0 } Value;
+ };
+ }
+
+ /**
+ * Convert item to a string.
+ *
+ * \ingroup grpstringify
+ */
+ template <typename T_>
+ std::string
+ stringify(const T_ & item)
+ {
+ /* check that we're not trying to stringify a pointer or somesuch */
+ int check_for_stringifying_silly_things
+ PALUDIS_ATTRIBUTE((unused)) = stringify_internals::CheckType<T_>::value;
+
+ std::ostringstream s;
+ s << item;
+ return s.str();
+ }
+
+ /**
+ * Convert item to a string (overload for std::string).
+ *
+ * \ingroup grpstringify
+ */
+ inline std::string
+ stringify(const std::string & item)
+ {
+ return item;
+ }
+
+ /**
+ * Convert item to a string (overload for char).
+ *
+ * \ingroup grpstringify
+ */
+ inline std::string
+ stringify(const char & item)
+ {
+ return std::string(1, item);
+ }
+
+ /**
+ * Convert item to a string (overload for unsigned char).
+ *
+ * \ingroup grpstringify
+ */
+ inline std::string
+ stringify(const unsigned char & item)
+ {
+ return std::string(1, item);
+ }
+
+ /**
+ * Convert item to a string (overload for bool).
+ *
+ * \ingroup grpstringify
+ */
+ inline std::string
+ stringify(const bool & item)
+ {
+ return item ? "true" : "false";
+ }
+
+ /**
+ * Convert item to a string (overload for char *, which isn't a
+ * screwup like other pointers).
+ *
+ * \ingroup grpstringify
+ */
+ inline std::string
+ stringify(const char * const item)
+ {
+ return std::string(item);
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/stringify_TEST.cc b/0.8.0/paludis/util/stringify_TEST.cc
new file mode 100644
index 000000000..b97c4df21
--- /dev/null
+++ b/0.8.0/paludis/util/stringify_TEST.cc
@@ -0,0 +1,129 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/stringify.hh>
+#include <string>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for stringify.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /** \test
+ * Test stringify on int.
+ *
+ * \ingroup grptestcases
+ */
+ struct StringifyIntTests : TestCase
+ {
+ StringifyIntTests() : TestCase("stringify int") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(stringify(0), "0");
+ TEST_CHECK_EQUAL(stringify(1), "1");
+ TEST_CHECK_EQUAL(stringify(99), "99");
+ TEST_CHECK_EQUAL(stringify(-99), "-99");
+ TEST_CHECK_EQUAL(stringify(12345), "12345");
+ }
+ } test_case_stringify_int;
+
+ /** \test
+ * Test stringify on char *.
+ *
+ * \ingroup grptestcases
+ */
+ struct StringifyCharStarTests : TestCase
+ {
+ StringifyCharStarTests() : TestCase("stringify char *") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(stringify("moo"), std::string("moo"));
+ TEST_CHECK_EQUAL(stringify(""), std::string(""));
+ TEST_CHECK(stringify("").empty());
+ TEST_CHECK_EQUAL(stringify(" quack quack "), std::string(" quack quack "));
+ }
+ } test_case_stringify_char_star;
+
+ /** \test
+ * Test stringify on std::string.
+ *
+ * \ingroup grptestcases
+ */
+ struct StringifyStringTests : TestCase
+ {
+ StringifyStringTests() : TestCase("stringify string") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(stringify(std::string("moo")), std::string("moo"));
+ TEST_CHECK_EQUAL(stringify(std::string("")), std::string(""));
+ TEST_CHECK(stringify(std::string("")).empty());
+ TEST_CHECK_EQUAL(stringify(std::string(" quack quack ")), std::string(" quack quack "));
+ }
+ } test_case_stringify_string;
+
+ /** \test
+ * Test stringify on char.
+ *
+ * \ingroup grptestcases
+ */
+ struct StringifyCharTests : TestCase
+ {
+ StringifyCharTests() : TestCase("stringify char") { }
+
+ void run()
+ {
+ char c('a');
+ TEST_CHECK_EQUAL(stringify(c), std::string("a"));
+
+ unsigned char u('a');
+ TEST_CHECK_EQUAL(stringify(u), std::string("a"));
+
+ signed char s('a');
+ TEST_CHECK_EQUAL(stringify(s), std::string("a"));
+ }
+ } test_case_stringify_char;
+
+ /** \test
+ * Test stringify on bool.
+ *
+ * \ingroup grptestcases
+ */
+ struct StringifyBoolTests : TestCase
+ {
+ StringifyBoolTests() : TestCase("stringify bool") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(stringify(true), std::string("true"));
+ TEST_CHECK_EQUAL(stringify(false), std::string("false"));
+ }
+ } test_case_stringify_bool;
+}
+
diff --git a/0.8.0/paludis/util/strip.cc b/0.8.0/paludis/util/strip.cc
new file mode 100644
index 000000000..9259030b2
--- /dev/null
+++ b/0.8.0/paludis/util/strip.cc
@@ -0,0 +1,100 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/exception.hh>
+#include <paludis/util/strip.hh>
+#include <paludis/util/stringify.hh>
+
+/** \file
+ * Implementation of strip things.
+ *
+ * \ingroup grpstrippers
+ */
+
+namespace paludis
+{
+ std::string strip_leading_string(const std::string & s, const std::string & prefix)
+ {
+ try
+ {
+ if (0 == s.compare(0, prefix.length(), prefix))
+ return s.substr(prefix.length());
+ else
+ return s;
+ }
+ catch (const std::exception & e)
+ {
+ throw InternalError(PALUDIS_HERE, "Caught unexpected exception " +
+ stringify(e.what()));
+ }
+ }
+
+ std::string strip_leading(const std::string & s, const std::string & remove)
+ {
+ try
+ {
+ std::string::size_type p(s.find_first_not_of(remove));
+ if (std::string::npos == p)
+ return std::string();
+ else
+ return s.substr(p);
+ }
+ catch (const std::exception & e)
+ {
+ throw InternalError(PALUDIS_HERE, "Caught unexpected exception " +
+ stringify(e.what()));
+ }
+ }
+
+ std::string strip_trailing_string(const std::string & s, const std::string & suffix)
+ {
+ try
+ {
+ if (suffix.length() > s.length())
+ return s;
+ else if (0 == s.compare(s.length() - suffix.length(), suffix.length(), suffix))
+ return s.substr(0, s.length() - suffix.length());
+ else
+ return s;
+ }
+ catch (const std::exception & e)
+ {
+ throw InternalError(PALUDIS_HERE, "Caught unexpected exception " +
+ stringify(e.what()) + " with s='" + s + "', suffix='" + suffix + "'");
+ }
+ }
+
+ std::string strip_trailing(const std::string & s, const std::string & remove)
+ {
+ try
+ {
+ std::string::size_type p(s.find_last_not_of(remove));
+ if (std::string::npos == p)
+ return std::string();
+ else
+ return s.substr(0, p + 1);
+ }
+ catch (const std::exception & e)
+ {
+ throw InternalError(PALUDIS_HERE, "Caught unexpected exception " +
+ stringify(e.what()));
+ }
+ }
+}
+
diff --git a/0.8.0/paludis/util/strip.hh b/0.8.0/paludis/util/strip.hh
new file mode 100644
index 000000000..6a3790a6e
--- /dev/null
+++ b/0.8.0/paludis/util/strip.hh
@@ -0,0 +1,130 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_STRIP_HH
+#define PALUDIS_GUARD_PALUDIS_STRIP_HH 1
+
+#include <functional>
+#include <string>
+#include <paludis/util/attributes.hh>
+
+/** \file
+ * Strip functions and adapters.
+ *
+ * \ingroup grpstrippers
+ */
+
+namespace paludis
+{
+ /**
+ * Return a string equal to s minus any leading characters that are
+ * contained in prefix.
+ *
+ * \ingroup grpstrippers
+ */
+ std::string strip_leading_string(const std::string & s, const std::string & prefix) PALUDIS_VISIBLE;
+
+ /**
+ * Return a string equal to s, minus the string remove if remove occurs at
+ * the start of s.
+ *
+ * \ingroup grpstrippers
+ */
+ std::string strip_leading(const std::string & s, const std::string & remove) PALUDIS_VISIBLE;
+
+ /**
+ * Return a string equal to s minus any trailing characters that are
+ * contained in suffix.
+ *
+ * \ingroup grpstrippers
+ */
+ std::string strip_trailing_string(const std::string & s, const std::string & suffix) PALUDIS_VISIBLE;
+
+ /**
+ * Return a string equal to s, minus the string remove if remove occurs at
+ * the end of s.
+ *
+ * \ingroup grpstrippers
+ */
+ std::string strip_trailing(const std::string & s, const std::string & remove) PALUDIS_VISIBLE;
+
+ /**
+ * Adapt one of the strip_ functions for use as a std::unary_function by
+ * binding a value to the second parameter (avoids the reference to const
+ * issue with std::bind2nd).
+ *
+ * \ingroup grpstrippers
+ */
+ template <std::string (* f_)(const std::string &, const std::string &)>
+ class StripAdapter :
+ public std::unary_function<std::string, const std::string>
+ {
+ private:
+ const std::string _second;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ StripAdapter(const std::string & second) :
+ _second(second)
+ {
+ }
+
+ ///\}
+
+ /**
+ * Operation.
+ */
+ std::string operator() (const std::string & first) const
+ {
+ return (*f_)(first, _second);
+ }
+ };
+
+ /**
+ * Adapt strip_leading_string to a functor by binding its second argument.
+ *
+ * \ingroup grpstrippers
+ */
+ typedef StripAdapter<&strip_leading_string> StripLeadingString;
+
+ /**
+ * Adapt strip_leading to a functor by binding its second argument.
+ *
+ * \ingroup grpstrippers
+ */
+ typedef StripAdapter<&strip_leading> StripLeading;
+
+ /**
+ * Adapt strip_trailing_string to a functor by binding its second argument.
+ *
+ * \ingroup grpstrippers
+ */
+ typedef StripAdapter<&strip_trailing_string> StripTrailingString;
+
+ /**
+ * Adapt strip_trailing to a functor by binding its second argument.
+ *
+ * \ingroup grpstrippers
+ */
+ typedef StripAdapter<&strip_trailing> StripTrailing;
+}
+
+#endif
diff --git a/0.8.0/paludis/util/strip_TEST.cc b/0.8.0/paludis/util/strip_TEST.cc
new file mode 100644
index 000000000..54cf287e8
--- /dev/null
+++ b/0.8.0/paludis/util/strip_TEST.cc
@@ -0,0 +1,123 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Mark Loeser <halcy0n@gentoo.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <algorithm>
+#include <paludis/util/strip.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for strip.hh.
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test StripLeadingString.
+ *
+ * \ingroup grptestcases
+ */
+ struct StripLeadingStringTest : TestCase
+ {
+ StripLeadingStringTest() : TestCase("StripLeadingString") { }
+
+ void run()
+ {
+ StripLeadingString a("foo");
+
+ TEST_CHECK("bar" == a("foobar"));
+ TEST_CHECK("fishbar" == a("fishbar"));
+ TEST_CHECK("" == a("foo"));
+ TEST_CHECK("fishfoobar" == a("fishfoobar"));
+ TEST_CHECK("blahfoo" == a("blahfoo"));
+ }
+ } test_strip_leading_string;
+
+ /**
+ * \test Test StripLeading.
+ *
+ * \ingroup grptestcases
+ */
+ struct StripLeadingTest : TestCase
+ {
+ StripLeadingTest() : TestCase("StripLeading") {}
+
+ void run()
+ {
+ StripLeading a("foo");
+
+ TEST_CHECK("bar" == a("foobar"));
+ TEST_CHECK("ishbar" == a("fishbar"));
+ TEST_CHECK("" == a("foo"));
+ TEST_CHECK("ishfoobar" == a("fishfoobar"));
+ TEST_CHECK("blahfoo" == a("blahfoo"));
+ }
+ } test_strip_leading;
+
+ /**
+ * \test Test StripTrailingString.
+ *
+ * \ingroup grptestcases
+ */
+ struct StripTrailingStringTest : TestCase
+ {
+ StripTrailingStringTest() : TestCase("StripTrailingString") { }
+
+ void run()
+ {
+ StripTrailingString a("foo");
+
+ TEST_CHECK("foobar" == a("foobar"));
+ TEST_CHECK("fishbar" == a("fishbar"));
+ TEST_CHECK("" == a("foo"));
+ TEST_CHECK("fishfoobar" == a("fishfoobar"));
+ TEST_CHECK("blah" == a("blahfoo"));
+ }
+ } test_strip_trailing_string;
+
+ /**
+ * \test Test StripTrailing.
+ *
+ * \ingroup grptestcases
+ */
+ struct StripTrailingTest : TestCase
+ {
+ StripTrailingTest() : TestCase("StripTrailing") {}
+
+ void run()
+ {
+ StripTrailing a("foo");
+
+ TEST_CHECK("foobar" == a("foobar"));
+ TEST_CHECK("fishbar" == a("fishbar"));
+ TEST_CHECK("" == a("foo"));
+ TEST_CHECK("fishfoobar" == a("fishfoobar"));
+ TEST_CHECK("blah" == a("blahfoo"));
+ }
+ } test_strip_trailing;
+
+}
+
diff --git a/0.8.0/paludis/util/system.cc b/0.8.0/paludis/util/system.cc
new file mode 100644
index 000000000..d88198b72
--- /dev/null
+++ b/0.8.0/paludis/util/system.cc
@@ -0,0 +1,230 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <cstdlib>
+#include <paludis/util/system.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/fs_entry.hh>
+#include <paludis/util/stringify.hh>
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+#include "config.h"
+
+/** \file
+ * Implementation of various system utilities.
+ *
+ * \ingroup grpsystem
+ */
+
+using namespace paludis;
+
+namespace
+{
+ static int stdout_write_fd = -1;
+ static int stdout_close_fd = -1;
+
+ static int stderr_write_fd = -1;
+ static int stderr_close_fd = -1;
+
+ /**
+ * Runs a command in a directory if needed, wait for it to terminate
+ * and return its exit status.
+ *
+ * \ingroup grpsystem
+ */
+ int
+ real_run_command(const std::string & cmd, const FSEntry * const fsentry)
+ {
+ pid_t child(fork());
+ if (0 == child)
+ {
+ if (fsentry)
+ if (-1 == chdir(stringify(*fsentry).c_str()))
+ throw RunCommandError("chdir failed: " + stringify(strerror(errno)));
+
+ if (-1 != stdout_write_fd)
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "dup2 " +
+ stringify(stdout_write_fd) + " 2");
+
+ if (-1 == dup2(stdout_write_fd, 1))
+ throw RunCommandError("dup2 failed");
+
+ if (-1 != stdout_close_fd)
+ close(stdout_close_fd);
+ }
+
+ if (-1 != stderr_write_fd)
+ {
+ Log::get_instance()->message(ll_debug, lc_no_context, "dup2 " +
+ stringify(stderr_write_fd) + " 2");
+
+ if (-1 == dup2(stderr_write_fd, 2))
+ throw RunCommandError("dup2 failed");
+
+ if (-1 != stderr_close_fd)
+ close(stderr_close_fd);
+ }
+
+ Log::get_instance()->message(ll_debug, lc_no_context, "execl /bin/sh -c " + cmd);
+ execl("/bin/sh", "sh", "-c", cmd.c_str(), static_cast<char *>(0));
+ throw RunCommandError("execl /bin/sh -c '" + cmd + "' failed:"
+ + stringify(strerror(errno)));
+ }
+ else if (-1 == child)
+ throw RunCommandError("fork failed: " + stringify(strerror(errno)));
+ else
+ {
+ int status(-1);
+ if (-1 == wait(&status))
+ throw RunCommandError("wait failed: " + stringify(strerror(errno)));
+ return ((status & 0xff00) >> 8);
+ }
+
+ throw InternalError(PALUDIS_HERE, "should never be reached");
+ }
+}
+
+void
+paludis::set_run_command_stdout_fds(const int w, const int c)
+{
+ stdout_write_fd = w;
+ stdout_close_fd = c;
+}
+
+void
+paludis::set_run_command_stderr_fds(const int w, const int c)
+{
+ stderr_write_fd = w;
+ stderr_close_fd = c;
+}
+
+GetenvError::GetenvError(const std::string & key) throw () :
+ Exception("Environment variable '" + key + "' not set")
+{
+}
+
+RunCommandError::RunCommandError(const std::string & our_message) throw () :
+ Exception(our_message)
+{
+}
+
+std::string
+paludis::getenv_with_default(const std::string & key, const std::string & def)
+{
+ const char * const e(std::getenv(key.c_str()));
+ return e ? e : def;
+}
+
+std::string
+paludis::getenv_or_error(const std::string & key)
+{
+ const char * const e(std::getenv(key.c_str()));
+ if (! e)
+ throw GetenvError(key);
+ return e;
+}
+
+namespace
+{
+ /**
+ * Fetch the kernel version, for paludis::kernel_version.
+ *
+ * \ingroup grpsystem
+ */
+ std::string get_kernel_version()
+ {
+ struct utsname u;
+ if (0 != uname(&u))
+ throw InternalError(PALUDIS_HERE, "uname call failed");
+ return u.release;
+ }
+}
+
+std::string
+paludis::kernel_version()
+{
+ static const std::string result(get_kernel_version());
+ return result;
+}
+
+int
+paludis::run_command(const std::string & cmd)
+{
+ return real_run_command(cmd, 0);
+}
+
+int
+paludis::run_command_in_directory(const std::string & cmd, const FSEntry & fsentry)
+{
+ return real_run_command(cmd, &fsentry);
+}
+
+MakeEnvCommand::MakeEnvCommand(const std::string & c,
+ const std::string & a) :
+ cmd(c),
+ args(a)
+{
+}
+
+MakeEnvCommand
+MakeEnvCommand::operator() (const std::string & k,
+ const std::string & v) const
+{
+ std::string vv;
+ for (std::string::size_type p(0) ; p < v.length() ; ++p)
+ if ('\'' == v[p])
+ vv.append("'\"'\"'");
+ else
+ vv.append(v.substr(p, 1));
+
+ return MakeEnvCommand(cmd, args + k + "='" + vv + "' ");
+}
+
+MakeEnvCommand::operator std::string() const
+{
+ return "/usr/bin/env " + args + cmd;
+}
+
+const MakeEnvCommand
+paludis::make_env_command(const std::string & cmd)
+{
+ return MakeEnvCommand(cmd, "");
+}
+
+const std::string
+paludis::make_sandbox_command(const std::string & cmd)
+{
+#if HAVE_SANDBOX
+ if (! getenv_with_default("SANDBOX_ACTIVE", "").empty())
+ {
+ Log::get_instance()->message(ll_warning, lc_no_context,
+ "Already inside sandbox, not spawning another sandbox instance");
+ return cmd;
+ }
+ else
+ return "sandbox " + cmd;
+#else
+ return cmd;
+#endif
+}
+
diff --git a/0.8.0/paludis/util/system.hh b/0.8.0/paludis/util/system.hh
new file mode 100644
index 000000000..4183a45b7
--- /dev/null
+++ b/0.8.0/paludis/util/system.hh
@@ -0,0 +1,168 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_SYSTEM_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_SYSTEM_HH 1
+
+#include <paludis/util/exception.hh>
+#include <string>
+
+/** \file
+ * Various system utilities.
+ *
+ * \ingroup grpsystem
+ */
+
+namespace paludis
+{
+ class FSEntry;
+
+ /**
+ * Thrown if getenv_or_error fails.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpsystem
+ */
+ class PALUDIS_VISIBLE GetenvError : public Exception
+ {
+ public:
+ ///\name Basic operations
+ ///\{
+
+ GetenvError(const std::string & key) throw ();
+
+ ///\}
+ };
+
+ /**
+ * Thrown if fork, wait or chdir fail when running a command.
+ *
+ * \ingroup grpexceptions
+ * \ingroup grpsystem
+ */
+ class PALUDIS_VISIBLE RunCommandError : public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ RunCommandError(const std::string & message) throw ();
+ };
+
+ /**
+ * Fetch the value of environment variable key, or def if the variable is
+ * not defined.
+ *
+ * \ingroup grpsystem
+ */
+ std::string getenv_with_default(const std::string & key, const std::string & def) PALUDIS_VISIBLE;
+
+ /**
+ * Fetch the value of environment variable key, or throw a GetenvError if
+ * the variable is not defined.
+ *
+ * \ingroup grpsystem
+ */
+ std::string getenv_or_error(const std::string & key) PALUDIS_VISIBLE;
+
+ /**
+ * Fetch the kernel version, for $KV.
+ *
+ * \ingroup grpsystem
+ */
+ std::string kernel_version() PALUDIS_VISIBLE;
+
+ /**
+ * Run a command, wait for it to terminate and return its exit status.
+ *
+ * Use PStream instead if you need to capture stdout.
+ *
+ * \ingroup grpsystem
+ */
+ int run_command(const std::string & cmd) PALUDIS_VISIBLE;
+
+ /**
+ * Run a command in a directory, wait for it to terminate and return
+ * its exit status.
+ *
+ * \ingroup grpsystem
+ */
+ int run_command_in_directory(const std::string & cmd, const FSEntry & fsentry) PALUDIS_VISIBLE;
+
+ /**
+ * Set the stderr and close for stdout fds used by run_command and
+ * run_command_in_directory.
+ *
+ * \ingroup grpsystem
+ */
+ void set_run_command_stdout_fds(const int, const int) PALUDIS_VISIBLE;
+
+ /**
+ * Set the stderr and close for stderr fds used by run_command and
+ * run_command_in_directory.
+ *
+ * \ingroup grpsystem
+ */
+ void set_run_command_stderr_fds(const int, const int) PALUDIS_VISIBLE;
+
+ /**
+ * Make a command that's run in a particular environment.
+ */
+ class PALUDIS_VISIBLE MakeEnvCommand
+ {
+ private:
+ std::string cmd;
+ std::string args;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ explicit MakeEnvCommand(const std::string &, const std::string &);
+
+ ///\}
+
+ /**
+ * Add some environment.
+ */
+ MakeEnvCommand operator() (const std::string &, const std::string &) const;
+
+ /**
+ * Turn ourself into a command string.
+ */
+ operator std::string() const;
+ };
+
+ /**
+ * Make a command, with environment.
+ *
+ * \ingroup grpsystem
+ */
+ const MakeEnvCommand make_env_command(const std::string & cmd) PALUDIS_VISIBLE;
+
+ /**
+ * Make a command that is run inside the sandbox, if sandbox is enabled.
+ *
+ * \ingroup grpsystem
+ */
+ const std::string make_sandbox_command(const std::string & cmd) PALUDIS_VISIBLE;
+}
+
+#endif
+
diff --git a/0.8.0/paludis/util/system_TEST.cc b/0.8.0/paludis/util/system_TEST.cc
new file mode 100644
index 000000000..e3fd16a5e
--- /dev/null
+++ b/0.8.0/paludis/util/system_TEST.cc
@@ -0,0 +1,184 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/system.hh>
+#include <paludis/util/pstream.hh>
+#include <paludis/util/fs_entry.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+/** \file
+ * Test cases for system.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+using namespace test;
+using namespace paludis;
+
+namespace test_cases
+{
+
+ /**
+ * \test Test getenv_with_default.
+ *
+ * \ingroup grptestcases
+ */
+ struct GetenvWithDefaultTest : TestCase
+ {
+ GetenvWithDefaultTest() : TestCase("getenv_with_default") { }
+
+ void run()
+ {
+ TEST_CHECK(! getenv_with_default("HOME", "!").empty());
+ TEST_CHECK_EQUAL(getenv_with_default("HOME", "!").at(0), '/');
+ TEST_CHECK_EQUAL(getenv_with_default("THEREISNOSUCHVARIABLE", "moo"), "moo");
+ }
+ } test_getenv_with_default;
+
+ /**
+ * \test Test getenv_or_error.
+ *
+ * \ingroup grptestcases
+ */
+ struct GetenvOrErrorTest : TestCase
+ {
+ GetenvOrErrorTest() : TestCase("getenv_or_error") { }
+
+ void run()
+ {
+ TEST_CHECK(! getenv_or_error("HOME").empty());
+ TEST_CHECK_THROWS(getenv_or_error("THEREISNOSUCHVARIABLE"), GetenvError);
+ }
+ } test_getenv_or_error;
+
+ /**
+ * \test Test kernel_version.
+ *
+ * \ingroup grptestcases
+ */
+ struct KernelVersionTest : TestCase
+ {
+ KernelVersionTest() : TestCase("kernel version") { }
+
+ void run()
+ {
+ TEST_CHECK(! kernel_version().empty());
+#ifdef linux
+ TEST_CHECK('2' == kernel_version().at(0));
+ TEST_CHECK('.' == kernel_version().at(1));
+#elif defined(__FreeBSD__)
+ TEST_CHECK('6' == kernel_version().at(0));
+ TEST_CHECK('.' == kernel_version().at(1));
+#else
+# error You need to write a sanity test for kernel_version() for your platform.
+#endif
+ }
+ } test_kernel_version;
+
+ /**
+ * \test Test run_command.
+ *
+ * \ingroup grptestcases
+ */
+ struct RunCommandTest : TestCase
+ {
+ RunCommandTest() : TestCase("run_command") { }
+
+ void run()
+ {
+ TEST_CHECK(0 == run_command("true"));
+ TEST_CHECK(0 != run_command("false"));
+ TEST_CHECK_EQUAL(77, run_command("exit 77"));
+ }
+ } test_run_command;
+
+ /**
+ * \test Test run_command_in_directory.
+ *
+ * \ingroup grptestcases
+ */
+ struct RunCommandInDirectoryTest : TestCase
+ {
+ RunCommandInDirectoryTest() : TestCase("run_command_in_directory") { }
+
+ void run()
+ {
+ FSEntry dir("system_TEST_dir");
+ TEST_CHECK(dir.is_directory());
+
+ run_command_in_directory("touch in_directory", dir);
+ TEST_CHECK(FSEntry(dir / "in_directory").exists());
+ run_command_in_directory("rm in_directory", dir);
+ TEST_CHECK(! FSEntry(dir / "in_directory").exists());
+ }
+ } test_run_command_in_directory;
+
+ /**
+ * \test Test make_env_command.
+ *
+ * \ingroup grptestcases
+ */
+ struct MakeEnvCommandTest : TestCase
+ {
+ MakeEnvCommandTest() : TestCase("make_env_command") { }
+
+ void run()
+ {
+ TEST_CHECK(0 != run_command(make_env_command("printenv PALUDUS_TEST_ENV_VAR")));
+ TEST_CHECK(0 == run_command(make_env_command("bash -c '[[ -z $PALUDUS_TEST_ENV_VAR ]]'")));
+ TEST_CHECK(0 == run_command(make_env_command("bash -c '[[ -z $PALUDUS_TEST_ENV_VAR ]]'")(
+ "PALUDUS_TEST_ENV_VAR", "")));
+ TEST_CHECK(0 == run_command(make_env_command("bash -c '[[ -n $PALUDUS_TEST_ENV_VAR ]]'")(
+ "PALUDUS_TEST_ENV_VAR", "foo")));
+ TEST_CHECK(0 != run_command(make_env_command("bash -c '[[ -z $PALUDUS_TEST_ENV_VAR ]]'")(
+ "PALUDUS_TEST_ENV_VAR", "foo")));
+ TEST_CHECK(0 != run_command(make_env_command("bash -c '[[ -n $PALUDUS_TEST_ENV_VAR ]]'")));
+ TEST_CHECK(0 != run_command(make_env_command("bash -c '[[ -n $PALUDUS_TEST_ENV_VAR ]]'")(
+ "PALUDUS_TEST_ENV_VAR", "")));
+ TEST_CHECK(0 == run_command(make_env_command("bash -c '[[ $PALUDUS_TEST_ENV_VAR == foo ]]'")(
+ "PALUDUS_TEST_ENV_VAR", "foo")));
+ TEST_CHECK(0 != run_command(make_env_command("bash -c '[[ $PALUDUS_TEST_ENV_VAR == foo ]]'")));
+ TEST_CHECK(0 != run_command(make_env_command("bash -c '[[ $PALUDUS_TEST_ENV_VAR == foo ]]'")(
+ "PALUDUS_TEST_ENV_VAR", "")));
+ TEST_CHECK(0 != run_command(make_env_command("bash -c '[[ $PALUDUS_TEST_ENV_VAR == foo ]]'")(
+ "PALUDUS_TEST_ENV_VAR", "bar")));
+ }
+ } test_make_env_command;
+
+ /**
+ * \test Test make_env_command with quotes.
+ *
+ * \ingroup grptestcases
+ */
+ struct MakeEnvCommandQuoteTest : TestCase
+ {
+ MakeEnvCommandQuoteTest() : TestCase("make_env_command quotes") { }
+
+ void run()
+ {
+ TEST_CHECK(0 == run_command(make_env_command(
+ "bash -c '[[ x$PALUDUS_TEST_ENV_VAR == \"x....\" ]]'")
+ ("PALUDUS_TEST_ENV_VAR", "....")));
+ TEST_CHECK(0 == run_command(make_env_command(
+ "bash -c '[[ x$PALUDUS_TEST_ENV_VAR == \"x..'\"'\"'..\" ]]'")
+ ("PALUDUS_TEST_ENV_VAR", "..'..")));
+ }
+ } test_make_env_command_quotes;
+}
diff --git a/0.8.0/paludis/util/system_TEST_cleanup.sh b/0.8.0/paludis/util/system_TEST_cleanup.sh
new file mode 100755
index 000000000..1dca3c3a3
--- /dev/null
+++ b/0.8.0/paludis/util/system_TEST_cleanup.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+if [ -d system_TEST_dir ] ; then
+ rm -fr system_TEST_dir
+else
+ true
+fi
+
diff --git a/0.8.0/paludis/util/system_TEST_setup.sh b/0.8.0/paludis/util/system_TEST_setup.sh
new file mode 100755
index 000000000..d1c9e7623
--- /dev/null
+++ b/0.8.0/paludis/util/system_TEST_setup.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+# vim: set ft=sh sw=4 sts=4 et :
+
+mkdir system_TEST_dir || exit 2
+cd system_TEST_dir || exit 3
diff --git a/0.8.0/paludis/util/test_extras.cc b/0.8.0/paludis/util/test_extras.cc
new file mode 100644
index 000000000..459a324e7
--- /dev/null
+++ b/0.8.0/paludis/util/test_extras.cc
@@ -0,0 +1,73 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <exception>
+#include <paludis/util/attributes.hh>
+#include <paludis/util/exception.hh>
+#include <paludis/util/log.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/system.hh>
+#include <paludis/util/pstream.hh>
+#include <sstream>
+#include <fcntl.h>
+#include <test/test_framework.hh>
+
+/** \file
+ * Some extras, for test cases.
+ *
+ * \ingroup grptestcases
+ */
+
+using namespace paludis;
+
+namespace
+{
+ std::string verbose_exception_to_debug_string(
+ const std::exception & e) PALUDIS_ATTRIBUTE((noinline));
+
+ struct C
+ {
+ std::stringstream s;
+ int dev_null_pid;
+
+ C() :
+ dev_null_pid(open("/dev/stderr", O_RDONLY))
+ {
+ test::set_exception_to_debug_string(&verbose_exception_to_debug_string);
+ Log::get_instance()->set_log_stream(&s);
+
+ set_run_command_stderr_fds(dev_null_pid, -1);
+ PStream::set_stderr_fd(dev_null_pid, -1);
+ }
+ };
+
+ static const C my_c;
+
+ std::string verbose_exception_to_debug_string(const std::exception & e)
+ {
+ const paludis::Exception * ee;
+ if (0 != ((ee = dynamic_cast<const Exception *>(&e))))
+ return stringify(ee->what()) + " (message " + ee->message() +
+ (ee->empty() ? std::string(", no backtrace") :
+ ", backtrace " + ee->backtrace(" -> ")) + ")";
+ else
+ return e.what();
+ }
+}
+
diff --git a/0.8.0/paludis/util/tokeniser.cc b/0.8.0/paludis/util/tokeniser.cc
new file mode 100644
index 000000000..982256d2f
--- /dev/null
+++ b/0.8.0/paludis/util/tokeniser.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "tokeniser.hh"
+
+using namespace paludis;
+
+WhitespaceTokeniser::WhitespaceTokeniser() :
+ Tokeniser<delim_kind::AnyOfTag, delim_mode::DelimiterTag>(" \t\r\n")
+{
+}
+
diff --git a/0.8.0/paludis/util/tokeniser.hh b/0.8.0/paludis/util/tokeniser.hh
new file mode 100644
index 000000000..2768a7d65
--- /dev/null
+++ b/0.8.0/paludis/util/tokeniser.hh
@@ -0,0 +1,245 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_TOKENISER_HH
+#define PALUDIS_GUARD_PALUDIS_TOKENISER_HH 1
+
+#include <iterator>
+#include <paludis/util/instantiation_policy.hh>
+#include <string>
+
+/** \file
+ * Declarations for Tokeniser and related utilities.
+ *
+ * \ingroup grptokenise
+ */
+
+namespace paludis
+{
+ /**
+ * Delimiter policy for Tokeniser.
+ *
+ * \ingroup grptokenise
+ */
+ namespace delim_kind
+ {
+ /**
+ * Any of the characters split, and the delimiter is discarded.
+ *
+ * \ingroup grptokenise
+ */
+ struct AnyOfTag
+ {
+ };
+ }
+
+ /**
+ * Delimiter mode for Tokeniser.
+ *
+ * \ingroup grptokenise
+ */
+ namespace delim_mode
+ {
+ /**
+ * Discard the delimiters.
+ *
+ * \ingroup grptokenise
+ */
+ struct DelimiterTag
+ {
+ };
+
+ /**
+ * Keep the delimiters.
+ *
+ * \ingroup grptokenise
+ */
+ struct BoundaryTag
+ {
+ };
+ }
+
+ /**
+ * Tokeniser internal use only.
+ *
+ * \ingroup grptokenise
+ */
+ namespace tokeniser_internals
+ {
+ /**
+ * A Writer handles Tokeniser's writes.
+ *
+ * \ingroup grptokenise
+ */
+ template <typename DelimMode_, typename Char_, typename Iter_>
+ struct Writer;
+
+ /**
+ * A Writer handles Tokeniser's writes (specialisation for
+ * delim_mode::DelimiterTag).
+ *
+ * \ingroup grptokenise
+ */
+ template <typename Char_, typename Iter_>
+ struct Writer<delim_mode::DelimiterTag, Char_, Iter_>
+ {
+ /**
+ * Handle a token.
+ */
+ static void handle_token(const std::basic_string<Char_> & s, Iter_ & i)
+ {
+ *i++ = s;
+ }
+
+ /**
+ * Handle a delimiter.
+ */
+ static void handle_delim(const std::basic_string<Char_> &, const Iter_ &)
+ {
+ }
+ };
+
+ /**
+ * A Writer handles Tokeniser's writes (specialisation for
+ * delim_mode::BoundaryTag).
+ *
+ * \ingroup grptokenise
+ */
+ template <typename Char_, typename Iter_>
+ struct Writer<delim_mode::BoundaryTag, Char_, Iter_>
+ {
+ /**
+ * Handle a token.
+ */
+ static void handle_token(const std::basic_string<Char_> & s, Iter_ & i)
+ {
+ *i++ = s;
+ }
+
+ /**
+ * Handle a delimiter.
+ */
+ static void handle_delim(const std::basic_string<Char_> & s, Iter_ & i)
+ {
+ *i++ = s;
+ }
+ };
+
+ }
+
+ /**
+ * Tokeniser splits up strings into smaller strings.
+ *
+ * \ingroup grptokenise
+ */
+ template <typename DelimKind_, typename DelimMode_, typename Char_ = std::string::value_type>
+ struct Tokeniser;
+
+ /**
+ * Tokeniser: specialisation for delim_kind::AnyOfTag.
+ *
+ * \ingroup grptokenise
+ */
+ template <typename DelimMode_, typename Char_>
+ class Tokeniser<delim_kind::AnyOfTag, DelimMode_, Char_> :
+ private InstantiationPolicy<Tokeniser<delim_kind::AnyOfTag, DelimMode_, Char_>,
+ instantiation_method::NonCopyableTag>
+ {
+ private:
+ const std::basic_string<Char_> _delims;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ Tokeniser(const std::basic_string<Char_> & delims) :
+ _delims(delims)
+ {
+ }
+
+ ///\}
+
+ /**
+ * Do the tokenisation.
+ */
+ template <typename Iter_>
+ void tokenise(const std::basic_string<Char_> & s, Iter_ iter) const;
+ };
+
+ template <typename DelimMode_, typename Char_>
+ template <typename Iter_>
+ void
+ Tokeniser<delim_kind::AnyOfTag, DelimMode_, Char_>::tokenise(
+ const std::basic_string<Char_> & s, Iter_ iter) const
+ {
+ typename std::basic_string<Char_>::size_type p(0), old_p(0);
+ bool in_delim((! s.empty()) && std::basic_string<Char_>::npos != _delims.find(s[0]));
+
+ for ( ; p < s.length() ; ++p)
+ {
+ if (in_delim)
+ {
+ if (std::basic_string<Char_>::npos == _delims.find(s[p]))
+ {
+ tokeniser_internals::Writer<DelimMode_, Char_, Iter_>::handle_delim(
+ s.substr(old_p, p - old_p), iter);
+ in_delim = false;
+ old_p = p;
+ }
+ }
+ else
+ {
+ if (std::basic_string<Char_>::npos != _delims.find(s[p]))
+ {
+ tokeniser_internals::Writer<DelimMode_, Char_, Iter_>::handle_token(
+ s.substr(old_p, p - old_p), iter);
+ in_delim = true;
+ old_p = p;
+ }
+ }
+ }
+
+ if (old_p != p)
+ {
+ if (in_delim)
+ tokeniser_internals::Writer<DelimMode_, Char_, Iter_>::handle_delim(
+ s.substr(old_p, p - old_p), iter);
+ else
+ tokeniser_internals::Writer<DelimMode_, Char_, Iter_>::handle_token(
+ s.substr(old_p, p - old_p), iter);
+ }
+ }
+
+ /**
+ * Convenience singleton class for tokenising on whitespace.
+ *
+ * \ingroup grptokenise
+ */
+ class PALUDIS_VISIBLE WhitespaceTokeniser :
+ public InstantiationPolicy<WhitespaceTokeniser, instantiation_method::SingletonAtStartupTag>,
+ public Tokeniser<delim_kind::AnyOfTag, delim_mode::DelimiterTag>
+ {
+ friend class InstantiationPolicy<WhitespaceTokeniser, instantiation_method::SingletonAtStartupTag>;
+
+ private:
+ WhitespaceTokeniser();
+ };
+}
+
+#endif
diff --git a/0.8.0/paludis/util/tokeniser_TEST.cc b/0.8.0/paludis/util/tokeniser_TEST.cc
new file mode 100644
index 000000000..4d91a08b0
--- /dev/null
+++ b/0.8.0/paludis/util/tokeniser_TEST.cc
@@ -0,0 +1,139 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <iterator>
+#include <paludis/util/tokeniser.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for tokeniser.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test Tokeniser<AnyOfTag, DelimiterTag>
+ *
+ * \ingroup grptestcases
+ */
+ struct TestTokeniserAD : TestCase
+ {
+ TestTokeniserAD() : TestCase("Tokeniser<AnyOfTag, DelimiterTag>") { }
+
+ void run()
+ {
+ Tokeniser<delim_kind::AnyOfTag, delim_mode::DelimiterTag> t(",.+");
+ std::vector<std::string> tokens;
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("one,two...+...three...", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 3);
+ TEST_CHECK_EQUAL(tokens.at(0), "one");
+ TEST_CHECK_EQUAL(tokens.at(1), "two");
+ TEST_CHECK_EQUAL(tokens.at(2), "three");
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("...one,two...+...three", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 3);
+ TEST_CHECK_EQUAL(tokens.at(0), "one");
+ TEST_CHECK_EQUAL(tokens.at(1), "two");
+ TEST_CHECK_EQUAL(tokens.at(2), "three");
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("one", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 1);
+ TEST_CHECK_EQUAL(tokens.at(0), "one");
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise(".+.,.", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 0);
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 0);
+ tokens.clear();
+ }
+ } test_tokeniser_ad;
+
+ /**
+ * \test Test Tokeniser<AnyOfTag, BoundaryTag>
+ *
+ * \ingroup grptestcases
+ */
+ struct TestTokeniserAB : TestCase
+ {
+ TestTokeniserAB() : TestCase("Tokeniser<AnyOfTag, BoundaryTag>") { }
+
+ void run()
+ {
+ Tokeniser<delim_kind::AnyOfTag, delim_mode::BoundaryTag> t(",.+");
+ std::vector<std::string> tokens;
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("one,two...+...three...", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 6);
+ TEST_CHECK_EQUAL(tokens.at(0), "one");
+ TEST_CHECK_EQUAL(tokens.at(1), ",");
+ TEST_CHECK_EQUAL(tokens.at(2), "two");
+ TEST_CHECK_EQUAL(tokens.at(3), "...+...");
+ TEST_CHECK_EQUAL(tokens.at(4), "three");
+ TEST_CHECK_EQUAL(tokens.at(5), "...");
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("...one,two...+...three", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 6);
+ TEST_CHECK_EQUAL(tokens.at(0), "...");
+ TEST_CHECK_EQUAL(tokens.at(1), "one");
+ TEST_CHECK_EQUAL(tokens.at(2), ",");
+ TEST_CHECK_EQUAL(tokens.at(3), "two");
+ TEST_CHECK_EQUAL(tokens.at(4), "...+...");
+ TEST_CHECK_EQUAL(tokens.at(5), "three");
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("one", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 1);
+ TEST_CHECK_EQUAL(tokens.at(0), "one");
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise(".+.,.", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 1);
+ TEST_CHECK_EQUAL(tokens.at(0), ".+.,.");
+ tokens.clear();
+
+ TEST_CHECK(tokens.empty());
+ t.tokenise("", std::back_inserter(tokens));
+ TEST_CHECK_EQUAL(tokens.size(), 0);
+ tokens.clear();
+ }
+ } test_tokeniser_ab;
+}
diff --git a/0.8.0/paludis/util/util.hh.m4 b/0.8.0/paludis/util/util.hh.m4
new file mode 100644
index 000000000..437206c81
--- /dev/null
+++ b/0.8.0/paludis/util/util.hh.m4
@@ -0,0 +1,42 @@
+#if 0
+ifdef(`__gnu__',`',`errprint(`This is not GNU m4...
+')m4exit(1)') include(`misc/generated-file.txt')
+dnl vim: set ft=cpp et sw=4 sts=4 :
+#endif
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_UTIL_UTIL_HH
+#define PALUDIS_GUARD_PALUDIS_UTIL_UTIL_HH 1
+
+/** \file
+ * Master include file for util.
+ */
+
+define(`addhh', `dnl
+#include <paludis/util/$1.hh>
+')dnl
+define(`addthis', `ifelse(`$2', `hh', `addhh(`$1')',`')')
+define(`add', `addthis(`$1',`$2')addthis(`$1',`$3')addthis(`$1',`$4')dnl
+addthis(`$1',`$5')addthis(`$1',`$6')')dnl
+
+include(`paludis/util/files.m4')
+
+#endif
+
+
diff --git a/0.8.0/paludis/util/validated.hh b/0.8.0/paludis/util/validated.hh
new file mode 100644
index 000000000..0cb54b7e5
--- /dev/null
+++ b/0.8.0/paludis/util/validated.hh
@@ -0,0 +1,124 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_VALIDATED_HH
+#define PALUDIS_GUARD_PALUDIS_VALIDATED_HH 1
+
+#include <iosfwd>
+#include <paludis/util/comparison_policy.hh>
+
+/** \file
+ * Validated declarations.
+ *
+ * \ingroup grpvalidated
+ */
+
+namespace paludis
+{
+ /**
+ * A Validated wraps a particular class instance, ensuring that it always
+ * meets certain validation criteria.
+ *
+ * \ingroup grpvalidated
+ */
+ template <typename ValidatedDataType_, typename Validator_>
+ class Validated : public ComparisonPolicy<
+ Validated<ValidatedDataType_, Validator_>,
+ comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<ValidatedDataType_> >
+ {
+ private:
+ ValidatedDataType_ _value;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ /**
+ * Copy constructor (no validation needed).
+ */
+ Validated(const Validated<ValidatedDataType_, Validator_> & other);
+
+ /**
+ * Constructor (validation needed).
+ */
+ explicit Validated(const ValidatedDataType_ & value);
+
+ /**
+ * Assignment (no validation needed).
+ */
+ const Validated<ValidatedDataType_, Validator_> & operator=
+ (const Validated<ValidatedDataType_,Validator_> & other)
+ {
+ _value = other._value;
+ return *this;
+ }
+
+ ///\}
+
+ /**
+ * Fetch to our ValidatedDataType_. This should not be a cast
+ * operator to avoid problems with ambiguous comparison operators.
+ */
+ const ValidatedDataType_ & data() const
+ {
+ return _value;
+ }
+ };
+
+
+ template <typename ValidatedDataType_, typename Validator_>
+ Validated<ValidatedDataType_, Validator_>::Validated(
+ const Validated<ValidatedDataType_, Validator_> & other) :
+ ComparisonPolicy<
+ Validated<ValidatedDataType_, Validator_>,
+ comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<ValidatedDataType_> >
+ (other),
+ _value(other._value)
+ {
+ }
+
+ template <typename ValidatedDataType_, typename Validator_>
+ Validated<ValidatedDataType_, Validator_>::Validated(const ValidatedDataType_ & value) :
+ ComparisonPolicy<
+ Validated<ValidatedDataType_, Validator_>,
+ comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<ValidatedDataType_> >
+ (&Validated<ValidatedDataType_, Validator_>::_value),
+ _value(value)
+ {
+ Validator_::validate(_value);
+ }
+
+ /**
+ * Writing a Validated instance to a stream is done by its data.
+ *
+ * \ingroup grpvalidated
+ */
+ template <typename D_, typename V_>
+ std::ostream &
+ operator<< (std::ostream & s, const Validated<D_, V_> & v)
+ {
+ s << v.data();
+ return s;
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/validated_TEST.cc b/0.8.0/paludis/util/validated_TEST.cc
new file mode 100644
index 000000000..5adbe384d
--- /dev/null
+++ b/0.8.0/paludis/util/validated_TEST.cc
@@ -0,0 +1,126 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/validated.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for validated.hh .
+ *
+ * \ingroup grpvalidated
+ */
+
+#ifndef DOXYGEN
+struct PositiveEvenValidator
+{
+ struct NotValid
+ {
+ };
+
+ static void validate(int value)
+ {
+ if ((value < 0) || (value % 2))
+ throw NotValid();
+ }
+};
+
+typedef Validated<int, PositiveEvenValidator> PositiveEven;
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Validated<PositiveEven> tests.
+ *
+ * \ingroup grpvalidated
+ */
+ struct ValidatedPositiveEvenTests : TestCase
+ {
+ ValidatedPositiveEvenTests() : TestCase("Validated<PositiveEven> tests") { }
+
+ void run()
+ {
+ PositiveEven v(2);
+ TEST_CHECK_EQUAL(v, PositiveEven(2));
+ v = PositiveEven(4);
+ TEST_CHECK_EQUAL(v, PositiveEven(4));
+ TEST_CHECK_THROWS(((v = PositiveEven(5))), PositiveEvenValidator::NotValid);
+ TEST_CHECK_EQUAL(v, PositiveEven(4));
+ TEST_CHECK_THROWS(PositiveEven w(5), PositiveEvenValidator::NotValid);
+ }
+ } test_validated_positive_even;
+
+ /**
+ * \test Validated<PositiveEven> comparison tests.
+ *
+ * \ingroup grpvalidated
+ */
+ struct ValidatedPositiveEvenComparisonTests : TestCase
+ {
+ ValidatedPositiveEvenComparisonTests() :
+ TestCase("Validated<PositiveEven> comparison tests") { }
+
+ void run()
+ {
+ PositiveEven v2(2);
+ PositiveEven v4(4);
+ PositiveEven v4b(4);
+
+ TEST_CHECK(v2 < v4);
+ TEST_CHECK(v2 <= v4);
+ TEST_CHECK(! (v2 == v4));
+ TEST_CHECK(v2 != v4);
+ TEST_CHECK(! (v2 >= v4));
+ TEST_CHECK(! (v2 > v4));
+
+ TEST_CHECK(! (v4 < v2));
+ TEST_CHECK(! (v4 <= v2));
+ TEST_CHECK(! (v4 == v2));
+ TEST_CHECK(v4 != v2);
+ TEST_CHECK(v4 >= v2);
+ TEST_CHECK(v4 > v2);
+
+ TEST_CHECK(! (v2 < v2));
+ TEST_CHECK(v2 <= v2);
+ TEST_CHECK(v2 == v2);
+ TEST_CHECK(! (v2 != v2));
+ TEST_CHECK(v2 >= v2);
+ TEST_CHECK(! (v2 > v2));
+
+ TEST_CHECK(! (v4 < v4));
+ TEST_CHECK(v4 <= v4);
+ TEST_CHECK(v4 == v4);
+ TEST_CHECK(! (v4 != v4));
+ TEST_CHECK(v4 >= v4);
+ TEST_CHECK(! (v4 > v4));
+
+ TEST_CHECK(! (v4 < v4b));
+ TEST_CHECK(v4 <= v4b);
+ TEST_CHECK(v4 == v4b);
+ TEST_CHECK(! (v4 != v4b));
+ TEST_CHECK(v4 >= v4b);
+ TEST_CHECK(! (v4 > v4b));
+ }
+ } test_validated_positive_even_comparisons;
+}
+
diff --git a/0.8.0/paludis/util/virtual_constructor.hh b/0.8.0/paludis/util/virtual_constructor.hh
new file mode 100644
index 000000000..ab4f88fe4
--- /dev/null
+++ b/0.8.0/paludis/util/virtual_constructor.hh
@@ -0,0 +1,243 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_VIRTUAL_CONSTRUCTOR_HH
+#define PALUDIS_GUARD_PALUDIS_VIRTUAL_CONSTRUCTOR_HH 1
+
+#include <paludis/util/exception.hh>
+#include <paludis/util/instantiation_policy.hh>
+#include <paludis/util/stringify.hh>
+#include <paludis/util/iterator.hh>
+
+#include <algorithm>
+#include <vector>
+
+/** \file
+ * Declarations for VirtualConstructor and related classes.
+ *
+ * \ingroup grpvc
+ */
+
+namespace paludis
+{
+ /**
+ * Behaviour policy classes for what to do if an appropriate constructor
+ * cannot be found for a VirtualConstructor::find_maker call.
+ *
+ * \ingroup grpvc
+ */
+ namespace virtual_constructor_not_found
+ {
+ /**
+ * Throw an exception of type ExceptionType_, which should have a
+ * constructor that takes a single parameter of KeyType_.
+ *
+ * \ingroup grpvc
+ */
+ template <typename ExceptionType_>
+ struct ThrowException
+ {
+ /**
+ * Internal use: provide handle_not_found.
+ *
+ * \ingroup grpvc
+ */
+ template <typename KeyType_, typename ValueType_>
+ struct Parent
+ {
+ /**
+ * Internal use: called when we cannot find a key.
+ */
+ ValueType_ handle_not_found(const KeyType_ & k) const PALUDIS_ATTRIBUTE((noreturn));
+ };
+ };
+
+ template <typename ExceptionType_>
+ template <typename KeyType_, typename ValueType_>
+ ValueType_
+ ThrowException<ExceptionType_>::Parent<KeyType_, ValueType_>::handle_not_found(
+ const KeyType_ & k) const
+ {
+ throw ExceptionType_(k);
+ }
+ }
+
+ /**
+ * For internal use by VirtualConstructor.
+ *
+ * \ingroup grpvc
+ */
+ namespace virtual_constructor_internals
+ {
+ /**
+ * Comparator class for our entries.
+ *
+ * \ingroup grpvc
+ */
+ template <typename First_, typename Second_>
+ struct ComparePairByFirst
+ {
+ /**
+ * Compare, with the entry on the LHS.
+ */
+ bool operator() (const std::pair<First_, Second_> & a, const First_ & b) const
+ {
+ return a.first < b;
+ }
+
+ /**
+ * Compare, with the entry on the RHS.
+ */
+ bool operator() (const First_ & a, const std::pair<First_, Second_> & b) const
+ {
+ return a < b.first;
+ }
+ };
+ }
+
+ /**
+ * A VirtualConstructor can be used where a mapping between the value of
+ * some key type (often a string) to the construction of some kind of
+ * class (possibly via a functor) is required.
+ *
+ * \ingroup grpvc
+ */
+ template <typename KeyType_, typename ValueType_, typename NotFoundBehaviour_>
+ class PALUDIS_VISIBLE VirtualConstructor :
+ public NotFoundBehaviour_::template Parent<KeyType_, ValueType_>,
+ public InstantiationPolicy<VirtualConstructor<KeyType_, ValueType_, NotFoundBehaviour_>,
+ instantiation_method::SingletonAsNeededTag>
+ {
+ friend class InstantiationPolicy<
+ VirtualConstructor<KeyType_, ValueType_, NotFoundBehaviour_>,
+ instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ VirtualConstructor()
+ {
+ }
+
+ protected:
+ /**
+ * Our entries, sorted.
+ */
+ std::vector<std::pair<KeyType_, ValueType_> > entries;
+
+ public:
+ /**
+ * The type of our key.
+ */
+ typedef KeyType_ KeyType;
+
+ /**
+ * The type of our value.
+ */
+ typedef ValueType_ ValueType;
+
+ /**
+ * The behaviour policy for when a key is not found.
+ */
+ typedef NotFoundBehaviour_ NotFoundBehaviour;
+
+ /**
+ * Find a value for the specified key, or perform the appropriate
+ * NotFoundBehaviour.
+ */
+ ValueType_ find_maker(const KeyType_ & k) const;
+
+ /**
+ * Convenience alias for find_maker.
+ */
+ ValueType_ operator[] (const KeyType_ & k) const
+ {
+ return find_maker(k);
+ }
+
+ /**
+ * Register a new maker (should usually be called by the
+ * RegisterMaker child class.
+ */
+ void register_maker(const KeyType_ & k, const ValueType_ & v);
+
+ /**
+ * Copy out our keys.
+ */
+ template <typename T_>
+ void copy_keys(T_ out_iter) const;
+
+ /**
+ * An instance of this class registers a new maker with the
+ * specified key.
+ *
+ * \ingroup grpvc
+ */
+ struct RegisterMaker
+ {
+ /**
+ * Constructor.
+ */
+ RegisterMaker(const KeyType_ & k, const ValueType_ & v)
+ {
+ VirtualConstructor<KeyType_, ValueType_, NotFoundBehaviour_>::get_instance()->
+ register_maker(k, v);
+ }
+ };
+ };
+
+ template <typename KeyType_, typename ValueType_, typename NotFoundBehaviour_>
+ ValueType_
+ VirtualConstructor<KeyType_, ValueType_, NotFoundBehaviour_>::find_maker(
+ const KeyType_ & k) const
+ {
+ std::pair<
+ typename std::vector<std::pair<KeyType_, ValueType_> >::const_iterator,
+ typename std::vector<std::pair<KeyType_, ValueType_> >::const_iterator > m(
+ std::equal_range(entries.begin(), entries.end(), k,
+ virtual_constructor_internals::ComparePairByFirst<KeyType_, ValueType_>()));
+ if (m.first == m.second)
+ return this->handle_not_found(k);
+ else
+ return m.first->second;
+ }
+
+ template <typename KeyType_, typename ValueType_, typename NotFoundBehaviour_>
+ void
+ VirtualConstructor<KeyType_, ValueType_, NotFoundBehaviour_>::register_maker(
+ const KeyType_ & k, const ValueType_ & v)
+ {
+ std::pair<
+ typename std::vector<std::pair<KeyType_, ValueType_> >::iterator,
+ typename std::vector<std::pair<KeyType_, ValueType_> >::iterator > m(
+ std::equal_range(entries.begin(), entries.end(), k,
+ virtual_constructor_internals::ComparePairByFirst<KeyType_, ValueType_>()));
+ if (m.first == m.second)
+ entries.insert(m.first, std::make_pair(k, v));
+ }
+
+ template <typename KeyType_, typename ValueType_, typename NotFoundBehaviour_>
+ template <typename T_>
+ void
+ VirtualConstructor<KeyType_, ValueType_, NotFoundBehaviour_>::copy_keys(T_ out_iter) const
+ {
+ std::copy(entries.begin(), entries.end(), TransformInsertIterator<
+ T_, SelectFirst<KeyType_, ValueType_> >(out_iter));
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/virtual_constructor_TEST.cc b/0.8.0/paludis/util/virtual_constructor_TEST.cc
new file mode 100644
index 000000000..673f0c13d
--- /dev/null
+++ b/0.8.0/paludis/util/virtual_constructor_TEST.cc
@@ -0,0 +1,190 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <paludis/util/counted_ptr.hh>
+#include <paludis/util/virtual_constructor.hh>
+#include <set>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+/** \file
+ * Test cases for VirtualConstructor.
+ *
+ * \ingroup grptestcases
+ */
+
+using namespace test;
+using namespace paludis;
+
+#ifndef DOXYGEN
+enum CookieSize
+{
+ cs_small,
+ cs_large
+};
+
+class Cookie :
+ public InternalCounted<Cookie>
+{
+ private:
+ CookieSize _size;
+
+ protected:
+ Cookie(CookieSize size) :
+ _size(size)
+ {
+ };
+
+ public:
+ virtual std::string flavour() const = 0;
+
+ virtual ~Cookie()
+ {
+ }
+
+ CookieSize size() const
+ {
+ return _size;
+ }
+};
+
+struct NoCookie
+{
+ NoCookie(const std::string &)
+ {
+ }
+};
+
+typedef VirtualConstructor<std::string,
+ CountedPtr<Cookie> (*) (CookieSize),
+ virtual_constructor_not_found::ThrowException<NoCookie> > CookieMaker;
+
+class ChocolateChipCookie : public Cookie
+{
+ public:
+ ChocolateChipCookie(CookieSize size) :
+ Cookie(size)
+ {
+ }
+
+ std::string flavour() const
+ {
+ return "Chocolate Chip";
+ }
+
+ static CountedPtr<Cookie> make(CookieSize size)
+ {
+ return CountedPtr<Cookie>(new ChocolateChipCookie(size));
+ }
+};
+
+CookieMaker::RegisterMaker register_chocolate_chip("chocolate chip", &ChocolateChipCookie::make);
+
+class GingerCookie : public Cookie
+{
+ private:
+ bool _with_crunchy_bits;
+
+ public:
+ GingerCookie(CookieSize size, bool with_crunchy_bits) :
+ Cookie(size),
+ _with_crunchy_bits(with_crunchy_bits)
+ {
+ }
+
+ std::string flavour() const
+ {
+ return _with_crunchy_bits ? "Crunchy Ginger" : "Ginger";
+ }
+
+ bool with_crunchy_bits() const
+ {
+ return _with_crunchy_bits;
+ }
+
+ static CountedPtr<Cookie> make(CookieSize size)
+ {
+ return CountedPtr<Cookie>(new GingerCookie(size, false));
+ }
+
+ static CountedPtr<Cookie> make_crunchy(CookieSize size)
+ {
+ return CountedPtr<Cookie>(new GingerCookie(size, true));
+ }
+};
+
+CookieMaker::RegisterMaker register_ginger("ginger", &GingerCookie::make);
+CookieMaker::RegisterMaker register_crunchy_ginger("crunchy ginger", &GingerCookie::make_crunchy);
+
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Test VirtualConstructor.
+ *
+ * \ingroup grptestcases
+ */
+ struct VirtualConstructorTest : TestCase
+ {
+ VirtualConstructorTest() : TestCase("virtual constructor") { }
+
+ void run()
+ {
+ TEST_CHECK_EQUAL(CookieMaker::get_instance()->find_maker(
+ "chocolate chip")(cs_large)->flavour(), "Chocolate Chip");
+ TEST_CHECK_EQUAL(CookieMaker::get_instance()->find_maker(
+ "chocolate chip")(cs_large)->size(), cs_large);
+ TEST_CHECK_EQUAL(CookieMaker::get_instance()->find_maker(
+ "chocolate chip")(cs_small)->size(), cs_small);
+
+ TEST_CHECK_EQUAL((*CookieMaker::get_instance())["ginger"](cs_small)->flavour(),
+ "Ginger");
+ TEST_CHECK_EQUAL((*CookieMaker::get_instance())["crunchy ginger"](cs_small)->flavour(),
+ "Crunchy Ginger");
+
+ TEST_CHECK_THROWS(CookieMaker::get_instance()->find_maker(
+ "gerbil")(cs_large)->flavour(), NoCookie);
+ }
+ } test_virtual_constructor;
+
+ /**
+ * \test Test VirtualConstructor keys
+ *
+ * \ingroup grptestcases
+ */
+ struct VirtualConstructorKeysTest : TestCase
+ {
+ VirtualConstructorKeysTest() : TestCase("virtual constructor keys") { }
+
+ void run()
+ {
+ std::set<std::string> keys;
+
+ TEST_CHECK(keys.empty());
+ CookieMaker::get_instance()->copy_keys(std::inserter(keys, keys.begin()));
+ TEST_CHECK(! keys.empty());
+ TEST_CHECK(keys.end() != keys.find("crunchy ginger"));
+ TEST_CHECK(keys.end() != keys.find("ginger"));
+ TEST_CHECK(keys.end() != keys.find("chocolate chip"));
+ TEST_CHECK(keys.end() == keys.find("gerbil"));
+ }
+ } test_virtual_constructor_keys;
+}
+
diff --git a/0.8.0/paludis/util/visitor.hh b/0.8.0/paludis/util/visitor.hh
new file mode 100644
index 000000000..70ebd11f0
--- /dev/null
+++ b/0.8.0/paludis/util/visitor.hh
@@ -0,0 +1,359 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PALUDIS_GUARD_PALUDIS_VISITOR_HH
+#define PALUDIS_GUARD_PALUDIS_VISITOR_HH 1
+
+/** \file
+ * Declares the Visitor and related classes.
+ *
+ * \ingroup grpvisitor
+ */
+
+namespace paludis
+{
+ template <typename NodePtrType_>
+ class Visits;
+
+ /**
+ * Internal use for Visitor classes.
+ *
+ * \ingroup grpvisitor
+ */
+ namespace visitor_internals
+ {
+ /**
+ * Used as a default parameter when no type is provided. The n_
+ * parameter is used to avoid inheriting the same class more than once
+ * from a single parent.
+ *
+ * \ingroup grpvisitor
+ */
+ template <unsigned n_>
+ struct NoType
+ {
+ };
+
+ /**
+ * Make a pointer to a const.
+ *
+ * \ingroup grpvisitor
+ */
+ template <typename>
+ struct MakePointerToConst;
+
+ /**
+ * Make a pointer to a const (specialisation for non-const pointers).
+ *
+ * \ingroup grpvisitor
+ */
+ template <typename T_>
+ struct MakePointerToConst<T_ *>
+ {
+ /**
+ * Our type.
+ */
+ typedef const T_ * Type;
+ };
+
+ /**
+ * Interface: visit a class of NodePtrType_.
+ *
+ * \ingroup grpvisitor
+ */
+ template <typename NodePtrType_>
+ class Visits
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ virtual ~Visits()
+ {
+ }
+
+ ///\}
+
+ public:
+ ///\name Visitor operations
+ ///\{
+
+ /**
+ * Visit a node of the specified type.
+ */
+ virtual void visit(NodePtrType_ const) = 0;
+
+ ///\}
+ };
+
+ /**
+ * Interface: don't visit NoType things.
+ *
+ * \ingroup grpvisitor
+ */
+ template <unsigned n_>
+ class Visits<const visitor_internals::NoType<n_> * >
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ ~Visits()
+ {
+ }
+
+ ///\}
+ };
+
+ /**
+ * Interface: don't visit NoType things.
+ *
+ * \ingroup grpvisitor
+ */
+ template <unsigned n_>
+ class Visits<visitor_internals::NoType<n_> * >
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ ~Visits()
+ {
+ }
+
+ ///\}
+ };
+ }
+
+ /**
+ * A class that inherits virtually from VisitableInterface can accept a
+ * visitor that is descended from one of the VisitorType_ subclasses.
+ *
+ * \ingroup grpvisitor
+ */
+ template <typename VisitorType_>
+ class VisitableInterface
+ {
+ protected:
+ /**
+ * Destructor.
+ */
+ virtual ~VisitableInterface()
+ {
+ }
+
+ public:
+ ///\name Visitor operations
+ ///\{
+
+ /**
+ * Accept a visitor.
+ */
+ virtual void accept(typename VisitorType_::Visitor * const) = 0;
+
+ /**
+ * Accept a constant visitor.
+ */
+ virtual void accept(typename VisitorType_::ConstVisitor * const) const = 0;
+
+ ///\}
+ };
+
+ /**
+ * A class that inherits (non-virtually) from Visitable provides an
+ * implementation of VisitableInterface.
+ *
+ * \ingroup grpvisitor
+ */
+ template <typename OurType_, typename VisitorType_>
+ class Visitable :
+ public virtual VisitableInterface<VisitorType_>
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ virtual ~Visitable()
+ {
+ }
+
+ ///\}
+
+ public:
+ ///\name Visitor operations
+ ///\{
+
+ virtual void accept(typename VisitorType_::Visitor * const v)
+ {
+ static_cast<visitor_internals::Visits<OurType_ *> *>(v)->visit(
+ static_cast<OurType_ *>(this));
+ }
+
+ virtual void accept(typename VisitorType_::ConstVisitor * const v) const
+ {
+ static_cast<visitor_internals::Visits<const OurType_ *> *>(v)->visit(
+ static_cast<const OurType_ *>(this));
+ }
+
+ ///\}
+ };
+
+ /**
+ * Create the base classes for constant and non-constant visitors to the
+ * specified node types.
+ *
+ * \ingroup grpvisitor
+ */
+ template <
+ typename N1_,
+ typename N2_ = visitor_internals::NoType<2> *,
+ typename N3_ = visitor_internals::NoType<3> *,
+ typename N4_ = visitor_internals::NoType<4> *,
+ typename N5_ = visitor_internals::NoType<5> *,
+ typename N6_ = visitor_internals::NoType<6> *,
+ typename N7_ = visitor_internals::NoType<7> *,
+ typename N8_ = visitor_internals::NoType<8> *,
+ typename N9_ = visitor_internals::NoType<9> *>
+ class VisitorTypes
+ {
+ private:
+ VisitorTypes();
+
+ public:
+ /**
+ * A ConstVisitor descendent visits nodes via a const pointer.
+ */
+ class ConstVisitor :
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N1_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N2_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N3_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N4_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N5_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N6_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N7_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N8_>::Type>,
+ public visitor_internals::Visits<typename visitor_internals::MakePointerToConst<N9_>::Type>
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ ~ConstVisitor();
+
+ ///\}
+ };
+
+ /**
+ * A Visitor descendent visits nodes via a non-const pointer.
+ */
+ class Visitor :
+ public visitor_internals::Visits<N1_>,
+ public visitor_internals::Visits<N2_>,
+ public visitor_internals::Visits<N3_>,
+ public visitor_internals::Visits<N4_>,
+ public visitor_internals::Visits<N5_>,
+ public visitor_internals::Visits<N6_>,
+ public visitor_internals::Visits<N7_>,
+ public visitor_internals::Visits<N8_>,
+ public visitor_internals::Visits<N9_>
+ {
+ protected:
+ ///\name Basic operations
+ ///\{
+
+ ~Visitor();
+
+ ///\}
+ };
+ };
+
+ template <
+ typename N1_,
+ typename N2_,
+ typename N3_,
+ typename N4_,
+ typename N5_,
+ typename N6_,
+ typename N7_,
+ typename N8_,
+ typename N9_>
+ VisitorTypes<N1_, N2_, N3_, N4_, N5_, N6_, N7_, N8_, N9_>::ConstVisitor::~ConstVisitor()
+ {
+ }
+
+ template <
+ typename N1_,
+ typename N2_,
+ typename N3_,
+ typename N4_,
+ typename N5_,
+ typename N6_,
+ typename N7_,
+ typename N8_,
+ typename N9_>
+ VisitorTypes<N1_, N2_, N3_, N4_, N5_, N6_, N7_, N8_, N9_>::Visitor::~Visitor()
+ {
+ }
+
+ /**
+ * Functor: simplify calling accept on a visitor when we have a container of
+ * pointers to nodes.
+ *
+ * \ingroup grpvisitor
+ */
+ template <typename VisitorPointer_>
+ class AcceptVisitor
+ {
+ private:
+ VisitorPointer_ * const _p;
+
+ public:
+ ///\name Basic operations
+ ///\{
+
+ AcceptVisitor(VisitorPointer_ * const p) :
+ _p(p)
+ {
+ }
+
+ ///\}
+
+ /**
+ * Operator.
+ */
+ template <typename T_>
+ void operator() (T_ t) const
+ {
+ t->accept(_p);
+ }
+ };
+
+ /**
+ * Convenience function: create an AcceptVisitor.
+ *
+ * \ingroup grpvisitor
+ */
+ template <typename VisitorPointer_>
+ AcceptVisitor<VisitorPointer_> accept_visitor(VisitorPointer_ * const p)
+ {
+ return AcceptVisitor<VisitorPointer_>(p);
+ }
+}
+
+#endif
diff --git a/0.8.0/paludis/util/visitor_TEST.cc b/0.8.0/paludis/util/visitor_TEST.cc
new file mode 100644
index 000000000..6e66a6a6d
--- /dev/null
+++ b/0.8.0/paludis/util/visitor_TEST.cc
@@ -0,0 +1,190 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@ciaranm.org>
+ *
+ * This file is part of the Paludis package manager. Paludis is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU General
+ * Public License version 2, as published by the Free Software Foundation.
+ *
+ * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <algorithm>
+#include <paludis/util/iterator.hh>
+#include <paludis/util/visitor.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for visitor.hh .
+ *
+ * \ingroup grptestcases
+ */
+
+#ifndef DOXYGEN
+
+namespace
+{
+ class Deleter
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ Deleter()
+ {
+ }
+
+ /**
+ * Delete an item.
+ */
+ template <typename T_>
+ void operator() (T_ t)
+ {
+ delete t;
+ }
+ };
+
+ class Node;
+ class FooNode;
+ class BarNode;
+
+ typedef VisitorTypes<FooNode *, BarNode *> NodeVisitorTypes;
+
+ struct Node :
+ virtual VisitableInterface<NodeVisitorTypes>
+ {
+ };
+
+ struct FooNode :
+ Node,
+ Visitable<FooNode, NodeVisitorTypes>
+ {
+ std::string c_foo() const
+ {
+ return "c_foo";
+ }
+
+ std::string foo()
+ {
+ return "foo";
+ }
+ };
+
+ struct BarNode :
+ Node,
+ Visitable<BarNode, NodeVisitorTypes>
+ {
+ std::string c_bar() const
+ {
+ return "c_bar";
+ }
+
+ std::string bar()
+ {
+ return "bar";
+ }
+ };
+
+ struct NodeCVisitor :
+ NodeVisitorTypes::ConstVisitor
+ {
+ std::string r;
+
+ virtual void visit(const FooNode * const f)
+ {
+ r.append(f->c_foo());
+ }
+
+ virtual void visit(const BarNode * const b)
+ {
+ r.append(b->c_bar());
+ }
+ };
+
+ struct NodeVisitor :
+ NodeVisitorTypes::Visitor
+ {
+ std::string r;
+
+ virtual void visit(FooNode * const f)
+ {
+ r.append(f->foo());
+ }
+
+ virtual void visit(BarNode * const b)
+ {
+ r.append(b->bar());
+ }
+ };
+}
+
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Test const visitors.
+ *
+ * \ingroup grptestcases
+ */
+ struct ConstVisitorTest : TestCase
+ {
+ ConstVisitorTest() : TestCase("const visitor") { }
+
+ void run()
+ {
+ std::vector<Node *> v;
+
+ v.push_back(new FooNode);
+ v.push_back(new BarNode);
+ v.push_back(new FooNode);
+
+ NodeCVisitor c;
+ TEST_CHECK_EQUAL(c.r, "");
+ std::for_each(v.begin(), v.end(), accept_visitor(&c));
+ TEST_CHECK_EQUAL(c.r, "c_fooc_barc_foo");
+
+ std::for_each(v.begin(), v.end(), Deleter());
+ }
+ } test_const_visitor;
+
+ /**
+ * \test Test non-const visitors.
+ *
+ * \ingroup grptestcases
+ */
+ struct VisitorTest : TestCase
+ {
+ VisitorTest() : TestCase("visitor") { }
+
+ void run()
+ {
+ std::vector<Node *> v;
+
+ v.push_back(new FooNode);
+ v.push_back(new BarNode);
+ v.push_back(new FooNode);
+
+ NodeVisitor c;
+ TEST_CHECK_EQUAL(c.r, "");
+ std::for_each(v.begin(), v.end(), accept_visitor(&c));
+ TEST_CHECK_EQUAL(c.r, "foobarfoo");
+
+ std::for_each(v.begin(), v.end(), Deleter());
+ }
+ } test_visitor;
+}
+