aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-01-17 00:27:43 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-01-17 00:27:43 +0000
commit103e5770f120d70b1580bfc3cab8219c6608bc21 (patch)
tree55d04f6fbf26db1698fb12264ac3b86c40455187
downloadpaludis-103e5770f120d70b1580bfc3cab8219c6608bc21.tar.gz
paludis-103e5770f120d70b1580bfc3cab8219c6608bc21.tar.xz
Initial import
-rw-r--r--AUTHORS12
-rw-r--r--Makefile.am12
-rw-r--r--NEWS3
-rw-r--r--README14
-rwxr-xr-xautogen.bash54
-rw-r--r--configure.ac202
-rw-r--r--doc/Makefile.am23
-rw-r--r--doc/doc_main.doxygen182
-rw-r--r--doc/doc_mainpage.doxygen28
-rw-r--r--doc/doxygen.conf.in1223
-rw-r--r--misc/Makefile.am4
-rw-r--r--misc/generated-file.txt9
-rw-r--r--misc/svn-version-filter-data.bash.in1
-rwxr-xr-xmisc/svn-version-filter.bash30
-rw-r--r--paludis/Makefile.am.m439
-rw-r--r--paludis/about.hh.in67
-rw-r--r--paludis/about_TEST.cc86
-rw-r--r--paludis/all_dep_atom.cc31
-rw-r--r--paludis/all_dep_atom.hh51
-rw-r--r--paludis/all_masked_error.cc28
-rw-r--r--paludis/all_masked_error.hh40
-rw-r--r--paludis/ambiguous_package_name_error.cc23
-rw-r--r--paludis/ambiguous_package_name_error.hh62
-rw-r--r--paludis/any_dep_atom.cc32
-rw-r--r--paludis/any_dep_atom.hh51
-rw-r--r--paludis/args/Makefile.am30
-rw-r--r--paludis/args/alias_arg.cc38
-rw-r--r--paludis/args/alias_arg.hh70
-rw-r--r--paludis/args/args.cc27
-rw-r--r--paludis/args/args.hh37
-rw-r--r--paludis/args/args_TEST.cc102
-rw-r--r--paludis/args/args_error.cc35
-rw-r--r--paludis/args/args_error.hh54
-rw-r--r--paludis/args/args_group.cc43
-rw-r--r--paludis/args/args_group.hh93
-rw-r--r--paludis/args/args_handler.cc130
-rw-r--r--paludis/args/args_handler.hh129
-rw-r--r--paludis/args/args_option.cc68
-rw-r--r--paludis/args/args_option.hh240
-rw-r--r--paludis/args/args_visitor.cc74
-rw-r--r--paludis/args/args_visitor.hh77
-rw-r--r--paludis/args/bad_argument.cc35
-rw-r--r--paludis/args/bad_argument.hh53
-rw-r--r--paludis/args/bad_value.cc32
-rw-r--r--paludis/args/bad_value.hh51
-rw-r--r--paludis/args/switch_arg.cc35
-rw-r--r--paludis/args/switch_arg.hh59
-rw-r--r--paludis/attributes.cc21
-rw-r--r--paludis/attributes.hh42
-rw-r--r--paludis/bad_version_spec_error.cc28
-rw-r--r--paludis/bad_version_spec_error.hh50
-rw-r--r--paludis/block_dep_atom.cc34
-rw-r--r--paludis/block_dep_atom.hh67
-rw-r--r--paludis/block_error.cc10
-rw-r--r--paludis/block_error.hh38
-rw-r--r--paludis/category_name_part.cc21
-rw-r--r--paludis/category_name_part.hh44
-rw-r--r--paludis/category_name_part_collection.cc31
-rw-r--r--paludis/category_name_part_collection.hh48
-rw-r--r--paludis/category_name_part_error.cc28
-rw-r--r--paludis/category_name_part_error.hh52
-rw-r--r--paludis/category_name_part_validator.cc49
-rw-r--r--paludis/category_name_part_validator.hh51
-rw-r--r--paludis/circular_dependency_error.cc21
-rw-r--r--paludis/circular_dependency_error.hh46
-rw-r--r--paludis/comparison_policy.cc21
-rw-r--r--paludis/comparison_policy.hh.m4406
-rw-r--r--paludis/comparison_policy_TEST.cc39
-rw-r--r--paludis/composite_dep_atom.cc32
-rw-r--r--paludis/composite_dep_atom.hh85
-rw-r--r--paludis/composite_pattern.cc21
-rw-r--r--paludis/composite_pattern.hh64
-rw-r--r--paludis/composite_visitor_pattern-impl.hh41
-rw-r--r--paludis/composite_visitor_pattern.cc21
-rw-r--r--paludis/composite_visitor_pattern.hh55
-rw-r--r--paludis/config_file.cc64
-rw-r--r--paludis/config_file.hh92
-rw-r--r--paludis/config_file_TEST.cc90
-rw-r--r--paludis/config_file_error.cc29
-rw-r--r--paludis/config_file_error.hh44
-rw-r--r--paludis/container_entry.cc21
-rw-r--r--paludis/container_entry.hh66
-rw-r--r--paludis/container_entry_TEST.cc60
-rw-r--r--paludis/counted_ptr.cc21
-rw-r--r--paludis/counted_ptr.hh540
-rw-r--r--paludis/counted_ptr_TEST.cc350
-rw-r--r--paludis/counted_ptr_error.cc29
-rw-r--r--paludis/counted_ptr_error.hh51
-rw-r--r--paludis/create_insert_iterator.cc4
-rw-r--r--paludis/create_insert_iterator.hh111
-rw-r--r--paludis/create_insert_iterator_TEST.cc45
-rw-r--r--paludis/default_config.cc199
-rw-r--r--paludis/default_config.hh169
-rw-r--r--paludis/default_config_error.cc10
-rw-r--r--paludis/default_config_error.hh17
-rw-r--r--paludis/default_environment.cc141
-rw-r--r--paludis/default_environment.hh61
-rw-r--r--paludis/deleter.cc26
-rw-r--r--paludis/deleter.hh55
-rw-r--r--paludis/deleter_TEST.cc79
-rw-r--r--paludis/dep_atom.cc31
-rw-r--r--paludis/dep_atom.hh58
-rw-r--r--paludis/dep_atom_dumper.cc93
-rw-r--r--paludis/dep_atom_dumper.hh66
-rw-r--r--paludis/dep_atom_dumper_TEST.cc68
-rw-r--r--paludis/dep_atom_visitor.cc30
-rw-r--r--paludis/dep_atom_visitor.hh65
-rw-r--r--paludis/dep_lexer.cc66
-rw-r--r--paludis/dep_lexer.hh86
-rw-r--r--paludis/dep_lexer_TEST.cc232
-rw-r--r--paludis/dep_list.cc479
-rw-r--r--paludis/dep_list.hh124
-rw-r--r--paludis/dep_list_TEST.cc614
-rw-r--r--paludis/dep_list_entry.cc31
-rw-r--r--paludis/dep_list_entry.hh67
-rw-r--r--paludis/dep_list_error.cc28
-rw-r--r--paludis/dep_list_error.hh40
-rw-r--r--paludis/dep_list_stack_too_deep_error.cc30
-rw-r--r--paludis/dep_list_stack_too_deep_error.hh41
-rw-r--r--paludis/dep_parser.cc267
-rw-r--r--paludis/dep_parser.hh52
-rw-r--r--paludis/dep_parser_TEST.cc245
-rw-r--r--paludis/dep_string_error.cc28
-rw-r--r--paludis/dep_string_error.hh52
-rw-r--r--paludis/dep_string_lex_error.cc28
-rw-r--r--paludis/dep_string_lex_error.hh52
-rw-r--r--paludis/dep_string_nesting_error.cc28
-rw-r--r--paludis/dep_string_nesting_error.hh48
-rw-r--r--paludis/dep_string_parse_error.cc29
-rw-r--r--paludis/dep_string_parse_error.hh52
-rw-r--r--paludis/dir_iterator.cc128
-rw-r--r--paludis/dir_iterator.hh110
-rw-r--r--paludis/dir_open_error.cc29
-rw-r--r--paludis/dir_open_error.hh49
-rw-r--r--paludis/duplicate_repository_error.cc28
-rw-r--r--paludis/duplicate_repository_error.hh45
-rw-r--r--paludis/environment.cc73
-rw-r--r--paludis/environment.hh111
-rw-r--r--paludis/exception.cc38
-rw-r--r--paludis/exception.hh75
-rw-r--r--paludis/fake_repository.cc196
-rw-r--r--paludis/fake_repository.hh109
-rw-r--r--paludis/files.m4119
-rw-r--r--paludis/filter_insert_iterator.cc4
-rw-r--r--paludis/filter_insert_iterator.hh113
-rw-r--r--paludis/filter_insert_iterator_TEST.cc60
-rw-r--r--paludis/fs_entry.cc178
-rw-r--r--paludis/fs_entry.hh131
-rw-r--r--paludis/fs_entry_TEST.cc61
-rw-r--r--paludis/fs_error.cc28
-rw-r--r--paludis/fs_error.hh46
-rw-r--r--paludis/getenv.cc27
-rw-r--r--paludis/getenv.hh40
-rw-r--r--paludis/getenv_TEST.cc34
-rw-r--r--paludis/indirect_iterator.cc21
-rw-r--r--paludis/indirect_iterator.hh159
-rw-r--r--paludis/indirect_iterator_TEST.cc146
-rw-r--r--paludis/instantiation_policy.cc21
-rw-r--r--paludis/instantiation_policy.hh184
-rw-r--r--paludis/instantiation_policy_TEST.cc127
-rw-r--r--paludis/internal_error.cc33
-rw-r--r--paludis/internal_error.hh61
-rw-r--r--paludis/is_const.cc21
-rw-r--r--paludis/is_const.hh60
-rw-r--r--paludis/is_const_TEST.cc58
-rw-r--r--paludis/is_file_with_extension.cc20
-rw-r--r--paludis/is_file_with_extension.hh54
-rw-r--r--paludis/is_file_with_extension_TEST.cc24
-rw-r--r--paludis/join.cc21
-rw-r--r--paludis/join.hh57
-rw-r--r--paludis/join_TEST.cc101
-rw-r--r--paludis/key_value_config_file.cc26
-rw-r--r--paludis/key_value_config_file.hh55
-rw-r--r--paludis/key_value_config_file_TEST.cc24
-rw-r--r--paludis/keyword_name.cc22
-rw-r--r--paludis/keyword_name.hh43
-rw-r--r--paludis/keyword_name_error.cc29
-rw-r--r--paludis/keyword_name_error.hh54
-rw-r--r--paludis/keyword_name_validator.cc63
-rw-r--r--paludis/keyword_name_validator.hh51
-rw-r--r--paludis/line_config_file.cc36
-rw-r--r--paludis/line_config_file.hh66
-rw-r--r--paludis/line_config_file_TEST.cc75
-rw-r--r--paludis/mask_reasons.cc4
-rw-r--r--paludis/mask_reasons.hh30
-rw-r--r--paludis/name_error.cc28
-rw-r--r--paludis/name_error.hh54
-rw-r--r--paludis/no_resolvable_option_error.cc28
-rw-r--r--paludis/no_resolvable_option_error.hh40
-rw-r--r--paludis/no_such_package_error.cc28
-rw-r--r--paludis/no_such_package_error.hh45
-rw-r--r--paludis/no_such_repository_error.cc28
-rw-r--r--paludis/no_such_repository_error.hh45
-rw-r--r--paludis/no_such_version_error.cc30
-rw-r--r--paludis/no_such_version_error.hh47
-rw-r--r--paludis/package_database.cc207
-rw-r--r--paludis/package_database.hh116
-rw-r--r--paludis/package_database_TEST.cc197
-rw-r--r--paludis/package_database_entry.cc30
-rw-r--r--paludis/package_database_entry.hh74
-rw-r--r--paludis/package_database_entry_collection.cc21
-rw-r--r--paludis/package_database_entry_collection.hh50
-rw-r--r--paludis/package_database_error.cc28
-rw-r--r--paludis/package_database_error.hh41
-rw-r--r--paludis/package_database_lookup_error.cc28
-rw-r--r--paludis/package_database_lookup_error.hh41
-rw-r--r--paludis/package_dep_atom.cc137
-rw-r--r--paludis/package_dep_atom.hh115
-rw-r--r--paludis/package_name_part.cc21
-rw-r--r--paludis/package_name_part.hh44
-rw-r--r--paludis/package_name_part_TEST.cc111
-rw-r--r--paludis/package_name_part_collection.cc31
-rw-r--r--paludis/package_name_part_collection.hh48
-rw-r--r--paludis/package_name_part_error.cc28
-rw-r--r--paludis/package_name_part_error.hh52
-rw-r--r--paludis/package_name_part_validator.cc67
-rw-r--r--paludis/package_name_part_validator.hh51
-rw-r--r--paludis/paludis.cc21
-rw-r--r--paludis/paludis.hh.m445
-rw-r--r--paludis/portage_repository.cc420
-rw-r--r--paludis/portage_repository.hh93
-rw-r--r--paludis/private_implementation_pattern.cc21
-rw-r--r--paludis/private_implementation_pattern.hh60
-rw-r--r--paludis/pstream.cc22
-rw-r--r--paludis/pstream.hh76
-rw-r--r--paludis/pstream_TEST.cc106
-rw-r--r--paludis/pstream_error.cc29
-rw-r--r--paludis/pstream_error.hh48
-rw-r--r--paludis/pstream_in_buf.cc81
-rw-r--r--paludis/pstream_in_buf.hh97
-rw-r--r--paludis/qualified_package_name.cc59
-rw-r--r--paludis/qualified_package_name.hh68
-rw-r--r--paludis/qualified_package_name_TEST.cc102
-rw-r--r--paludis/qualified_package_name_collection.cc32
-rw-r--r--paludis/qualified_package_name_collection.hh46
-rw-r--r--paludis/qualified_package_name_error.cc28
-rw-r--r--paludis/qualified_package_name_error.hh42
-rw-r--r--paludis/repository.cc38
-rw-r--r--paludis/repository.hh293
-rw-r--r--paludis/repository_name.cc21
-rw-r--r--paludis/repository_name.hh44
-rw-r--r--paludis/repository_name_collection.cc32
-rw-r--r--paludis/repository_name_collection.hh46
-rw-r--r--paludis/repository_name_error.cc28
-rw-r--r--paludis/repository_name_error.hh53
-rw-r--r--paludis/repository_name_validator.cc40
-rw-r--r--paludis/repository_name_validator.hh51
-rw-r--r--paludis/save.cc21
-rw-r--r--paludis/save.hh77
-rw-r--r--paludis/save_TEST.cc69
-rw-r--r--paludis/sequential_collection.cc23
-rw-r--r--paludis/sequential_collection.hh117
-rw-r--r--paludis/slot_name.cc21
-rw-r--r--paludis/slot_name.hh43
-rw-r--r--paludis/slot_name_error.cc28
-rw-r--r--paludis/slot_name_error.hh52
-rw-r--r--paludis/slot_name_validator.cc50
-rw-r--r--paludis/slot_name_validator.hh52
-rw-r--r--paludis/smart_record.cc21
-rw-r--r--paludis/smart_record.hh.m4602
-rw-r--r--paludis/smart_record_TEST.cc78
-rw-r--r--paludis/sorted_collection.cc23
-rw-r--r--paludis/sorted_collection.hh169
-rw-r--r--paludis/stringify.cc21
-rw-r--r--paludis/stringify.hh85
-rw-r--r--paludis/stringify_TEST.cc129
-rw-r--r--paludis/strip.cc41
-rw-r--r--paludis/strip.hh44
-rw-r--r--paludis/strip_TEST.cc24
-rw-r--r--paludis/test_environment.cc57
-rw-r--r--paludis/test_environment.hh51
-rw-r--r--paludis/tokeniser.cc22
-rw-r--r--paludis/tokeniser.hh206
-rw-r--r--paludis/tokeniser_TEST.cc141
-rw-r--r--paludis/translate_insert_iterator.cc4
-rw-r--r--paludis/translate_insert_iterator.hh116
-rw-r--r--paludis/translate_insert_iterator_TEST.cc54
-rw-r--r--paludis/use_dep_atom.cc35
-rw-r--r--paludis/use_dep_atom.hh72
-rw-r--r--paludis/use_flag_name.cc21
-rw-r--r--paludis/use_flag_name.hh43
-rw-r--r--paludis/use_flag_name_error.cc27
-rw-r--r--paludis/use_flag_name_error.hh54
-rw-r--r--paludis/use_flag_name_validator.cc49
-rw-r--r--paludis/use_flag_name_validator.hh51
-rw-r--r--paludis/validated.cc21
-rw-r--r--paludis/validated.hh101
-rw-r--r--paludis/validated_TEST.cc126
-rw-r--r--paludis/version_metadata.cc147
-rw-r--r--paludis/version_metadata.hh100
-rw-r--r--paludis/version_operator.cc134
-rw-r--r--paludis/version_operator.hh120
-rw-r--r--paludis/version_operator_TEST.cc114
-rw-r--r--paludis/version_spec.cc308
-rw-r--r--paludis/version_spec.hh89
-rw-r--r--paludis/version_spec_TEST.cc167
-rw-r--r--paludis/version_spec_collection.cc31
-rw-r--r--paludis/version_spec_collection.hh46
-rw-r--r--paludis/visitor_pattern-impl.hh34
-rw-r--r--paludis/visitor_pattern.cc21
-rw-r--r--paludis/visitor_pattern.hh105
-rw-r--r--paludis/visitor_pattern_TEST.cc192
-rw-r--r--src/Makefile.am21
-rw-r--r--src/colour.cc22
-rw-r--r--src/colour.hh57
-rw-r--r--src/command_line.cc59
-rw-r--r--src/command_line.hh137
-rw-r--r--src/install.cc168
-rw-r--r--src/install.hh33
-rw-r--r--src/list_repositories.cc49
-rw-r--r--src/list_repositories.hh31
-rw-r--r--src/paludis.cc160
-rw-r--r--src/query.cc169
-rw-r--r--src/query.hh33
-rw-r--r--test/Makefile.am25
-rwxr-xr-xtest/run_test.sh32
-rw-r--r--test/test_fail_TEST.cc48
-rw-r--r--test/test_framework.cc206
-rw-r--r--test/test_framework.hh238
-rw-r--r--test/test_pass_TEST.cc52
-rw-r--r--test/test_runner.cc55
-rw-r--r--test/test_runner.hh31
322 files changed, 24695 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..9a50aa3
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,12 @@
+Authors of Paludis
+==================
+
+Ciaran McCreesh <ciaranm@gentoo.org>
+ Main code
+
+Stephen P. Bennet <spb@gentoo.org>
+ Contributor
+
+Marc Loeser <halcy0n@gentoo.org>
+ Contributor
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..5b2565f
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,12 @@
+CLEANFILES = *~
+MAINTAINERCLEANFILES = Makefile.in configure config/* aclocal.m4 \
+ config.h config.h.in INSTALL COPYING
+AUTOMAKE_OPTIONS = dist-bzip2 no-dist-gzip
+EXTRA_DIST = autogen.bash
+SUBDIRS = misc test paludis src doc
+
+doxygen :
+ $(MAKE) -C doc doxygen
+
+
+
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..eee1b47
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,3 @@
+News for Paludis
+================
+
diff --git a/README b/README
new file mode 100644
index 0000000..2226fdb
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+README for Paludis
+==================
+
+Paludis is in the really early prototype not intended for real use stage. If you
+aren't comfortable with C++, ebuild internals and Gentoo in general then you
+shouldn't be touching it.
+
+Developer documentation is available via 'make doxygen' (you need Doxygen
+installed, and having GraphViz will help too). It will be created under
+'doc/html/'. User documentation is kept in the bottom of a locked filing cabinet
+stuck in a disused lavatory with a sign on the door saying 'Beware of the
+Leopard'.
+
+.. vim: set spell spelllang=en tw=80 : ..
diff --git a/autogen.bash b/autogen.bash
new file mode 100755
index 0000000..e9ecfac
--- /dev/null
+++ b/autogen.bash
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+# vim: set sw=4 sts=4 et tw=80 :
+
+if test "xyes" = x"${BASH_VERSION}" ; then
+ echo "This is not bash!"
+ exit 127
+fi
+
+trap 'echo "exiting." ; exit 250' 15
+KILL_PID=$$
+
+run() {
+ echo ">>> $@" 1>&2
+ if ! $@ ; then
+ echo "oops!" 1>&2
+ exit 127
+ fi
+}
+
+make_from_m4() {
+ echo ">>> $(get_m4 ) -E ${1}.m4 > ${1}"
+ if ! $(get_m4 ) -E ${1}.m4 > ${1} ; then
+ echo "oops!" 1>&2
+ exit 127
+ fi
+}
+
+get() {
+ type ${1}-${2} &>/dev/null && echo ${1}-${2} && return
+ type ${1}${2//.} &>/dev/null && echo ${1}${2//.} && return
+ type ${1} &>/dev/null && echo ${1} && return
+ echo "Could not find ${1} ${2}" 1>&2
+ kill $KILL_PID
+}
+
+get_m4() {
+ type "gm4" &>/dev/null && echo gm4 && return
+ type "m4" &>/dev/null && echo m4 && return
+ echo "Could not find m4" 1>&2
+ kill $KILL_PID
+}
+
+make_from_m4 paludis/Makefile.am
+make_from_m4 paludis/paludis.hh
+make_from_m4 paludis/smart_record.hh
+make_from_m4 paludis/comparison_policy.hh
+run mkdir -p config
+run $(get libtoolize 1.5 ) --copy --force --automake
+rm -f config.cache
+run $(get aclocal 1.9 )
+run $(get autoheader 2.59 )
+run $(get autoconf 2.59 )
+run $(get automake 1.9 ) -a --copy
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..a8ed448
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,202 @@
+dnl vim: set sw=4 sts=4 ts=4 noet ft=config foldmethod=marker foldmarker={{{,}}} :
+
+dnl {{{ program, version
+AC_PREREQ(2.59)
+AC_INIT([paludis/paludis.hh])
+AC_CONFIG_AUX_DIR(config)
+
+VERSION_MAJOR=0
+VERSION_MINOR=1
+VERSION_MICRO=0
+VERSION_FULL="$VERSION_MAJOR.$VERSION_MINOR.$VERSION_MICRO"
+VERSION="$VERSION_FULL"
+
+AC_SUBST([VERSION_MAJOR])
+AC_SUBST([VERSION_MINOR])
+AC_SUBST([VERSION_MICRO])
+AC_SUBST([VERSION_FULL])
+
+AM_INIT_AUTOMAKE(paludis, [$VERSION_FULL])
+dnl }}}
+
+dnl {{{ basic toolchain checks
+AC_LANG([C++])
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_LN_S
+AC_PROG_RANLIB
+AC_PROG_MAKE_SET
+dnl }}}
+
+dnl {{{ check for basic_string and string::find_last_not_of
+AC_MSG_CHECKING([for a sufficiently standard std::basic_string<>])
+AC_COMPILE_IFELSE([
+#include <string>
+int main(int, char **)
+{
+ std::string s("test");
+ std::basic_string<int> t;
+ return std::string::npos != s.find_last_not_of("abcde") ? 0 : 1;
+}
+],
+ [AC_MSG_RESULT([yes])],
+ [
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([I need a less broken std::basic_string<> implementation])
+ ])
+dnl }}}
+
+dnl {{{ check for limits
+AC_MSG_CHECKING([for a usable std::numeric_limits])
+AC_COMPILE_IFELSE([
+#include <limits>
+int main(int, char **)
+{
+ return std::numeric_limits<unsigned>::digits >> 3;
+}
+],
+ [AC_MSG_RESULT([yes])],
+ [
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([Your std::numeric_limits either doesn't exist or hates me])
+ ])
+dnl }}}
+
+dnl {{{ we need libebt.
+dnl don't use AC_CHECK_HEADER, it does silly things
+AC_MSG_CHECKING([for libebt])
+AC_COMPILE_IFELSE([
+#include <libebt/libebt.hh>
+#include <string>
+struct Tag { };
+int main(int, char **)
+{
+ libebt::BacktraceContext<Tag> context("blah");
+}
+],
+ [AC_MSG_RESULT([yes])],
+ [AC_MSG_RESULT([no])
+ AC_MSG_ERROR([libebt (http://libebt.berlios.de/) is required])])
+dnl }}}
+
+dnl {{{ check for various misc functions.
+dnl It's probably possible to make many of these optional rather than
+dnl hard requirements. If any of these fail for you, send patches.
+AC_CHECK_FUNCS([alarm], [], [AC_MSG_ERROR([I need alarm])])
+AC_CHECK_FUNCS([strerror], [], [AC_MSG_ERROR([I need strerror])])
+AC_CHECK_FUNCS([signal], [], [AC_MSG_ERROR([I need signal])])
+AC_CHECK_FUNCS([popen], [], [AC_MSG_ERROR([I need popen])])
+dnl }}}
+
+dnl {{{ check for cxxflags
+AC_DEFUN([CHECK_CXXFLAG], [
+ save_CXXFLAGS=$CXXFLAGS
+ CXXFLAGS="$CXXFLAGS $1 -Werror"
+ AC_MSG_CHECKING([for usable $1 flag])
+ AC_COMPILE_IFELSE([
+#include <string>
+#include <iostream>
+int main(int, char **)
+{
+ std::string s("test");
+ std::cout << s << std::endl;
+}
+ ],
+ [cxxflag_success=yes],
+ [cxxflag_success=no])
+ AC_MSG_RESULT($cxxflag_success)
+ CXXFLAGS="$save_CXXFLAGS"
+ if test "x$cxxflag_success" = "xyes" ; then
+ CXXFLAGS="$CXXFLAGS $1"
+ fi
+ ])
+
+AC_MSG_CHECKING([whether our compiler is iccy])
+AC_COMPILE_IFELSE([
+#ifndef __ICC
+#error nope
+#endif
+],
+ [cxx_compiler_icc=yes],
+ [cxx_compiler_icc=no])
+AC_MSG_RESULT([${cxx_compiler_icc}])
+
+if test "x${cxx_compiler_icc}" = "xyes" ; then
+ CHECK_CXXFLAG([-Wall])
+ CHECK_CXXFLAG([-wd279])
+ CHECK_CXXFLAG([-wd304])
+ CHECK_CXXFLAG([-wd383])
+ CHECK_CXXFLAG([-wd444])
+ CHECK_CXXFLAG([-wd488])
+ CHECK_CXXFLAG([-wd981])
+ CHECK_CXXFLAG([-wd1125])
+ CHECK_CXXFLAG([-wd1418])
+elif test "x${ac_cv_cxx_compiler_gnu}" = "xyes" ; then
+ CHECK_CXXFLAG([-W])
+ CHECK_CXXFLAG([-Wall])
+ CHECK_CXXFLAG([-Wextra])
+ CHECK_CXXFLAG([-Wold-style-cast])
+ CHECK_CXXFLAG([-Wno-overloaded-virtual])
+ CHECK_CXXFLAG([-Wredundant-decls])
+ CHECK_CXXFLAG([-pedantic])
+else
+ CHECK_CXXFLAG([-Wall])
+fi
+dnl }}}
+
+dnl {{{ doxygen, dot
+AC_MSG_CHECKING([whether to enable doxygen])
+AC_ARG_ENABLE([doxygen],
+ [ --enable-doxygen Enable 'make doxygen' (developer docs)],
+ [HAVE_DOXYGEN=$enableval
+ AC_MSG_RESULT([$enableval])],
+ [AC_MSG_RESULT([autodetect])
+ AC_CHECK_PROG(HAVE_DOXYGEN, [doxygen], [yes], [no])])
+AC_SUBST([HAVE_DOXYGEN])
+AM_CONDITIONAL([HAVE_DOXYGEN], test "x$HAVE_DOXYGEN" = "xyes")
+
+AC_MSG_CHECKING([whether to enable dot])
+AC_ARG_ENABLE([dot],
+ [ --enable-dot Enable 'HAVE_DOT' in doxygen.conf],
+ [HAVE_DOT=$enableval
+ AC_MSG_RESULT([$enableval])],
+ [AC_MSG_RESULT([autodetect])
+ AC_CHECK_PROG(HAVE_DOT, [dot], [yes], [no])])
+AC_SUBST([HAVE_DOT])
+AM_CONDITIONAL([HAVE_DOT], test "x$HAVE_DOT" = "xyes")
+dnl }}}
+
+dnl {{{ built sources
+GENERATED_FILE=misc/generated-file.txt
+AC_SUBST_FILE(GENERATED_FILE)
+
+BUILDUSER=`whoami`
+AC_SUBST([BUILDUSER])
+BUILDHOST=`hostname`
+AC_SUBST([BUILDHOST])
+BUILDDATE=`date`
+AC_SUBST([BUILDDATE])
+if test -d "${ac_top_srcdir:-./}/.svn" ; then
+ SVNVERSION=`svnversion "${ac_top_srcdir:-./}"`
+else
+ SVNVERSION=
+fi
+AC_SUBST([SVNVERSION])
+dnl }}}
+
+dnl {{{ output
+AM_CONFIG_HEADER(config.h)
+AC_OUTPUT(
+ Makefile
+ doc/Makefile
+ doc/doxygen.conf
+ misc/Makefile
+ misc/svn-version-filter-data.bash
+ paludis/Makefile
+ paludis/about.hh
+ paludis/args/Makefile
+ src/Makefile
+ test/Makefile
+ )
+dnl }}}
+
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 0000000..c601740
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,23 @@
+CLEANFILES = *~ html/* html
+MAINTAINERCLEANFILES = Makefile.in
+
+docfiles = \
+ doc_main.doxygen \
+ doc_mainpage.doxygen
+
+EXTRA_DIST = doxygen.conf.in $(docfiles)
+
+if HAVE_DOXYGEN
+
+doxygen : doxygen.conf $(top_srcdir)/paludis/*.cc $(top_srcdir)/paludis/*.hh \
+ $(docfiles)
+ nice doxygen doxygen.conf
+
+else
+
+doxygen :
+ @echo "You don't have doxygen installed!"
+ exit 1
+
+endif
+
diff --git a/doc/doc_main.doxygen b/doc/doc_main.doxygen
new file mode 100644
index 0000000..3afc5b7
--- /dev/null
+++ b/doc/doc_main.doxygen
@@ -0,0 +1,182 @@
+/* vim: set ft=cpp tw=80 sw=4 et : */
+
+/** \namespace test_cases
+ * Test cases.
+ *
+ * \ingroup Test
+ */
+
+/** \namespace test
+ * Test framework.
+ *
+ * \ingroup Test
+ */
+
+/** \namespace paludis::args
+ * Commandline argument handling.
+ *
+ * \ingroup Args
+ */
+
+/** \namespace paludis
+ * Paludis library code.
+ */
+
+/** \dir paludis
+ * Paludis library code.
+ */
+
+/** \defgroup DepResolver Dependency parsing and resolution
+ * Dependency parsing and resolution.
+ *
+ * Dependency resolution is handled in stages. We convert a dependency string
+ * into a tree structure, and then define a visitor over this structure.
+ *
+ * \section DepResolverImportant Important Classes
+ *
+ * - paludis::DepList creates and holds dependency lists
+ * - paludis::DepParser turns a dependency string into a paludis::DepAtom
+ * heirarchy.
+ */
+
+/** \defgroup Environment Environment
+ * Environment.
+ *
+ * These classes represent the environment in which paludis is running.
+ *
+ * \section EnvironmentImportant Important Classes
+ *
+ * - paludis::Environment represents an environment.
+ * - paludis::DefaultEnvironment represents the usual environment that should
+ * be used when writing normal programs (other paludis::Environment
+ * descendents exist, e.g. for testing).
+ */
+
+/** \defgroup Database Package database functionality
+ * Package database functionality.
+ *
+ * These classes provide checked representations for common data types, as
+ * well as the core queryable package database functionality.
+ *
+ * \section DatabaseImportant Important Classes
+ *
+ * - paludis::PackageDatabase represents a package database, which
+ * is queryable and holds zero or more paludis::Repository instances.
+ *
+ * \ingroup Environment
+ */
+
+
+/** \defgroup Utility Utilities
+ * Utilities.
+ *
+ * Various miscellaneous utilities.
+ */
+
+/** \defgroup Exception Exception handling
+ * Exception handling.
+ *
+ * All exceptions thrown from paludis should be a subclass of
+ * paludis::Exception, which provides a message and (via libebt) a backtrace
+ * giving details of the error. It is probably wise to also check for
+ * std::exception when writing error handling code.
+ *
+ * \section ExceptionImportant Important classes
+ *
+ * - paludis::Exception is the base exception class. All exceptions thrown
+ * by paludis should be descended from this class (although it's best to
+ * check for std::exception too just in case).
+ *
+ * \ingroup Utility
+ */
+
+/** \defgroup Args Command line argument handling
+ * Command line handling for a program.
+ *
+ * Command line handling for a program is done via a subclass of ArgsHandler.
+ * The class will have member variables of type ArgsGroup to handle groups of
+ * related arguments, and member variables of subtypes of ArgsOption to handle
+ * individual switches.
+ *
+ * \ingroup Utility
+ */
+
+/** \defgroup Pointer Pointers
+ * Pointers.
+ *
+ * We use shared pointers in various places. Different policies are available
+ * for different reference count models.
+ *
+ * \section PointerImportant Important Classes
+ *
+ * - paludis::CountedPtr is used for reference counted pointers.
+ *
+ * \ingroup Utility
+ */
+
+/** \defgroup Tokeniser Tokeniser
+ * Tokeniser.
+ *
+ * The paludis::Tokeniser class provides a way of splitting strings into
+ * smaller strings.
+ *
+ * \section TokeniserImportant Important Classes
+ *
+ * - paludis::Tokeniser is the main class.
+ *
+ * \ingroup Utility
+ */
+
+/** \defgroup Filesystem Filesystem wrapper utilities
+ * Filesystem wrapper utilities.
+ *
+ * The C++ standard library doesn't provide anything for working with
+ * filesystem entries or directories. Rather than repeatedly making calls
+ * to stat(2) and opendir(3) all over the place (or using the bloatware
+ * utilities from Boost), we provide a few lightweight wrapper classes.
+ *
+ * \section FilesystemImportant Important Classes
+ *
+ * - paludis::FSEntry represents a filesystem entry.
+ * - paludis::DirIterator is an iterator for directories.
+ *
+ * \ingroup Utility
+ */
+
+/** \defgroup PStream Process handling
+ * Process handling.
+ *
+ * The paludis::PStream class can be used to execute a process and get its
+ * standard output.
+ *
+ * \section PStreamImportant Important Classes
+ *
+ * - paludis::PStream is a front-end std::istream descendent for process
+ * invokation.
+ *
+ * \ingroup Utility
+ */
+
+/** \defgroup ConfigFile Configuration handling
+ * Configuration handling.
+ *
+ * The paludis::ConfigFile class is a handler for generic configuration files
+ * using a general line-oriented, comments start with a # format. Various
+ * subclasses provide interfaces for different file formats.
+ *
+ * \section ConfigFileImportant Important Classes
+ *
+ * - paludis::KeyValueFile represents a configuration file containing
+ * KEY="value" type statements.
+ * - paludis::LineConfigFile represents a configuration file containing
+ * lines of text.
+ */
+
+/** \defgroup Test Test cases and framework
+ * Test cases and framework.
+ *
+ * Test cases are classes that are descended from TestCase. Declaring an
+ * instance of a TestCase subclass will register it with the test case
+ * list.
+ */
+
diff --git a/doc/doc_mainpage.doxygen b/doc/doc_mainpage.doxygen
new file mode 100644
index 0000000..e5f43e7
--- /dev/null
+++ b/doc/doc_mainpage.doxygen
@@ -0,0 +1,28 @@
+/* vim: set ft=cpp tw=80 sw=4 et : */
+
+/** \mainpage
+ *
+ * \section developerdocs For Developers
+ *
+ * It's best to start by skimming over the main program to get a feel for how
+ * everything fits together. Useful files:
+ *
+ * - src/paludis.cc The main program.
+ * - src/query.cc The --query action handler.
+ * - src/install.cc The --install action handler.
+ *
+ * After that, the following classes are good places to begin:
+ *
+ * - paludis::DefaultEnvironment provides a representation of the default
+ * operating environment.
+ * - paludis::PackageDatabase provides routines for querying packages. An
+ * instance can be obtained via paludis::DefaultEnvironment.
+ *
+ * The <a href="modules.html">Modules</a> link in the header bar will probably
+ * be of more use than any of the full class lists.
+ *
+ * \section userdocs For End Users
+ *
+ * You shouldn't be touching paludis at the moment. Go away.
+ *
+ */
diff --git a/doc/doxygen.conf.in b/doc/doxygen.conf.in
new file mode 100644
index 0000000..c7159cf
--- /dev/null
+++ b/doc/doxygen.conf.in
@@ -0,0 +1,1223 @@
+# Doxyfile 1.4.2
+
+@GENERATED_FILE@
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = @PACKAGE@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER = "Version @VERSION@"
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ./
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = YES
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the progam writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER = "../misc/svn-version-filter.bash"
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../paludis ../paludis/args ../test ../doc
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS = *.hh *.cc *.doxygen
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = YES
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH = ../
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER = "grep -v '^#define .*_GUARD_'"
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+### HTML_HEADER = header.html
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+### HTML_FOOTER = footer.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+### DISABLE_INDEX = YES
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = @HAVE_DOT@
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = NO
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = NO
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+
+
diff --git a/misc/Makefile.am b/misc/Makefile.am
new file mode 100644
index 0000000..91a5cf3
--- /dev/null
+++ b/misc/Makefile.am
@@ -0,0 +1,4 @@
+CLEANFILES = *~
+MAINTAINERCLEANFILES = Makefile.in svn-version-filter-data.bash
+EXTRA_DIST = generated-file.txt svn-version-filter-data.bash.in
+
diff --git a/misc/generated-file.txt b/misc/generated-file.txt
new file mode 100644
index 0000000..25c83f2
--- /dev/null
+++ b/misc/generated-file.txt
@@ -0,0 +1,9 @@
+#if 0
+# vim: set ro :
+
+# *********************************************************
+# THIS IS A GENERATED FILE! DO NOT EDIT THIS FILE DIRECTLY!
+# *********************************************************
+#
+#endif
+
diff --git a/misc/svn-version-filter-data.bash.in b/misc/svn-version-filter-data.bash.in
new file mode 100644
index 0000000..6b4b249
--- /dev/null
+++ b/misc/svn-version-filter-data.bash.in
@@ -0,0 +1 @@
+export VERSION=@VERSION@
diff --git a/misc/svn-version-filter.bash b/misc/svn-version-filter.bash
new file mode 100755
index 0000000..38a36b7
--- /dev/null
+++ b/misc/svn-version-filter.bash
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# For Doxygen. See:
+# http://www.stack.nl/~dimitri/doxygen/config.html#cfg_file_version_filter
+
+source ${0/.bash/-data.bash}
+
+case $1 in
+ *.svn*)
+ echo $VERSION
+ ;;
+
+ *)
+ case "$(basename $1 )" in
+ *.cc|*.hh|*.hh.in)
+ if type svn &>/dev/null ; then
+ echo -n "svn "
+ svn stat -v $1 | sed -n 's/^[ A-Z?\*|!]\{1,15\}/r/;s/ \{1,15\}/\/r/;s/ .*//p'
+ else
+ echo $VERSION
+ fi
+ ;;
+
+ *)
+ echo $VERSION
+ ;;
+ esac
+ ;;
+esac
+
diff --git a/paludis/Makefile.am.m4 b/paludis/Makefile.am.m4
new file mode 100644
index 0000000..df69f74
--- /dev/null
+++ b/paludis/Makefile.am.m4
@@ -0,0 +1,39 @@
+ifdef(`__gnu__',`',`errprint(`This is not GNU m4...
+')m4exit(1)') include(`misc/generated-file.txt')
+
+dnl vim: set ft=m4 et :
+
+define(`filelist', `')dnl
+define(`testlist', `')dnl
+define(`addtest', `define(`testlist', testlist `$1_TEST')
+$1_TEST_SOURCES = $1_TEST.cc
+$1_TEST_LDADD = $(top_builddir)/test/libtest.a libpaludis.a
+')dnl
+define(`addhh', `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', `cc', `addcc(`$1')', `')dnl
+ifelse(`$2', `impl', `addimpl(`$1')', `')dnl
+ifelse(`$2', `test', `addtest(`$1')', `')')dnl
+define(`add', `addthis(`$1',`$2')addthis(`$1',`$3')addthis(`$1',`$4')dnl
+addthis(`$1',`$5')addthis(`$1',`$6')')dnl
+
+include(`paludis/files.m4')
+
+CLEANFILES = *~
+MAINTAINERCLEANFILES = Makefile.in Makefile.am about.hh paludis.hh smart_record.hh comparison_policy.hh
+AM_CXXFLAGS = -I$(top_srcdir)
+DEFS=-DSYSCONFDIR=\"$(sysconfdir)\"
+EXTRA_DIST = about.hh.in Makefile.am.m4 paludis.hh.m4 files.m4 smart_record.hh.m4 comparison_policy.hh.m4
+SUBDIRS = . args
+
+libpaludis_a_SOURCES = filelist
+
+TESTS = testlist
+
+TESTS_ENVIRONMENT = $(SHELL) $(top_srcdir)/test/run_test.sh
+noinst_PROGRAMS = $(TESTS)
+noinst_LIBRARIES = libpaludis.a
+
diff --git a/paludis/about.hh.in b/paludis/about.hh.in
new file mode 100644
index 0000000..e31b118
--- /dev/null
+++ b/paludis/about.hh.in
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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
+ */
+
+@GENERATED_FILE@
+
+#ifndef PALUDIS_GUARD_PALUDIS_ABOUT_HH
+#define PALUDIS_GUARD_PALUDIS_ABOUT_HH 1
+
+/** \file
+ * Defines constants giving the Paludis version number and information about
+ * how Paludis was built.
+ */
+
+/// The package name (eg Paludis)
+#define PALUDIS_PACKAGE "@PACKAGE@"
+
+/// The major version (eg 0.4.1 -> 0)
+#define PALUDIS_VERSION_MAJOR @VERSION_MAJOR@
+
+/// The minor version (eg 0.4.1 -> 4)
+#define PALUDIS_VERSION_MINOR @VERSION_MINOR@
+
+/// The micro version (eg 0.4.1 -> 1)
+#define PALUDIS_VERSION_MICRO @VERSION_MICRO@
+
+/// The version, two digits per part (eg 1.3.5 -> 10305)
+#define PALUDIS_VERSION ((100 * 100 * PALUDIS_VERSION_MAJOR) \
+ + (100 * PALUDIS_VERSION_MINOR) + PALUDIS_VERSION_MICRO)
+
+/// The subversion revision, if applicable (eg "65" or "65M" or "").
+#define PALUDIS_SUBVERSION_REVISION "@SVNVERSION@"
+
+/// The CXXFLAGS used to build Paludis.
+#define PALUDIS_BUILD_CXXFLAGS "@CXXFLAGS@"
+
+/// The LDFLAGS used to build Paludis.
+#define PALUDIS_BUILD_LDFLAGS "@LDFLAGS@"
+
+/// The compiler used to build Paludis.
+#define PALUDIS_BUILD_CXX "@CXX@"
+
+/// The user who built Paludis.
+#define PALUDIS_BUILD_USER "@BUILDUSER@"
+
+/// The host on which Paludis was built.
+#define PALUDIS_BUILD_HOST "@BUILDHOST@"
+
+/// The date when Paludis was built.
+#define PALUDIS_BUILD_DATE "@BUILDDATE@"
+
+#endif
diff --git a/paludis/about_TEST.cc b/paludis/about_TEST.cc
new file mode 100644
index 0000000..66b7c0b
--- /dev/null
+++ b/paludis/about_TEST.cc
@@ -0,0 +1,86 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "about.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+/**
+ * \file
+ * Test cases for about.hh .
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Version tests.
+ *
+ * \ingroup Test
+ */
+ struct VersionTest : TestCase
+ {
+ VersionTest() : TestCase("about test") { }
+
+ void run()
+ {
+ TEST_CHECK(PALUDIS_VERSION_MAJOR >= 0);
+ TEST_CHECK(PALUDIS_VERSION_MAJOR <= 9);
+
+ TEST_CHECK(PALUDIS_VERSION_MINOR >= 0);
+ TEST_CHECK(PALUDIS_VERSION_MINOR <= 99);
+
+ TEST_CHECK(PALUDIS_VERSION_MICRO >= 0);
+ TEST_CHECK(PALUDIS_VERSION_MICRO <= 99);
+
+ TEST_CHECK(PALUDIS_VERSION >= 0);
+ TEST_CHECK(PALUDIS_VERSION <= 99999);
+ TEST_CHECK_EQUAL(PALUDIS_VERSION, 10000 * PALUDIS_VERSION_MAJOR +
+ 100 * PALUDIS_VERSION_MINOR + PALUDIS_VERSION_MICRO);
+
+ TEST_CHECK(std::string(PALUDIS_SUBVERSION_REVISION) != "i am a fish");
+ }
+ } test_case_about;
+
+ /**
+ * \test Build info tests.
+ *
+ * \ingroup Test
+ */
+ struct BuildInfoTest : TestCase
+ {
+ BuildInfoTest() : TestCase("build info test") { }
+
+ void run()
+ {
+ TEST_CHECK(! std::string(PALUDIS_BUILD_CXX).empty());
+ TEST_CHECK(! std::string(PALUDIS_BUILD_CXXFLAGS).empty());
+ TEST_CHECK(std::string(PALUDIS_BUILD_LDFLAGS) != "i am a fish");
+
+ TEST_CHECK(! std::string(PALUDIS_BUILD_USER).empty());
+ TEST_CHECK(! std::string(PALUDIS_BUILD_HOST).empty());
+ TEST_CHECK(! std::string(PALUDIS_BUILD_DATE).empty());
+ }
+ } test_case_build_info;
+}
+
diff --git a/paludis/all_dep_atom.cc b/paludis/all_dep_atom.cc
new file mode 100644
index 0000000..4db11fe
--- /dev/null
+++ b/paludis/all_dep_atom.cc
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "dep_atom_visitor.hh"
+#include "visitor_pattern-impl.hh"
+
+using namespace paludis;
+
+AllDepAtom::AllDepAtom()
+{
+}
diff --git a/paludis/all_dep_atom.hh b/paludis/all_dep_atom.hh
new file mode 100644
index 0000000..9d499e5
--- /dev/null
+++ b/paludis/all_dep_atom.hh
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ALL_DEP_ATOM_HH
+#define PALUDIS_GUARD_PALUDIS_ALL_DEP_ATOM_HH 1
+
+#include <paludis/composite_dep_atom.hh>
+#include <paludis/dep_atom_visitor.hh>
+
+/** \file
+ * Declarations for the AllDepAtom class.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * Represents a ( first second third ) or top level group of dependency
+ * atoms.
+ *
+ * \ingroup DepResolver
+ */
+ class AllDepAtom : public CompositeDepAtom,
+ public Visitable<AllDepAtom, DepAtomVisitor>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ AllDepAtom();
+ };
+}
+
+#endif
diff --git a/paludis/all_masked_error.cc b/paludis/all_masked_error.cc
new file mode 100644
index 0000000..5490c0c
--- /dev/null
+++ b/paludis/all_masked_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "all_masked_error.hh"
+
+using namespace paludis;
+
+AllMaskedError::AllMaskedError(const std::string & query) throw () :
+ DepListError("Error searching for '" + query + "': no available versions")
+{
+}
+
diff --git a/paludis/all_masked_error.hh b/paludis/all_masked_error.hh
new file mode 100644
index 0000000..0471007
--- /dev/null
+++ b/paludis/all_masked_error.hh
@@ -0,0 +1,40 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ALL_MASKED_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_ALL_MASKED_ERROR_HH 1
+
+#include <paludis/dep_list_error.hh>
+
+namespace paludis
+{
+ /**
+ * Thrown if all versions of a particular atom are masked.
+ */
+ class AllMaskedError : public DepListError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ AllMaskedError(const std::string & query) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/ambiguous_package_name_error.cc b/paludis/ambiguous_package_name_error.cc
new file mode 100644
index 0000000..8610645
--- /dev/null
+++ b/paludis/ambiguous_package_name_error.cc
@@ -0,0 +1,23 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "ambiguous_package_name_error.hh"
+
+using namespace paludis;
+
diff --git a/paludis/ambiguous_package_name_error.hh b/paludis/ambiguous_package_name_error.hh
new file mode 100644
index 0000000..4b4c4f4
--- /dev/null
+++ b/paludis/ambiguous_package_name_error.hh
@@ -0,0 +1,62 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_AMBIGUOUS_PACKAGE_NAME_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_AMBIGUOUS_PACKAGE_NAME_ERROR_HH 1
+
+#include <paludis/package_database_lookup_error.hh>
+#include <paludis/join.hh>
+
+/** \file
+ * Declarations for AmbiguousPackageNameError.
+ *
+ * \ingroup Exception
+ * \ingroup Database
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if a PackageDatabase query results in more than one matching
+ * Package.
+ *
+ * \ingroup Exception
+ * \ingroup Database
+ */
+ class AmbiguousPackageNameError : public PackageDatabaseLookupError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ template <typename I_>
+ AmbiguousPackageNameError(const std::string & name,
+ I_ begin, const I_ end) throw ();
+ };
+
+ template <typename I_>
+ AmbiguousPackageNameError::AmbiguousPackageNameError(const std::string & name,
+ I_ begin, const I_ end) throw () :
+ PackageDatabaseLookupError("Ambiguous package name '" + name + "' (candidates are " +
+ join(begin, end, ", ") + ")")
+ {
+ }
+}
+
+#endif
diff --git a/paludis/any_dep_atom.cc b/paludis/any_dep_atom.cc
new file mode 100644
index 0000000..e2432b6
--- /dev/null
+++ b/paludis/any_dep_atom.cc
@@ -0,0 +1,32 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "dep_atom_visitor.hh"
+#include "visitor_pattern-impl.hh"
+
+using namespace paludis;
+
+AnyDepAtom::AnyDepAtom()
+{
+}
+
diff --git a/paludis/any_dep_atom.hh b/paludis/any_dep_atom.hh
new file mode 100644
index 0000000..002471b
--- /dev/null
+++ b/paludis/any_dep_atom.hh
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ANY_DEP_ATOM_HH
+#define PALUDIS_GUARD_PALUDIS_ANY_DEP_ATOM_HH 1
+
+#include <paludis/composite_dep_atom.hh>
+
+/** \file
+ * Declarations for AnyDepAtom.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ class DepAtomVisitor;
+
+ /**
+ * Represents a "|| ( )" dependency block.
+ *
+ * \ingroup DepResolver
+ */
+ class AnyDepAtom : public CompositeDepAtom,
+ public Visitable<AnyDepAtom, DepAtomVisitor>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ AnyDepAtom();
+ };
+}
+
+#endif
diff --git a/paludis/args/Makefile.am b/paludis/args/Makefile.am
new file mode 100644
index 0000000..e114af5
--- /dev/null
+++ b/paludis/args/Makefile.am
@@ -0,0 +1,30 @@
+CLEANFILES = *~
+MAINTAINERCLEANFILES = Makefile.in
+AM_CXXFLAGS = -I$(top_srcdir)
+
+TESTS = \
+ args_TEST
+
+libpaludisargs_a_SOURCES = \
+ alias_arg.hh alias_arg.cc \
+ args.hh args.cc \
+ args_error.hh args_error.cc \
+ args_group.hh args_group.cc \
+ args_handler.hh args_handler.cc \
+ args_option.hh args_option.cc \
+ bad_argument.hh bad_argument.cc \
+ switch_arg.hh switch_arg.cc \
+ args_visitor.hh args_visitor.cc \
+ bad_value.hh bad_value.cc
+
+noinst_LIBRARIES = libpaludisargs.a
+noinst_PROGRAMS = $(TESTS)
+
+test_ldadd = \
+ libpaludisargs.a \
+ $(top_builddir)/test/libtest.a \
+ $(top_builddir)/paludis/libpaludis.a
+
+args_TEST_SOURCES = args_TEST.cc
+args_TEST_LDADD = $(test_ldadd)
+
diff --git a/paludis/args/alias_arg.cc b/paludis/args/alias_arg.cc
new file mode 100644
index 0000000..8c930c5
--- /dev/null
+++ b/paludis/args/alias_arg.cc
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "alias_arg.hh"
+#include "args_group.hh"
+#include "args_handler.hh"
+
+/** \file
+ * Implementation for AliasArg.
+ *
+ * \ingroup Args
+ */
+
+using namespace paludis::args;
+
+AliasArg::AliasArg(ArgsOption * const other, const std::string & long_name) :
+ ArgsOption(other->group(), long_name, '\0', "Alias for --" + other->long_name()),
+ _other(other)
+{
+ other->group()->handler()->add_option(other, long_name);
+}
+
diff --git a/paludis/args/alias_arg.hh b/paludis/args/alias_arg.hh
new file mode 100644
index 0000000..e154667
--- /dev/null
+++ b/paludis/args/alias_arg.hh
@@ -0,0 +1,70 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_ALIAS_ARG_HH
+#define PALUDIS_GUARD_PALUDIS_ARGS_ALIAS_ARG_HH 1
+
+#include <paludis/args/args_option.hh>
+#include <string>
+
+/** \file
+ * Declaration for AliasArg.
+ *
+ * \ingroup Args
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * An AliasArg is an alias for another argument.
+ *
+ * \ingroup Args
+ */
+ class AliasArg : public ArgsOption
+ {
+ private:
+ ArgsOption * const _other;
+
+ public:
+ /**
+ * Constructor.
+ */
+ AliasArg(ArgsOption * const other, const std::string & new_long_name);
+
+ virtual bool specified() const
+ {
+ return _other->specified();
+ }
+
+ virtual void set_specified(const bool value)
+ {
+ _other->set_specified(value);
+ }
+
+ void accept(ArgsVisitor * const v)
+ {
+ v->visit(this);
+ }
+ };
+ }
+}
+
+#endif
diff --git a/paludis/args/args.cc b/paludis/args/args.cc
new file mode 100644
index 0000000..2433110
--- /dev/null
+++ b/paludis/args/args.cc
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "args.hh"
+
+/** \file
+ * Implementation for args.hh .
+ *
+ * \ingroup Args
+ */
+
diff --git a/paludis/args/args.hh b/paludis/args/args.hh
new file mode 100644
index 0000000..f9c8b2f
--- /dev/null
+++ b/paludis/args/args.hh
@@ -0,0 +1,37 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_ARGS_HH
+#define PALUDIS_GUARD_ARGS_ARGS_HH 1
+
+/** \file
+ * Master include file for command line argument handling.
+ *
+ * \ingroup Args
+ */
+
+#include <paludis/args/alias_arg.hh>
+#include <paludis/args/args_error.hh>
+#include <paludis/args/args_group.hh>
+#include <paludis/args/args_handler.hh>
+#include <paludis/args/args_option.hh>
+#include <paludis/args/bad_argument.hh>
+#include <paludis/args/switch_arg.hh>
+
+#endif
diff --git a/paludis/args/args_TEST.cc b/paludis/args/args_TEST.cc
new file mode 100644
index 0000000..4b0207e
--- /dev/null
+++ b/paludis/args/args_TEST.cc
@@ -0,0 +1,102 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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/args/args.hh>
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace paludis::args;
+using namespace test;
+
+/** \file
+ * Test cases for paludis::args things.
+ */
+
+#ifndef DOXYGEN
+
+static const char * const arg_enum_args[3] = { "one", "two", "three" };
+
+struct CommandLine : public ArgsHandler
+{
+ ArgsGroup group_one;
+ SwitchArg arg_foo;
+ SwitchArg arg_bar;
+ SwitchArg arg_dummy;
+
+ ArgsGroup group_two;
+ SwitchArg arg_baz;
+ AliasArg arg_other_baz;
+ StringArg arg_something;
+ IntegerArg arg_somenum;
+ EnumArg arg_enum;
+
+ CommandLine() :
+ group_one(this, "Group one"),
+ arg_foo(&group_one, "foo", 'f', "Enable foo"),
+ arg_bar(&group_one, "bar", 'b', "Enable bar"),
+ arg_dummy(&group_one, "dummy", 'd', "Enable something else"),
+
+ group_two(this, "Group two"),
+ arg_baz(&group_two, "baz", 'z', "Enable baz"),
+ arg_other_baz(&arg_baz, "other-baz"),
+ arg_something(&group_two, "something", 's', "Value of something"),
+ arg_somenum(&group_two, "num", 'n', "Some number"),
+ arg_enum(&group_two, "enum", 'e', "One of three", arg_enum_args)
+ {
+ }
+};
+
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Simple args tests.
+ */
+ struct ArgsTestSimple : TestCase
+ {
+ ArgsTestSimple() : TestCase("simple") { }
+
+ void run()
+ {
+ char * args[] = { "program-name", "--other-baz", "-fsne", "blah", "7", "three", "--", "--dummy",
+ "one", "two" };
+ CommandLine c1;
+ c1.run(10, args);
+ TEST_CHECK(c1.arg_foo.specified());
+ TEST_CHECK(! c1.arg_bar.specified());
+ TEST_CHECK(c1.arg_baz.specified());
+ TEST_CHECK(c1.arg_other_baz.specified());
+ TEST_CHECK(c1.arg_something.specified());
+ TEST_CHECK(c1.arg_something.argument() == "blah");
+ TEST_CHECK(c1.arg_somenum.specified());
+ TEST_CHECK(c1.arg_somenum.argument() == 7);
+ TEST_CHECK(c1.arg_enum.specified());
+ TEST_CHECK(c1.arg_enum.argument() == "three");
+ TEST_CHECK(! c1.arg_dummy.specified());
+
+ TEST_CHECK_EQUAL(std::distance(c1.begin_parameters(), c1.end_parameters()), 3);
+ TEST_CHECK_EQUAL(*c1.begin_parameters(), "--dummy");
+ TEST_CHECK_EQUAL(*++c1.begin_parameters(), "one");
+ TEST_CHECK_EQUAL(*++(++(c1.begin_parameters())), "two");
+ }
+ } test_args_simple;
+}
+
diff --git a/paludis/args/args_error.cc b/paludis/args/args_error.cc
new file mode 100644
index 0000000..6e9bd2b
--- /dev/null
+++ b/paludis/args/args_error.cc
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "args_error.hh"
+
+/** \file
+ * Implementation for ArgsError.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+using namespace paludis::args;
+
+ArgsError::ArgsError(const std::string & message) throw () :
+ paludis::Exception("Error handling command line: " + message)
+{
+}
+
diff --git a/paludis/args/args_error.hh b/paludis/args/args_error.hh
new file mode 100644
index 0000000..ee06851
--- /dev/null
+++ b/paludis/args/args_error.hh
@@ -0,0 +1,54 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_ARGS_ERROR_HH
+#define PALUDIS_GUARD_ARGS_ARGS_ERROR_HH 1
+
+#include <paludis/exception.hh>
+#include <string>
+
+/** \file
+ * Declaration for ArgsError.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Thrown if an invalid command line argument is provided.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+ class ArgsError : public paludis::Exception
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ ArgsError(const std::string & message) throw ();
+ };
+ }
+}
+
+#endif
diff --git a/paludis/args/args_group.cc b/paludis/args/args_group.cc
new file mode 100644
index 0000000..25c1fad
--- /dev/null
+++ b/paludis/args/args_group.cc
@@ -0,0 +1,43 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "args.hh"
+
+/** \file
+ * Implementation for ArgsGroup.
+ *
+ * \ingroup Args
+ */
+
+using namespace paludis::args;
+
+ArgsGroup::ArgsGroup(ArgsHandler * h, const std::string & name) :
+ _name(name),
+ _handler(h)
+{
+ h->add(this);
+}
+
+void
+ArgsGroup::add(ArgsOption * const value)
+{
+ /// \bug Should check for uniqueness of short and long names.
+ _args_options.push_back(value);
+}
+
diff --git a/paludis/args/args_group.hh b/paludis/args/args_group.hh
new file mode 100644
index 0000000..643eb31
--- /dev/null
+++ b/paludis/args/args_group.hh
@@ -0,0 +1,93 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_ARGS_GROUP_HH
+#define PALUDIS_GUARD_ARGS_ARGS_GROUP_HH 1
+
+#include <paludis/args/args_option.hh>
+#include <list>
+#include <string>
+
+/** \file
+ * Declaration for ArgsGroup.
+ *
+ * \ingroup Args
+ */
+
+namespace paludis
+{
+
+ namespace args
+ {
+ class ArgsHandler;
+
+ /**
+ * Contains a related group of command line arguments.
+ *
+ * \ingroup Args
+ */
+ class ArgsGroup
+ {
+ friend class ArgsHandler;
+ friend class ArgsOption;
+
+ private:
+ ArgsGroup(const ArgsGroup &);
+
+ void operator= (const ArgsGroup &);
+
+ const std::string _name;
+
+ std::list<ArgsOption *> _args_options;
+
+ ArgsHandler * _handler;
+
+ protected:
+ /**
+ * Add an ArgsOption instance (called by the ArgsOption
+ * constructor).
+ */
+ void add(ArgsOption * const value);
+
+ public:
+ /**
+ * Constructor.
+ */
+ ArgsGroup(ArgsHandler * h, const std::string & name);
+
+ /**
+ * Fetch our name.
+ */
+ const std::string & name() const
+ {
+ return _name;
+ }
+
+ /**
+ * Fetch our handler.
+ */
+ ArgsHandler * handler() const
+ {
+ return _handler;
+ }
+ };
+ }
+}
+
+#endif
diff --git a/paludis/args/args_handler.cc b/paludis/args/args_handler.cc
new file mode 100644
index 0000000..0cbfd6a
--- /dev/null
+++ b/paludis/args/args_handler.cc
@@ -0,0 +1,130 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "args.hh"
+
+/** \file
+ * Implementation for ArgsHandler.
+ *
+ * \ingroup Args
+ */
+
+using namespace paludis::args;
+
+ArgsHandler::ArgsHandler()
+{
+}
+
+void
+ArgsHandler::add(ArgsGroup * const g)
+{
+ /// \bug Should check for name uniqueness.
+ _groups.push_back(g);
+}
+
+#ifndef DOXYGEN
+struct Found
+{
+};
+#endif
+
+void
+ArgsHandler::run(const int argc, const char * const * const argv)
+{
+ std::list<std::string> args(argv + 1, &argv[argc]);
+ std::list<std::string>::iterator argit = args.begin(), arge = args.end();
+
+ ArgsVisitor visitor(&argit);
+
+ for ( ; argit != arge; ++argit )
+ {
+ std::string arg = *argit;
+
+ if (arg == "--")
+ {
+ ++argit;
+ break;
+ }
+ else if (0 == arg.compare(0, 2, "--"))
+ {
+ arg.erase(0, 2);
+ std::map<std::string, ArgsOption*>::iterator it = _longopts.find(arg);
+ if(it == _longopts.end())
+ {
+ throw BadArgument("--" + arg);
+ }
+ (*it).second->accept(&visitor);
+ }
+ else if (arg[0] == '-')
+ {
+ arg.erase(0, 1);
+ for(std::string::iterator c = arg.begin(); c != arg.end(); ++c)
+ {
+ std::map<char, ArgsOption*>::iterator it = _shortopts.find(*c);
+ if(it == _shortopts.end())
+ {
+ throw BadArgument(std::string("-") + *c);
+ }
+ (*it).second->accept(&visitor);
+ }
+ }
+ else
+ {
+ _parameters.push_back(arg);
+ }
+ }
+
+ _parameters.insert(_parameters.end(), argit, args.end());
+}
+
+void
+ArgsHandler::dump_to_stream(std::ostream & s) const
+{
+ std::list<ArgsGroup *>::const_iterator g(_groups.begin()), g_end(_groups.end());
+ for ( ; g != g_end ; ++g)
+ {
+ s << (*g)->name() << ":" << std::endl;
+
+ std::list<ArgsOption *>::const_iterator a((*g)->_args_options.begin()),
+ a_end((*g)->_args_options.end());
+ for ( ; a != a_end ; ++a)
+ {
+ std::stringstream p;
+ p << " --" << (*a)->long_name();
+ if ((*a)->short_name())
+ p << ", -" << (*a)->short_name();
+ if (p.str().length() < 24)
+ p << std::string(24 - p.str().length(), ' ');
+ s << p.str();
+ s << " " << (*a)->description() << std::endl;
+ }
+
+ s << std::endl;
+ }
+}
+
+#ifndef DOXYGEN
+std::ostream &
+paludis::args::operator<< (std::ostream & s, const ArgsHandler & h)
+{
+ h.dump_to_stream(s);
+ return s;
+}
+#endif
+
diff --git a/paludis/args/args_handler.hh b/paludis/args/args_handler.hh
new file mode 100644
index 0000000..9203d0e
--- /dev/null
+++ b/paludis/args/args_handler.hh
@@ -0,0 +1,129 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_ARGS_HANDLER_HH
+#define PALUDIS_GUARD_ARGS_ARGS_HANDLER_HH 1
+
+#include <paludis/args/args_group.hh>
+#include <paludis/instantiation_policy.hh>
+#include <string>
+#include <ostream>
+#include <map>
+
+/** \file
+ * Declaration for ArgsHandler.
+ *
+ * \ingroup Args
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Handles command line arguments.
+ *
+ * \ingroup Args
+ */
+ class ArgsHandler : private InstantiationPolicy<ArgsHandler, instantiation_method::NonCopyableTag>
+ {
+ friend class ArgsGroup;
+ friend std::ostream & operator<< (std::ostream &, const ArgsHandler &);
+
+ private:
+ std::list<ArgsGroup *> _groups;
+ std::list<std::string> _parameters;
+
+ std::map<std::string, ArgsOption *> _longopts;
+ std::map<char, ArgsOption *> _shortopts;
+
+ protected:
+ /**
+ * Add an new ArgsGroup (called by the ArgsGroup constructor).
+ */
+ void add(ArgsGroup * const);
+
+ /**
+ * Dump, for --help output (called by operator<<).
+ */
+ void dump_to_stream(std::ostream & s) const;
+
+ public:
+ /**
+ * Constructor.
+ */
+ ArgsHandler();
+
+ /**
+ * Parse command line arguments.
+ */
+ void run(const int, const char * const * const);
+
+ /**
+ * Iterate over our parameters (non - and -- switches and their
+ * values).
+ */
+ typedef std::list<std::string>::const_iterator ParametersIterator;
+
+ /**
+ * Pointer to the start of our parameters.
+ */
+ ParametersIterator begin_parameters() const
+ {
+ return _parameters.begin();
+ }
+
+ /**
+ * Pointer to past the end of our parameters.
+ */
+ ParametersIterator end_parameters() const
+ {
+ return _parameters.end();
+ }
+
+ /**
+ * Do we have no parameters?
+ */
+ bool empty() const
+ {
+ return _parameters.empty();
+ }
+
+ /**
+ * Add an ArgsOption instance.
+ */
+ void add_option(ArgsOption *opt, const std::string long_name, const char short_name = '\0')
+ {
+ _longopts[long_name] = opt;
+ if (short_name != '\0')
+ _shortopts[short_name] = opt;
+ }
+
+ };
+
+ /**
+ * Output an ArgsHandler to an ostream, for --help output.
+ *
+ * \ingroup Args
+ */
+ std::ostream & operator<< (std::ostream &, const ArgsHandler &);
+ }
+}
+
+#endif
diff --git a/paludis/args/args_option.cc b/paludis/args/args_option.cc
new file mode 100644
index 0000000..7ec879d
--- /dev/null
+++ b/paludis/args/args_option.cc
@@ -0,0 +1,68 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "args.hh"
+#include "bad_value.hh"
+
+/** \file
+ * Implementation for ArgsOption.
+ *
+ * \ingroup Args
+ */
+
+using namespace paludis::args;
+
+ArgsOption::ArgsOption(ArgsGroup * const g, const std::string & long_name,
+ const char short_name, const std::string & description) :
+ _group(g),
+ _long_name(long_name),
+ _short_name(short_name),
+ _description(description),
+ _specified(false)
+{
+ g->add(this);
+ g->_handler->add_option(this, long_name, short_name);
+}
+
+StringArg::StringArg(ArgsGroup * const g, const std::string & long_name,
+ const char short_name, const std::string & description) :
+ ArgsOption(g, long_name, short_name, description)
+{
+}
+
+SwitchArg::SwitchArg(ArgsGroup * const group, std::string long_name, char short_name,
+ std::string description) :
+ ArgsOption(group, long_name, short_name, description)
+{
+}
+
+IntegerArg::IntegerArg(ArgsGroup * const group, const std::string& long_name,
+ char short_name, const std::string& description) :
+ ArgsOption(group, long_name, short_name, description)
+{
+}
+
+void EnumArg::set_argument(const std::string & arg)
+{
+ if(_allowed_args.find(arg) == _allowed_args.end())
+ {
+ throw(BadValue("--" + long_name(), arg));
+ }
+ _argument = arg;
+}
diff --git a/paludis/args/args_option.hh b/paludis/args/args_option.hh
new file mode 100644
index 0000000..47d9d47
--- /dev/null
+++ b/paludis/args/args_option.hh
@@ -0,0 +1,240 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_ARGS_OPTION_HH
+#define PALUDIS_GUARD_ARGS_ARGS_OPTION_HH 1
+
+#include <string>
+#include <set>
+#include "args_visitor.hh"
+
+/** \file
+ * Declaration for ArgsOption.
+ *
+ * \ingroup Args
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ class ArgsGroup;
+
+ /**
+ * Base class for a command line option.
+ *
+ * \ingroup Args
+ */
+ class ArgsOption
+ {
+ friend class ArgsHandler;
+
+ private:
+ ArgsGroup * const _group;
+
+ const std::string _long_name;
+ const char _short_name;
+ const std::string _description;
+
+ bool _specified;
+
+ ArgsOption(const ArgsOption &);
+
+ void operator= (const ArgsOption &);
+
+ protected:
+ /**
+ * Constructor.
+ */
+ ArgsOption(ArgsGroup * const, const std::string & long_name,
+ const char short_name, const std::string & description);
+
+ public:
+ /**
+ * Fetch our long name.
+ */
+ const std::string & long_name() const
+ {
+ return _long_name;
+ }
+
+ /**
+ * Fetch our short name (may be 0).
+ */
+ char short_name() const
+ {
+ return _short_name;
+ }
+
+ /**
+ * Fetch our description.
+ */
+ const std::string & description() const
+ {
+ return _description;
+ }
+
+ /**
+ * Fetch whether or not we were specified on the
+ * command line.
+ */
+ virtual bool specified() const
+ {
+ return _specified;
+ }
+
+ /**
+ * Set the value returned by specified().
+ */
+ virtual void set_specified(const bool value)
+ {
+ _specified = value;
+ }
+
+ /**
+ * Fetch our group.
+ */
+ ArgsGroup * group()
+ {
+ return _group;
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~ArgsOption()
+ {
+ }
+
+ /**
+ * Accept a visitor.
+ */
+ virtual void accept(ArgsVisitor * const) = 0;
+ };
+
+ /**
+ * An option that takes a string argument.
+ *
+ * \ingroup Args
+ */
+ class StringArg : public ArgsOption
+ {
+ private:
+ std::string _argument;
+
+ public:
+
+ /**
+ * Constructor
+ */
+ StringArg(ArgsGroup * const, const std::string & long_name,
+ const char short_name, const std::string & description);
+
+ /**
+ * Fetch the argument that was given to this option.
+ */
+ const std::string& argument() const { return _argument; }
+
+ /**
+ * Set the argument returned by argument().
+ */
+ void set_argument(const std::string& arg) { _argument = arg; }
+
+ void accept(ArgsVisitor * const v)
+ {
+ v->visit(this);
+ }
+ };
+
+ /**
+ * An option that takes an integer argument.
+ *
+ * \ingroup Args
+ */
+ class IntegerArg : public ArgsOption
+ {
+ private:
+ int _argument;
+
+ public:
+ /**
+ * Constructor
+ */
+ IntegerArg(ArgsGroup * const, const std::string & long_name,
+ const char short_name, const std::string & description);
+ /**
+ * Fetch the argument that was given to this option.
+ */
+ int argument() const { return _argument; }
+
+ /**
+ * Set the argument returned by argument().
+ */
+ void set_argument(const int arg) { _argument = arg; }
+
+ void accept(ArgsVisitor * const v)
+ {
+ v->visit(this);
+ }
+ };
+
+ /**
+ * An option that takes one of a predefined set of string arguments.
+ *
+ * \ingroup Args
+ */
+ class EnumArg : public ArgsOption
+ {
+ private:
+ const std::set<std::string> _allowed_args;
+ std::string _argument;
+
+ public:
+ /**
+ * Constructor.
+ */
+ template <typename T_>
+ EnumArg(ArgsGroup * const group, const std::string & long_name,
+ const char short_name, const std::string & description,
+ const T_ * allowed_args) :
+ ArgsOption(group, long_name, short_name, description),
+ _allowed_args(&allowed_args[0], &allowed_args[sizeof(allowed_args)-1])
+ {
+ }
+
+ /**
+ * Fetch the argument that was given to this option.
+ */
+ const std::string & argument() const { return _argument; }
+
+ /**
+ * Set the argument returned by argument(), having verified that
+ * it is one of the arguments allowed for this option.
+ */
+ void set_argument(const std::string & arg);
+
+ void accept(ArgsVisitor * const v)
+ {
+ v->visit(this);
+ }
+ };
+ }
+}
+
+#endif
diff --git a/paludis/args/args_visitor.cc b/paludis/args/args_visitor.cc
new file mode 100644
index 0000000..d3648d1
--- /dev/null
+++ b/paludis/args/args_visitor.cc
@@ -0,0 +1,74 @@
+#include "args_visitor.hh"
+#include "args_option.hh"
+#include "alias_arg.hh"
+#include "switch_arg.hh"
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "bad_value.hh"
+
+#include <sstream>
+
+using namespace paludis;
+using namespace args;
+
+ArgsVisitor::ArgsVisitor(std::list<std::string>::iterator *ai) : _args_index(ai)
+{
+}
+
+void ArgsVisitor::visit(ArgsOption * const arg)
+{
+ arg->set_specified(true);
+}
+
+void ArgsVisitor::visit(StringArg * const arg)
+{
+ visit(static_cast<ArgsOption *>(arg));
+ arg->set_argument(*++(*_args_index));
+}
+
+void ArgsVisitor::visit(AliasArg * const arg)
+{
+ visit(static_cast<ArgsOption *>(arg));
+}
+
+void ArgsVisitor::visit(SwitchArg * const arg)
+{
+ visit(static_cast<ArgsOption *>(arg));
+}
+
+void ArgsVisitor::visit(IntegerArg * const arg)
+{
+ visit(static_cast<ArgsOption*>(arg));
+ std::stringstream ss;
+ std::string param = *++(*_args_index);
+ ss << param;
+ int i;
+ ss >> i;
+ if(!ss.eof() || ss.bad())
+ {
+ throw BadValue("--" + arg->long_name(), param);
+ }
+ arg->set_argument(i);
+}
+
+void ArgsVisitor::visit(EnumArg * const arg)
+{
+ visit(static_cast<ArgsOption*>(arg));
+ arg->set_argument(*++(*_args_index));
+}
diff --git a/paludis/args/args_visitor.hh b/paludis/args/args_visitor.hh
new file mode 100644
index 0000000..8fd8e71
--- /dev/null
+++ b/paludis/args/args_visitor.hh
@@ -0,0 +1,77 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_ARGS_VISITOR_HH
+#define PALUDIS_GUARD_ARGS_ARGS_VISITOR_HH 1
+
+#include <list>
+
+/** \file
+ * Declaration for ArgsVisitor
+ *
+ * \ingroup Args
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ class ArgsOption;
+ class StringArg;
+ class AliasArg;
+ class SwitchArg;
+ class IntegerArg;
+ class EnumArg;
+
+ /**
+ * Visitor class. Processes command-line options as they are found.
+ */
+ class ArgsVisitor
+ {
+ private:
+ std::list<std::string>::iterator *_args_index;
+
+ public:
+ /**
+ * Constructor
+ */
+ ArgsVisitor(std::list<std::string>::iterator *);
+
+ /// Visit an ArgsOption.
+ void visit(ArgsOption * const);
+
+ /// Visit a StringArg.
+ void visit(StringArg * const);
+
+ /// Visit an AliasArg.
+ void visit(AliasArg * const);
+
+ /// Visit a SwitchArg.
+ void visit(SwitchArg * const);
+
+ /// Visit an IntegerArg.
+ void visit(IntegerArg * const);
+
+ /// Visit an EnumArg.
+ void visit(EnumArg * const);
+ };
+ }
+}
+
+#endif
diff --git a/paludis/args/bad_argument.cc b/paludis/args/bad_argument.cc
new file mode 100644
index 0000000..4108c3e
--- /dev/null
+++ b/paludis/args/bad_argument.cc
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "bad_argument.hh"
+
+/** \file
+ * Implementation for BadArgument.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+using namespace paludis::args;
+
+BadArgument::BadArgument(const std::string & option) throw () :
+ ArgsError("Bad argument '" + option + "'")
+{
+}
+
diff --git a/paludis/args/bad_argument.hh b/paludis/args/bad_argument.hh
new file mode 100644
index 0000000..c548152
--- /dev/null
+++ b/paludis/args/bad_argument.hh
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_BAD_ARGUMENT_HH
+#define PALUDIS_GUARD_ARGS_BAD_ARGUMENT_HH 1
+
+#include <paludis/args/args_error.hh>
+
+/** \file
+ * Declaration for BadArgument.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Thrown if an unrecognised command line argument is specified.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+ class BadArgument : public ArgsError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ BadArgument(const std::string & option) throw ();
+ };
+ }
+}
+
+#endif
diff --git a/paludis/args/bad_value.cc b/paludis/args/bad_value.cc
new file mode 100644
index 0000000..b6a6271
--- /dev/null
+++ b/paludis/args/bad_value.cc
@@ -0,0 +1,32 @@
+#include "bad_value.hh"
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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
+ */
+
+/** \file
+ * Implementation for BadValue
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+using namespace paludis::args;
+
+BadValue::BadValue(const std::string& option, const std::string& value) throw () :
+ ArgsError("Invalid parameter '" + value + "' for argument '" + option + "'")
+{
+}
diff --git a/paludis/args/bad_value.hh b/paludis/args/bad_value.hh
new file mode 100644
index 0000000..427f1bd
--- /dev/null
+++ b/paludis/args/bad_value.hh
@@ -0,0 +1,51 @@
+#ifndef PALUDIS_GUARD_ARGS_BAD_VALUE_HH
+#define PALUDIS_GUARD_ARGS_BAD_VALUE_HH 1
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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/args/args_error.hh>
+
+/** \file
+ * Declaration for BadValue.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * Thrown if an invalid parameter is passed to a valid command line argument.
+ *
+ * \ingroup Args
+ * \ingroup Exception
+ */
+ class BadValue : public ArgsError
+ {
+ public:
+ /**
+ * Constructor
+ */
+ BadValue(const std::string& option, const std::string& value) throw();
+ };
+ }
+}
+
+#endif
diff --git a/paludis/args/switch_arg.cc b/paludis/args/switch_arg.cc
new file mode 100644
index 0000000..72976a0
--- /dev/null
+++ b/paludis/args/switch_arg.cc
@@ -0,0 +1,35 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "switch_arg.hh"
+
+/** \file
+ * Implementation for SwitchArg.
+ *
+ * \ingroup Args
+ */
+
+using namespace paludis::args;
+
+SwitchArg::SwitchArg(ArgsGroup * const group, std::string long_name, char short_name,
+ std::string description) :
+ ArgsOption(group, long_name, short_name, description)
+{
+}
+
diff --git a/paludis/args/switch_arg.hh b/paludis/args/switch_arg.hh
new file mode 100644
index 0000000..fd85e06
--- /dev/null
+++ b/paludis/args/switch_arg.hh
@@ -0,0 +1,59 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ARGS_SWITCH_ARG_HH
+#define PALUDIS_GUARD_ARGS_SWITCH_ARG_HH 1
+
+#include <paludis/args/args_option.hh>
+#include <string>
+
+/** \file
+ * Declaration for SwitchArg.
+ *
+ * \ingroup Args
+ */
+
+namespace paludis
+{
+ namespace args
+ {
+ /**
+ * A SwitchArg is an option that can either be specified or not
+ * specified, and that takes no value (for example, --help).
+ *
+ * \ingroup Args
+ */
+ class SwitchArg : public ArgsOption
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ SwitchArg(ArgsGroup * const group, std::string long_name, char short_name,
+ std::string description);
+
+ void accept(ArgsVisitor * const v)
+ {
+ v->visit(this);
+ }
+ };
+ }
+}
+
+#endif
diff --git a/paludis/attributes.cc b/paludis/attributes.cc
new file mode 100644
index 0000000..c6b5791
--- /dev/null
+++ b/paludis/attributes.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "attributes.hh"
+
diff --git a/paludis/attributes.hh b/paludis/attributes.hh
new file mode 100644
index 0000000..b462767
--- /dev/null
+++ b/paludis/attributes.hh
@@ -0,0 +1,42 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ATTRIBUTES_HH
+#define PALUDIS_GUARD_PALUDIS_ATTRIBUTES_HH 1
+
+/** \file
+ * Declare the PALUDIS_ATTRIBUTE macro.
+ */
+
+/** \def PALUDIS_ATTRIBUTE
+ * If we're using GCC, expands to __attribute__, otherwise discards its
+ * arguments.
+ */
+
+#ifdef __GNUC__
+# if ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
+# define PALUDIS_ATTRIBUTE(x) __attribute__(x)
+# else
+# define PALUDIS_ATTRIBUTE(x)
+# endif
+#else
+# define PALUDIS_ATTRIBUTE(x)
+#endif
+
+#endif
diff --git a/paludis/bad_version_spec_error.cc b/paludis/bad_version_spec_error.cc
new file mode 100644
index 0000000..e283554
--- /dev/null
+++ b/paludis/bad_version_spec_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "bad_version_spec_error.hh"
+
+using namespace paludis;
+
+BadVersionSpecError::BadVersionSpecError(const std::string & name) throw () :
+ NameError(name, "version spec")
+{
+}
+
diff --git a/paludis/bad_version_spec_error.hh b/paludis/bad_version_spec_error.hh
new file mode 100644
index 0000000..b9b1059
--- /dev/null
+++ b/paludis/bad_version_spec_error.hh
@@ -0,0 +1,50 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_BAD_VERSION_SPEC_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_BAD_VERSION_SPEC_ERROR_HH 1
+
+#include <paludis/name_error.hh>
+
+/** \file
+ * Declarations for the VersionSpec class.
+ *
+ * \ingroup Exception
+ * \ingroup Database
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if a VersionSpec is created from an invalid version string.
+ *
+ * \ingroup Exception
+ * \ingroup Database
+ */
+ class BadVersionSpecError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ BadVersionSpecError(const std::string & name) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/block_dep_atom.cc b/paludis/block_dep_atom.cc
new file mode 100644
index 0000000..e0e94b4
--- /dev/null
+++ b/paludis/block_dep_atom.cc
@@ -0,0 +1,34 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "block_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "dep_atom_visitor.hh"
+#include "visitor_pattern-impl.hh"
+
+using namespace paludis;
+
+BlockDepAtom::BlockDepAtom(PackageDepAtom::ConstPointer a) :
+ _atom(a)
+{
+}
+
diff --git a/paludis/block_dep_atom.hh b/paludis/block_dep_atom.hh
new file mode 100644
index 0000000..8709bcf
--- /dev/null
+++ b/paludis/block_dep_atom.hh
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_BLOCK_DEP_ATOM_HH
+#define PALUDIS_GUARD_PALUDIS_BLOCK_DEP_ATOM_HH 1
+
+#include <paludis/dep_atom.hh>
+#include <paludis/package_dep_atom.hh>
+
+/** \file
+ * Declarations for the BlockDepAtom class.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * A BlockDepAtom represents a block on a package name (for example,
+ * 'app-editors/vim'), possibly with associated version and SLOT
+ * restrictions.
+ *
+ * \ingroup DepResolver
+ */
+ class BlockDepAtom : public DepAtom,
+ public Visitable<BlockDepAtom, DepAtomVisitor>
+ {
+ private:
+ PackageDepAtom::ConstPointer _atom;
+
+ public:
+ /**
+ * Constructor, with blocking atom.
+ */
+ BlockDepAtom(PackageDepAtom::ConstPointer atom);
+
+ /**
+ * Fetch the atom we're blocking.
+ */
+ PackageDepAtom::ConstPointer blocked_atom() const
+ {
+ return _atom;
+ }
+
+ typedef CountedPtr<BlockDepAtom, count_policy::InternalCountTag> Pointer;
+ typedef CountedPtr<const BlockDepAtom, count_policy::InternalCountTag> ConstPointer;
+ };
+}
+
+
+#endif
diff --git a/paludis/block_error.cc b/paludis/block_error.cc
new file mode 100644
index 0000000..6099be2
--- /dev/null
+++ b/paludis/block_error.cc
@@ -0,0 +1,10 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "block_error.hh"
+
+using namespace paludis;
+
+BlockError::BlockError(const std::string & msg) throw () :
+ DepListError("Block: " + msg)
+{
+}
diff --git a/paludis/block_error.hh b/paludis/block_error.hh
new file mode 100644
index 0000000..6b16c2a
--- /dev/null
+++ b/paludis/block_error.hh
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_BLOCK_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_BLOCK_ERROR_HH 1
+
+#include <paludis/dep_list_error.hh>
+
+namespace paludis
+{
+ /**
+ * Thrown if a block is encountered.
+ */
+ class BlockError : public DepListError
+ {
+ public:
+ BlockError(const std::string & msg) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/category_name_part.cc b/paludis/category_name_part.cc
new file mode 100644
index 0000000..7f84ca1
--- /dev/null
+++ b/paludis/category_name_part.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "category_name_part.hh"
+
diff --git a/paludis/category_name_part.hh b/paludis/category_name_part.hh
new file mode 100644
index 0000000..4512395
--- /dev/null
+++ b/paludis/category_name_part.hh
@@ -0,0 +1,44 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_CATEGORY_NAME_PART_HH
+#define PALUDIS_GUARD_PALUDIS_CATEGORY_NAME_PART_HH 1
+
+#include <paludis/validated.hh>
+#include <paludis/category_name_part_validator.hh>
+#include <string>
+
+/** \file
+ * Declaration for the CategoryNamePart class.
+ *
+ * \ingroup Database
+ */
+
+namespace paludis
+{
+ /**
+ * A CategoryNamePart holds a std::string that is a valid name for the
+ * category part of a QualifiedPackageName.
+ *
+ * \ingroup Database
+ */
+ typedef Validated<std::string, CategoryNamePartValidator> CategoryNamePart;
+}
+
+#endif
diff --git a/paludis/category_name_part_collection.cc b/paludis/category_name_part_collection.cc
new file mode 100644
index 0000000..360cea3
--- /dev/null
+++ b/paludis/category_name_part_collection.cc
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "category_name_part_collection.hh"
+
+using namespace paludis;
+
+CategoryNamePartCollection::CategoryNamePartCollection()
+{
+}
+
+CategoryNamePartCollection::~CategoryNamePartCollection()
+{
+}
+
diff --git a/paludis/category_name_part_collection.hh b/paludis/category_name_part_collection.hh
new file mode 100644
index 0000000..040d505
--- /dev/null
+++ b/paludis/category_name_part_collection.hh
@@ -0,0 +1,48 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_CATEGORY_NAME_PART_COLLECTION_HH
+#define PALUDIS_GUARD_PALUDIS_CATEGORY_NAME_PART_COLLECTION_HH 1
+
+#include <paludis/category_name_part.hh>
+#include <paludis/sorted_collection.hh>
+
+namespace paludis
+{
+ /**
+ * Holds a set of CategoryNamePart instances.
+ *
+ * \ingroup Database
+ */
+ class CategoryNamePartCollection : public SortedCollection<CategoryNamePart>
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ CategoryNamePartCollection();
+
+ /**
+ * Destructor.
+ */
+ virtual ~CategoryNamePartCollection();
+ };
+}
+
+#endif
diff --git a/paludis/category_name_part_error.cc b/paludis/category_name_part_error.cc
new file mode 100644
index 0000000..4aded7b
--- /dev/null
+++ b/paludis/category_name_part_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "category_name_part_error.hh"
+
+using namespace paludis;
+
+CategoryNamePartError::CategoryNamePartError(const std::string & name) throw () :
+ NameError(name, "category name part")
+{
+}
+
diff --git a/paludis/category_name_part_error.hh b/paludis/category_name_part_error.hh
new file mode 100644
index 0000000..9823473
--- /dev/null
+++ b/paludis/category_name_part_error.hh
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_CATEGORY_NAME_PART_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_CATEGORY_NAME_PART_ERROR_HH 1
+
+#include <paludis/name_error.hh>
+#include <string>
+
+/** \file
+ * Declaration for the CategoryNamePartError exception.
+ *
+ * \ingroup Exception
+ * \ingroup Database
+ */
+
+namespace paludis
+{
+ /**
+ * A CategoryNamePartError is thrown if an invalid value is assigned to
+ * a CategoryNamePart.
+ *
+ * \ingroup Exception
+ * \ingroup Database
+ */
+ class CategoryNamePartError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ CategoryNamePartError(const std::string & name) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/category_name_part_validator.cc b/paludis/category_name_part_validator.cc
new file mode 100644
index 0000000..e5e7bec
--- /dev/null
+++ b/paludis/category_name_part_validator.cc
@@ -0,0 +1,49 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "category_name_part_validator.hh"
+#include "category_name_part_error.hh"
+
+using namespace paludis;
+
+void
+CategoryNamePartValidator::validate(const std::string & s)
+{
+ /* this gets called a lot, make it fast */
+
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_");
+
+ do
+ {
+ if (s.empty())
+ break;
+
+ if (std::string::npos != s.find_first_not_of(allowed_chars))
+ break;
+
+ return;
+
+ } while (false);
+
+ Context c("When validating category name '" + s + "':");
+ throw CategoryNamePartError(s);
+}
diff --git a/paludis/category_name_part_validator.hh b/paludis/category_name_part_validator.hh
new file mode 100644
index 0000000..f74cf95
--- /dev/null
+++ b/paludis/category_name_part_validator.hh
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_CATEGORY_NAME_PART_VALIDATOR_HH
+#define PALUDIS_GUARD_PALUDIS_CATEGORY_NAME_PART_VALIDATOR_HH 1
+
+#include <string>
+#include <paludis/instantiation_policy.hh>
+
+/** \file
+ * Declaration for the CategoryNamePartValidator class.
+ *
+ * \ingroup Database
+ */
+
+namespace paludis
+{
+ /**
+ * A CategoryNamePartValidator handles validation rules for the value
+ * of a CategoryNamePart.
+ *
+ * \ingroup Database
+ */
+ struct CategoryNamePartValidator :
+ private InstantiationPolicy<CategoryNamePartValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a CategoryNamePart,
+ * throw a CategoryNamePartError.
+ */
+ static void validate(const std::string &);
+ };
+}
+
+#endif
diff --git a/paludis/circular_dependency_error.cc b/paludis/circular_dependency_error.cc
new file mode 100644
index 0000000..4d7d50f
--- /dev/null
+++ b/paludis/circular_dependency_error.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "circular_dependency_error.hh"
+
diff --git a/paludis/circular_dependency_error.hh b/paludis/circular_dependency_error.hh
new file mode 100644
index 0000000..fd4111b
--- /dev/null
+++ b/paludis/circular_dependency_error.hh
@@ -0,0 +1,46 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_CIRCULAR_DEPENDENCY_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_CIRCULAR_DEPENDENCY_ERROR_HH 1
+
+#include <paludis/dep_list_error.hh>
+#include <paludis/join.hh>
+
+namespace paludis
+{
+ /**
+ * Thrown if a circular dependency is encountered.
+ */
+ class CircularDependencyError : public DepListError
+ {
+ public:
+ /**
+ * Constructor, from a sequence of the items causing the circular
+ * dependency.
+ */
+ template <typename I_>
+ CircularDependencyError(I_ begin, const I_ end) throw () :
+ DepListError("Circular dependency: " + join(begin, end, " -> "))
+ {
+ }
+ };
+}
+
+#endif
diff --git a/paludis/comparison_policy.cc b/paludis/comparison_policy.cc
new file mode 100644
index 0000000..c123566
--- /dev/null
+++ b/paludis/comparison_policy.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "comparison_policy.hh"
+
diff --git a/paludis/comparison_policy.hh.m4 b/paludis/comparison_policy.hh.m4
new file mode 100644
index 0000000..b33f2f8
--- /dev/null
+++ b/paludis/comparison_policy.hh.m4
@@ -0,0 +1,406 @@
+#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) 2005, 2006 Ciaran McCreesh <ciaranm@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_COMPARISON_POLICY_HH
+#define PALUDIS_GUARD_PALUDIS_COMPARISON_POLICY_HH 1
+
+namespace paludis
+{
+ /**
+ * Comparison modes for paludis::ComparisonPolicy.
+ */
+ namespace comparison_mode
+ {
+ /**
+ * No comparisons can be made.
+ */
+ struct NoComparisonTag
+ {
+ };
+
+ /**
+ * Comparisons can be made via operator== and operator!=.
+ */
+ struct EqualityComparisonTag
+ {
+ };
+
+ /**
+ * The full range of comparison operators is available.
+ */
+ struct FullComparisonTag
+ {
+ };
+ }
+
+ /**
+ * Comparison methods for paludis::ComparisonPolicy.
+ */
+ namespace comparison_method
+ {
+ /**
+ * Comparisons are done via a member of type MemberType_.
+ */
+ 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).
+ */
+ struct CompareByMemberComparisonFunctionTag
+ {
+ };
+
+
+ /**
+ * Comparisons are done via a member function that returns an item of
+ * type MemberType_.
+ */
+ template <typename MemberType_>
+ struct CompareByMemberFetchFunctionTag
+ {
+ };
+ }
+
+#ifdef DOXYGEN
+ /**
+ * ComparisonPolicy specifies the availabillity of comparison methods and
+ * the strategy used to do comparisons.
+ */
+ template <typename OurType_, typename ComparisonModeTag_, typename ComparisonMethodTag_>
+ struct ComparisonPolicy
+ {
+ };
+#else
+ template <typename OurType_, typename ComparisonModeTag_, typename ComparisonMethodTag_>
+ struct ComparisonPolicy;
+#endif
+
+ /**
+ * ComparisonPolicy: specialisation for NoComparisonTag.
+ */
+ template <typename OurType_, typename ComparisonMethodTag_>
+ class ComparisonPolicy<OurType_, comparison_mode::NoComparisonTag, ComparisonMethodTag_>
+ {
+ public:
+ /// 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.
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberTag<MemberType_> >
+ {
+ private:
+ const MemberType_ OurType_::* const _v;
+
+ public:
+ /// 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;
+
+ /// Constructor.
+ ComparisonPolicy(const MemberType_ OurType_::* const v) :
+ _v(v)
+ {
+ }
+
+ /// Copy constructor.
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+define(`make_operator', `
+ /// $1 operator.
+ bool operator$1 (const OurType_ & other) const
+ {
+ return static_cast<const OurType_ *>(this)->*_v $1 other.*(
+ (static_cast<const ComparisonPolicyType *>(&other))->_v);
+ }
+')
+make_operator(`==')
+make_operator(`!=')
+
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for EqualityComparisonTag +
+ * CompareByMemberComparisonFunctionTag.
+ */
+ template <typename OurType_>
+ class ComparisonPolicy<OurType_, comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberComparisonFunctionTag>
+ {
+ private:
+ bool (OurType_::* const _v)(const OurType_ &) const;
+
+ public:
+ /// 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;
+
+ /// Constructor.
+ ComparisonPolicy(bool (OurType_::* const v)(const OurType_ &) const) :
+ _v(v)
+ {
+ }
+
+ /// Copy constructor.
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+ /// Equal operator.
+ bool operator== (const OurType_ & other) const
+ {
+ return (static_cast<const OurType_ *>(this)->*_v)(other);
+ }
+
+ /// Not equal operator.
+ bool operator!= (const OurType_ & other) const
+ {
+ return ! (static_cast<const OurType_ *>(this)->*_v)(other);
+ }
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for FullComparisonTag +
+ * CompareByMemberTag.
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<MemberType_> >
+ {
+ private:
+ const MemberType_ OurType_::* const _v;
+
+ public:
+ /// 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;
+
+ /// Constructor.
+ ComparisonPolicy(const MemberType_ OurType_::* const v) :
+ _v(v)
+ {
+ }
+
+ /// Copy constructor.
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+define(`make_operator', `
+ /// $1 operator.
+ bool operator$1 (const OurType_ & other) const
+ {
+ return static_cast<const OurType_ *>(this)->*_v $1 other.*(
+ (static_cast<const ComparisonPolicyType *>(&other))->_v);
+ }
+')
+make_operator(`==')
+make_operator(`!=')
+make_operator(`<=')
+make_operator(`>=')
+make_operator(`<')
+make_operator(`>')
+
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for FullComparisonTag +
+ * CompareByMemberComparisonFunctionTag.
+ */
+ template <typename OurType_>
+ class ComparisonPolicy<OurType_, comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberComparisonFunctionTag>
+ {
+ private:
+ int (OurType_::* const _v)(const OurType_ &) const;
+
+ public:
+ /// 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;
+
+ /// Constructor.
+ ComparisonPolicy(int (OurType_::* v)(const OurType_ &) const) :
+ _v(v)
+ {
+ }
+
+ /// Copy constructor.
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+define(`make_operator', `
+ /// $1 operator.
+ bool operator$1 (const OurType_ & other) const
+ {
+ return (static_cast<const OurType_ *>(this)->*_v)(other) $1 0;
+ }
+')
+make_operator(`==')
+make_operator(`!=')
+make_operator(`<=')
+make_operator(`>=')
+make_operator(`<')
+make_operator(`>')
+
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for EqualityComparisonTag +
+ * CompareByMemberFetchFunctionTag.
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberFetchFunctionTag<MemberType_> >
+ {
+ private:
+ MemberType_ (OurType_::* const _v)() const;
+
+ public:
+ /// 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;
+
+ /// Constructor.
+ ComparisonPolicy(MemberType_ (OurType_::* const v)() const) :
+ _v(v)
+ {
+ }
+
+ /// Copy constructor.
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+define(`make_operator', `
+ /// $1 operator.
+ bool operator$1 (const OurType_ & other) const
+ {
+ return (static_cast<const OurType_ *>(this)->*_v)() $1 (other.*other._v)();
+ }
+')
+make_operator(`==')
+make_operator(`!=')
+ };
+
+ /**
+ * ComparisonPolicy: specialisation for FullComparisonTag +
+ * CompareByMemberFetchFunctionTag.
+ */
+ template <typename OurType_, typename MemberType_>
+ class ComparisonPolicy<OurType_, comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberFetchFunctionTag<MemberType_> >
+ {
+ private:
+ MemberType_ (OurType_::* const _v)() const;
+
+ public:
+ /// 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;
+
+ /// Constructor.
+ ComparisonPolicy(MemberType_ (OurType_::* const v)() const) :
+ _v(v)
+ {
+ }
+
+ /// Copy constructor.
+ ComparisonPolicy(const ComparisonPolicy & other) :
+ _v(other._v)
+ {
+ }
+
+define(`make_operator', `
+ /// $1 operator.
+ bool operator$1 (const OurType_ & other) const
+ {
+ return ((static_cast<const OurType_ *>(this)->*_v)()) $1
+ ((other.*(static_cast<const OurType_ *>(&other)->_v))());
+ }
+')
+make_operator(`==')
+make_operator(`!=')
+make_operator(`>=')
+make_operator(`<=')
+make_operator(`>')
+make_operator(`<')
+
+ };
+}
+
+#endif
diff --git a/paludis/comparison_policy_TEST.cc b/paludis/comparison_policy_TEST.cc
new file mode 100644
index 0000000..1bdbe1c
--- /dev/null
+++ b/paludis/comparison_policy_TEST.cc
@@ -0,0 +1,39 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "comparison_policy.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+/// \todo
+
+namespace test_cases
+{
+ struct ComparisonTest : TestCase
+ {
+ ComparisonTest() : TestCase("comparison") { }
+
+ void run()
+ {
+ }
+ } test_comparison;
+}
diff --git a/paludis/composite_dep_atom.cc b/paludis/composite_dep_atom.cc
new file mode 100644
index 0000000..c6b0ca7
--- /dev/null
+++ b/paludis/composite_dep_atom.cc
@@ -0,0 +1,32 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "composite_dep_atom.hh"
+
+using namespace paludis;
+
+CompositeDepAtom::CompositeDepAtom()
+{
+}
+
+void
+CompositeDepAtom::add_child(DepAtom::ConstPointer c)
+{
+ _children.push_back(c);
+}
diff --git a/paludis/composite_dep_atom.hh b/paludis/composite_dep_atom.hh
new file mode 100644
index 0000000..e4c20cc
--- /dev/null
+++ b/paludis/composite_dep_atom.hh
@@ -0,0 +1,85 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_COMPOSITE_DEP_ATOM_HH
+#define PALUDIS_GUARD_PALUDIS_COMPOSITE_DEP_ATOM_HH 1
+
+#include <paludis/dep_atom.hh>
+#include <paludis/counted_ptr.hh>
+#include <list>
+
+/** \file
+ * Declarations for the CompositeDepAtom class.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * Class for dependency atoms that have a number of child dependency
+ * atoms.
+ *
+ * \ingroup DepResolver
+ */
+ class CompositeDepAtom : public DepAtom,
+ public virtual Composite<DepAtom, CompositeDepAtom>
+ {
+ private:
+ std::list<DepAtom::ConstPointer> _children;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ CompositeDepAtom();
+
+ public:
+ /**
+ * Append a child to our collection.
+ */
+ virtual void add_child(DepAtom::ConstPointer);
+
+ /**
+ * Iterator for iterating over our children.
+ */
+ typedef std::list<DepAtom::ConstPointer>::const_iterator Iterator;
+
+ /**
+ * Iterator to the start of our children.
+ */
+ Iterator begin() const
+ {
+ return _children.begin();
+ }
+
+ /**
+ * Iterator to past the end of our children.
+ */
+ Iterator end() const
+ {
+ return _children.end();
+ }
+
+ typedef CountedPtr<CompositeDepAtom, count_policy::InternalCountTag> Pointer;
+ typedef CountedPtr<const CompositeDepAtom, count_policy::InternalCountTag> ConstPointer;
+ };
+}
+
+#endif
diff --git a/paludis/composite_pattern.cc b/paludis/composite_pattern.cc
new file mode 100644
index 0000000..986fb55
--- /dev/null
+++ b/paludis/composite_pattern.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "composite_pattern.hh"
+
diff --git a/paludis/composite_pattern.hh b/paludis/composite_pattern.hh
new file mode 100644
index 0000000..fecb47c
--- /dev/null
+++ b/paludis/composite_pattern.hh
@@ -0,0 +1,64 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_COMPOSITE_PATTERN_HH
+#define PALUDIS_GUARD_PALUDIS_COMPOSITE_PATTERN_HH 1
+
+/** \file
+ * Declarations for the Composite template class.
+ *
+ * \ingroup Utility
+ */
+
+namespace paludis
+{
+ /**
+ * A Composite class represents both a class and a collection of
+ * child instances of the same class.
+ */
+ template <typename ChildClass_, typename CompositeClass_ = ChildClass_>
+ class Composite
+ {
+ private:
+ mutable CompositeClass_ * _composite;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ Composite() :
+ _composite(0)
+ {
+ }
+
+ public:
+ /**
+ * Fetch a CompositeClass_ representation of ourself, or 0 if we
+ * are not composite.
+ */
+ CompositeClass_ * get_composite() const
+ {
+ if (0 == _composite)
+ _composite = & dynamic_cast<CompositeClass_>(*this);
+ return _composite;
+ }
+ };
+}
+
+#endif
diff --git a/paludis/composite_visitor_pattern-impl.hh b/paludis/composite_visitor_pattern-impl.hh
new file mode 100644
index 0000000..d3c1b0c
--- /dev/null
+++ b/paludis/composite_visitor_pattern-impl.hh
@@ -0,0 +1,41 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_COMPOSITE_VISITOR_PATTERN_IMPL_HH
+#define PALUDIS_GUARD_PALUDIS_COMPOSITE_VISITOR_PATTERN_IMPL_HH 1
+
+#include <paludis/visitor_pattern-impl.hh>
+
+namespace paludis
+{
+ template <typename OurType_, typename CNodeType_>
+ void
+ VisitsComposite<OurType_, CNodeType_>::visit(const CNodeType_ * const n)
+ {
+ enter(n);
+
+ typename CNodeType_::Iterator i(n->begin()), e(n->end());
+ for ( ; i != e ; ++i)
+ (*i)->accept(static_cast<OurType_ *>(this));
+
+ leave(n);
+ }
+}
+
+#endif
diff --git a/paludis/composite_visitor_pattern.cc b/paludis/composite_visitor_pattern.cc
new file mode 100644
index 0000000..08b162a
--- /dev/null
+++ b/paludis/composite_visitor_pattern.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "composite_visitor_pattern.hh"
+#include "composite_visitor_pattern-impl.hh"
diff --git a/paludis/composite_visitor_pattern.hh b/paludis/composite_visitor_pattern.hh
new file mode 100644
index 0000000..5d76895
--- /dev/null
+++ b/paludis/composite_visitor_pattern.hh
@@ -0,0 +1,55 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_COMPOSITE_VISITOR_PATTERN_HH
+#define PALUDIS_GUARD_PALUDIS_COMPOSITE_VISITOR_PATTERN_HH 1
+
+#include <paludis/visitor_pattern.hh>
+
+namespace paludis
+{
+ /**
+ * Declares that a class can visit a node of type NodeType_, which is
+ * a composite node, and that it should use enter and leave rather than
+ * visit.
+ *
+ * \ingroup Utility
+ */
+ template <typename OurType_, typename CNodeType_>
+ class VisitsComposite : public virtual Visits<CNodeType_>
+ {
+ public:
+ /**
+ * Implement visit to call enter, then our children, then leave.
+ */
+ virtual void visit(const CNodeType_ * const n);
+
+ /**
+ * Interface: enter a node.
+ */
+ virtual void enter(const CNodeType_ * const n) = 0;
+
+ /**
+ * Interface: leave a node.
+ */
+ virtual void leave(const CNodeType_ * const n) = 0;
+ };
+}
+
+#endif
diff --git a/paludis/config_file.cc b/paludis/config_file.cc
new file mode 100644
index 0000000..f63ab06
--- /dev/null
+++ b/paludis/config_file.cc
@@ -0,0 +1,64 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "config_file.hh"
+#include "config_file_error.hh"
+#include "strip.hh"
+
+using namespace paludis;
+
+ConfigFile::ConfigFile(std::istream * const stream) :
+ _stream(stream),
+ _has_lines(false)
+{
+}
+
+void
+ConfigFile::need_lines() const
+{
+ if (_has_lines)
+ return;
+
+ std::string line;
+ while (std::getline(*_stream, line))
+ {
+ normalise_line(line);
+ if (skip_line(line))
+ continue;
+ accept_line(line);
+ }
+ if (! _stream->eof())
+ throw ConfigFileError("Error reading from file");
+
+ _has_lines = true;
+}
+
+void
+ConfigFile::normalise_line(std::string & s) const
+{
+ s = strip_leading(strip_trailing(s, " \t\n"), " \t\n");
+}
+
+bool
+ConfigFile::skip_line(const std::string & s) const
+{
+ return (s.empty() || '#' == s.at(0));
+}
+
diff --git a/paludis/config_file.hh b/paludis/config_file.hh
new file mode 100644
index 0000000..198891f
--- /dev/null
+++ b/paludis/config_file.hh
@@ -0,0 +1,92 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_CONFIG_FILE_HH
+#define PALUDIS_GUARD_PALUDIS_CONFIG_FILE_HH 1
+
+#include <paludis/instantiation_policy.hh>
+#include <istream>
+#include <list>
+#include <string>
+
+/** \file
+ * Declarations for the ConfigFile class.
+ *
+ * \ingroup ConfigFile
+ */
+
+namespace paludis
+{
+ /**
+ * A ConfigFile is a file containing one entry per line, with lines
+ * starting with a # being ignored and leading and trailing whitespace
+ * being discarded.
+ *
+ * \ingroup ConfigFile
+ */
+ class ConfigFile :
+ paludis::InstantiationPolicy<ConfigFile, instantiation_method::NonCopyableTag>
+ {
+ private:
+ std::istream * const _stream;
+
+ mutable bool _has_lines;
+
+ protected:
+ /**
+ * In-place normalise a line. By default, trims leading and
+ * trailing whitespace. Child classes may override.
+ */
+ virtual void normalise_line(std::string &) const;
+
+ /**
+ * Return whether to skip a line. By default, skips on blank
+ * lines and lines starting with a #. Child classes may
+ * override. This is called on a normalised line, not a raw
+ * string.
+ */
+ virtual bool skip_line(const std::string &) const;
+
+ /**
+ * Accept a normalised line that is not to be skipped.
+ */
+ virtual void accept_line(const std::string &) const = 0;
+
+ /**
+ * If we have not done so already, read in our lines.
+ */
+ void need_lines() const;
+
+ /**
+ * Constructor.
+ */
+ ConfigFile(std::istream * const stream);
+
+ public:
+ /**
+ * Destructor.
+ */
+ virtual ~ConfigFile()
+ {
+ }
+ };
+}
+
+#endif
diff --git a/paludis/config_file_TEST.cc b/paludis/config_file_TEST.cc
new file mode 100644
index 0000000..1371a76
--- /dev/null
+++ b/paludis/config_file_TEST.cc
@@ -0,0 +1,90 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "config_file.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <sstream>
+#include <vector>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for config_file.hh .
+ *
+ * \ingroup Test
+ * \ingroup ConfigFile
+ */
+
+#ifndef DOXYGEN
+class TestFile : protected ConfigFile
+{
+ public:
+ TestFile(std::istream * const stream) :
+ ConfigFile(stream)
+ {
+ need_lines();
+ }
+
+ mutable std::vector<std::string> lines;
+
+ protected:
+ void accept_line(const std::string & s) const
+ {
+ lines.push_back(s);
+ }
+};
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Test ConfigFile.
+ *
+ * \ingroup Test
+ */
+ struct ConfigFileTest : TestCase
+ {
+ ConfigFileTest() : TestCase("config file") { }
+
+ void run()
+ {
+ std::stringstream s;
+ s << "one" << std::endl;
+ s << " two \t " << std::endl;
+ s << " \t " << std::endl;
+ s << "" << std::endl;
+ s << "three" << std::endl;
+ s << "# blah" << std::endl;
+ s << " # blah" << std::endl;
+ s << "#" << std::endl;
+ s << " # \t " << std::endl;
+ s << "four four" << std::endl;
+ TestFile f(&s);
+ TEST_CHECK_EQUAL(f.lines.size(), 4);
+ TEST_CHECK_EQUAL(f.lines.at(0), "one");
+ TEST_CHECK_EQUAL(f.lines.at(1), "two");
+ TEST_CHECK_EQUAL(f.lines.at(2), "three");
+ TEST_CHECK_EQUAL(f.lines.at(3), "four four");
+ }
+ } test_config_file;
+}
+
diff --git a/paludis/config_file_error.cc b/paludis/config_file_error.cc
new file mode 100644
index 0000000..1dd881b
--- /dev/null
+++ b/paludis/config_file_error.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "config_file_error.hh"
+
+using namespace paludis;
+
+ConfigFileError::ConfigFileError(const std::string & message) throw () :
+ Exception("Config file error: " + message)
+{
+}
+
diff --git a/paludis/config_file_error.hh b/paludis/config_file_error.hh
new file mode 100644
index 0000000..f14534c
--- /dev/null
+++ b/paludis/config_file_error.hh
@@ -0,0 +1,44 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_CONFIG_FILE_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_CONFIG_FILE_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+namespace paludis
+{
+ /**
+ * Thrown if an error occurs when reading a ConfigFile.
+ *
+ * \ingroup Exception
+ * \ingroup ConfigFile
+ */
+ class ConfigFileError : public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ ConfigFileError(const std::string & message) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/container_entry.cc b/paludis/container_entry.cc
new file mode 100644
index 0000000..99bd3fb
--- /dev/null
+++ b/paludis/container_entry.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "container_entry.hh"
+
diff --git a/paludis/container_entry.hh b/paludis/container_entry.hh
new file mode 100644
index 0000000..bbab402
--- /dev/null
+++ b/paludis/container_entry.hh
@@ -0,0 +1,66 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_CONTAINER_ENTRY_HH
+#define PALUDIS_GUARD_PALUDIS_CONTAINER_ENTRY_HH 1
+
+#include <list>
+
+namespace paludis
+{
+ /**
+ * Hold an entry in a container for as long as our ContainerEntry instance
+ * is in scope (RAII).
+ */
+ template <typename Container_>
+ struct ContainerEntry;
+
+ /**
+ * Hold an entry in a container for as long as our ContainerEntry instance
+ * is in scope (RAII, partial specialisation for std::list).
+ */
+ template <typename Item_>
+ class ContainerEntry<std::list<Item_> >
+ {
+ private:
+ std::list<Item_> * const _list;
+
+ typename std::list<Item_>::iterator _item;
+
+ public:
+ /**
+ * Constructor.
+ */
+ ContainerEntry(std::list<Item_> * const list, const Item_ & item) :
+ _list(list),
+ _item(list->insert(list->begin(), item))
+ {
+ }
+
+ /**
+ * Destructor.
+ */
+ ~ContainerEntry()
+ {
+ _list->erase(_item);
+ }
+ };
+}
+
+#endif
diff --git a/paludis/container_entry_TEST.cc b/paludis/container_entry_TEST.cc
new file mode 100644
index 0000000..91a74db
--- /dev/null
+++ b/paludis/container_entry_TEST.cc
@@ -0,0 +1,60 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include "container_entry.hh"
+#include <algorithm>
+
+using namespace test;
+using namespace paludis;
+
+namespace test_cases
+{
+ struct ContainerEntryListTest : TestCase
+ {
+ ContainerEntryListTest() : TestCase("list") { }
+
+ void run()
+ {
+ std::list<int> list;
+ TEST_CHECK(list.empty());
+ {
+ ContainerEntry<std::list<int> > e1(&list, 5);
+ TEST_CHECK(list.begin() != list.end());
+ TEST_CHECK_EQUAL(std::distance(list.begin(), list.end()), 1);
+ TEST_CHECK(list.end() != std::find(list.begin(), list.end(), 5));
+
+ {
+ ContainerEntry<std::list<int> > e2(&list, 4);
+ TEST_CHECK(list.begin() != list.end());
+ TEST_CHECK_EQUAL(std::distance(list.begin(), list.end()), 2);
+ TEST_CHECK(list.end() != std::find(list.begin(), list.end(), 5));
+ TEST_CHECK(list.end() != std::find(list.begin(), list.end(), 4));
+ }
+
+ TEST_CHECK(list.begin() != list.end());
+ TEST_CHECK_EQUAL(std::distance(list.begin(), list.end()), 1);
+ TEST_CHECK(list.end() != std::find(list.begin(), list.end(), 5));
+ }
+ TEST_CHECK(list.empty());
+ }
+ } test_container_entry_list;
+}
+
diff --git a/paludis/counted_ptr.cc b/paludis/counted_ptr.cc
new file mode 100644
index 0000000..eb9f788
--- /dev/null
+++ b/paludis/counted_ptr.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "counted_ptr.hh"
+
diff --git a/paludis/counted_ptr.hh b/paludis/counted_ptr.hh
new file mode 100644
index 0000000..51cac27
--- /dev/null
+++ b/paludis/counted_ptr.hh
@@ -0,0 +1,540 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_COUNTED_PTR_HH
+#define PALUDIS_GUARD_PALUDIS_COUNTED_PTR_HH 1
+
+#include <paludis/attributes.hh>
+#include <paludis/comparison_policy.hh>
+#include <paludis/counted_ptr_error.hh>
+
+/** \file
+ * Declaration for the CountedPtr template class.
+ *
+ * \ingroup Pointer
+ */
+
+namespace paludis
+{
+ /**
+ * Contains CountedPtr count policies.
+ *
+ * \ingroup Pointer
+ */
+ namespace count_policy
+ {
+ /**
+ * CountedPtr policy: reference counts are stored separately.
+ *
+ * \ingroup Pointer
+ */
+ struct ExternalCountTag
+ {
+ };
+
+ /**
+ * CountedPtr policy: reference counts are stored by the class via the
+ * Counted subclass.
+ *
+ * \ingroup Pointer
+ */
+ struct InternalCountTag
+ {
+ };
+ }
+
+ /**
+ * Contains CountedPtr dereference policies.
+ *
+ * \ingroup Pointer
+ */
+ namespace dereference_policy
+ {
+ /**
+ * CountedPtr dereferences are not checked.
+ *
+ * \ingroup Pointer
+ */
+ struct UncheckedDereferenceTag
+ {
+ };
+
+ /**
+ * CountedPtr dereferences are checked, and a CountedPtrError is
+ * thrown for 0 dereferences.
+ *
+ * \ingroup Pointer
+ */
+ struct CheckedDereferenceTag
+ {
+ };
+ }
+
+ /**
+ * CountedPtr internals.
+ *
+ * \ingroup Pointer
+ */
+ namespace counted_ptr_internals
+ {
+ /**
+ * Base class for CountedPtr.
+ */
+ template <typename T_, typename DereferencePolicy_>
+ class CountedPtrBase;
+
+ /**
+ * Base class for CountedPtr (specialisation for UncheckedDereferenceTag).
+ */
+ template <typename T_>
+ class CountedPtrBase<T_, dereference_policy::UncheckedDereferenceTag> :
+ public ComparisonPolicy<CountedPtrBase<T_, dereference_policy::UncheckedDereferenceTag>,
+ 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;
+
+ CountedPtrBase(T_ * ptr) :
+ ComparisonPolicy<CountedPtrBase<T_, dereference_policy::UncheckedDereferenceTag>,
+ comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberTag<T_ *> >(
+ &CountedPtrBase::_ptr),
+ _ptr(ptr)
+ {
+ }
+
+ ~CountedPtrBase()
+ {
+ }
+
+ public:
+ /**
+ * Dereference operator (const).
+ */
+ inline const T_ & operator* () const PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Dereference to member operator (const).
+ */
+ inline const T_ * operator-> () const PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Dereference operator (non const).
+ */
+ T_ & operator* () PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Dereference to member operator (non const).
+ */
+ T_ * operator-> () PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Not null?
+ */
+ operator bool() const
+ {
+ return _ptr;
+ }
+
+ /**
+ * Fetch our raw pointer.
+ */
+ T_ * raw_pointer() const
+ {
+ return _ptr;
+ }
+ };
+
+ template <typename T_>
+ const T_ & CountedPtrBase<T_, dereference_policy::UncheckedDereferenceTag>::operator* () const
+ {
+ return *_ptr;
+ }
+
+ template <typename T_>
+ const T_ * CountedPtrBase<T_, dereference_policy::UncheckedDereferenceTag>::operator-> () const
+ {
+ return _ptr;
+ }
+
+ template <typename T_>
+ T_ & CountedPtrBase<T_, dereference_policy::UncheckedDereferenceTag>::operator* ()
+ {
+ return *_ptr;
+ }
+
+ template <typename T_>
+ T_ * CountedPtrBase<T_, dereference_policy::UncheckedDereferenceTag>::operator-> ()
+ {
+ return _ptr;
+ }
+ /**
+ * Base class for CountedPtr (specialisation for CheckedDereferenceTag).
+ */
+ template <typename T_>
+ class CountedPtrBase<T_, dereference_policy::CheckedDereferenceTag> :
+ public ComparisonPolicy<CountedPtrBase<T_, dereference_policy::CheckedDereferenceTag>,
+ 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;
+
+ CountedPtrBase(T_ * ptr) :
+ ComparisonPolicy<CountedPtrBase<T_, dereference_policy::CheckedDereferenceTag>,
+ comparison_mode::EqualityComparisonTag,
+ comparison_method::CompareByMemberTag<T_ *> >(
+ &CountedPtrBase::_ptr),
+ _ptr(ptr)
+ {
+ }
+
+ ~CountedPtrBase()
+ {
+ }
+
+ public:
+ /**
+ * Dereference operator (const).
+ */
+ inline const T_ & operator* () const PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Dereference to member operator (const).
+ */
+ inline const T_ * operator-> () const PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Dereference operator (non const).
+ */
+ T_ & operator* () PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Dereference to member operator (non const).
+ */
+ T_ * operator-> () PALUDIS_ATTRIBUTE((pure));
+
+ /**
+ * Not null?
+ */
+ operator bool() const
+ {
+ return _ptr;
+ }
+
+ /**
+ * Fetch our raw pointer.
+ */
+ T_ * raw_pointer() const
+ {
+ return _ptr;
+ }
+ };
+
+ template <typename T_>
+ const T_ & CountedPtrBase<T_, dereference_policy::CheckedDereferenceTag>::operator* () const
+ {
+ if (0 == _ptr)
+ throw CountedPtrError();
+ return *_ptr;
+ }
+
+ template <typename T_>
+ const T_ * CountedPtrBase<T_, dereference_policy::CheckedDereferenceTag>::operator-> () const
+ {
+ if (0 == _ptr)
+ throw CountedPtrError();
+ return _ptr;
+ }
+
+ template <typename T_>
+ T_ & CountedPtrBase<T_, dereference_policy::CheckedDereferenceTag>::operator* ()
+ {
+ if (0 == _ptr)
+ throw CountedPtrError();
+ return *_ptr;
+ }
+
+ template <typename T_>
+ T_ * CountedPtrBase<T_, dereference_policy::CheckedDereferenceTag>::operator-> ()
+ {
+ if (0 == _ptr)
+ throw CountedPtrError();
+ return _ptr;
+ }
+ }
+
+ /**
+ * Reference counted pointer class.
+ *
+ * \ingroup Pointer
+ */
+ template <typename T_, typename CountPolicy_ = count_policy::InternalCountTag,
+ typename DereferencePolicy_ = dereference_policy::UncheckedDereferenceTag>
+ class CountedPtr;
+
+ /**
+ * Base for an internal counted class.
+ *
+ * \ingroup Pointer
+ */
+ template <typename T_, typename DereferencePolicy_ = dereference_policy::UncheckedDereferenceTag>
+ class InternalCounted;
+
+ /**
+ * Reference counted pointer class (specialisation for ExternalCountTag).
+ *
+ * \ingroup Pointer
+ */
+ template <typename T_, typename DereferencePolicy_>
+ class CountedPtr<T_, count_policy::ExternalCountTag, DereferencePolicy_> :
+ public counted_ptr_internals::CountedPtrBase<T_, DereferencePolicy_>
+ {
+ private:
+ unsigned * _ref_count;
+
+ public:
+ /**
+ * Constructor, from a raw pointer.
+ */
+ explicit CountedPtr(T_ * const ptr) :
+ counted_ptr_internals::CountedPtrBase<T_, DereferencePolicy_>(ptr),
+ _ref_count(new unsigned(1))
+ {
+ }
+
+ /**
+ * Constructor, from another CountedPtr.
+ */
+ CountedPtr(const CountedPtr & other) :
+ counted_ptr_internals::CountedPtrBase<T_, DereferencePolicy_>(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_, DereferencePolicy_>(other._ptr),
+ _ref_count(other.reference_count_pointer())
+ {
+ ++*_ref_count;
+ }
+
+ /**
+ * Destructor.
+ */
+ ~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;
+ }
+
+ /**
+ * Fetch our reference count pointer.
+ */
+ unsigned * reference_count_pointer() const
+ {
+ return _ref_count;
+ }
+ };
+
+ /**
+ * Reference counted pointer class (specialisation for InternalCountTag).
+ *
+ * \ingroup Pointer
+ */
+ template <typename T_, typename DereferencePolicy_>
+ class CountedPtr<T_, count_policy::InternalCountTag, DereferencePolicy_> :
+ public counted_ptr_internals::CountedPtrBase<T_, DereferencePolicy_>
+ {
+ public:
+ /**
+ * Constructor, from a raw pointer.
+ */
+ explicit CountedPtr(T_ * const ptr) :
+ counted_ptr_internals::CountedPtrBase<T_, DereferencePolicy_>(ptr)
+ {
+ if (0 != this->_ptr)
+ ++*this->_ptr->reference_count_pointer();
+ }
+
+ /**
+ * Constructor, from another CountedPtr.
+ */
+ CountedPtr(const CountedPtr & other) :
+ counted_ptr_internals::CountedPtrBase<T_, DereferencePolicy_>(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_, DereferencePolicy_>(other.raw_pointer())
+ {
+ if (0 != this->_ptr)
+ ++*this->_ptr->reference_count_pointer();
+ }
+
+ /**
+ * Destructor.
+ */
+ ~CountedPtr()
+ {
+ if (0 != this->_ptr)
+ if (0 == --(*this->_ptr->reference_count_pointer()))
+ delete this->_ptr;
+ }
+
+ /**
+ * Assignment, from another 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;
+ }
+
+ /**
+ * Fetch our reference count pointer.
+ */
+ unsigned * reference_count_pointer() const
+ {
+ if (0 != this->_ptr)
+ return this->_ptr->reference_count_pointer();
+ else
+ return 0;
+ }
+ };
+}
+
+#include <paludis/instantiation_policy.hh>
+
+namespace paludis
+{
+ /**
+ * Base class for an internally counted class.
+ *
+ * \ingroup Pointer
+ */
+ template <typename T_, typename DereferencePolicy_>
+ class InternalCounted :
+ private InstantiationPolicy<InternalCounted<T_, DereferencePolicy_>,
+ instantiation_method::NonCopyableTag>
+ {
+ private:
+ mutable unsigned _ref_count;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ InternalCounted() :
+ _ref_count(0)
+ {
+ }
+
+ /**
+ * Destructor.
+ */
+ ~InternalCounted()
+ {
+ }
+
+ public:
+ /**
+ * A CountedPtr to us.
+ */
+ typedef CountedPtr<T_, count_policy::InternalCountTag, DereferencePolicy_> Pointer;
+
+ /**
+ * A CountedPtr to us (const).
+ */
+ typedef CountedPtr<const T_, count_policy::InternalCountTag, DereferencePolicy_> ConstPointer;
+
+ /**
+ * Fetch a pointer to our reference count (may be zero).
+ */
+ unsigned * reference_count_pointer() const
+ {
+ return & _ref_count;
+ }
+ };
+}
+
+#endif
+
diff --git a/paludis/counted_ptr_TEST.cc b/paludis/counted_ptr_TEST.cc
new file mode 100644
index 0000000..aec8020
--- /dev/null
+++ b/paludis/counted_ptr_TEST.cc
@@ -0,0 +1,350 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "counted_ptr.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <string>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for counted_ptr.hh .
+ *
+ * \ingroup Test
+ * \ingroup Pointer
+ */
+
+#ifndef DOXYGEN
+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;
+ }
+};
+
+std::ostream & operator<< (std::ostream & s, const MyClass & c)
+{
+ s << c.value();
+ return s;
+}
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test CountedPtr creation tests.
+ *
+ * \ingroup Test
+ */
+ 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 Test
+ */
+ 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);
+ }
+ } counted_ptr_dereference_tests;
+
+ /**
+ * \test CountedPtr copy tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_copy_tests;
+
+ /**
+ * \test CountedPtr dereference-assign tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_dereference_assign_tests;
+
+ /**
+ * \test CountedPtr assign value tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_assign_value_tests;
+
+ /**
+ * \test CountedPtr assign pointer tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_assign_pointer_tests;
+
+ /**
+ * \test CountedPtr internal creation tests.
+ *
+ * \ingroup Test
+ */
+ 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 Test
+ */
+ 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);
+ }
+ } counted_ptr_internal_dereference_tests;
+
+ /**
+ * \test CountedPtr internal copy tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_internal_copy_tests;
+
+ /**
+ * \test CountedPtr internal dereference-assign tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_internal_dereference_assign_tests;
+
+ /**
+ * \test CountedPtr internal assign value tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_internal_assign_value_tests;
+
+ /**
+ * \test CountedPtr internal assign pointer tests.
+ *
+ * \ingroup Test
+ */
+ 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);
+ }
+ } counted_ptr_internal_assign_pointer_tests;
+}
+
diff --git a/paludis/counted_ptr_error.cc b/paludis/counted_ptr_error.cc
new file mode 100644
index 0000000..e729370
--- /dev/null
+++ b/paludis/counted_ptr_error.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "counted_ptr_error.hh"
+
+using namespace paludis;
+
+CountedPtrError::CountedPtrError() throw () :
+ Exception("CountedPtr dereference error")
+{
+}
+
diff --git a/paludis/counted_ptr_error.hh b/paludis/counted_ptr_error.hh
new file mode 100644
index 0000000..f3a39c8
--- /dev/null
+++ b/paludis/counted_ptr_error.hh
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_COUNTED_PTR_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+/** \file
+ * Declarations for the CountedPtrError exception class.
+ *
+ * \ingroup Pointer
+ * \ingroup Exception
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown when a CountedPtr check fails.
+ *
+ * \ingroup Pointer
+ * \ingroup Exception
+ */
+ class CountedPtrError : public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ CountedPtrError() throw ();
+ };
+}
+
+#endif
diff --git a/paludis/create_insert_iterator.cc b/paludis/create_insert_iterator.cc
new file mode 100644
index 0000000..b8585d7
--- /dev/null
+++ b/paludis/create_insert_iterator.cc
@@ -0,0 +1,4 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "create_insert_iterator.hh"
+
diff --git a/paludis/create_insert_iterator.hh b/paludis/create_insert_iterator.hh
new file mode 100644
index 0000000..2a3341c
--- /dev/null
+++ b/paludis/create_insert_iterator.hh
@@ -0,0 +1,111 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_CREATE_INSERT_ITERATOR_HH
+#define PALUDIS_GUARD_PALUDIS_CREATE_INSERT_ITERATOR_HH 1
+
+#include <functional>
+#include <iterator>
+
+namespace paludis
+{
+ 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:
+ struct container_type
+ {
+ typedef Type_ value_type;
+ };
+
+ /**
+ * Constructor, from an iterator.
+ */
+ CreateInsertIterator(const Iter_ & i) :
+ _i(i)
+ {
+ }
+
+ /**
+ * Copy constructor.
+ */
+ CreateInsertIterator(const CreateInsertIterator & other) :
+ _i(other._i)
+ {
+ }
+
+ /**
+ * Assignment.
+ */
+ template <typename T_>
+ const CreateInsertIterator & operator= (const T_ value)
+ {
+ *_i = Type_(value);
+ return *this;
+ }
+
+ /**
+ * Dereference.
+ */
+ CreateInsertIterator & operator* ()
+ {
+ return *this;
+ }
+
+ /**
+ * Dereference arrow.
+ */
+ CreateInsertIterator * operator-> ()
+ {
+ return this;
+ }
+
+ /**
+ * Increment.
+ */
+ CreateInsertIterator & operator++ ()
+ {
+ return *this;
+ }
+
+ /**
+ * Increment.
+ */
+ CreateInsertIterator & operator++ (int)
+ {
+ return *this;
+ }
+ };
+
+ /**
+ * Convenience function: make a TranslateInsertIterator.
+ */
+ template <typename Type_, typename Iter_>
+ CreateInsertIterator<Iter_, Type_> create_inserter(const Iter_ & i)
+ {
+ return CreateInsertIterator<Iter_, Type_>(i);
+ }
+}
+
+#endif
diff --git a/paludis/create_insert_iterator_TEST.cc b/paludis/create_insert_iterator_TEST.cc
new file mode 100644
index 0000000..b835590
--- /dev/null
+++ b/paludis/create_insert_iterator_TEST.cc
@@ -0,0 +1,45 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "create_insert_iterator.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+#include <algorithm>
+
+using namespace paludis;
+using namespace test;
+
+#ifndef DOXYGEN
+struct C
+{
+ std::string s;
+
+ explicit C(const std::string & ss) :
+ s(ss)
+ {
+ }
+};
+#endif
+
+namespace test_cases
+{
+ 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/paludis/default_config.cc b/paludis/default_config.cc
new file mode 100644
index 0000000..6848505
--- /dev/null
+++ b/paludis/default_config.cc
@@ -0,0 +1,199 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "default_config.hh"
+#include "fs_entry.hh"
+#include "dir_iterator.hh"
+#include "getenv.hh"
+#include "key_value_config_file.hh"
+#include "default_config_error.hh"
+#include "filter_insert_iterator.hh"
+#include "is_file_with_extension.hh"
+#include "stringify.hh"
+#include "tokeniser.hh"
+#include "line_config_file.hh"
+#include "create_insert_iterator.hh"
+#include <fstream>
+#include <algorithm>
+
+using namespace paludis;
+
+DefaultConfig::DefaultConfig()
+{
+ Context context("When loading default configuration:");
+
+ Tokeniser<delim_kind::AnyOfTag, delim_mode::DelimiterTag> tokeniser(" \t\n");
+
+ /* repositories */
+ {
+ std::list<FSEntry> dirs;
+ if (! getenv_with_default("PALUDIS_CONFIG_DIR", "").empty())
+ dirs.push_back(FSEntry(getenv_or_error("PALUDIS_CONFIG_DIR")) / "repositories");
+ else
+ {
+ dirs.push_back(FSEntry(getenv_with_default("ROOT", "/") + "" SYSCONFDIR)
+ / "paludis" / "repositories");
+ dirs.push_back(FSEntry(getenv_or_error("HOME")) / ".paludis" / "repositories");
+ }
+
+ std::list<FSEntry> repo_files;
+ for (std::list<FSEntry>::const_iterator dir(dirs.begin()), dir_end(dirs.end()) ;
+ dir != dir_end ; ++dir)
+ {
+ if (! dir->exists())
+ continue;
+
+ std::copy(DirIterator(*dir), DirIterator(),
+ filter_inserter(std::back_inserter(repo_files), IsFileWithExtension(".conf")));
+ }
+
+ for (std::list<FSEntry>::const_iterator repo_file(repo_files.begin()), repo_file_end(repo_files.end()) ;
+ repo_file != repo_file_end ; ++repo_file)
+ {
+ Context local_context("When reading repository file '" + stringify(*repo_file) + "':");
+
+ std::ifstream kf(stringify(*repo_file).c_str());
+ if (! kf)
+ throw DefaultConfigError("Couldn't open " + stringify(*repo_file));
+
+ KeyValueConfigFile k(&kf);
+
+ if (k.get("location").empty())
+ throw DefaultConfigError("Key 'location' empty or not specified in " +
+ stringify(*repo_file));
+ if (k.get("format").empty())
+ throw DefaultConfigError("Key 'format' empty or not specified in " +
+ stringify(*repo_file));
+ if (k.get("profile").empty())
+ throw DefaultConfigError("Key 'profile' empty or not specified in " +
+ stringify(*repo_file));
+
+ _repos.push_back(RepositoryConfigEntry(k.get("location"),
+ k.get("profile"), k.get("format")));
+ }
+
+ if (_repos.empty())
+ throw DefaultConfigError("No repositories specified");
+ }
+
+ /* keywords */
+ {
+ std::list<FSEntry> files;
+ if (! getenv_with_default("PALUDIS_CONFIG_DIR", "").empty())
+ files.push_back(FSEntry(getenv_or_error("PALUDIS_CONFIG_DIR")) / "keywords.conf");
+ else
+ {
+ files.push_back(FSEntry(getenv_with_default("ROOT", "/") + "" SYSCONFDIR)
+ / "paludis" / "keywords.conf");
+ files.push_back(FSEntry(getenv_or_error("HOME")) / ".paludis" / "keywords.conf");
+ }
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading keywords file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ std::ifstream kf(stringify(*file).c_str());
+ if (! kf)
+ throw DefaultConfigError("Couldn't open " + stringify(*file));
+
+ LineConfigFile f(&kf);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ std::vector<std::string> tokens;
+ tokeniser.tokenise(*line, std::back_inserter(tokens));
+ if (tokens.empty())
+ continue;
+ if ("*" == tokens.at(0))
+ {
+ _default_keywords.clear();
+ std::copy(++(tokens.begin()), tokens.end(),
+ create_inserter<KeywordName>(std::back_inserter(_default_keywords)));
+ }
+ else
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(tokens.at(0)));
+ for (std::vector<std::string>::const_iterator t(++(tokens.begin())), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ _keywords[a->package()].push_back(std::make_pair(a, *t));
+ }
+ }
+ }
+
+ if (_default_keywords.empty())
+ throw DefaultConfigError("No default keywords specified (a keywords.conf file should "
+ "contain an entry in the form '* keyword')");
+ }
+
+ /* user mask */
+ {
+ std::list<FSEntry> files;
+ if (! getenv_with_default("PALUDIS_CONFIG_DIR", "").empty())
+ files.push_back(FSEntry(getenv_or_error("PALUDIS_CONFIG_DIR")) / "package_mask.conf");
+ else
+ {
+ files.push_back(FSEntry(getenv_with_default("ROOT", "/") + "" SYSCONFDIR)
+ / "paludis" / "package_mask.conf");
+ files.push_back(FSEntry(getenv_or_error("HOME")) / ".paludis" / "package_mask.conf");
+ }
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading package_mask file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ std::ifstream kf(stringify(*file).c_str());
+ if (! kf)
+ throw DefaultConfigError("Couldn't open " + stringify(*file));
+
+ LineConfigFile f(&kf);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(*line));
+ _user_masks[a->package()].push_back(a);
+ }
+ }
+ }
+
+ /* user unmask */
+ {
+ std::list<FSEntry> files;
+ if (! getenv_with_default("PALUDIS_CONFIG_DIR", "").empty())
+ files.push_back(FSEntry(getenv_or_error("PALUDIS_CONFIG_DIR")) / "package_unmask.conf");
+ else
+ {
+ files.push_back(FSEntry(getenv_with_default("ROOT", "/") + "" SYSCONFDIR)
+ / "paludis" / "package_unmask.conf");
+ files.push_back(FSEntry(getenv_or_error("HOME")) / ".paludis" / "package_unmask.conf");
+ }
+
+ for (std::list<FSEntry>::const_iterator file(files.begin()), file_end(files.end()) ;
+ file != file_end ; ++file)
+ {
+ Context local_context("When reading package_unmask file '" + stringify(*file) + "':");
+
+ if (! file->is_regular_file())
+ continue;
+
+ std::ifstream kf(stringify(*file).c_str());
+ if (! kf)
+ throw DefaultConfigError("Couldn't open " + stringify(*file));
+
+ LineConfigFile f(&kf);
+ for (LineConfigFile::Iterator line(f.begin()), line_end(f.end()) ;
+ line != line_end ; ++line)
+ {
+ PackageDepAtom::ConstPointer a(new PackageDepAtom(*line));
+ _user_unmasks[a->package()].push_back(a);
+ }
+ }
+ }
+}
+
diff --git a/paludis/default_config.hh b/paludis/default_config.hh
new file mode 100644
index 0000000..f8c54f6
--- /dev/null
+++ b/paludis/default_config.hh
@@ -0,0 +1,169 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_DEFAULT_CONFIG_HH
+#define PALUDIS_GUARD_PALUDIS_DEFAULT_CONFIG_HH 1
+
+#include <paludis/instantiation_policy.hh>
+#include <paludis/smart_record.hh>
+#include <paludis/fs_entry.hh>
+#include <paludis/qualified_package_name.hh>
+#include <paludis/package_dep_atom.hh>
+#include <paludis/keyword_name.hh>
+#include <paludis/indirect_iterator.hh>
+#include <map>
+#include <vector>
+
+namespace paludis
+{
+ enum RepositoryConfigEntryKeys
+ {
+ rce_location,
+ rce_profile,
+ rce_format
+ };
+
+ struct RepositoryConfigEntryTag :
+ SmartRecordTag<comparison_mode::FullComparisonTag, comparison_method::SmartRecordCompareByAllTag>,
+ SmartRecordKeys<RepositoryConfigEntryKeys, 3>,
+ SmartRecordKey<rce_location, FSEntry>,
+ SmartRecordKey<rce_profile, FSEntry>,
+ SmartRecordKey<rce_format, std::string>
+ {
+ };
+
+ typedef MakeSmartRecord<RepositoryConfigEntryTag>::Type RepositoryConfigEntry;
+
+ class DefaultConfig :
+ public InstantiationPolicy<DefaultConfig, instantiation_method::SingletonAsNeededTag>
+ {
+ friend class InstantiationPolicy<DefaultConfig, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ DefaultConfig();
+
+ std::list<RepositoryConfigEntry> _repos;
+
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, KeywordName> > > _keywords;
+
+ const std::vector<std::pair<PackageDepAtom::ConstPointer, KeywordName> > _empty_keywords;
+
+ std::vector<KeywordName> _default_keywords;
+
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> > _user_masks;
+
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> > _user_unmasks;
+
+ std::vector<PackageDepAtom::ConstPointer> _empty_masks;
+
+ public:
+ typedef std::list<RepositoryConfigEntry>::const_iterator RepositoryIterator;
+
+ RepositoryIterator begin_repositories() const
+ {
+ return _repos.begin();
+ }
+
+ RepositoryIterator end_repositories() const
+ {
+ return _repos.end();
+ }
+
+ typedef std::vector<std::pair<PackageDepAtom::ConstPointer, KeywordName> >::const_iterator
+ PackageKeywordsIterator;
+
+ PackageKeywordsIterator begin_package_keywords(const QualifiedPackageName & d) const
+ {
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, KeywordName> > >::const_iterator r;
+ if (_keywords.end() != ((r = _keywords.find(d))))
+ return r->second.begin();
+ else
+ return _empty_keywords.begin();
+ }
+
+ PackageKeywordsIterator end_package_keywords(const QualifiedPackageName & d) const
+ {
+ std::map<QualifiedPackageName, std::vector<
+ std::pair<PackageDepAtom::ConstPointer, KeywordName> > >::const_iterator r;
+ if (_keywords.end() != ((r = _keywords.find(d))))
+ return r->second.end();
+ else
+ return _empty_keywords.end();
+ }
+
+ typedef std::vector<KeywordName>::const_iterator DefaultKeywordsIterator;
+
+ DefaultKeywordsIterator begin_default_keywords() const
+ {
+ return _default_keywords.begin();
+ }
+
+ DefaultKeywordsIterator end_default_keywords() const
+ {
+ return _default_keywords.end();
+ }
+
+ typedef IndirectIterator<std::vector<PackageDepAtom::ConstPointer>::const_iterator,
+ const PackageDepAtom> UserMasksIterator;
+
+ UserMasksIterator begin_user_masks(const QualifiedPackageName & d) const
+ {
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_user_masks.end() != ((r = _user_masks.find(d))))
+ return r->second.begin();
+ else
+ return _empty_masks.begin();
+ }
+
+ UserMasksIterator end_user_masks(const QualifiedPackageName & d) const
+ {
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_user_masks.end() != ((r = _user_masks.find(d))))
+ return r->second.end();
+ else
+ return _empty_masks.end();
+ }
+
+ typedef IndirectIterator<std::vector<PackageDepAtom::ConstPointer>::const_iterator,
+ const PackageDepAtom> UserUnmasksIterator;
+
+ UserUnmasksIterator begin_user_unmasks(const QualifiedPackageName & d) const
+ {
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_user_unmasks.end() != ((r = _user_unmasks.find(d))))
+ return r->second.begin();
+ else
+ return _empty_masks.begin();
+ }
+
+ UserUnmasksIterator end_user_unmasks(const QualifiedPackageName & d) const
+ {
+ std::map<QualifiedPackageName, std::vector<PackageDepAtom::ConstPointer> >::const_iterator r;
+ if (_user_unmasks.end() != ((r = _user_unmasks.find(d))))
+ return r->second.end();
+ else
+ return _empty_masks.end();
+ }
+ };
+}
+
+#endif
diff --git a/paludis/default_config_error.cc b/paludis/default_config_error.cc
new file mode 100644
index 0000000..53164ce
--- /dev/null
+++ b/paludis/default_config_error.cc
@@ -0,0 +1,10 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "default_config_error.hh"
+
+using namespace paludis;
+
+DefaultConfigError::DefaultConfigError(const std::string & msg) throw () :
+ Exception("Default configuration error: " + msg)
+{
+}
diff --git a/paludis/default_config_error.hh b/paludis/default_config_error.hh
new file mode 100644
index 0000000..24b6f1a
--- /dev/null
+++ b/paludis/default_config_error.hh
@@ -0,0 +1,17 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#ifndef PALUDIS_GUARD_PALUDIS_DEFAULT_CONFIG_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DEFAULT_CONFIG_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+namespace paludis
+{
+ class DefaultConfigError : public Exception
+ {
+ public:
+ DefaultConfigError(const std::string & msg) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/default_environment.cc b/paludis/default_environment.cc
new file mode 100644
index 0000000..29f0bd6
--- /dev/null
+++ b/paludis/default_environment.cc
@@ -0,0 +1,141 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "default_environment.hh"
+#include "default_config_error.hh"
+#include "package_database.hh"
+#include "portage_repository.hh"
+#include "default_config.hh"
+#include "stringify.hh"
+#include <list>
+#include <vector>
+
+using namespace paludis;
+
+DefaultEnvironment::DefaultEnvironment() :
+ Environment(PackageDatabase::Pointer(new PackageDatabase),
+ PackageDatabase::Pointer(new PackageDatabase))
+{
+ Context context("When loading default environment:");
+
+ for (DefaultConfig::RepositoryIterator r(DefaultConfig::get_instance()->begin_repositories()),
+ r_end(DefaultConfig::get_instance()->end_repositories()) ; r != r_end ; ++r)
+ {
+ /// \todo abstract factory
+ if (r->get<rce_format>() != "portage")
+ throw DefaultConfigError("Unknown repository format '" + r->get<rce_format>() + "'");
+ Repository::Pointer repo(new PortageRepository(r->get<rce_location>(),
+ r->get<rce_profile>()));
+ package_db()->add_repository(repo);
+ }
+
+ /// \bug vdb
+}
+
+DefaultEnvironment::~DefaultEnvironment()
+{
+}
+
+bool
+DefaultEnvironment::query_use(const UseFlagName &, const PackageDatabaseEntry * const) const
+{
+ /// \todo
+ return false;
+}
+
+bool
+DefaultEnvironment::accept_keyword(const KeywordName & keyword, const PackageDatabaseEntry * const d) const
+{
+ if (keyword == KeywordName("*"))
+ return true;
+
+ Context context("When checking accept_keyword of '" + stringify(keyword) +
+ (d ? "' for " + stringify(*d) : stringify("'")) + ":");
+
+ bool result(false);
+
+ if (d)
+ for (DefaultConfig::PackageKeywordsIterator
+ k(DefaultConfig::get_instance()->begin_package_keywords(d->get<pde_package>())),
+ k_end(DefaultConfig::get_instance()->end_package_keywords(d->get<pde_package>())) ;
+ k != k_end ; ++k)
+ {
+ if (k->first->package() != d->get<pde_package>())
+ continue;
+ if (k->first->version_spec_ptr() && ! (((d->get<pde_version>()).*
+ (k->first->version_operator().as_version_spec_operator()))
+ (*k->first->version_spec_ptr())))
+ continue;
+ /// \bug slot
+
+ result |= k->second == keyword;
+ }
+
+ result |= DefaultConfig::get_instance()->end_default_keywords() !=
+ std::find(DefaultConfig::get_instance()->begin_default_keywords(),
+ DefaultConfig::get_instance()->end_default_keywords(),
+ keyword);
+
+ return result;
+}
+
+bool
+DefaultEnvironment::query_user_masks(const PackageDatabaseEntry & d) const
+{
+ for (DefaultConfig::UserMasksIterator
+ k(DefaultConfig::get_instance()->begin_user_masks(d.get<pde_package>())),
+ k_end(DefaultConfig::get_instance()->end_user_masks(d.get<pde_package>())) ;
+ k != k_end ; ++k)
+ {
+ if (k->package() != d.get<pde_package>())
+ continue;
+ if (k->version_spec_ptr() && ! (((d.get<pde_version>()).*
+ (k->version_operator().as_version_spec_operator()))
+ (*k->version_spec_ptr())))
+ continue;
+ /// \bug slot
+
+ return true;
+ }
+
+ return false;
+}
+
+bool
+DefaultEnvironment::query_user_unmasks(const PackageDatabaseEntry & d) const
+{
+ for (DefaultConfig::UserMasksIterator
+ k(DefaultConfig::get_instance()->begin_user_unmasks(d.get<pde_package>())),
+ k_end(DefaultConfig::get_instance()->end_user_unmasks(d.get<pde_package>())) ;
+ k != k_end ; ++k)
+ {
+ if (k->package() != d.get<pde_package>())
+ continue;
+ if (k->version_spec_ptr() && ! (((d.get<pde_version>()).*
+ (k->version_operator().as_version_spec_operator()))
+ (*k->version_spec_ptr())))
+ continue;
+ /// \bug slot
+
+ return true;
+ }
+
+ return false;
+}
+
diff --git a/paludis/default_environment.hh b/paludis/default_environment.hh
new file mode 100644
index 0000000..9aaea81
--- /dev/null
+++ b/paludis/default_environment.hh
@@ -0,0 +1,61 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEFAULT_ENVIRONMENT_HH
+#define PALUDIS_GUARD_PALUDIS_DEFAULT_ENVIRONMENT_HH 1
+
+#include <paludis/environment.hh>
+#include <paludis/package_database.hh>
+
+/** \file
+ * Declarations for the DefaultEnvironment class.
+ *
+ * \ingroup Environment
+ */
+
+namespace paludis
+{
+ /**
+ * The DefaultEnvironment is an Environment that corresponds to the normal
+ * operating evironment.
+ *
+ * \ingroup Environment
+ */
+ class DefaultEnvironment :
+ public Environment,
+ public InstantiationPolicy<DefaultEnvironment, instantiation_method::SingletonAsNeededTag>
+ {
+ friend class InstantiationPolicy<DefaultEnvironment, instantiation_method::SingletonAsNeededTag>;
+
+ private:
+ DefaultEnvironment();
+
+ ~DefaultEnvironment();
+
+ protected:
+ virtual bool query_use(const UseFlagName &, const PackageDatabaseEntry * const) const;
+
+ virtual bool accept_keyword(const KeywordName &, const PackageDatabaseEntry * const) const;
+
+ virtual bool query_user_masks(const PackageDatabaseEntry &) const;
+
+ virtual bool query_user_unmasks(const PackageDatabaseEntry &) const;
+ };
+}
+#endif
diff --git a/paludis/deleter.cc b/paludis/deleter.cc
new file mode 100644
index 0000000..9775a35
--- /dev/null
+++ b/paludis/deleter.cc
@@ -0,0 +1,26 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "deleter.hh"
+
+using namespace paludis;
+
+Deleter::Deleter()
+{
+}
diff --git a/paludis/deleter.hh b/paludis/deleter.hh
new file mode 100644
index 0000000..21dc4ae
--- /dev/null
+++ b/paludis/deleter.hh
@@ -0,0 +1,55 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DELETER_HH
+#define PALUDIS_GUARD_PALUDIS_DELETER_HH 1
+
+/** \file
+ * Declarations for the Deleter class.
+ *
+ * \ingroup Utility
+ */
+
+namespace paludis
+{
+ /**
+ * A Deleter is a functor that deletes something.
+ *
+ * \ingroup Utility
+ */
+ class Deleter
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ Deleter();
+
+ /**
+ * Delete an item.
+ */
+ template <typename T_>
+ void operator() (T_ t)
+ {
+ delete t;
+ }
+ };
+}
+
+#endif
diff --git a/paludis/deleter_TEST.cc b/paludis/deleter_TEST.cc
new file mode 100644
index 0000000..7ae4645
--- /dev/null
+++ b/paludis/deleter_TEST.cc
@@ -0,0 +1,79 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "deleter.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <algorithm>
+#include <vector>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for deleter.hh.
+ *
+ * \ingroup Test
+ */
+
+#ifndef DOXYGEN
+struct MyClass
+{
+ static int instances;
+
+ MyClass()
+ {
+ ++instances;
+ }
+
+ ~MyClass()
+ {
+ --instances;
+ }
+};
+
+int MyClass::instances = 0;
+#endif
+
+namespace test_cases
+{
+ /**
+ * Test Deleter.
+ *
+ * \ingroup Test
+ */
+ struct DeleterTest : TestCase
+ {
+ DeleterTest() : TestCase("deleter") { }
+
+ void run()
+ {
+ std::vector<MyClass *> v;
+ TEST_CHECK_EQUAL(MyClass::instances, 0);
+ v.push_back(new MyClass);
+ TEST_CHECK_EQUAL(MyClass::instances, 1);
+ v.push_back(new MyClass);
+ TEST_CHECK_EQUAL(MyClass::instances, 2);
+ v.push_back(new MyClass);
+ TEST_CHECK_EQUAL(MyClass::instances, 3);
+ std::for_each(v.begin(), v.end(), Deleter());
+ TEST_CHECK_EQUAL(MyClass::instances, 0);
+ }
+ } test_deleter;
+}
diff --git a/paludis/dep_atom.cc b/paludis/dep_atom.cc
new file mode 100644
index 0000000..58f0df9
--- /dev/null
+++ b/paludis/dep_atom.cc
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_atom.hh"
+
+using namespace paludis;
+
+DepAtom::DepAtom()
+{
+}
+
+DepAtom::~DepAtom()
+{
+}
+
diff --git a/paludis/dep_atom.hh b/paludis/dep_atom.hh
new file mode 100644
index 0000000..3100851
--- /dev/null
+++ b/paludis/dep_atom.hh
@@ -0,0 +1,58 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_ATOM_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_ATOM_HH 1
+
+#include <paludis/visitor_pattern.hh>
+#include <paludis/composite_pattern.hh>
+#include <paludis/instantiation_policy.hh>
+#include <paludis/counted_ptr.hh>
+
+/** \file
+ * Declarations for the DepAtom class.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ class DepAtomVisitor;
+ class CompositeDepAtom;
+
+ /**
+ * Base class for a dependency atom.
+ *
+ * \ingroup DepResolver
+ */
+ class DepAtom :
+ public virtual VisitableInterface<DepAtomVisitor>,
+ public virtual Composite<DepAtom, CompositeDepAtom>,
+ private InstantiationPolicy<DepAtom, instantiation_method::NonCopyableTag>,
+ public InternalCounted<DepAtom>
+ {
+ protected:
+ DepAtom();
+
+ public:
+ virtual ~DepAtom();
+ };
+}
+
+#endif
diff --git a/paludis/dep_atom_dumper.cc b/paludis/dep_atom_dumper.cc
new file mode 100644
index 0000000..dd81d82
--- /dev/null
+++ b/paludis/dep_atom_dumper.cc
@@ -0,0 +1,93 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "block_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "dep_atom_visitor.hh"
+#include "dep_atom_dumper.hh"
+
+#include "visitor_pattern-impl.hh"
+#include "composite_visitor_pattern-impl.hh"
+
+using namespace paludis;
+
+DepAtomDumper::DepAtomDumper(std::ostream * const o) :
+ _o(o)
+{
+}
+
+void
+DepAtomDumper::enter(const AllDepAtom * const)
+{
+ *_o << "<all>";
+}
+
+void
+DepAtomDumper::leave(const AllDepAtom * const)
+{
+ *_o << "</all>";
+}
+
+void
+DepAtomDumper::enter(const AnyDepAtom * const)
+{
+ *_o << "<any>";
+}
+
+void
+DepAtomDumper::leave(const AnyDepAtom * const)
+{
+ *_o << "</any>";
+}
+
+void
+DepAtomDumper::enter(const UseDepAtom * const f)
+{
+ *_o << "<use flag=\"" << f->flag() << "\" inverse=\""
+ << (f->inverse() ? "true" : "false") << "\">";
+}
+
+void
+DepAtomDumper::leave(const UseDepAtom * const)
+{
+ *_o << "</use>";
+}
+
+void
+DepAtomDumper::visit(const PackageDepAtom * const p)
+{
+ *_o << "<package";
+ if (p->slot_ptr())
+ *_o << " slot=\"" << *p->slot_ptr() << "\"";
+ if (p->version_spec_ptr())
+ *_o << " version=\"" << p->version_operator() << *p->version_spec_ptr() << "\"";
+ *_o << ">" << p->package() << "</package>";
+}
+
+void
+DepAtomDumper::visit(const BlockDepAtom * const b)
+{
+ *_o << "<block>";
+ b->blocked_atom()->accept(this);
+ *_o << "</block>";
+}
+
diff --git a/paludis/dep_atom_dumper.hh b/paludis/dep_atom_dumper.hh
new file mode 100644
index 0000000..e8f9b3a
--- /dev/null
+++ b/paludis/dep_atom_dumper.hh
@@ -0,0 +1,66 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_ATOM_DUMPER_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_ATOM_DUMPER_HH 1
+
+#include <paludis/dep_atom_visitor.hh>
+#include <paludis/instantiation_policy.hh>
+#include <ostream>
+
+/** \file
+ * Declarations for the DepAtomDumper class.
+ */
+
+namespace paludis
+{
+ /**
+ * Dump dependency atoms to a stream in pseudo-XML form, for testing.
+ */
+ class DepAtomDumper : public DepAtomVisitor,
+ public VisitsComposite<DepAtomDumper, AllDepAtom>,
+ public VisitsComposite<DepAtomDumper, AnyDepAtom>,
+ public VisitsComposite<DepAtomDumper, UseDepAtom>,
+ private InstantiationPolicy<DepAtomDumper, instantiation_method::NonCopyableTag>
+ {
+ private:
+ std::ostream * const _o;
+
+ public:
+ /**
+ * Constructor.
+ */
+ DepAtomDumper(std::ostream * const o);
+
+ void enter(const AllDepAtom * const);
+ void leave(const AllDepAtom * const);
+
+ void enter(const AnyDepAtom * const);
+ void leave(const AnyDepAtom * const);
+
+ void enter(const UseDepAtom * const);
+ void leave(const UseDepAtom * const);
+
+ void visit(const PackageDepAtom * const);
+
+ void visit(const BlockDepAtom * const);
+ };
+}
+
+#endif
diff --git a/paludis/dep_atom_dumper_TEST.cc b/paludis/dep_atom_dumper_TEST.cc
new file mode 100644
index 0000000..71819c1
--- /dev/null
+++ b/paludis/dep_atom_dumper_TEST.cc
@@ -0,0 +1,68 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "dep_atom_visitor.hh"
+#include "dep_atom_dumper.hh"
+#include <sstream>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for DepAtomDumper.
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test DepAtomDumper.
+ *
+ * \ingroup Test
+ */
+ struct DepAtomDumperTest : TestCase
+ {
+ DepAtomDumperTest() : TestCase("dump") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ AllDepAtom::Pointer all(new AllDepAtom);
+ PackageDepAtom::Pointer p1(new PackageDepAtom(make_qualified_package_name("one/one")));
+ AnyDepAtom::Pointer any(new AnyDepAtom);
+ PackageDepAtom::Pointer p2(new PackageDepAtom(make_qualified_package_name("two/two")));
+ PackageDepAtom::Pointer p3(new PackageDepAtom(make_qualified_package_name("three/three")));
+ all->add_child(p1);
+ all->add_child(any);
+ any->add_child(p2);
+ any->add_child(p3);
+ all->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><package>one/one</package>"
+ "<any><package>two/two</package><package>three/three</package></any></all>");
+ }
+ } test_dep_atom_dumper;
+}
diff --git a/paludis/dep_atom_visitor.cc b/paludis/dep_atom_visitor.cc
new file mode 100644
index 0000000..404b795
--- /dev/null
+++ b/paludis/dep_atom_visitor.cc
@@ -0,0 +1,30 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_atom_visitor.hh"
+
+using namespace paludis;
+
+DepAtomVisitor::DepAtomVisitor()
+{
+}
+
+DepAtomVisitor::~DepAtomVisitor()
+{
+}
diff --git a/paludis/dep_atom_visitor.hh b/paludis/dep_atom_visitor.hh
new file mode 100644
index 0000000..d241bab
--- /dev/null
+++ b/paludis/dep_atom_visitor.hh
@@ -0,0 +1,65 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_ATOM_VISITOR_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_ATOM_VISITOR_HH 1
+
+#include <paludis/dep_atom.hh>
+#include <paludis/visitor_pattern.hh>
+#include <paludis/composite_visitor_pattern.hh>
+
+/** \file
+ * Declarations for the DepAtomVisitor base class.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ class PackageDepAtom;
+ class AllDepAtom;
+ class AnyDepAtom;
+ class UseDepAtom;
+ class BlockDepAtom;
+
+ /**
+ * A DepAtomVisitor is a generic base class for traversing a DepAtom
+ * collection.
+ */
+ class DepAtomVisitor : public virtual Visits<PackageDepAtom>,
+ public virtual Visits<AllDepAtom>,
+ public virtual Visits<AnyDepAtom>,
+ public virtual Visits<UseDepAtom>,
+ public virtual Visits<BlockDepAtom>
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ DepAtomVisitor();
+
+ public:
+ /**
+ * Destructor.
+ */
+ virtual ~DepAtomVisitor();
+ };
+}
+
+#endif
diff --git a/paludis/dep_lexer.cc b/paludis/dep_lexer.cc
new file mode 100644
index 0000000..b4da333
--- /dev/null
+++ b/paludis/dep_lexer.cc
@@ -0,0 +1,66 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "dep_atom_visitor.hh"
+#include "dep_lexer.hh"
+#include "exception.hh"
+#include "dep_string_lex_error.hh"
+#include "tokeniser.hh"
+#include <vector>
+
+using namespace paludis;
+
+DepLexer::DepLexer(const std::string & s)
+{
+ Context context("When lexing dependency string '" + s + "':");
+
+ Tokeniser<delim_kind::AnyOfTag, delim_mode::BoundaryTag> tokeniser(" \n\t");
+ std::vector<std::string> tokens;
+ tokeniser.tokenise(s, std::back_inserter(tokens));
+
+ for (std::vector<std::string>::const_iterator t(tokens.begin()), t_end(tokens.end()) ;
+ t != t_end ; ++t)
+ {
+ if (t->empty())
+ continue;
+
+ if (*t == "||")
+ _tokens.push_back(std::make_pair(dpl_double_bar, *t));
+ else if ('|' == (*t)[0])
+ throw DepStringLexError(s, "'|' should be followed by '|'");
+ else if (*t == "(")
+ _tokens.push_back(std::make_pair(dpl_open_paren, *t));
+ else if ('(' == (*t)[0])
+ throw DepStringLexError(s, "'(' should be followed by whitespace");
+ else if (*t == ")")
+ _tokens.push_back(std::make_pair(dpl_close_paren, *t));
+ else if (')' == (*t)[0])
+ throw DepStringLexError(s, "')' should be followed by whitespace");
+ else if (std::string::npos == t->find_first_not_of(" \t\n"))
+ _tokens.push_back(std::make_pair(dpl_whitespace, *t));
+ else if ('?' == (*t)[t->length() - 1])
+ _tokens.push_back(std::make_pair(dpl_use_flag, *t));
+ else
+ _tokens.push_back(std::make_pair(dpl_package, *t));
+ }
+}
diff --git a/paludis/dep_lexer.hh b/paludis/dep_lexer.hh
new file mode 100644
index 0000000..74eac45
--- /dev/null
+++ b/paludis/dep_lexer.hh
@@ -0,0 +1,86 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_PARSER_LEXER_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_PARSER_LEXER_HH 1
+
+#include <paludis/instantiation_policy.hh>
+#include <list>
+#include <string>
+
+/** \file
+ * Declarations for the DepLexer class.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * Lexemes used by DepLexer.
+ */
+ enum DepLexerLexeme
+ {
+ dpl_whitespace, ///< whitespace
+ dpl_package, ///< a package name
+ dpl_use_flag, ///< a use flag
+ dpl_double_bar, ///< a double bar ('any' marker)
+ dpl_open_paren, ///< open paren
+ dpl_close_paren ///< close paren
+ };
+
+ /**
+ * Converts a dependency string into a sequence of tokens.
+ */
+ class DepLexer :
+ private InstantiationPolicy<DepLexer, instantiation_method::NonCopyableTag>
+ {
+ private:
+ std::list<std::pair<DepLexerLexeme, std::string> > _tokens;
+
+ public:
+ /**
+ * Iterator for our tokens.
+ */
+ typedef std::list<std::pair<DepLexerLexeme, std::string> >::const_iterator Iterator;
+
+ /**
+ * Iterator to the start of our tokens.
+ */
+ Iterator begin() const
+ {
+ return _tokens.begin();
+ }
+
+ /**
+ * Iterator to the end of our tokens.
+ */
+ Iterator end() const
+ {
+ return _tokens.end();
+ }
+
+ /**
+ * Constructor.
+ */
+ DepLexer(const std::string &);
+ };
+}
+
+#endif
diff --git a/paludis/dep_lexer_TEST.cc b/paludis/dep_lexer_TEST.cc
new file mode 100644
index 0000000..71a09a8
--- /dev/null
+++ b/paludis/dep_lexer_TEST.cc
@@ -0,0 +1,232 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include "dep_lexer.hh"
+#include <sstream>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for DepLexer.
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test DepLexer with an empty input.
+ *
+ * \ingroup Test
+ */
+ struct DepLexerEmptyTest : TestCase
+ {
+ DepLexerEmptyTest() : TestCase("empty") { }
+
+ void run()
+ {
+ DepLexer l("");
+ DepLexer::Iterator i(l.begin());
+ TEST_CHECK(i == l.end());
+ }
+ } test_dep_atom_parser_lexer_empty;
+
+ /**
+ * \test Test DepLexer with a blank input.
+ *
+ * \ingroup Test
+ */
+ struct DepLexerBlankTest : TestCase
+ {
+ DepLexerBlankTest() : TestCase("blank") { }
+
+ void run()
+ {
+ DepLexer l(" \n \t");
+ DepLexer::Iterator i(l.begin());
+ TEST_CHECK(i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " \n \t");
+ TEST_CHECK(++i == l.end());
+ }
+ } test_dep_atom_parser_lexer_blank;
+
+ /**
+ * \test Test DepLexer with a package.
+ *
+ * \ingroup Test
+ */
+ struct DepLexerPackageTest : TestCase
+ {
+ DepLexerPackageTest() : TestCase("package") { }
+
+ void run()
+ {
+ DepLexer l("app-editors/vim");
+ DepLexer::Iterator i(l.begin());
+ TEST_CHECK(i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_package);
+ TEST_CHECK_EQUAL(i->second, "app-editors/vim");
+ TEST_CHECK(++i == l.end());
+ }
+ } test_dep_atom_parser_lexer_package;
+
+ /**
+ * \test Test DepParser with a sequence of packages.
+ *
+ * \ingroup Test
+ */
+ struct DepLexerPackagesTest : TestCase
+ {
+ DepLexerPackagesTest() : TestCase("packages") { }
+
+ void run()
+ {
+ DepLexer l("app-editors/vim app-misc/hilite \nsys-apps/findutils");
+ DepLexer::Iterator i(l.begin());
+
+ TEST_CHECK(i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_package);
+ TEST_CHECK_EQUAL(i->second, "app-editors/vim");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_package);
+ TEST_CHECK_EQUAL(i->second, "app-misc/hilite");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " \n");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_package);
+ TEST_CHECK_EQUAL(i->second, "sys-apps/findutils");
+
+ TEST_CHECK(++i == l.end());
+ }
+ } test_dep_atom_parser_lexer_packages;
+
+ /**
+ * \test Test DepLexer with an any group.
+ *
+ * \ingroup Test
+ */
+ struct DepLexerAnyTest : TestCase
+ {
+ DepLexerAnyTest() : TestCase("any") { }
+
+ void run()
+ {
+ DepLexer l("|| ( one/one two/two )");
+ DepLexer::Iterator i(l.begin());
+
+ TEST_CHECK(i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_double_bar);
+ TEST_CHECK_EQUAL(i->second, "||");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_open_paren);
+ TEST_CHECK_EQUAL(i->second, "(");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_package);
+ TEST_CHECK_EQUAL(i->second, "one/one");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_package);
+ TEST_CHECK_EQUAL(i->second, "two/two");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_close_paren);
+ TEST_CHECK_EQUAL(i->second, ")");
+
+ TEST_CHECK(++i == l.end());
+ }
+ } test_dep_atom_parser_lexer_any;
+
+ /**
+ * \test Test DepLexer with a use group.
+ *
+ * \ingroup Test
+ */
+ struct DepLexerUseTest : TestCase
+ {
+ DepLexerUseTest() : TestCase("use") { }
+
+ void run()
+ {
+ DepLexer l("foo? ( one/one )");
+ DepLexer::Iterator i(l.begin());
+
+ TEST_CHECK(i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_use_flag);
+ TEST_CHECK_EQUAL(i->second, "foo?");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_open_paren);
+ TEST_CHECK_EQUAL(i->second, "(");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_package);
+ TEST_CHECK_EQUAL(i->second, "one/one");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_whitespace);
+ TEST_CHECK_EQUAL(i->second, " ");
+
+ TEST_CHECK(++i != l.end());
+ TEST_CHECK_EQUAL(i->first, dpl_close_paren);
+ TEST_CHECK_EQUAL(i->second, ")");
+
+ TEST_CHECK(++i == l.end());
+ }
+ } test_dep_atom_parser_lexer_use;
+}
+
+
diff --git a/paludis/dep_list.cc b/paludis/dep_list.cc
new file mode 100644
index 0000000..808159e
--- /dev/null
+++ b/paludis/dep_list.cc
@@ -0,0 +1,479 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_list.hh"
+#include "dep_list_error.hh"
+#include "dep_list_stack_too_deep_error.hh"
+#include "dep_parser.hh"
+#include "all_masked_error.hh"
+#include "no_resolvable_option_error.hh"
+#include "circular_dependency_error.hh"
+#include "internal_error.hh"
+#include "visitor_pattern-impl.hh"
+#include "composite_visitor_pattern-impl.hh"
+#include "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "block_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "stringify.hh"
+#include "container_entry.hh"
+#include "save.hh"
+#include "indirect_iterator.hh"
+#include "block_error.hh"
+#include "join.hh"
+#include "filter_insert_iterator.hh"
+
+#include <algorithm>
+#include <functional>
+
+using namespace paludis;
+
+namespace paludis
+{
+ template<>
+ struct Implementation<DepList> :
+ InstantiationPolicy<Implementation<DepList>, instantiation_method::NonCopyableTag>,
+ InternalCounted<Implementation<DepList> >
+ {
+ const Environment * const environment;
+
+ std::list<DepListEntry> merge_list;
+ std::list<DepListEntry> pending_list;
+ bool check_existing_only;
+ bool in_pdepend;
+ bool match_found;
+ const PackageDatabaseEntry * current_package;
+ int stack_depth;
+
+ bool rdepend_post;
+ bool drop_circular;
+ bool drop_self_circular;
+ bool ignore_installed;
+ bool recursive_deps;
+ int max_stack_depth;
+
+ Implementation(const Environment * const e) :
+ environment(e),
+ check_existing_only(false),
+ in_pdepend(false),
+ match_found(false),
+ current_package(0),
+ stack_depth(0),
+ rdepend_post(false),
+ drop_circular(false),
+ drop_self_circular(false),
+ ignore_installed(false),
+ recursive_deps(false),
+ max_stack_depth(100)
+ {
+ }
+ };
+}
+
+DepList::DepList(const Environment * const e) :
+ PrivateImplementationPattern<DepList>(new Implementation<DepList>(e))
+{
+}
+
+DepList::~DepList()
+{
+}
+
+void
+DepList::add(DepAtom::ConstPointer atom)
+{
+ /* keep track of stack depth */
+ Save<int> old_stack_depth(&_implementation->stack_depth,
+ _implementation->stack_depth + 1);
+ if (_implementation->stack_depth > _implementation->max_stack_depth)
+ throw DepListStackTooDeepError(_implementation->stack_depth);
+
+ /* we need to make sure that merge_list doesn't get h0rked in the
+ * event of a failure. */
+ bool merge_list_was_empty(_implementation->merge_list.empty());
+ std::list<DepListEntry>::iterator m_save(merge_list_was_empty ?
+ _implementation->merge_list.end() : --(_implementation->merge_list.end()));
+
+ try
+ {
+ atom->accept(this);
+ }
+ catch (...)
+ {
+ if (merge_list_was_empty)
+ _implementation->merge_list.clear();
+ else
+ _implementation->merge_list.erase(++m_save, _implementation->merge_list.end());
+ throw;
+ }
+}
+
+void
+DepList::_add_in_role(DepAtom::ConstPointer atom, const std::string & role)
+{
+ Context context("When adding " + role + ":");
+ add(atom);
+}
+
+DepList::Iterator
+DepList::begin() const
+{
+ return _implementation->merge_list.begin();
+}
+
+DepList::Iterator
+DepList::end() const
+{
+ return _implementation->merge_list.end();
+}
+
+void
+DepList::enter(const AllDepAtom * const)
+{
+}
+
+void
+DepList::leave(const AllDepAtom * const)
+{
+}
+
+struct DepListEntryMatcher :
+ public std::unary_function<bool, const DepListEntry &>
+{
+ const PackageDepAtom & atom;
+
+ DepListEntryMatcher(const PackageDepAtom & p) :
+ atom(p)
+ {
+ }
+
+ bool operator() (const DepListEntry & e) const
+ {
+ if (e.get<dle_name>() != atom.package())
+ return false;
+ if (atom.slot_ptr())
+ if (e.get<dle_slot>() != *atom.slot_ptr())
+ return false;
+ if (atom.version_spec_ptr())
+ if (! (((e.get<dle_version>()).*(atom.version_operator().as_version_spec_operator()))(
+ *atom.version_spec_ptr())))
+ return false;
+ return true;
+ }
+};
+
+void
+DepList::visit(const PackageDepAtom * const p)
+{
+ Context context("When resolving package dependency '" + stringify(*p) + "':");
+
+ bool already_there = false;
+ bool do_rdepend_post = false;
+
+ /* are we already installed? */
+ if ((! _implementation->ignore_installed) &&
+ (! _implementation->environment->installed_db()->query(p)->empty()))
+ already_there = true;
+
+ /* will we be installed by this point? */
+ if ((! already_there) && (_implementation->merge_list.end() != std::find_if(
+ _implementation->merge_list.begin(), _implementation->merge_list.end(),
+ DepListEntryMatcher(*p))))
+ return;
+
+ if (already_there && ((! _implementation->recursive_deps) || (_implementation->check_existing_only)))
+ return;
+
+ /* are we allowed to install things? */
+ if (_implementation->check_existing_only && ! _implementation->in_pdepend)
+ {
+ _implementation->match_found = false;
+ return;
+ }
+
+ /* are we pending? (circular dep check) */
+ {
+ std::list<DepListEntry>::iterator i;
+ if (_implementation->pending_list.end() != ((i = std::find_if(
+ _implementation->pending_list.begin(), _implementation->pending_list.end(),
+ DepListEntryMatcher(*p)))))
+ {
+ std::list<std::string> entries;
+ entries.push_front(stringify(*p));
+ std::transform(_implementation->pending_list.begin(), ++i,
+ std::back_inserter(entries), &stringify<DepListEntry>);
+ if (_implementation->in_pdepend)
+ return;
+ else if (_implementation->drop_circular)
+ return;
+ else if (_implementation->drop_self_circular && entries.size() <= 2)
+ return;
+ else
+ throw CircularDependencyError(entries.begin(), entries.end());
+ }
+ }
+
+ /* are we allowed to install things? */
+ if (_implementation->check_existing_only)
+ {
+ _implementation->match_found = false;
+ return;
+ }
+
+ /* find the matching package */
+ PackageDatabaseEntryCollection::Pointer matches(
+ _implementation->environment->package_db()->query(p));
+
+ const PackageDatabaseEntry * match(0);
+ VersionMetadata::ConstPointer metadata(0);
+ for (PackageDatabaseEntryCollection::ReverseIterator e(matches->rbegin()),
+ e_end(matches->rend()) ; e != e_end ; ++e)
+ {
+ /* check masks */
+ if (_implementation->environment->mask_reasons(*e).any())
+ continue;
+
+ metadata = _implementation->environment->package_db()->fetch_metadata(*e);
+ match = &*e;
+ break;
+ }
+
+ if (! match)
+ throw AllMaskedError(stringify(*p));
+
+ Save<const PackageDatabaseEntry *> old_current_package(&_implementation->current_package, match);
+
+ context.change_context("When resolving package dependency '" + stringify(*p) +
+ "' -> '" + stringify(*match) + "':");
+
+ /* make merge entry */
+ DepListEntry merge_entry(match->get<pde_package>(), match->get<pde_version>(),
+ SlotName(metadata->get(vmk_slot)), match->get<pde_repository>());
+
+ {
+ /* pending */
+ ContainerEntry<std::list<DepListEntry> > pending(&_implementation->pending_list, merge_entry);
+
+ /* merge dependencies */
+ _add_in_role(DepParser::parse(metadata->get(vmk_depend)), "DEPEND");
+
+ try
+ {
+ _add_in_role(DepParser::parse(metadata->get(vmk_rdepend)), "RDEPEND");
+ }
+ catch (const CircularDependencyError &)
+ {
+ if (_implementation->rdepend_post)
+ do_rdepend_post = true;
+ else
+ throw;
+ }
+ }
+
+ /* merge package */
+ if (! already_there)
+ _implementation->merge_list.push_back(merge_entry);
+
+ /* merge post dependencies */
+ {
+ Save<bool> save_ignore_cdep(&_implementation->in_pdepend, true);
+ if (do_rdepend_post)
+ _add_in_role(DepParser::parse(metadata->get(vmk_rdepend)), "RDEPEND (as PDEPEND)");
+ _add_in_role(DepParser::parse(metadata->get(vmk_pdepend)), "PDEPEND");
+ }
+}
+
+void
+DepList::visit(const UseDepAtom * const u)
+{
+ if (_implementation->environment->query_use(u->flag(),
+ _implementation->current_package) ^ u->inverse())
+ std::for_each(u->begin(), u->end(), std::bind1st(std::mem_fun(&DepList::add), this));
+}
+
+struct IsViable :
+ public std::unary_function<bool, DepAtom::ConstPointer>
+{
+ const Implementation<DepList> & _impl;
+
+ IsViable(const Implementation<DepList> & impl) :
+ _impl(impl)
+ {
+ }
+
+ bool operator() (DepAtom::ConstPointer a)
+ {
+ /// \todo don't use dynamic_cast<>, it sucks
+ const UseDepAtom * u(0);
+ if (0 != ((u = dynamic_cast<const UseDepAtom *>(a.raw_pointer()))))
+ return _impl.environment->query_use(u->flag(),
+ _impl.current_package) ^ u->inverse();
+ else
+ return true;
+ }
+};
+
+void
+DepList::visit(const AnyDepAtom * const a)
+{
+ /* try to resolve each of our children in return. note the annoying
+ * special case for use? () flags:
+ *
+ * || ( ) -> nothing
+ * || ( off1? ( blah1 ) off2? ( blah2 ) blah3 ) -> blah3
+ * || ( off1? ( blah1 ) off2? ( blah2 ) ) -> nothing
+ * || ( ( off1? ( blah1 ) ) blah2 ) -> nothing
+ *
+ * we handle this by keeping a list of 'viable children'.
+ */
+
+ std::list<DepAtom::ConstPointer> viable_children;
+ std::copy(a->begin(), a->end(), filter_inserter(
+ std::back_inserter(viable_children), IsViable(*_implementation)));
+
+ if (viable_children.empty())
+ return;
+
+ bool found(false);
+ for (CompositeDepAtom::Iterator i(viable_children.begin()),
+ i_end(viable_children.end()) ; i != i_end ; ++i)
+ {
+ Save<bool> save_check(&_implementation->check_existing_only, true);
+ Save<bool> save_match(&_implementation->match_found, true);
+ add(*i);
+ if ((found = _implementation->match_found))
+ break;
+ }
+ if (found)
+ return;
+
+ if (_implementation->check_existing_only)
+ {
+ _implementation->match_found = false;
+ return;
+ }
+
+ /* try to merge each of our viable children in turn. */
+ for (CompositeDepAtom::Iterator i(viable_children.begin()), i_end(viable_children.end()) ;
+ i != i_end ; ++i)
+ {
+ try
+ {
+ add(*i);
+ return;
+ }
+ catch (const DepListStackTooDeepError &)
+ {
+ /* don't work around a stack too deep error. our item may be
+ * resolvable with a deeper stack. */
+ throw;
+ }
+ catch (const DepListError &)
+ {
+ }
+ }
+
+ /* no match */
+ throw NoResolvableOptionError();
+}
+
+void
+DepList::visit(const BlockDepAtom * const d)
+{
+ Context context("When checking block '!" + stringify(*(d->blocked_atom())) + "':");
+
+ /* special case: the provider of virtual/blah can DEPEND upon !virtual/blah. */
+ /// \bug This may have issues if a virtual is provided by a virtual...
+
+ PackageDatabaseEntryCollection::ConstPointer q(0);
+ std::list<DepListEntry>::const_iterator m;
+
+ /* are we already installed? */
+ if (! ((q = _implementation->environment->installed_db()->query(d->blocked_atom())))->empty())
+ {
+ if (! _implementation->current_package)
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by installed package '"
+ + stringify(*q->begin()) + "'");
+
+ VersionMetadata::ConstPointer metadata(
+ _implementation->environment->installed_db()->fetch_metadata(
+ *_implementation->current_package));
+ if (metadata->end_provide() == std::find(
+ metadata->begin_provide(), metadata->end_provide(),
+ d->blocked_atom()->package()))
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by installed package '"
+ + stringify(*q->begin()) + "'");
+ }
+
+ /* will we be installed by this point? */
+ if (_implementation->merge_list.end() != ((m = std::find_if(
+ _implementation->merge_list.begin(), _implementation->merge_list.end(),
+ DepListEntryMatcher(*(d->blocked_atom()))))))
+ {
+ if (! _implementation->current_package)
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by pending package '"
+ + stringify(*m));
+
+ VersionMetadata::ConstPointer metadata(_implementation->environment->package_db()->fetch_metadata(
+ *_implementation->current_package));
+ if (metadata->end_provide() == std::find(
+ metadata->begin_provide(), metadata->end_provide(),
+ d->blocked_atom()->package()))
+ throw BlockError("'" + stringify(*(d->blocked_atom())) + "' blocked by pending package '"
+ + stringify(*m) + "' ~ " + join(metadata->begin_provide(), metadata->end_provide(), " ~ "));
+ }
+}
+
+void
+DepList::set_rdepend_post(const bool value)
+{
+ _implementation->rdepend_post = value;
+}
+
+void
+DepList::set_drop_circular(const bool value)
+{
+ _implementation->drop_circular = value;
+}
+
+void
+DepList::set_drop_self_circular(const bool value)
+{
+ _implementation->drop_self_circular = value;
+}
+
+void
+DepList::set_ignore_installed(const bool value)
+{
+ _implementation->ignore_installed = value;
+}
+
+void
+DepList::set_recursive_deps(const bool value)
+{
+ _implementation->recursive_deps = value;
+}
+
+void
+DepList::set_max_stack_depth(const int value)
+{
+ _implementation->max_stack_depth = value;
+}
+
diff --git a/paludis/dep_list.hh b/paludis/dep_list.hh
new file mode 100644
index 0000000..e3dcf8b
--- /dev/null
+++ b/paludis/dep_list.hh
@@ -0,0 +1,124 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_LIST_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_LIST_HH 1
+
+#include <paludis/instantiation_policy.hh>
+#include <paludis/private_implementation_pattern.hh>
+#include <paludis/dep_atom.hh>
+#include <paludis/environment.hh>
+#include <paludis/dep_atom_visitor.hh>
+#include <paludis/dep_list_entry.hh>
+#include <list>
+
+namespace paludis
+{
+ /**
+ * Holds a list of dependencies in merge order.
+ */
+ class DepList :
+ private InstantiationPolicy<DepList, instantiation_method::NonCopyableTag>,
+ private PrivateImplementationPattern<DepList>,
+ protected DepAtomVisitor,
+ protected VisitsComposite<DepList, AllDepAtom>
+ {
+ friend class VisitsComposite<DepList, AllDepAtom>;
+
+ private:
+ void _add_in_role(DepAtom::ConstPointer, const std::string & role);
+
+ protected:
+ void visit(const PackageDepAtom * const);
+ void visit(const UseDepAtom * const);
+ void visit(const AnyDepAtom * const);
+ void visit(const BlockDepAtom * const);
+
+ void enter(const AllDepAtom * const);
+ void leave(const AllDepAtom * const);
+
+ public:
+ /**
+ * Iterator for our children.
+ */
+ typedef std::list<DepListEntry>::const_iterator Iterator;
+
+ /**
+ * Constructor.
+ */
+ DepList(const Environment * const);
+
+ /**
+ * Destructor.
+ */
+ virtual ~DepList();
+
+ /**
+ * Add the packages required to resolve an additional dependency
+ * atom.
+ */
+ void add(DepAtom::ConstPointer);
+
+ /**
+ * Start of our dependency list.
+ */
+ Iterator begin() const;
+
+ /**
+ * One past the end of our dependency list.
+ */
+ Iterator end() const;
+
+ /**
+ * Behaviour: if set, RDEPEND entries can be treated as PDEPEND
+ * where necessary.
+ */
+ void set_rdepend_post(const bool value);
+
+ /**
+ * Behaviour: if set, a package that depends directly upon itself
+ * will be accepted.
+ */
+ void set_drop_self_circular(const bool value);
+
+ /**
+ * Behaviour: if set, any circular dependencies are treated as if
+ * they do not exist.
+ */
+ void set_drop_circular(const bool value);
+
+ /**
+ * Behaviour: ignore installed packages.
+ */
+ void set_ignore_installed(const bool value);
+
+ /**
+ * Behaviour: check nth level dependencies for packages that are
+ * already installed.
+ */
+ void set_recursive_deps(const bool value);
+
+ /**
+ * Behaviour: set the maximum stack depth.
+ */
+ void set_max_stack_depth(const int value);
+ };
+}
+
+#endif
diff --git a/paludis/dep_list_TEST.cc b/paludis/dep_list_TEST.cc
new file mode 100644
index 0000000..36c7c79
--- /dev/null
+++ b/paludis/dep_list_TEST.cc
@@ -0,0 +1,614 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ /**
+ * \test Test dep list: one package.
+ *
+ * \ingroup Test
+ */
+ struct DepListOnePackageTest : TestCase
+ {
+ DepListOnePackageTest() : TestCase("one package") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one exists */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1");
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ TEST_CHECK(d.begin() != d.end());
+ TEST_CHECK_EQUAL(std::distance(d.begin(), d.end()), 1);
+ TEST_CHECK_EQUAL(*d.begin(), DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("slot1"), RepositoryName("repo")));
+ }
+ } test_dep_list_one_package;
+
+ /**
+ * \test Test dep list: one installed package.
+ *
+ * \ingroup Test
+ */
+ struct DepListOneInstalledPackageTest : TestCase
+ {
+ DepListOneInstalledPackageTest() : TestCase("one installed package") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one exists and is already installed. */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1");
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("0.9"))->
+ set(vmk_slot, "slot1");
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ TEST_CHECK(d.begin() == d.end());
+ }
+ } test_dep_list_one_installed_package;
+
+ /**
+ * \test Test dep list: dep.
+ *
+ * \ingroup Test
+ */
+ struct DepListDepTest : TestCase
+ {
+ DepListDepTest() : TestCase("dep") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one DEPENDs upon t/two */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1").
+ set(vmk_depend, "t/two");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot2");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("two")),
+ VersionSpec("1.0"), SlotName("slot2"), RepositoryName("repo")));
+ TEST_CHECK(++di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("slot1"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+ } test_dep_list_dep;
+
+ /**
+ * \test Test dep list: pdep.
+ *
+ * \ingroup Test
+ */
+ struct DepListPDepTest : TestCase
+ {
+ DepListPDepTest() : TestCase("pdep") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one PDEPENDs upon t/two */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1").
+ set(vmk_pdepend, "t/two");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot2");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("slot1"), RepositoryName("repo")));
+ TEST_CHECK(++di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("two")),
+ VersionSpec("1.0"), SlotName("slot2"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+ } test_dep_list_pdep;
+
+ /**
+ * \test Test dep list: common deps.
+ *
+ * \ingroup Test
+ */
+ struct DepListCommonDepsTest : TestCase
+ {
+ DepListCommonDepsTest() : TestCase("common deps") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one DEPENDs upon ( t/two t/three ) ; t/two DEPENDs upon t/three */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1").
+ set(vmk_depend, "t/two t/three");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot2").
+ set(vmk_depend, "t/three");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot3");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("three")),
+ VersionSpec("1.0"), SlotName("slot3"), RepositoryName("repo")));
+ TEST_CHECK(++di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("two")),
+ VersionSpec("1.0"), SlotName("slot2"), RepositoryName("repo")));
+ TEST_CHECK(++di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("slot1"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+ } test_dep_list_common_deps;
+
+ /**
+ * \test Test dep list: dep failure.
+ *
+ * \ingroup Test
+ */
+ struct DepListDepFailureTest : TestCase
+ {
+ DepListDepFailureTest() : TestCase("dep failure") { }
+
+ void run_d(VersionMetadataKey dep_kind)
+ {
+ TestMessageSuffix suffix(stringify(dep_kind), true);
+ TestEnvironment e;
+
+ /* t/one DEPENDs upon t/two and t/three. t/three has unresolvable
+ * deps. */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1").
+ set(dep_kind, "t/two t/three");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot2");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot3").
+ set(dep_kind, "t/bad");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ TEST_CHECK_THROWS(d.add(DepParser::parse("t/one")), Exception);
+ TEST_CHECK(d.begin() == d.end());
+
+ /* try again, with some stuff already in the dep list. */
+ d.add(DepParser::parse("t/two"));
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("two")),
+ VersionSpec("1.0"), SlotName("slot2"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+
+ TEST_CHECK_THROWS(d.add(DepParser::parse("t/one")), Exception);
+ di = d.begin();
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("two")),
+ VersionSpec("1.0"), SlotName("slot2"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+
+ void run()
+ {
+ run_d(vmk_depend);
+ run_d(vmk_rdepend);
+ run_d(vmk_pdepend);
+ }
+ } test_dep_list_dep_failure;
+
+ /**
+ * \test Test dep list: indirect circular deps.
+ *
+ * \ingroup Test
+ */
+ struct DepListIndirectCircularDepTest : TestCase
+ {
+ DepListIndirectCircularDepTest() : TestCase("indirect circular deps") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one DEPENDs upon t/two. t/two DEPENDs upon t/three. t/three DEPENDs
+ * upon t/two */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1").
+ set(vmk_depend, "t/two");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot2").
+ set(vmk_depend, "t/three");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot3").
+ set(vmk_depend, "t/two");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ TEST_CHECK_THROWS(d.add(DepParser::parse("t/one")), CircularDependencyError);
+ TEST_CHECK(d.begin() == d.end());
+
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"));
+ d.add(DepParser::parse("t/one"));
+
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("two")),
+ VersionSpec("1.0"), SlotName("slot2"), RepositoryName("repo")));
+ TEST_CHECK(++di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("slot1"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+ } test_dep_list_indirect_circular_deps;
+
+ /**
+ * \test Test dep list: self circular deps.
+ *
+ * \ingroup Test
+ */
+ struct DepListSelfCircularDepTest : TestCase
+ {
+ DepListSelfCircularDepTest() : TestCase("self circular deps") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one DEPENDs upon t/two. t/two DEPENDs upon t/two. */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1").
+ set(vmk_depend, "t/two");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot2").
+ set(vmk_depend, "t/two");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ TEST_CHECK_THROWS(d.add(DepParser::parse("t/one")), CircularDependencyError);
+ TEST_CHECK(d.begin() == d.end());
+
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"));
+ d.add(DepParser::parse("t/one"));
+
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("slot1"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+ } test_dep_list_self_circular_deps;
+
+ /**
+ * \test Test dep list: met or dep.
+ *
+ * \ingroup Test
+ */
+ struct DepListMetOrDepTest : TestCase
+ {
+ DepListMetOrDepTest() : TestCase("met or dep") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ /* t/one DEPENDs upon || ( t/two t/three ). t/three is already
+ * installed */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot1").
+ set(vmk_depend, "|| ( t/two t/three )");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"))->
+ set(vmk_slot, "slot2");
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("slot1"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+ } test_dep_list_met_or_dep;
+
+ /**
+ * \test Test dep list: complex met or dep.
+ *
+ * \ingroup Test
+ */
+ struct DepListComplexMetOrDepTest : TestCase
+ {
+ DepListComplexMetOrDepTest() : TestCase("complex met or dep") { }
+
+ void run_n(int n)
+ {
+ TestEnvironment e;
+ TestMessageSuffix(stringify(n), true);
+
+ /* t/one DEPENDs upon
+ * || (
+ * ( t/two t/three )
+ * (
+ * t/four
+ * || (
+ * t/five
+ * ( t/six t/seven )
+ * )
+ * )
+ * )
+ */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "1").
+ set(vmk_depend, "|| ( ( t/two t/three ) ( t/four || ( t/five ( t/six t/seven ) ) ) )");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+
+ if (n == 1)
+ {
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"));
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"));
+ }
+ else if (n == 2)
+ {
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("four"), VersionSpec("1.0"));
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("five"), VersionSpec("1.0"));
+ }
+ else if (n == 3)
+ {
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("four"), VersionSpec("1.0"));
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("six"), VersionSpec("1.0"));
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("seven"), VersionSpec("1.0"));
+ }
+
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("1"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+
+ void run()
+ {
+ for (int n = 1 ; n <= 3 ; ++n)
+ run_n(n);
+ }
+ } test_dep_list_complex_met_or_dep;
+
+ /**
+ * \test Test dep list: complex unmet or dep.
+ *
+ * \ingroup Test
+ */
+ struct DepListComplexUnmetOrDepTest : TestCase
+ {
+ DepListComplexUnmetOrDepTest() : TestCase("complex unmet or dep") { }
+
+ void run_n(int n)
+ {
+ TestEnvironment e;
+ TestMessageSuffix suffix(stringify(n), true);
+
+ /* t/one DEPENDs upon
+ * || (
+ * ( t/two t/three )
+ * (
+ * t/four
+ * || (
+ * t/five
+ * ( t/six t/seven )
+ * )
+ * )
+ * )
+ */
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "1").
+ set(vmk_depend, "|| ( ( t/two t/three ) ( t/four || ( t/five ( t/six t/seven ) ) ) )");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+
+ if (n == 1)
+ {
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"));
+ }
+ else if (n == 2)
+ {
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"));
+ }
+ else if (n == 3)
+ {
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("five"), VersionSpec("1.0"));
+ }
+ else if (n == 4)
+ {
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("four"), VersionSpec("1.0"));
+ installed->add_version(CategoryNamePart("t"), PackageNamePart("seven"), VersionSpec("1.0"));
+ }
+
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ TEST_CHECK(d.begin() == d.end());
+ TEST_CHECK_THROWS(d.add(DepParser::parse("t/one")), DepListError);
+ TEST_CHECK(d.begin() == d.end());
+ }
+
+ void run()
+ {
+ for (int n = 1 ; n <= 4 ; ++n)
+ run_n(n);
+ }
+ } test_dep_list_complex_unmet_or_dep;
+
+ /**
+ * \test Test dep list: or all use dep.
+ *
+ * \ingroup Test
+ */
+ struct DepListOrAllUseDepTest : TestCase
+ {
+ DepListOrAllUseDepTest() : TestCase("or all use dep") { }
+
+ void run()
+ {
+ TestEnvironment e;
+
+ FakeRepository::Pointer repo(new FakeRepository(RepositoryName("repo")));
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("one"), VersionSpec("1.0"))->
+ set(vmk_slot, "1").
+ set(vmk_depend, "|| ( t/two ( off? ( t/three ) ) )");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("two"), VersionSpec("1.0"))->
+ set(vmk_slot, "1");
+
+ repo->add_version(CategoryNamePart("t"), PackageNamePart("three"), VersionSpec("1.0"))->
+ set(vmk_slot, "1");
+
+ e.package_db()->add_repository(repo);
+
+ FakeRepository::Pointer installed(new FakeRepository(RepositoryName("installed")));
+ e.installed_db()->add_repository(installed);
+
+ DepList d(&e);
+ d.add(DepParser::parse("t/one"));
+ DepList::Iterator di(d.begin()), di_end(d.end());
+ TEST_CHECK(di != di_end);
+ TEST_CHECK_EQUAL(*di, DepListEntry(
+ QualifiedPackageName(CategoryNamePart("t"), PackageNamePart("one")),
+ VersionSpec("1.0"), SlotName("1"), RepositoryName("repo")));
+ TEST_CHECK(++di == di_end);
+ }
+ } test_dep_list_or_all_use;
+
+}
+
diff --git a/paludis/dep_list_entry.cc b/paludis/dep_list_entry.cc
new file mode 100644
index 0000000..6a6e34b
--- /dev/null
+++ b/paludis/dep_list_entry.cc
@@ -0,0 +1,31 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_list_entry.hh"
+
+using namespace paludis;
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const DepListEntry & e)
+{
+ s << e.get<dle_name>() << "-" << e.get<dle_version>() << ":"
+ << e.get<dle_slot>() << "::" << e.get<dle_repository>();
+ return s;
+}
+
diff --git a/paludis/dep_list_entry.hh b/paludis/dep_list_entry.hh
new file mode 100644
index 0000000..72524db
--- /dev/null
+++ b/paludis/dep_list_entry.hh
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_LIST_ENTRY_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_LIST_ENTRY_HH 1
+
+#include <paludis/smart_record.hh>
+#include <paludis/qualified_package_name.hh>
+#include <paludis/version_spec.hh>
+#include <paludis/slot_name.hh>
+#include <paludis/repository_name.hh>
+#include <ostream>
+
+namespace paludis
+{
+ /**
+ * Keys for a DepListEntry.
+ */
+ enum DepListEntryKeys
+ {
+ dle_name, ///< Package name
+ dle_version, ///< Package version
+ dle_slot, ///< Package SLOT
+ dle_repository ///< Repository name
+ };
+
+ /**
+ * Tag for a DepListEntry.
+ */
+ struct DepListEntryTag :
+ SmartRecordTag<comparison_mode::FullComparisonTag, comparison_method::SmartRecordCompareByAllTag>,
+ SmartRecordKeys<DepListEntryKeys, 4>,
+ SmartRecordKey<dle_name, QualifiedPackageName>,
+ SmartRecordKey<dle_version, VersionSpec>,
+ SmartRecordKey<dle_slot, SlotName>,
+ SmartRecordKey<dle_repository, RepositoryName>
+ {
+ };
+
+ /**
+ * A DepListEntry represents an entry in a DepList.
+ */
+ typedef MakeSmartRecord<DepListEntryTag>::Type DepListEntry;
+
+ /**
+ * A DepListEntry can be written to a stream.
+ */
+ std::ostream & operator<< (std::ostream &, const DepListEntry &);
+}
+
+#endif
diff --git a/paludis/dep_list_error.cc b/paludis/dep_list_error.cc
new file mode 100644
index 0000000..40ca8e0
--- /dev/null
+++ b/paludis/dep_list_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_list_error.hh"
+
+using namespace paludis;
+
+DepListError::DepListError(const std::string & m) throw () :
+ Exception(m)
+{
+}
+
diff --git a/paludis/dep_list_error.hh b/paludis/dep_list_error.hh
new file mode 100644
index 0000000..64d96ce
--- /dev/null
+++ b/paludis/dep_list_error.hh
@@ -0,0 +1,40 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_LIST_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_LIST_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+namespace paludis
+{
+ /**
+ * Thrown if an error occurs whilst building a DepList.
+ */
+ class DepListError : public Exception
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ DepListError(const std::string &) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/dep_list_stack_too_deep_error.cc b/paludis/dep_list_stack_too_deep_error.cc
new file mode 100644
index 0000000..fc3ca03
--- /dev/null
+++ b/paludis/dep_list_stack_too_deep_error.cc
@@ -0,0 +1,30 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "dep_list_stack_too_deep_error.hh"
+#include "stringify.hh"
+
+using namespace paludis;
+
+DepListStackTooDeepError::DepListStackTooDeepError(int level) throw () :
+ DepListError("DepList stack too deep (" + stringify(level) + " entries)")
+{
+}
+
diff --git a/paludis/dep_list_stack_too_deep_error.hh b/paludis/dep_list_stack_too_deep_error.hh
new file mode 100644
index 0000000..1aa64c3
--- /dev/null
+++ b/paludis/dep_list_stack_too_deep_error.hh
@@ -0,0 +1,41 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_DEP_LIST_STACK_TOO_DEEP_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_LIST_STACK_TOO_DEEP_ERROR_HH 1
+
+#include <paludis/dep_list_error.hh>
+
+namespace paludis
+{
+ /**
+ * Thrown if a DepList's add stack gets too deep.
+ */
+ class DepListStackTooDeepError : public DepListError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DepListStackTooDeepError(int level) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/dep_parser.cc b/paludis/dep_parser.cc
new file mode 100644
index 0000000..4729c0c
--- /dev/null
+++ b/paludis/dep_parser.cc
@@ -0,0 +1,267 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "exception.hh"
+#include "internal_error.hh"
+#include "stringify.hh"
+#include "dep_string_parse_error.hh"
+#include "dep_string_nesting_error.hh"
+#include "dep_parser.hh"
+#include "dep_lexer.hh"
+#include "all_dep_atom.hh"
+#include "any_dep_atom.hh"
+#include "use_dep_atom.hh"
+#include "block_dep_atom.hh"
+#include "package_dep_atom.hh"
+#include "dep_atom_visitor.hh"
+#include <stack>
+
+using namespace paludis;
+
+enum DepParserState
+{
+ dps_initial,
+ dps_had_double_bar,
+ dps_had_double_bar_space,
+ dps_had_paren,
+ dps_had_use_flag,
+ dps_had_use_flag_space
+};
+
+CompositeDepAtom::ConstPointer
+DepParser::parse(const std::string & s)
+{
+ Context context("When parsing dependency string '" + s + "':");
+
+ std::stack<CompositeDepAtom::Pointer> stack;
+ stack.push(CompositeDepAtom::Pointer(new AllDepAtom));
+
+ DepParserState state(dps_initial);
+ DepLexer lexer(s);
+ DepLexer::Iterator i(lexer.begin()), i_end(lexer.end());
+
+ for ( ; i != i_end ; ++i)
+ {
+ Context context("When handling lexer token '" + i->second +
+ "' (" + stringify(i->first) + "):");
+ do
+ {
+ switch (state)
+ {
+ case dps_initial:
+ do
+ {
+ switch (i->first)
+ {
+ case dpl_whitespace:
+ continue;
+
+ case dpl_package:
+ {
+ if (i->second.empty())
+ throw DepStringParseError(i->second, "Empty package name");
+ if ('!' == i->second.at(0))
+ stack.top()->add_child(DepAtom::Pointer(
+ new BlockDepAtom(
+ PackageDepAtom::Pointer(new PackageDepAtom(
+ i->second.substr(1))))));
+ else
+ stack.top()->add_child(DepAtom::Pointer(
+ new PackageDepAtom(i->second)));
+ }
+ continue;
+
+ case dpl_open_paren:
+ {
+ CompositeDepAtom::Pointer a(new AllDepAtom);
+ stack.top()->add_child(a);
+ stack.push(a);
+ state = dps_had_paren;
+ }
+ continue;
+
+ case dpl_close_paren:
+ if (stack.empty())
+ throw DepStringNestingError(s);
+ stack.pop();
+ if (stack.empty())
+ throw DepStringNestingError(s);
+ state = dps_had_paren;
+ continue;
+
+ case dpl_double_bar:
+ {
+ CompositeDepAtom::Pointer a(new AnyDepAtom);
+ stack.top()->add_child(a);
+ stack.push(a);
+ state = dps_had_double_bar;
+ }
+ continue;
+
+ case dpl_use_flag:
+ {
+ std::string f(i->second);
+ bool inv(f.length() && ('!' == f.at(0)));
+ if (inv)
+ f.erase(0, 1);
+
+ if (f.empty())
+ throw DepStringParseError(s,
+ "Bad use flag name '" + i->second + "'");
+ if ('?' != f.at(f.length() - 1))
+ throw DepStringParseError(s,
+ "Use flag name '" + i->second + "' missing '?'");
+
+ f.erase(f.length() - 1);
+ CompositeDepAtom::Pointer a(
+ new UseDepAtom(UseFlagName(f), inv));
+ stack.top()->add_child(a);
+ stack.push(a);
+ state = dps_had_use_flag;
+ }
+ continue;
+
+ }
+ throw InternalError(__PRETTY_FUNCTION__,
+ "dps_initial: i->first is " + stringify(i->first));
+
+ } while (0);
+ continue;
+
+ case dps_had_double_bar:
+ do
+ {
+ switch (i->first)
+ {
+ case dpl_whitespace:
+ state = dps_had_double_bar_space;
+ continue;
+
+ case dpl_package:
+ case dpl_use_flag:
+ case dpl_double_bar:
+ case dpl_open_paren:
+ case dpl_close_paren:
+ throw DepStringParseError(s, "Expected space after '||'");
+ }
+ throw InternalError(__PRETTY_FUNCTION__,
+ "dps_had_double_bar: i->first is " + stringify(i->first));
+
+ } while (0);
+ continue;
+
+ case dps_had_double_bar_space:
+ do
+ {
+ switch (i->first)
+ {
+ case dpl_open_paren:
+ state = dps_initial;
+ continue;
+
+ case dpl_whitespace:
+ case dpl_package:
+ case dpl_use_flag:
+ case dpl_double_bar:
+ case dpl_close_paren:
+ throw DepStringParseError(s, "Expected '(' after '|| '");
+ }
+ throw InternalError(__PRETTY_FUNCTION__,
+ "dps_had_double_bar_space: i->first is " + stringify(i->first));
+ } while (0);
+ continue;
+
+ case dps_had_paren:
+ do
+ {
+ switch (i->first)
+ {
+ case dpl_whitespace:
+ state = dps_initial;
+ continue;
+
+ case dpl_package:
+ case dpl_use_flag:
+ case dpl_double_bar:
+ case dpl_open_paren:
+ case dpl_close_paren:
+ throw DepStringParseError(s, "Expected space after '(' or ')'");
+ }
+ throw InternalError(__PRETTY_FUNCTION__,
+ "dps_had_paren: i->first is " + stringify(i->first));
+ } while (0);
+ continue;
+
+ case dps_had_use_flag:
+ do
+ {
+ switch (i->first)
+ {
+ case dpl_whitespace:
+ state = dps_had_use_flag_space;
+ continue;
+
+ case dpl_package:
+ case dpl_use_flag:
+ case dpl_double_bar:
+ case dpl_open_paren:
+ case dpl_close_paren:
+ throw DepStringParseError(s, "Expected space after use flag");
+ }
+ throw InternalError(__PRETTY_FUNCTION__,
+ "dps_had_use_flag: i->first is " + stringify(i->first));
+ } while (0);
+ continue;
+
+ case dps_had_use_flag_space:
+ do
+ {
+ switch (i->first)
+ {
+ case dpl_open_paren:
+ state = dps_had_paren;
+ continue;
+
+ case dpl_whitespace:
+ case dpl_package:
+ case dpl_use_flag:
+ case dpl_double_bar:
+ case dpl_close_paren:
+ throw DepStringParseError(s, "Expected '(' after use flag");
+ }
+ throw InternalError(__PRETTY_FUNCTION__,
+ "dps_had_use_flag_space: i->first is " + stringify(i->first));
+ } while (0);
+ continue;
+ }
+ throw InternalError(__PRETTY_FUNCTION__,
+ "state is " + stringify(state));
+
+ } while (0);
+ }
+
+ if (stack.empty())
+ throw DepStringNestingError(s);
+ CompositeDepAtom::Pointer result(stack.top());
+ stack.pop();
+ if (! stack.empty())
+ throw DepStringNestingError(s);
+ return result;
+}
+
diff --git a/paludis/dep_parser.hh b/paludis/dep_parser.hh
new file mode 100644
index 0000000..b8f800d
--- /dev/null
+++ b/paludis/dep_parser.hh
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_PARSER_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_PARSER_HH 1
+
+#include <paludis/composite_dep_atom.hh>
+#include <paludis/counted_ptr.hh>
+#include <paludis/instantiation_policy.hh>
+#include <string>
+
+/** \file
+ * Declarations for the DepParser class.
+ *
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * The DepParser converts string representations of a dependency
+ * specification into a DepAtom instance.
+ */
+ class DepParser :
+ private InstantiationPolicy<DepParser, instantiation_method::NonInstantiableTag>
+ {
+ public:
+ /**
+ * Parse a given dependency string, and return an appropriate
+ * DepAtom tree.
+ */
+ static CompositeDepAtom::ConstPointer parse(const std::string & s);
+ };
+}
+
+#endif
diff --git a/paludis/dep_parser_TEST.cc b/paludis/dep_parser_TEST.cc
new file mode 100644
index 0000000..da88d67
--- /dev/null
+++ b/paludis/dep_parser_TEST.cc
@@ -0,0 +1,245 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include "paludis.hh"
+#include <sstream>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for DepParser.
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test DepParser with an empty input.
+ *
+ * \ingroup Test
+ */
+ struct DepParserEmptyTest : TestCase
+ {
+ DepParserEmptyTest() : TestCase("empty") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse("")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all></all>");
+ }
+ } test_dep_atom_parser_empty;
+
+ /**
+ * \test Test DepParser with a blank input.
+ *
+ * \ingroup Test
+ */
+ struct DepParserBlankTest : TestCase
+ {
+ DepParserBlankTest() : TestCase("blank") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse(" \n \t")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all></all>");
+ }
+ } test_dep_atom_parser_blank;
+
+ /**
+ * \test Test DepParser with a package.
+ *
+ * \ingroup Test
+ */
+ struct DepParserPackageTest : TestCase
+ {
+ DepParserPackageTest() : TestCase("package") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse("app-editors/vim")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><package>app-editors/vim</package></all>");
+ }
+ } test_dep_atom_parser_package;
+
+ /**
+ * \test Test DepParser with a decorated package.
+ *
+ * \ingroup Test
+ */
+ struct DepParserDecoratedPackageTest : TestCase
+ {
+ DepParserDecoratedPackageTest() : TestCase("decorated package") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse(">=app-editors/vim-6.4_alpha")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><package version=\">=6.4_alpha\">"
+ "app-editors/vim</package></all>");
+ }
+ } test_dep_atom_parser_decorated_package;
+
+ /**
+ * \test Test DepParser with a sequence of packages.
+ *
+ * \ingroup Test
+ */
+ struct DepParserPackagesTest : TestCase
+ {
+ DepParserPackagesTest() : TestCase("packages") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse("app-editors/vim app-misc/hilite \nsys-apps/findutils")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><package>app-editors/vim</package>"
+ "<package>app-misc/hilite</package><package>sys-apps/findutils</package></all>");
+ }
+ } test_dep_atom_parser_packages;
+
+ /**
+ * \test Test DepParser with an any group.
+ *
+ * \ingroup Test
+ */
+ struct DepParserAnyTest : TestCase
+ {
+ DepParserAnyTest() : TestCase("any") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse("|| ( one/one two/two )")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><any><package>one/one</package>"
+ "<package>two/two</package></any></all>");
+ }
+ } test_dep_atom_parser_any;
+
+ /**
+ * \test Test DepParser with an all group.
+ *
+ * \ingroup Test
+ */
+ struct DepParserAllTest : TestCase
+ {
+ DepParserAllTest() : TestCase("all") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse(" ( one/one two/two ) ")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><all><package>one/one</package>"
+ "<package>two/two</package></all></all>");
+ }
+ } test_dep_atom_parser_all;
+
+ /**
+ * \test Test DepParser with a use group.
+ *
+ * \ingroup Test
+ */
+ struct DepParserUseTest : TestCase
+ {
+ DepParserUseTest() : TestCase("use") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse("foo? ( one/one )")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><use flag=\"foo\" inverse=\"false\"><package>one/one</package>"
+ "</use></all>");
+ }
+ } test_dep_atom_parser_use;
+
+ /**
+ * \test Test DepParser with an inverse use group.
+ *
+ * \ingroup Test
+ */
+ struct DepParserInvUseTest : TestCase
+ {
+ DepParserInvUseTest() : TestCase("!use") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ DepParser::parse("!foo? ( one/one )")->accept(&d);
+ TEST_CHECK_EQUAL(s.str(), "<all><use flag=\"foo\" inverse=\"true\"><package>one/one</package>"
+ "</use></all>");
+ }
+ } test_dep_atom_parser_inv_use;
+
+ /**
+ * \test Test DepParser nesting errors.
+ *
+ * \ingroup Test
+ */
+ struct DepParserBadNestingTest : TestCase
+ {
+ DepParserBadNestingTest() : TestCase("bad nesting") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ TEST_CHECK_THROWS(DepParser::parse("!foo? ( one/one")->accept(&d), DepStringError);
+ TEST_CHECK_THROWS(DepParser::parse("!foo? ( one/one ) )")->accept(&d), DepStringError);
+ TEST_CHECK_THROWS(DepParser::parse("( ( ( ) )")->accept(&d), DepStringError);
+ TEST_CHECK_THROWS(DepParser::parse("( ( ( ) ) ) )")->accept(&d), DepStringError);
+ TEST_CHECK_THROWS(DepParser::parse(")")->accept(&d), DepStringError);
+ }
+ } test_dep_atom_parser_bad_nesting;
+
+ /**
+ * \test Test DepParser weird errors.
+ *
+ * \ingroup Test
+ */
+ struct DepParserBadValuesTest : TestCase
+ {
+ DepParserBadValuesTest() : TestCase("bad values") { }
+
+ void run()
+ {
+ std::stringstream s;
+ DepAtomDumper d(&s);
+ TEST_CHECK_THROWS(DepParser::parse("!foo? ||")->accept(&d), DepStringError);
+ TEST_CHECK_THROWS(DepParser::parse("(((")->accept(&d), DepStringError);
+ TEST_CHECK_THROWS(DepParser::parse(")")->accept(&d), DepStringError);
+ TEST_CHECK_THROWS(DepParser::parse("(foo/bar)")->accept(&d), DepStringError);
+ }
+ } test_dep_atom_parser_bad_values;
+}
+
diff --git a/paludis/dep_string_error.cc b/paludis/dep_string_error.cc
new file mode 100644
index 0000000..5f9e10e
--- /dev/null
+++ b/paludis/dep_string_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_string_error.hh"
+
+using namespace paludis;
+
+DepStringError::DepStringError(const std::string & d, const std::string & m) throw () :
+ Exception("Bad dependency string '" + d + "': " + m)
+{
+}
+
diff --git a/paludis/dep_string_error.hh b/paludis/dep_string_error.hh
new file mode 100644
index 0000000..a95706e
--- /dev/null
+++ b/paludis/dep_string_error.hh
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_STRING_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_STRING_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+/** \file
+ * Declarations for DepStringError.
+ *
+ * \ingroup Exception
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * A DepStringError descendent is thrown if an invalid depend string is
+ * encountered.
+ *
+ * \ingroup Exception
+ * \ingroup DepResolver
+ */
+ class DepStringError : public Exception
+ {
+ protected:
+ /**
+ * Constructor.
+ */
+ DepStringError(const std::string & dep_string,
+ const std::string & message) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/dep_string_lex_error.cc b/paludis/dep_string_lex_error.cc
new file mode 100644
index 0000000..38584e1
--- /dev/null
+++ b/paludis/dep_string_lex_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_string_lex_error.hh"
+
+using namespace paludis;
+
+DepStringLexError::DepStringLexError(const std::string & dep_string,
+ const std::string & message) throw () :
+ DepStringError(dep_string, "in lex phase: " + message)
+{
+}
diff --git a/paludis/dep_string_lex_error.hh b/paludis/dep_string_lex_error.hh
new file mode 100644
index 0000000..19ba3d4
--- /dev/null
+++ b/paludis/dep_string_lex_error.hh
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_STRING_LEX_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_STRING_LEX_ERROR_HH 1
+
+#include <paludis/dep_string_error.hh>
+
+/** \file
+ * Declarations for the DepStringLexError class.
+ *
+ * \ingroup Exception
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * A DepStringLexError is thrown if a lex-level error is encountered when
+ * parsing a dependency string.
+ *
+ * \ingroup Exception
+ * \ingroup DepResolver
+ */
+ class DepStringLexError : public DepStringError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DepStringLexError(const std::string & dep_string,
+ const std::string & message) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/dep_string_nesting_error.cc b/paludis/dep_string_nesting_error.cc
new file mode 100644
index 0000000..5b16a4f
--- /dev/null
+++ b/paludis/dep_string_nesting_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_string_nesting_error.hh"
+
+using namespace paludis;
+
+DepStringNestingError::DepStringNestingError(const std::string & dep_string) throw () :
+ DepStringParseError(dep_string, "improperly balanced parentheses")
+{
+}
+
diff --git a/paludis/dep_string_nesting_error.hh b/paludis/dep_string_nesting_error.hh
new file mode 100644
index 0000000..c37e60d
--- /dev/null
+++ b/paludis/dep_string_nesting_error.hh
@@ -0,0 +1,48 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_STRING_NESTING_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_STRING_NESTING_ERROR_HH 1
+
+#include <paludis/dep_string_parse_error.hh>
+
+/** \file
+ * Declarations for the DepStringNestingError exception.
+ *
+ * \ingroup Exception
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * A DepStringNestingError is thrown if a dependency string does not have
+ * properly balanced parentheses.
+ */
+ class DepStringNestingError : public DepStringParseError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DepStringNestingError(const std::string & dep_string) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/dep_string_parse_error.cc b/paludis/dep_string_parse_error.cc
new file mode 100644
index 0000000..d1aaa86
--- /dev/null
+++ b/paludis/dep_string_parse_error.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dep_string_parse_error.hh"
+
+using namespace paludis;
+
+DepStringParseError::DepStringParseError(const std::string & d,
+ const std::string & m) throw () :
+ DepStringError(d, "in parse phase: " + m)
+{
+}
+
diff --git a/paludis/dep_string_parse_error.hh b/paludis/dep_string_parse_error.hh
new file mode 100644
index 0000000..8a29a01
--- /dev/null
+++ b/paludis/dep_string_parse_error.hh
@@ -0,0 +1,52 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DEP_STRING_PARSE_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DEP_STRING_PARSE_ERROR_HH 1
+
+#include <paludis/dep_string_error.hh>
+
+/** \file
+ * Declarations for the DepStringParseError class.
+ *
+ * \ingroup Exception
+ * \ingroup DepResolver
+ */
+
+namespace paludis
+{
+ /**
+ * A DepStringParseError is thrown if an error is encountered when parsing
+ * a dependency string.
+ *
+ * \ingroup Exception
+ * \ingroup DepResolver
+ */
+ class DepStringParseError : public DepStringError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DepStringParseError(const std::string & dep_string,
+ const std::string & message) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/dir_iterator.cc b/paludis/dir_iterator.cc
new file mode 100644
index 0000000..60da68a
--- /dev/null
+++ b/paludis/dir_iterator.cc
@@ -0,0 +1,128 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dir_iterator.hh"
+#include "dir_open_error.hh"
+#include "internal_error.hh"
+#include "stringify.hh"
+#include <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+
+/** \file
+ * Implementation of paludis::DirIterator.
+ *
+ * \ingroup Filesystem
+ */
+
+using namespace paludis;
+
+DirIterator::DirIterator(const FSEntry & base) :
+ _base(base),
+ _items(new std::set<FSEntry>)
+{
+ DIR * d(opendir(stringify(base).c_str()));
+ if (0 == d)
+ throw DirOpenError(base, errno);
+
+ struct dirent * de;
+ while (0 != ((de = readdir(d))))
+ if ('.' != de->d_name[0])
+ _items->insert(_base / std::string(de->d_name));
+ _iter = _items->begin();
+
+ closedir(d);
+}
+
+DirIterator::DirIterator(const DirIterator & other) :
+ _base(other._base),
+ _items(other._items),
+ _iter(other._iter)
+{
+}
+
+DirIterator::DirIterator() :
+ _base(""),
+ _items(new std::set<FSEntry>),
+ _iter(_items->end())
+{
+}
+
+DirIterator::~DirIterator()
+{
+}
+
+const DirIterator &
+DirIterator::operator= (const DirIterator & other)
+{
+ if (this != &other)
+ {
+ _base = other._base;
+ _items = other._items;
+ _iter = other._iter;
+ }
+ return *this;
+}
+
+const FSEntry &
+DirIterator::operator* () const
+{
+ return *_iter;
+}
+
+const FSEntry *
+DirIterator::operator-> () const
+{
+ return &*_iter;
+}
+
+DirIterator &
+DirIterator::operator++ ()
+{
+ ++_iter;
+ return *this;
+}
+
+DirIterator
+DirIterator::operator++ (int)
+{
+ DirIterator c(*this);
+ _iter++;
+ return c;
+}
+
+bool
+DirIterator::operator== (const DirIterator & other) const
+{
+ if (other._iter == other._items->end())
+ return _iter == _items->end();
+
+ if (other._items != _items)
+ throw InternalError(__PRETTY_FUNCTION__,
+ "comparing two different DirIterators.");
+
+ return other._iter == _iter;
+}
+
+bool
+DirIterator::operator!= (const DirIterator & other) const
+{
+ return ! operator== (other);
+}
+
diff --git a/paludis/dir_iterator.hh b/paludis/dir_iterator.hh
new file mode 100644
index 0000000..7a1be6c
--- /dev/null
+++ b/paludis/dir_iterator.hh
@@ -0,0 +1,110 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DIR_ITERATOR_HH
+#define PALUDIS_GUARD_PALUDIS_DIR_ITERATOR_HH 1
+
+#include <paludis/fs_entry.hh>
+#include <paludis/counted_ptr.hh>
+#include <iterator>
+#include <set>
+
+/** \file
+ * Declarations for paludis::DirIterator.
+ *
+ * \ingroup Filesystem
+ */
+
+namespace paludis
+{
+ /**
+ * 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 Filesystem
+ */
+ class DirIterator : public std::iterator<std::forward_iterator_tag, FSEntry>
+ {
+ private:
+ FSEntry _base;
+ CountedPtr<std::set<FSEntry>, count_policy::ExternalCountTag> _items;
+ std::set<FSEntry>::iterator _iter;
+
+ public:
+ /**
+ * Constructor, to an FSEntry which must be a directory.
+ */
+ explicit DirIterator(const FSEntry & base);
+
+ /**
+ * Copy constructor.
+ */
+ DirIterator(const DirIterator & other);
+
+ /**
+ * Constructor, creates an end() iterator.
+ */
+ DirIterator();
+
+ /**
+ * Destructor.
+ */
+ ~DirIterator();
+
+ /**
+ * Assign.
+ */
+ const DirIterator & operator= (const DirIterator & other);
+
+ /**
+ * Dereference.
+ */
+ const FSEntry & operator* () const;
+
+ /**
+ * Dereference.
+ */
+ const FSEntry * operator-> () const;
+
+ /**
+ * Increment.
+ */
+ DirIterator & operator++ ();
+
+ /**
+ * Increment.
+ */
+ DirIterator operator++ (int);
+
+ /**
+ * Compare.
+ */
+ bool operator== (const DirIterator & other) const;
+
+ /**
+ * Inverse compare.
+ */
+ bool operator!= (const DirIterator & other) const;
+ };
+}
+
+#endif
diff --git a/paludis/dir_open_error.cc b/paludis/dir_open_error.cc
new file mode 100644
index 0000000..550204d
--- /dev/null
+++ b/paludis/dir_open_error.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "dir_open_error.hh"
+#include "stringify.hh"
+
+using namespace paludis;
+
+DirOpenError::DirOpenError(const FSEntry & location, const int errno_value) throw () :
+ FSError("Error opening directory '" + stringify(location) + "': " + strerror(errno_value))
+{
+}
+
diff --git a/paludis/dir_open_error.hh b/paludis/dir_open_error.hh
new file mode 100644
index 0000000..743b94a
--- /dev/null
+++ b/paludis/dir_open_error.hh
@@ -0,0 +1,49 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DIR_OPEN_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DIR_OPEN_ERROR_HH 1
+
+#include <paludis/fs_error.hh>
+#include <paludis/fs_entry.hh>
+
+/** \file
+ * Declarations for DirOpenError.
+ *
+ * \ingroup Exception
+ */
+
+namespace paludis
+{
+ /**
+ * Raised when a directory open fails.
+ *
+ * \ingroup Exception
+ */
+ class DirOpenError : public FSError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DirOpenError(const FSEntry & location, const int errno_value) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/duplicate_repository_error.cc b/paludis/duplicate_repository_error.cc
new file mode 100644
index 0000000..ee379af
--- /dev/null
+++ b/paludis/duplicate_repository_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "duplicate_repository_error.hh"
+
+using namespace paludis;
+
+DuplicateRepositoryError::DuplicateRepositoryError(const std::string & name) throw () :
+ PackageDatabaseError("A repository named '" + name + "' already exists")
+{
+}
+
diff --git a/paludis/duplicate_repository_error.hh b/paludis/duplicate_repository_error.hh
new file mode 100644
index 0000000..8776a4f
--- /dev/null
+++ b/paludis/duplicate_repository_error.hh
@@ -0,0 +1,45 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_DUPLICATE_REPOSITORY_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_DUPLICATE_REPOSITORY_ERROR_HH 1
+
+#include <paludis/package_database_error.hh>
+
+/** \file
+ * Declarations for the DuplicateRepositoryError class.
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if a Repository with the same name as an existing member is added
+ * to a PackageDatabase.
+ */
+ class DuplicateRepositoryError : public PackageDatabaseError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ DuplicateRepositoryError(const std::string & name) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/environment.cc b/paludis/environment.cc
new file mode 100644
index 0000000..0c7fe79
--- /dev/null
+++ b/paludis/environment.cc
@@ -0,0 +1,73 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "package_database.hh"
+#include "environment.hh"
+#include "internal_error.hh"
+
+using namespace paludis;
+
+Environment::Environment(PackageDatabase::Pointer d, PackageDatabase::Pointer i) :
+ _package_db(d),
+ _installed_db(i)
+{
+}
+
+Environment::~Environment()
+{
+}
+
+MaskReasons
+Environment::mask_reasons(const PackageDatabaseEntry & e) const
+{
+ MaskReasons result;
+ VersionMetadata::ConstPointer metadata(package_db()->fetch_metadata(e));
+
+ if (metadata->get(vmk_eapi) != "0" && metadata->get(vmk_eapi) != "")
+ result.set(mr_eapi);
+ else
+ {
+
+ result.set(mr_keyword);
+ for (VersionMetadata::KeywordIterator k(metadata->begin_keywords()),
+ k_end(metadata->end_keywords()) ; k != k_end ; ++k)
+ if (accept_keyword(*k, &e))
+ {
+ result.reset(mr_keyword);
+ break;
+ }
+
+ if (! query_user_unmasks(e))
+ {
+ if (query_user_masks(e))
+ result.set(mr_user_mask);
+
+ if (package_db()->fetch_repository(e.get<pde_repository>())->query_profile_masks(e.get<pde_package>(),
+ e.get<pde_version>()))
+ result.set(mr_profile_mask);
+
+ if (package_db()->fetch_repository(e.get<pde_repository>())->query_repository_masks(e.get<pde_package>(),
+ e.get<pde_version>()))
+ result.set(mr_repository_mask);
+ }
+ }
+
+ return result;
+}
+
diff --git a/paludis/environment.hh b/paludis/environment.hh
new file mode 100644
index 0000000..5b0e4f4
--- /dev/null
+++ b/paludis/environment.hh
@@ -0,0 +1,111 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ENVIRONMENT_HH
+#define PALUDIS_GUARD_PALUDIS_ENVIRONMENT_HH 1
+
+#include <paludis/package_database_entry.hh>
+#include <paludis/package_database.hh>
+#include <paludis/use_flag_name.hh>
+#include <paludis/keyword_name.hh>
+#include <paludis/instantiation_policy.hh>
+#include <paludis/counted_ptr.hh>
+#include <paludis/mask_reasons.hh>
+
+/** \file
+ * Declarations for the Environment class.
+ *
+ * \ingroup Environment
+ */
+
+namespace paludis
+{
+ class PackageDatabase;
+
+ /**
+ * Represents a working environment, which contains an available packages
+ * database and an installed packages database and provides various methods
+ * for querying package visibility and options.
+ *
+ * \ingroup Environment
+ */
+ class Environment :
+ private InstantiationPolicy<Environment, instantiation_method::NonCopyableTag>
+ {
+ private:
+ PackageDatabase::Pointer _package_db;
+ PackageDatabase::Pointer _installed_db;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ Environment(PackageDatabase::Pointer, PackageDatabase::Pointer);
+
+ public:
+ /**
+ * Does the user want the specified USE flag set, possibly for a
+ * particular package?
+ */
+ virtual bool query_use(const UseFlagName &, const PackageDatabaseEntry * const) const = 0;
+
+ /**
+ * Is the specified KEYWORD accepted?
+ */
+ virtual bool accept_keyword(const KeywordName &, const PackageDatabaseEntry * const) const = 0;
+
+ /**
+ * Fetch the masks for a particular package.
+ */
+ MaskReasons mask_reasons(const PackageDatabaseEntry &) const;
+
+ /**
+ * Are there any user masks on a package?
+ */
+ virtual bool query_user_masks(const PackageDatabaseEntry &) const = 0;
+
+ /**
+ * Are there any user unmasks on a package?
+ */
+ virtual bool query_user_unmasks(const PackageDatabaseEntry &) const = 0;
+
+ /**
+ * Fetch our package database.
+ */
+ PackageDatabase::Pointer package_db() const
+ {
+ return _package_db;
+ }
+
+ /**
+ * Fetch our installed database.
+ */
+ PackageDatabase::Pointer installed_db() const
+ {
+ return _installed_db;
+ }
+
+ /**
+ * Destructor.
+ */
+ virtual ~Environment();
+ };
+}
+
+#endif
diff --git a/paludis/exception.cc b/paludis/exception.cc
new file mode 100644
index 0000000..346df8f
--- /dev/null
+++ b/paludis/exception.cc
@@ -0,0 +1,38 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "exception.hh"
+
+using namespace paludis;
+
+Exception::Exception(const std::string & message) throw () :
+ _message(message)
+{
+}
+
+Exception::~Exception() throw ()
+{
+}
+
+const std::string &
+Exception::message() const throw ()
+{
+ return _message;
+}
+
diff --git a/paludis/exception.hh b/paludis/exception.hh
new file mode 100644
index 0000000..b6b9003
--- /dev/null
+++ b/paludis/exception.hh
@@ -0,0 +1,75 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_EXCEPTION_HH
+#define PALUDIS_GUARD_PALUDIS_EXCEPTION_HH 1
+
+#include <paludis/attributes.hh>
+
+#include <string>
+#include <exception>
+#include <libebt/libebt.hh>
+
+/** \file
+ * Declaration for the Exception base class.
+ */
+
+namespace paludis
+{
+ /**
+ * Context tag for libebt.
+ */
+ struct PaludisBacktraceTag
+ {
+ };
+
+ /**
+ * Backtrace context class.
+ */
+ typedef libebt::BacktraceContext<PaludisBacktraceTag> Context;
+
+ /**
+ * Base exception class.
+ */
+ class Exception : public std::exception,
+ public libebt::Backtraceable<PaludisBacktraceTag>
+ {
+ private:
+ const std::string _message;
+
+ protected:
+ /**
+ * Constructor.
+ */
+ Exception(const std::string & message) throw ();
+
+ public:
+ /**
+ * Destructor.
+ */
+ virtual ~Exception() throw () PALUDIS_ATTRIBUTE((nothrow));
+
+ /**
+ * Return our descriptive error message.
+ */
+ const std::string & message() const throw () PALUDIS_ATTRIBUTE((nothrow));
+ };
+}
+
+#endif
diff --git a/paludis/fake_repository.cc b/paludis/fake_repository.cc
new file mode 100644
index 0000000..b7a202d
--- /dev/null
+++ b/paludis/fake_repository.cc
@@ -0,0 +1,196 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "fake_repository.hh"
+#include "package_name_part_collection.hh"
+#include "version_spec_collection.hh"
+#include "internal_error.hh"
+#include "version_metadata.hh"
+#include "stringify.hh"
+#include <map>
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for FakeRepository.
+ */
+ template<>
+ struct Implementation<FakeRepository> :
+ private InstantiationPolicy<Implementation<FakeRepository>, instantiation_method::NonCopyableTag>,
+ InternalCounted<Implementation<FakeRepository> >
+ {
+ /// Our category names.
+ CategoryNamePartCollection::Pointer category_names;
+
+ /// Our package names.
+ std::map<CategoryNamePart, PackageNamePartCollection::Pointer > package_names;
+
+ /// Our versions.
+ std::map<QualifiedPackageName, VersionSpecCollection::Pointer > versions;
+
+ /// Our metadata.
+ std::map<std::string, VersionMetadata::Pointer > metadata;
+
+ /// Constructor.
+ Implementation() :
+ category_names(new CategoryNamePartCollection)
+ {
+ }
+ };
+}
+
+FakeRepository::FakeRepository(const RepositoryName & name) :
+ Repository(name),
+ PrivateImplementationPattern<FakeRepository>(new Implementation<FakeRepository>)
+{
+ _info.insert(std::make_pair("format", "fake"));
+}
+
+FakeRepository::~FakeRepository()
+{
+}
+
+bool
+FakeRepository::do_has_category_named(const CategoryNamePart & c) const
+{
+ return (_implementation->category_names->end() != _implementation->category_names->find(c));
+}
+
+bool
+FakeRepository::do_has_package_named(const CategoryNamePart & c,
+ const PackageNamePart & p) const
+{
+ return has_category_named(c) &&
+ (_implementation->package_names.find(c)->second->end() !=
+ _implementation->package_names.find(c)->second->find(p));
+}
+
+CategoryNamePartCollection::ConstPointer
+FakeRepository::do_category_names() const
+{
+ return _implementation->category_names;
+}
+
+QualifiedPackageNameCollection::ConstPointer
+FakeRepository::do_package_names(const CategoryNamePart & c) const
+{
+ if (! has_category_named(c))
+ throw InternalError(__PRETTY_FUNCTION__, "no category named " + stringify(c));
+ QualifiedPackageNameCollection::Pointer result(new QualifiedPackageNameCollection);
+ PackageNamePartCollection::Iterator p(_implementation->package_names.find(c)->second->begin()),
+ p_end(_implementation->package_names.find(c)->second->end());
+ for ( ; p != p_end ; ++p)
+ result->insert(QualifiedPackageName(c, *p));
+ return result;
+}
+
+VersionSpecCollection::ConstPointer
+FakeRepository::do_version_specs(const QualifiedPackageName & n) const
+{
+ if (! has_category_named(n.get<qpn_category>()))
+ throw InternalError(__PRETTY_FUNCTION__, "no category");
+ if (! has_package_named(n.get<qpn_category>(), n.get<qpn_package>()))
+ throw InternalError(__PRETTY_FUNCTION__, "no package");
+ return _implementation->versions.find(n)->second;
+}
+
+bool
+FakeRepository::do_has_version(const CategoryNamePart & c,
+ const PackageNamePart & p, const VersionSpec & v) const
+{
+ if (! has_category_named(c))
+ throw InternalError(__PRETTY_FUNCTION__, "no category");
+ if (! has_package_named(c, p))
+ throw InternalError(__PRETTY_FUNCTION__, "no package");
+ return _implementation->versions.find(QualifiedPackageName(c, p))->second->find(v) !=
+ _implementation->versions.find(QualifiedPackageName(c, p))->second->end();
+}
+
+void
+FakeRepository::add_category(const CategoryNamePart & c)
+{
+ _implementation->category_names->insert(c);
+ _implementation->package_names.insert(std::make_pair(c, new PackageNamePartCollection));
+}
+
+void
+FakeRepository::add_package(const CategoryNamePart & c, const PackageNamePart & p)
+{
+ add_category(c);
+ _implementation->package_names.find(c)->second->insert(p);
+ _implementation->versions.insert(std::make_pair(QualifiedPackageName(c, p),
+ new VersionSpecCollection));
+}
+
+VersionMetadata::Pointer
+FakeRepository::add_version(const CategoryNamePart & c, const PackageNamePart & p,
+ const VersionSpec & v)
+{
+ add_package(c, p);
+ _implementation->versions.find(QualifiedPackageName(c, p))->second->insert(v);
+ _implementation->metadata.insert(
+ std::make_pair(stringify(c) + "/" + stringify(p) + "-" + stringify(v), new VersionMetadata));
+ VersionMetadata::Pointer r(_implementation->metadata.find(stringify(c) +
+ "/" + stringify(p) + "-" + stringify(v))->second);
+ r->set(vmk_slot, "0");
+ r->set(vmk_keywords, "test");
+ return r;
+}
+
+VersionMetadata::ConstPointer
+FakeRepository::do_version_metadata(
+ const CategoryNamePart & c, const PackageNamePart & p, const VersionSpec & v) const
+{
+ if (! has_version(c, p, v))
+ throw InternalError(__PRETTY_FUNCTION__, "no version");
+ return _implementation->metadata.find(stringify(c) + "/" + stringify(p) + "-" + stringify(v))->second;
+}
+
+bool
+FakeRepository::do_query_repository_masks(const CategoryNamePart &,
+ const PackageNamePart &, const VersionSpec &) const
+{
+ /// \todo?
+ return false;
+}
+
+bool
+FakeRepository::do_query_profile_masks(const CategoryNamePart &,
+ const PackageNamePart &, const VersionSpec &) const
+{
+ /// \todo?
+ return false;
+}
+
+bool
+FakeRepository::do_query_use(const UseFlagName &, const bool & d) const
+{
+ /// \todo?
+ return d;
+}
+
+bool
+FakeRepository::do_query_use_mask(const UseFlagName &) const
+{
+ /// \todo?
+ return false;
+}
+
diff --git a/paludis/fake_repository.hh b/paludis/fake_repository.hh
new file mode 100644
index 0000000..8abfcfa
--- /dev/null
+++ b/paludis/fake_repository.hh
@@ -0,0 +1,109 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_FAKE_REPOSITORY_HH
+#define PALUDIS_GUARD_PALUDIS_FAKE_REPOSITORY_HH 1
+
+#include <paludis/repository.hh>
+#include <paludis/private_implementation_pattern.hh>
+
+/** \file
+ * Declarations for the FakeRepository class.
+ *
+ * \ingroup Database
+ */
+
+namespace paludis
+{
+ /**
+ * A FakeRepository is a Repository subclass that is used for
+ * various test cases.
+ *
+ * \ingroup Database
+ */
+ class FakeRepository : public Repository,
+ private PrivateImplementationPattern<FakeRepository>
+ {
+ protected:
+ virtual bool do_has_category_named(const CategoryNamePart &) const;
+
+ virtual bool do_has_package_named(const CategoryNamePart &,
+ const PackageNamePart &) const;
+
+ virtual CategoryNamePartCollection::ConstPointer do_category_names() const;
+
+ virtual QualifiedPackageNameCollection::ConstPointer do_package_names(
+ const CategoryNamePart &) const;
+
+ virtual VersionSpecCollection::ConstPointer do_version_specs(
+ const QualifiedPackageName &) const;
+
+ virtual bool do_has_version(const CategoryNamePart &,
+ const PackageNamePart &, const VersionSpec &) const;
+
+ virtual VersionMetadata::ConstPointer do_version_metadata(
+ const CategoryNamePart &, const PackageNamePart &,
+ const VersionSpec &) const;
+
+ virtual bool do_query_repository_masks(const CategoryNamePart &,
+ const PackageNamePart &, const VersionSpec &) const;
+
+ virtual bool do_query_profile_masks(const CategoryNamePart &,
+ const PackageNamePart &, const VersionSpec &) const;
+
+ virtual bool do_query_use(const UseFlagName &, const bool &) const;
+
+ virtual bool do_query_use_mask(const UseFlagName &) const;
+
+ public:
+ /**
+ * Constructor.
+ */
+ FakeRepository(const RepositoryName & name);
+
+ /**
+ * Destructor.
+ */
+
+ ~FakeRepository();
+
+ /**
+ * Add a category.
+ */
+ void add_category(const CategoryNamePart &);
+
+ /**
+ * Add a package, and a category if necessary.
+ */
+ void add_package(const CategoryNamePart &, const PackageNamePart &);
+
+ /**
+ * Add a version, and a package and category if necessary, and set some
+ * default values for its metadata, and return said metadata.
+ */
+ VersionMetadata::Pointer add_version(
+ const CategoryNamePart &, const PackageNamePart &, const VersionSpec &);
+
+ typedef CountedPtr<FakeRepository, count_policy::InternalCountTag> Pointer;
+ typedef CountedPtr<const FakeRepository, count_policy::InternalCountTag> ConstPointer;
+ };
+}
+
+
+#endif
diff --git a/paludis/files.m4 b/paludis/files.m4
new file mode 100644
index 0000000..444f877
--- /dev/null
+++ b/paludis/files.m4
@@ -0,0 +1,119 @@
+dnl vim: set ft=m4 et :
+dnl This file is used by Makefile.am.m4 and paludis.hh.m4. You should
+dnl use the provided autogen.bash script to do all the hard work.
+
+add(`about', `hh', `test')
+add(`all_dep_atom', `hh', `cc')
+add(`all_masked_error', `hh', `cc')
+add(`ambiguous_package_name_error', `hh', `cc')
+add(`any_dep_atom', `hh', `cc')
+add(`attributes', `hh', `cc')
+add(`bad_version_spec_error', `hh', `cc')
+add(`block_dep_atom', `hh', `cc')
+add(`block_error', `hh', `cc')
+add(`category_name_part', `hh', `cc')
+add(`category_name_part_collection', `hh', `cc')
+add(`category_name_part_error', `hh', `cc')
+add(`category_name_part_validator', `hh', `cc')
+add(`circular_dependency_error', `hh', `cc')
+add(`comparison_policy', `hh', `cc', `test')
+add(`composite_dep_atom', `hh', `cc')
+add(`composite_pattern', `hh', `cc')
+add(`composite_visitor_pattern', `hh', `cc', `impl')
+add(`config_file', `hh', `cc', `test')
+add(`config_file_error', `hh', `cc')
+add(`container_entry', `hh', `cc', `test')
+add(`counted_ptr', `hh', `cc', `test')
+add(`counted_ptr_error', `hh', `cc')
+add(`create_insert_iterator', `hh', `cc', `test')
+add(`default_config', `hh', `cc')
+add(`default_config_error', `hh', `cc')
+add(`default_environment', `hh', `cc')
+add(`deleter', `hh', `cc', `test')
+add(`dep_atom', `hh', `cc')
+add(`dep_atom_dumper', `hh', `cc', `test')
+add(`dep_atom_visitor', `hh', `cc')
+add(`dep_lexer', `hh', `cc', `test')
+add(`dep_list', `hh', `cc', `test')
+add(`dep_list_entry', `hh', `cc')
+add(`dep_list_error', `hh', `cc')
+add(`dep_list_stack_too_deep_error', `hh', `cc')
+add(`dep_parser', `hh', `cc', `test')
+add(`dep_string_error', `hh', `cc')
+add(`dep_string_lex_error', `hh', `cc')
+add(`dep_string_nesting_error', `hh', `cc')
+add(`dep_string_parse_error', `hh', `cc')
+add(`dir_iterator', `hh', `cc')
+add(`dir_open_error', `hh', `cc')
+add(`duplicate_repository_error', `hh', `cc')
+add(`environment', `hh', `cc')
+add(`exception', `hh', `cc')
+add(`fake_repository', `hh', `cc')
+add(`filter_insert_iterator', `hh', `cc', `test')
+add(`fs_entry', `hh', `cc', `test')
+add(`fs_error', `hh', `cc')
+add(`getenv', `hh', `cc', `test')
+add(`indirect_iterator', `hh', `cc', `test')
+add(`instantiation_policy', `hh', `cc', `test')
+add(`internal_error', `hh', `cc')
+add(`is_const', `hh', `cc', `test')
+add(`is_file_with_extension', `hh', `cc', `test')
+add(`join', `hh', `cc', `test')
+add(`key_value_config_file', `hh', `cc', `test')
+add(`keyword_name', `hh', `cc')
+add(`keyword_name_error', `hh', `cc')
+add(`keyword_name_validator', `hh', `cc')
+add(`line_config_file', `hh', `cc', `test')
+add(`mask_reasons', `hh', `cc')
+add(`name_error', `hh', `cc')
+add(`no_resolvable_option_error', `hh', `cc')
+add(`no_such_package_error', `hh', `cc')
+add(`no_such_repository_error', `hh', `cc')
+add(`no_such_version_error', `hh', `cc')
+add(`package_database', `hh', `cc', `test')
+add(`package_database_entry', `hh', `cc')
+add(`package_database_entry_collection', `hh', `cc')
+add(`package_database_error', `hh', `cc')
+add(`package_database_lookup_error', `hh', `cc')
+add(`package_dep_atom', `hh', `cc')
+add(`package_name_part', `hh', `cc', `test')
+add(`package_name_part_collection', `hh', `cc')
+add(`package_name_part_error', `hh', `cc')
+add(`package_name_part_validator', `hh', `cc')
+add(`paludis', `hh', `cc')
+add(`portage_repository', `hh', `cc')
+add(`private_implementation_pattern', `hh', `cc')
+add(`pstream', `hh', `cc', `test')
+add(`pstream_error', `hh', `cc')
+add(`pstream_in_buf', `hh', `cc')
+add(`qualified_package_name', `hh', `cc', `test')
+add(`qualified_package_name_collection', `hh', `cc')
+add(`qualified_package_name_error', `hh', `cc')
+add(`repository', `hh', `cc')
+add(`repository_name', `hh', `cc')
+add(`repository_name_collection', `hh', `cc')
+add(`repository_name_error', `hh', `cc')
+add(`repository_name_validator', `hh', `cc')
+add(`save', `hh', `cc', `test')
+add(`sequential_collection', `hh', `cc')
+add(`smart_record', `hh', `cc', `test')
+add(`slot_name', `hh', `cc')
+add(`slot_name_error', `hh', `cc')
+add(`slot_name_validator', `hh', `cc')
+add(`sorted_collection', `hh', `cc')
+add(`stringify', `hh', `cc', `test')
+add(`strip', `hh', `cc', `test')
+add(`tokeniser', `hh', `cc', `test')
+add(`test_environment', `hh', `cc')
+add(`translate_insert_iterator', `hh', `cc', `test')
+add(`use_dep_atom', `hh', `cc')
+add(`use_flag_name', `hh', `cc')
+add(`use_flag_name_error', `hh', `cc')
+add(`use_flag_name_validator', `hh', `cc')
+add(`validated', `hh', `cc', `test')
+add(`version_metadata', `hh', `cc')
+add(`version_operator', `hh', `cc', `test')
+add(`version_spec', `hh', `cc', `test')
+add(`version_spec_collection', `hh', `cc')
+add(`visitor_pattern', `hh', `cc', `impl', `test')
+
diff --git a/paludis/filter_insert_iterator.cc b/paludis/filter_insert_iterator.cc
new file mode 100644
index 0000000..8f9dafc
--- /dev/null
+++ b/paludis/filter_insert_iterator.cc
@@ -0,0 +1,4 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "filter_insert_iterator.hh"
+
diff --git a/paludis/filter_insert_iterator.hh b/paludis/filter_insert_iterator.hh
new file mode 100644
index 0000000..79324ea
--- /dev/null
+++ b/paludis/filter_insert_iterator.hh
@@ -0,0 +1,113 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_FILTER_INSERT_ITERATOR_HH
+#define PALUDIS_GUARD_PALUDIS_FILTER_INSERT_ITERATOR_HH 1
+
+#include <functional>
+#include <iterator>
+
+namespace paludis
+{
+ 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:
+ typedef typename Iter_::container_type container_type;
+
+ /**
+ * Constructor, from an iterator.
+ */
+ FilterInsertIterator(const Iter_ & i, const Pred_ & p) :
+ _i(i),
+ _p(p)
+ {
+ }
+
+ /**
+ * Copy constructor.
+ */
+ FilterInsertIterator(const FilterInsertIterator & other) :
+ _i(other._i),
+ _p(other._p)
+ {
+ }
+
+ /**
+ * Assignment.
+ */
+ template <typename T_>
+ const FilterInsertIterator & operator= (const T_ value)
+ {
+ if (_p(value))
+ *_i = value;
+ return *this;
+ }
+
+ /**
+ * Dereference.
+ */
+ FilterInsertIterator & operator* ()
+ {
+ return *this;
+ }
+
+ /**
+ * Dereference arrow.
+ */
+ FilterInsertIterator * operator-> ()
+ {
+ return this;
+ }
+
+ /**
+ * Increment.
+ */
+ FilterInsertIterator & operator++ ()
+ {
+ return *this;
+ }
+
+ /**
+ * Increment.
+ */
+ FilterInsertIterator & operator++ (int)
+ {
+ return *this;
+ }
+ };
+
+ /**
+ * Convenience function: make a FilterInsertIterator.
+ */
+ template <typename Iter_, typename Pred_>
+ FilterInsertIterator<Iter_, Pred_> filter_inserter(
+ const Iter_ & i, const Pred_ & p)
+ {
+ return FilterInsertIterator<Iter_, Pred_>(i, p);
+ }
+}
+
+#endif
diff --git a/paludis/filter_insert_iterator_TEST.cc b/paludis/filter_insert_iterator_TEST.cc
new file mode 100644
index 0000000..8a17368
--- /dev/null
+++ b/paludis/filter_insert_iterator_TEST.cc
@@ -0,0 +1,60 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "filter_insert_iterator.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <set>
+
+using namespace test;
+using namespace paludis;
+
+#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
+{
+ 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;
+}
+
diff --git a/paludis/fs_entry.cc b/paludis/fs_entry.cc
new file mode 100644
index 0000000..f6e49e9
--- /dev/null
+++ b/paludis/fs_entry.cc
@@ -0,0 +1,178 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "fs_entry.hh"
+#include "fs_error.hh"
+#include "exception.hh"
+#include "internal_error.hh"
+#include "stringify.hh"
+
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+/** \file
+ * Implementation of paludis::FSEntry.
+ *
+ * \ingroup Filesystem
+ */
+
+using namespace paludis;
+
+FSEntry::FSEntry(const std::string & path) :
+ ComparisonPolicyType(&FSEntry::_path),
+ _path(path)
+{
+ _normalise();
+}
+
+FSEntry::FSEntry(const FSEntry & other) :
+ ComparisonPolicyType(&FSEntry::_path),
+ _path(other._path)
+{
+}
+
+FSEntry::~FSEntry()
+{
+}
+
+const FSEntry &
+FSEntry::operator= (const FSEntry & other)
+{
+ _path = other._path;
+ return *this;
+}
+
+FSEntry::operator std::string() const
+{
+ return _path;
+}
+
+FSEntry
+FSEntry::operator/ (const FSEntry & rhs) const
+{
+ return FSEntry(_path + "/" + rhs._path);
+}
+
+const FSEntry &
+FSEntry::operator/= (const FSEntry & rhs)
+{
+ _path.append("/");
+ _path.append(rhs._path);
+ _normalise();
+ return *this;
+}
+
+bool
+FSEntry::exists() const
+{
+ struct stat s;
+
+ if (0 != stat(_path.c_str(), &s))
+ {
+ if (errno != ENOENT)
+ throw FSError("Error checking whether '" + stringify(_path) + "' exists: "
+ + strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+bool
+FSEntry::is_directory() const
+{
+ struct stat s;
+
+ if (0 != stat(_path.c_str(), &s))
+ {
+ if (errno != ENOENT)
+ throw FSError("Error checking whether '" + stringify(_path) + "' is a directory: "
+ + strerror(errno));
+ return false;
+ }
+
+ return S_ISDIR(s.st_mode);
+}
+
+bool
+FSEntry::is_regular_file() const
+{
+ struct stat s;
+
+ if (0 != stat(_path.c_str(), &s))
+ {
+ if (errno != ENOENT)
+ throw FSError("Error checking whether '" + stringify(_path) + "' is a regular file: "
+ + strerror(errno));
+ return false;
+ }
+
+ return S_ISREG(s.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(__PRETTY_FUNCTION__,
+ "caught std::exception '" + stringify(e.what()) + "'");
+ }
+}
+
+std::string
+FSEntry::basename() const
+{
+ return _path.substr(_path.rfind('/') + 1);
+}
+
+std::ostream &
+paludis::operator<< (std::ostream & s, const FSEntry & f)
+{
+ s << std::string(f);
+ return s;
+}
+
+
diff --git a/paludis/fs_entry.hh b/paludis/fs_entry.hh
new file mode 100644
index 0000000..466fa94
--- /dev/null
+++ b/paludis/fs_entry.hh
@@ -0,0 +1,131 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 <string>
+#include <ostream>
+#include <paludis/comparison_policy.hh>
+
+/** \file
+ * Declarations for paludis::Filesystem.
+ *
+ * \ingroup Filesystem
+ */
+
+namespace paludis
+{
+ /**
+ * Represents an entry (which may or may not exist) in the filesystem.
+ *
+ * \ingroup Filesystem
+ */
+ class FSEntry : public ComparisonPolicy<
+ FSEntry,
+ comparison_mode::FullComparisonTag,
+ comparison_method::CompareByMemberTag<std::string> >
+ {
+ private:
+ std::string _path;
+
+ void _normalise();
+
+ public:
+ /**
+ * Constructor, from a path.
+ */
+ FSEntry(const std::string & path);
+
+ /**
+ * Copy constructor.
+ */
+ FSEntry(const FSEntry & other);
+
+ /**
+ * Destructor.
+ */
+ ~FSEntry();
+
+ /**
+ * Assignment, from another FSEntry.
+ */
+ const FSEntry & operator= (const FSEntry & other);
+
+ /**
+ * 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
+ {
+ return operator/ (FSEntry(rhs));
+ }
+
+ /**
+ * Append another path.
+ */
+ const FSEntry & operator/= (const std::string & rhs)
+ {
+ return operator/= (FSEntry(rhs));
+ }
+
+ /**
+ * Fetch a string representation of our path.
+ */
+ operator std::string() const;
+
+ /**
+ * 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;
+
+ /**
+ * Return the last part of our path (eg '/foo/bar' => 'bar').
+ */
+ std::string basename() const;
+ };
+
+ /**
+ * An FSEntry can be written to an ostream.
+ */
+ std::ostream & operator<< (std::ostream & s, const FSEntry & f);
+}
+
+#endif
diff --git a/paludis/fs_entry_TEST.cc b/paludis/fs_entry_TEST.cc
new file mode 100644
index 0000000..b2e1dd0
--- /dev/null
+++ b/paludis/fs_entry_TEST.cc
@@ -0,0 +1,61 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "fs_entry.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for fs_entry.hh.
+ *
+ * \todo this is nowhere near complete.
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test FSEntry construction and manipulation.
+ */
+ struct TestFSEntryManipulation : TestCase
+ {
+ TestFSEntryManipulation() : 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"));
+ }
+ } test_fs_entry_manipulation;
+}
diff --git a/paludis/fs_error.cc b/paludis/fs_error.cc
new file mode 100644
index 0000000..429164a
--- /dev/null
+++ b/paludis/fs_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "fs_error.hh"
+
+using namespace paludis;
+
+FSError::FSError(const std::string & message) throw () :
+ Exception(message)
+{
+}
+
diff --git a/paludis/fs_error.hh b/paludis/fs_error.hh
new file mode 100644
index 0000000..445da39
--- /dev/null
+++ b/paludis/fs_error.hh
@@ -0,0 +1,46 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_FS_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+/** \file
+ * Declarations for the FSError exception class.
+ */
+
+namespace paludis
+{
+ /**
+ * Generic filesystem error class.
+ *
+ * \ingroup Exception
+ */
+ class FSError : public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ FSError(const std::string & message) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/getenv.cc b/paludis/getenv.cc
new file mode 100644
index 0000000..d459acb
--- /dev/null
+++ b/paludis/getenv.cc
@@ -0,0 +1,27 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "getenv.hh"
+#include <cstdlib>
+
+using namespace paludis;
+
+GetenvError::GetenvError(const std::string & key) throw () :
+ Exception("Environment variable '" + key + "' not set")
+{
+}
+
+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;
+}
diff --git a/paludis/getenv.hh b/paludis/getenv.hh
new file mode 100644
index 0000000..b68d54b
--- /dev/null
+++ b/paludis/getenv.hh
@@ -0,0 +1,40 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_GETENV_HH
+#define PALUDIS_GUARD_PALUDIS_GETENV_HH 1
+
+#include <paludis/exception.hh>
+#include <string>
+
+namespace paludis
+{
+ class GetenvError : public Exception
+ {
+ public:
+ GetenvError(const std::string & key) throw ();
+ };
+
+ std::string getenv_with_default(const std::string & key, const std::string & def);
+
+ std::string getenv_or_error(const std::string & key);
+}
+
+#endif
diff --git a/paludis/getenv_TEST.cc b/paludis/getenv_TEST.cc
new file mode 100644
index 0000000..e699079
--- /dev/null
+++ b/paludis/getenv_TEST.cc
@@ -0,0 +1,34 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "getenv.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+using namespace paludis;
+
+namespace test_cases
+{
+ 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;
+
+ 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;
+}
diff --git a/paludis/indirect_iterator.cc b/paludis/indirect_iterator.cc
new file mode 100644
index 0000000..cac202d
--- /dev/null
+++ b/paludis/indirect_iterator.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "indirect_iterator.hh"
+
diff --git a/paludis/indirect_iterator.hh b/paludis/indirect_iterator.hh
new file mode 100644
index 0000000..a73b8cb
--- /dev/null
+++ b/paludis/indirect_iterator.hh
@@ -0,0 +1,159 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_INDIRECT_ITERATOR_HH
+#define PALUDIS_GUARD_PALUDIS_INDIRECT_ITERATOR_HH 1
+
+#include <iterator>
+#include <paludis/instantiation_policy.hh>
+#include <paludis/comparison_policy.hh>
+
+namespace paludis
+{
+ template <typename Iter_, typename Value_>
+ class IndirectIterator;
+
+ namespace
+ {
+ /**
+ * Determine the comparison class to use for IndirectIterator.
+ */
+ 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).
+ */
+ 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.
+ */
+ 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:
+ /**
+ * Constructor, from a base iterator.
+ */
+ IndirectIterator(const Iter_ & i) :
+ Comparisons<typename std::iterator_traits<Iter_>::iterator_category, Iter_, Value_>::Type(
+ &IndirectIterator<Iter_, Value_>::_i),
+ _i(i)
+ {
+ }
+
+ /**
+ * Copy constructor.
+ */
+ IndirectIterator(const IndirectIterator & other) :
+ Comparisons<typename std::iterator_traits<Iter_>::iterator_category, Iter_, Value_>::Type(
+ &IndirectIterator<Iter_, Value_>::_i),
+ _i(other._i)
+ {
+ }
+
+ /**
+ * Assignment.
+ */
+ const IndirectIterator & operator= (const IndirectIterator & other)
+ {
+ _i = other._i;
+ return *this;
+ }
+
+ /**
+ * Dereference.
+ */
+ Value_ & operator*()
+ {
+ return **_i;
+ }
+
+ /**
+ * Dereference arrow.
+ */
+ Value_ * operator->()
+ {
+ return &**_i;
+ }
+
+ /**
+ * Dereference, const.
+ */
+ const Value_ & operator*() const
+ {
+ return **_i;
+ }
+
+ /**
+ * Dereference arrow, const.
+ */
+ const Value_ * operator->() const
+ {
+ return &**_i;
+ }
+
+ /**
+ * Increment.
+ */
+ IndirectIterator & operator++ ()
+ {
+ ++_i;
+ return *this;
+ }
+
+ /**
+ * Increment.
+ */
+ IndirectIterator operator++ (int)
+ {
+ IndirectIterator tmp(*this);
+ ++_i;
+ return tmp;
+ }
+ };
+}
+
+#endif
diff --git a/paludis/indirect_iterator_TEST.cc b/paludis/indirect_iterator_TEST.cc
new file mode 100644
index 0000000..121daec
--- /dev/null
+++ b/paludis/indirect_iterator_TEST.cc
@@ -0,0 +1,146 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "indirect_iterator.hh"
+#include "counted_ptr.hh"
+#include "deleter.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+#include <list>
+#include <algorithm>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for IndirectIterator.
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test IndirectIterator over a vector of CountedPtr of int.
+ *
+ * \ingroup Test
+ */
+ 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 Test
+ */
+ 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 Test
+ */
+ 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 Test
+ */
+ 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;
+}
+
diff --git a/paludis/instantiation_policy.cc b/paludis/instantiation_policy.cc
new file mode 100644
index 0000000..9e2c0da
--- /dev/null
+++ b/paludis/instantiation_policy.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "instantiation_policy.hh"
+
diff --git a/paludis/instantiation_policy.hh b/paludis/instantiation_policy.hh
new file mode 100644
index 0000000..c4dbca9
--- /dev/null
+++ b/paludis/instantiation_policy.hh
@@ -0,0 +1,184 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_INSTANTIATION_POLICY_HH
+#define PALUDIS_GUARD_PALUDIS_INSTANTIATION_POLICY_HH 1
+
+namespace paludis
+{
+ /**
+ * Instantiation policies for paludis::InstantiationPolicy.
+ */
+ namespace instantiation_method
+ {
+ /**
+ * Cannot be copied or assigned to.
+ */
+ struct NonCopyableTag
+ {
+ };
+
+ /**
+ * Cannot be instantiated.
+ */
+ struct NonInstantiableTag
+ {
+ };
+
+ /**
+ * Single instance created at startup.
+ */
+ struct SingletonAtStartupTag
+ {
+ };
+
+ /**
+ * Single instance created when needed.
+ */
+ struct SingletonAsNeededTag
+ {
+ };
+ }
+
+#ifdef DOXYGEN
+ /**
+ * InstantiationPolicy is used to specify behaviour of classes that have
+ * something other than the default C++ instantiation behaviour.
+ */
+ template <typename OurType_, typename InstantiationMethodTag_>
+ struct InstantiationPolicy
+ {
+ };
+#else
+ template <typename OurType_, typename InstantiationMethodTag_>
+ struct InstantiationPolicy;
+#endif
+
+ /**
+ * InstantiationPolicy: specialisation for classes that cannot be copied
+ * or assigned to.
+ */
+ template<typename OurType_>
+ class InstantiationPolicy<OurType_, instantiation_method::NonCopyableTag>
+ {
+ private:
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ protected:
+ ~InstantiationPolicy()
+ {
+ }
+
+ InstantiationPolicy()
+ {
+ }
+ };
+
+ /**
+ * InstantiationPolicy: specialisation for classes that cannot be created.
+ */
+ template<typename OurType_>
+ class InstantiationPolicy<OurType_, instantiation_method::NonInstantiableTag>
+ {
+ private:
+ InstantiationPolicy();
+
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ protected:
+ ~InstantiationPolicy()
+ {
+ }
+ };
+}
+
+#include <paludis/counted_ptr.hh>
+
+namespace paludis
+{
+ /**
+ * InstantiationPolicy: specialisation for singleton classes that are
+ * created at startup.
+ */
+ template<typename OurType_>
+ class InstantiationPolicy<OurType_, instantiation_method::SingletonAtStartupTag>
+ {
+ private:
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ static CountedPtr<OurType_, count_policy::ExternalCountTag> _instance;
+
+ protected:
+ InstantiationPolicy()
+ {
+ }
+
+ public:
+ /**
+ * 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.
+ */
+ template<typename OurType_>
+ class InstantiationPolicy<OurType_, instantiation_method::SingletonAsNeededTag>
+ {
+ private:
+ InstantiationPolicy(const InstantiationPolicy &);
+
+ const InstantiationPolicy & operator= (const InstantiationPolicy &);
+
+ static OurType_ * _instance;
+
+ protected:
+ InstantiationPolicy()
+ {
+ }
+
+ public:
+ /**
+ * Fetch our instance.
+ */
+ static OurType_ * get_instance()
+ {
+ static OurType_ instance;
+ return &instance;
+ }
+ };
+}
+
+#endif
diff --git a/paludis/instantiation_policy_TEST.cc b/paludis/instantiation_policy_TEST.cc
new file mode 100644
index 0000000..d47ff51
--- /dev/null
+++ b/paludis/instantiation_policy_TEST.cc
@@ -0,0 +1,127 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "instantiation_policy.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <string>
+
+using namespace test;
+using namespace paludis;
+
+/**
+ * \file
+ * Test cases for instantiation_policy.hh .
+ */
+
+#ifndef DOXYGEN
+
+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;
+
+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;
+
+#endif
+
+namespace test_cases
+{
+ /**
+ * \test Test singleton behaviour.
+ */
+ 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_EQUAL(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 create at startup behaviour.
+ */
+ 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_EQUAL(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/paludis/internal_error.cc b/paludis/internal_error.cc
new file mode 100644
index 0000000..03fbff1
--- /dev/null
+++ b/paludis/internal_error.cc
@@ -0,0 +1,33 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "internal_error.hh"
+
+using namespace paludis;
+
+InternalError::InternalError(const char * const function, const std::string & message) throw () :
+ Exception("Eek! Internal error at " + std::string(function) + ": " + message)
+{
+}
+
+InternalError::InternalError(const char * const function) throw () :
+ Exception("Eek! Internal error at " + std::string(function))
+{
+}
+
diff --git a/paludis/internal_error.hh b/paludis/internal_error.hh
new file mode 100644
index 0000000..9cb0a11
--- /dev/null
+++ b/paludis/internal_error.hh
@@ -0,0 +1,61 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_INTERNAL_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_INTERNAL_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+/** \file
+ * Declaration for the InternalError exception class.
+ */
+
+namespace paludis
+{
+ /**
+ * An InternalError is an Exception that is thrown if something that is
+ * never supposed to happen happens.
+ */
+ class InternalError : public Exception
+ {
+ public:
+ /**
+ * Constructor.
+ *
+ * \param function Should be set to the __PRETTY_FUNCTION__ magic
+ * constant.
+ *
+ * \param message A short message.
+ */
+ InternalError(const char * const function, const std::string & message) throw ();
+
+ /**
+ * Constructor, with no message (deprecated).
+ *
+ * \param function Should be set to the __PRETTY_FUNCTION__ magic
+ * constant.
+ *
+ * \deprecated Use paludis::InternalError::InternalError(const char * const,
+ * const std::string &) instead.
+ */
+ InternalError(const char * const function) throw () PALUDIS_ATTRIBUTE((deprecated));
+ };
+}
+
+#endif
diff --git a/paludis/is_const.cc b/paludis/is_const.cc
new file mode 100644
index 0000000..ddfee60
--- /dev/null
+++ b/paludis/is_const.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "is_const.hh"
+
diff --git a/paludis/is_const.hh b/paludis/is_const.hh
new file mode 100644
index 0000000..67e6d8f
--- /dev/null
+++ b/paludis/is_const.hh
@@ -0,0 +1,60 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_IS_CONST_HH
+#define PALUDIS_GUARD_PALUDIS_IS_CONST_HH 1
+
+/** \file
+ * Declarations for the IsConst class.
+ */
+
+namespace paludis
+{
+ /**
+ * The value member will be true if a type is const and false otherwise.
+ */
+ template <typename T_>
+ struct IsConst
+ {
+ /// Are we const?
+ static const bool value = false;
+ };
+
+ /**
+ * IsConst: specialisation for const.
+ */
+ template <typename T_>
+ struct IsConst<const T_>
+ {
+ /// Are we const?
+ static const bool value = true;
+ };
+
+ /**
+ * IsConst: specialisation for const references.
+ */
+ template <typename T_>
+ struct IsConst<const T_ &>
+ {
+ /// Are we const?
+ static const bool value = true;
+ };
+}
+
+#endif
diff --git a/paludis/is_const_TEST.cc b/paludis/is_const_TEST.cc
new file mode 100644
index 0000000..da4a8cd
--- /dev/null
+++ b/paludis/is_const_TEST.cc
@@ -0,0 +1,58 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "is_const.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <string>
+
+using namespace test;
+using namespace paludis;
+
+/**
+ * \file
+ * Test cases for is_const.hh .
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test IsConst.
+ */
+ struct IsConstTest : TestCase
+ {
+ IsConstTest() : TestCase("is const") { }
+
+ void run()
+ {
+ TEST_CHECK(IsConst<const int>::value);
+ TEST_CHECK(IsConst<const std::string>::value);
+ TEST_CHECK(IsConst<const std::string &>::value);
+ TEST_CHECK(IsConst<int * const>::value);
+
+ TEST_CHECK(! IsConst<int>::value);
+ TEST_CHECK(! IsConst<std::string>::value);
+ TEST_CHECK(! IsConst<std::string &>::value);
+ TEST_CHECK(! IsConst<const int *>::value);
+ }
+ } test_is_const;
+}
+
+
+
diff --git a/paludis/is_file_with_extension.cc b/paludis/is_file_with_extension.cc
new file mode 100644
index 0000000..4182cb2
--- /dev/null
+++ b/paludis/is_file_with_extension.cc
@@ -0,0 +1,20 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "is_file_with_extension.hh"
+
+using namespace paludis;
+
+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();
+}
diff --git a/paludis/is_file_with_extension.hh b/paludis/is_file_with_extension.hh
new file mode 100644
index 0000000..659a5e8
--- /dev/null
+++ b/paludis/is_file_with_extension.hh
@@ -0,0 +1,54 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 <paludis/fs_entry.hh>
+#include <string>
+#include <functional>
+
+namespace paludis
+{
+ class IsFileWithExtension :
+ public std::unary_function<bool, FSEntry>
+ {
+ private:
+ const std::string _prefix;
+ const std::string _ext;
+
+ public:
+ IsFileWithExtension(const std::string & ext) :
+ _prefix(""),
+ _ext(ext)
+ {
+ }
+
+ IsFileWithExtension(const std::string & prefix, const std::string & ext) :
+ _prefix(prefix),
+ _ext(ext)
+ {
+ }
+
+ bool operator() (const FSEntry & f) const;
+ };
+}
+
+#endif
diff --git a/paludis/is_file_with_extension_TEST.cc b/paludis/is_file_with_extension_TEST.cc
new file mode 100644
index 0000000..49560c8
--- /dev/null
+++ b/paludis/is_file_with_extension_TEST.cc
@@ -0,0 +1,24 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "is_file_with_extension.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+#include <algorithm>
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ struct IsFileWithExtensionTest : TestCase
+ {
+ IsFileWithExtensionTest() : TestCase("is file with extension") { }
+
+ void run()
+ {
+ /// \todo
+ }
+ } test_is_file_with_extension;
+}
+
diff --git a/paludis/join.cc b/paludis/join.cc
new file mode 100644
index 0000000..ea1844d
--- /dev/null
+++ b/paludis/join.cc
@@ -0,0 +1,21 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "join.hh"
+
diff --git a/paludis/join.hh b/paludis/join.hh
new file mode 100644
index 0000000..5230183
--- /dev/null
+++ b/paludis/join.hh
@@ -0,0 +1,57 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_JOIN_HH
+#define PALUDIS_GUARD_PALUDIS_JOIN_HH 1
+
+#include <string>
+#include <paludis/stringify.hh>
+
+namespace paludis
+{
+ /**
+ * Join together the items from i to end using joiner.
+ */
+ 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.
+ */
+ 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/paludis/join_TEST.cc b/paludis/join_TEST.cc
new file mode 100644
index 0000000..9badb1e
--- /dev/null
+++ b/paludis/join_TEST.cc
@@ -0,0 +1,101 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "join.hh"
+#include <test/test_runner.hh>
+#include <test/test_framework.hh>
+#include <vector>
+#include <list>
+
+using namespace paludis;
+using namespace test;
+
+/** \file
+ * Test cases for join.hh .
+ *
+ * \ingroup Test
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test join on a vector.
+ *
+ * \ingroup Test
+ */
+ 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 Test
+ */
+ 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 Test
+ */
+ 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/paludis/key_value_config_file.cc b/paludis/key_value_config_file.cc
new file mode 100644
index 0000000..221747f
--- /dev/null
+++ b/paludis/key_value_config_file.cc
@@ -0,0 +1,26 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "key_value_config_file.hh"
+
+using namespace paludis;
+
+KeyValueConfigFile::KeyValueConfigFile(std::istream * const s) :
+ ConfigFile(s)
+{
+ need_lines();
+}
+
+void
+KeyValueConfigFile::accept_line(const std::string & line) const
+{
+ std::string::size_type p(line.find('='));
+ if (std::string::npos == p)
+ _entries[line] = "";
+ else
+ {
+ std::string key(line.substr(0, p)), value(line.substr(p + 1));
+ normalise_line(key);
+ normalise_line(value);
+ _entries[key] = value;
+ }
+}
diff --git a/paludis/key_value_config_file.hh b/paludis/key_value_config_file.hh
new file mode 100644
index 0000000..cf5aa84
--- /dev/null
+++ b/paludis/key_value_config_file.hh
@@ -0,0 +1,55 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#ifndef PALUDIS_GUARD_PALUDIS_KEY_VALUE_CONFIG_FILE_HH
+#define PALUDIS_GUARD_PALUDIS_KEY_VALUE_CONFIG_FILE_HH 1
+
+#include <paludis/config_file.hh>
+#include <map>
+
+/** \file
+ * Declarations for the KeyValueConfigFile class.
+ *
+ * \ingroup ConfigFile
+ */
+
+
+namespace paludis
+{
+ /**
+ * A KeyValueConfigFile is a ConfigFile that provides access to the
+ * normalised lines. Do not subclass.
+ *
+ * \ingroup ConfigFile
+ */
+ class KeyValueConfigFile : protected ConfigFile
+ {
+ private:
+ mutable std::map<std::string, std::string> _entries;
+
+ protected:
+ void accept_line(const std::string &) const;
+
+ public:
+ KeyValueConfigFile(std::istream * const);
+
+ typedef std::map<std::string, std::string>::const_iterator Iterator;
+
+ Iterator begin() const
+ {
+ return _entries.begin();
+ }
+
+ Iterator end() const
+ {
+ return _entries.end();
+ }
+
+ std::string get(const std::string & key)
+ {
+ return _entries[key];
+ }
+ };
+
+}
+
+#endif
diff --git a/paludis/key_value_config_file_TEST.cc b/paludis/key_value_config_file_TEST.cc
new file mode 100644
index 0000000..4c25b3d
--- /dev/null
+++ b/paludis/key_value_config_file_TEST.cc
@@ -0,0 +1,24 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "key_value_config_file.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <vector>
+#include <algorithm>
+
+using namespace paludis;
+using namespace test;
+
+namespace test_cases
+{
+ struct KeyValueConfigFileTest : TestCase
+ {
+ KeyValueConfigFileTest() : TestCase("key value config file") { }
+
+ void run()
+ {
+ /// \todo
+ }
+ } test_key_value_config_file;
+}
+
diff --git a/paludis/keyword_name.cc b/paludis/keyword_name.cc
new file mode 100644
index 0000000..da91aa3
--- /dev/null
+++ b/paludis/keyword_name.cc
@@ -0,0 +1,22 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "keyword_name.hh"
+
diff --git a/paludis/keyword_name.hh b/paludis/keyword_name.hh
new file mode 100644
index 0000000..156b028
--- /dev/null
+++ b/paludis/keyword_name.hh
@@ -0,0 +1,43 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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_KEYWORD_NAME_HH
+#define PALUDIS_GUARD_PALUDIS_KEYWORD_NAME_HH 1
+
+#include <paludis/validated.hh>
+#include <paludis/keyword_name_validator.hh>
+#include <string>
+
+/** \file
+ * Declarations for the KeywordName class.
+ *
+ * \ingroup Environment
+ */
+namespace paludis
+{
+ /**
+ * A KeywordName holds a std::string that is a valid name for a KEYWORD.
+ *
+ * \ingroup Database
+ */
+ typedef Validated<std::string, KeywordNameValidator> KeywordName;
+
+}
+
+#endif
diff --git a/paludis/keyword_name_error.cc b/paludis/keyword_name_error.cc
new file mode 100644
index 0000000..b9fdce4
--- /dev/null
+++ b/paludis/keyword_name_error.cc
@@ -0,0 +1,29 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "keyword_name_error.hh"
+
+using namespace paludis;
+
+KeywordNameError::KeywordNameError(const std::string & name) throw () :
+ NameError(name, "keyword name")
+{
+}
+
diff --git a/paludis/keyword_name_error.hh b/paludis/keyword_name_error.hh
new file mode 100644
index 0000000..40ed708
--- /dev/null
+++ b/paludis/keyword_name_error.hh
@@ -0,0 +1,54 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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_KEYWORD_NAME_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_KEYWORD_NAME_ERROR_HH 1
+
+#include <paludis/name_error.hh>
+#include <string>
+
+/** \file
+ * Declarations for KeywordNameError.
+ *
+ * \ingroup Environment
+ * \ingroup Exception
+ */
+
+namespace paludis
+{
+ /**
+ * A KeywordNameError is thrown if an invalid value is assigned to
+ * a KeywordNameName.
+ *
+ * \ingroup Environment
+ * \ingroup Exception
+ */
+ class KeywordNameError : public NameError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ KeywordNameError(const std::string & name) throw ();
+ };
+}
+
+
+
+#endif
diff --git a/paludis/keyword_name_validator.cc b/paludis/keyword_name_validator.cc
new file mode 100644
index 0000000..e65632c
--- /dev/null
+++ b/paludis/keyword_name_validator.cc
@@ -0,0 +1,63 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 "keyword_name_validator.hh"
+#include "keyword_name_error.hh"
+
+using namespace paludis;
+
+void
+KeywordNameValidator::validate(const std::string & s)
+{
+ static const std::string allowed_chars(
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789-+_");
+
+ do
+ {
+ switch (s.length())
+ {
+ case 0:
+ continue;
+
+ case 1:
+ if ("*" == s)
+ return;
+ continue;
+
+ case 2:
+ if ("-*" == s)
+ return;
+
+ /* fall throuth */
+ default:
+ if (std::string::npos != s.find_first_not_of(allowed_chars,
+ ('~' == s.at(0) ? 1 : 0)))
+ continue;
+ }
+
+ return;
+
+ } while (false);
+
+ Context c("When validating keyword name '" + s + "':");
+ throw KeywordNameError(s);
+}
+
diff --git a/paludis/keyword_name_validator.hh b/paludis/keyword_name_validator.hh
new file mode 100644
index 0000000..b956aa8
--- /dev/null
+++ b/paludis/keyword_name_validator.hh
@@ -0,0 +1,51 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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_KEYWORD_NAME_VALIDATOR_HH
+#define PALUDIS_GUARD_PALUDIS_KEYWORD_NAME_VALIDATOR_HH 1
+
+#include <paludis/instantiation_policy.hh>
+#include <string>
+
+/** \file
+ * Declarations for the KeywordNameValidator class.
+ *
+ * \ingroup Environment
+ */
+
+namespace paludis
+{
+ /**
+ * A KeywordNameValidator handles validation rules for the value of a
+ * UseFlagName.
+ *
+ * \ingroup Environment
+ */
+ struct KeywordNameValidator :
+ private InstantiationPolicy<KeywordNameValidator, instantiation_method::NonInstantiableTag>
+ {
+ /**
+ * If the parameter is not a valid value for a KeywordName,
+ * throw a KeywordNameError.
+ */
+ static void validate(const std::string &);
+ };
+}
+
+#endif
diff --git a/paludis/line_config_file.cc b/paludis/line_config_file.cc
new file mode 100644
index 0000000..46f760b
--- /dev/null
+++ b/paludis/line_config_file.cc
@@ -0,0 +1,36 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "line_config_file.hh"
+
+using namespace paludis;
+
+LineConfigFile::LineConfigFile(std::istream * const s) :
+ ConfigFile(s)
+{
+ need_lines();
+}
+
+void
+LineConfigFile::accept_line(const std::string & s) const
+{
+ _lines.push_back(s);
+}
+
diff --git a/paludis/line_config_file.hh b/paludis/line_config_file.hh
new file mode 100644
index 0000000..8f6b9ac
--- /dev/null
+++ b/paludis/line_config_file.hh
@@ -0,0 +1,66 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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_LINE_CONFIG_FILE_HH
+#define PALUDIS_GUARD_PALUDIS_LINE_CONFIG_FILE_HH 1
+
+#include <paludis/config_file.hh>
+#include <list>
+
+/** \file
+ * Declarations for the LineConfigFile class.
+ *
+ * \ingroup ConfigFile
+ */
+
+namespace paludis
+{
+ /**
+ * A LineConfigFile is a ConfigFile that provides access to the
+ * normalised lines. Do not subclass.
+ *
+ * \ingroup ConfigFile
+ */
+ class LineConfigFile : protected ConfigFile
+ {
+ private:
+ mutable std::list<std::string> _lines;
+
+ protected:
+ void accept_line(const std::string &) const;
+
+ public:
+ LineConfigFile(std::istream * const);
+
+ typedef std::list<std::string>::const_iterator Iterator;
+
+ Iterator begin() const
+ {
+ return _lines.begin();
+ }
+
+ Iterator end() const
+ {
+ return _lines.end();
+ }
+ };
+}
+
+#endif
diff --git a/paludis/line_config_file_TEST.cc b/paludis/line_config_file_TEST.cc
new file mode 100644
index 0000000..3020f83
--- /dev/null
+++ b/paludis/line_config_file_TEST.cc
@@ -0,0 +1,75 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaranm@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 as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * 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 "line_config_file.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+#include <sstream>
+#include <vector>
+#include <iterator>
+
+using namespace test;
+using namespace paludis;
+
+/** \file
+ * Test cases for line_config_file.hh .
+ *
+ * \ingroup Test
+ * \ingroup ConfigFile
+ */
+
+namespace test_cases
+{
+ /**
+ * \test Test LineConfigFile.
+ *
+ * \ingroup Test
+ */
+ struct LineConfigFileTest : TestCase
+ {
+ LineConfigFileTest() : TestCase("line config file") { }
+
+ void run()
+ {
+ std::stringstream s;
+ s << "one" << std::endl;
+ s << " two \t " << std::endl;
+ s << " \t " << std::endl;
+ s << "" << std::endl;
+ s << "three" << std::endl;
+ s << "# blah" << std::endl;
+ s << " # blah" << std::endl;
+ s << "#" << std::endl;
+ s << " # \t " << std::endl;
+ s << "four four" << std::endl;
+ LineConfigFile ff(&s);
+ std::vector<std::string> f;
+ std::copy(ff.begin(), ff.end(), std::back_inserter(f));
+
+ TEST_CHECK_EQUAL(f.size(), 4);
+ TEST_CHECK_EQUAL(f.at(0), "one");
+ TEST_CHECK_EQUAL(f.at(1), "two");
+ TEST_CHECK_EQUAL(f.at(2), "three");
+ TEST_CHECK_EQUAL(f.at(3), "four four");
+ }
+ } test_line_config_file;
+}
+
+
diff --git a/paludis/mask_reasons.cc b/paludis/mask_reasons.cc
new file mode 100644
index 0000000..503c311
--- /dev/null
+++ b/paludis/mask_reasons.cc
@@ -0,0 +1,4 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#include "mask_reasons.hh"
+
diff --git a/paludis/mask_reasons.hh b/paludis/mask_reasons.hh
new file mode 100644
index 0000000..2b3459a
--- /dev/null
+++ b/paludis/mask_reasons.hh
@@ -0,0 +1,30 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+#ifndef PALUDIS_GUARD_PALUDIS_MASK_REASONS_HH
+#define PALUDIS_GUARD_PALUDIS_MASK_REASONS_HH 1
+
+#include <bitset>
+
+namespace paludis
+{
+ /**
+ * Each value represents one reason for a package being
+ * masked.
+ */
+ enum MaskReason
+ {
+ mr_keyword, ///< no keyword match
+ mr_user_mask, ///< user package.mask
+ mr_profile_mask, ///< profile package.mask
+ mr_repository_mask, ///< repository package.mask
+ mr_eapi, ///< unknown eapi
+ last_mr ///< number of entries
+ };
+
+ /**
+ * A collection of reasons for why a package is masked.
+ */
+ typedef std::bitset<last_mr> MaskReasons;
+}
+
+#endif
diff --git a/paludis/name_error.cc b/paludis/name_error.cc
new file mode 100644
index 0000000..ff9ffe8
--- /dev/null
+++ b/paludis/name_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "name_error.hh"
+
+using namespace paludis;
+
+NameError::NameError(const std::string & name, const std::string & role) throw () :
+ Exception("Name '" + name + "' is not a valid " + role)
+{
+}
+
diff --git a/paludis/name_error.hh b/paludis/name_error.hh
new file mode 100644
index 0000000..19c75fe
--- /dev/null
+++ b/paludis/name_error.hh
@@ -0,0 +1,54 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_NAME_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_NAME_ERROR_HH 1
+
+#include <paludis/exception.hh>
+
+/** \file
+ * Declaration for the NameError exception class.
+ *
+ * \ingroup Database
+ * \ingroup Exception
+ */
+
+namespace paludis
+{
+ /**
+ * A NameError is an Exception that is thrown when some kind of invalid
+ * name is encountered.
+ *
+ * \ingroup Database
+ * \ingroup Exception
+ */
+ class 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 ();
+ };
+}
+
+#endif
diff --git a/paludis/no_resolvable_option_error.cc b/paludis/no_resolvable_option_error.cc
new file mode 100644
index 0000000..34fd7cb
--- /dev/null
+++ b/paludis/no_resolvable_option_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "no_resolvable_option_error.hh"
+
+using namespace paludis;
+
+NoResolvableOptionError::NoResolvableOptionError() throw () :
+ DepListError("No resolvable || ( ) option")
+{
+}
+
diff --git a/paludis/no_resolvable_option_error.hh b/paludis/no_resolvable_option_error.hh
new file mode 100644
index 0000000..3f0f4f1
--- /dev/null
+++ b/paludis/no_resolvable_option_error.hh
@@ -0,0 +1,40 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_NO_RESOLVABLE_OPTION_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_NO_RESOLVABLE_OPTION_ERROR_HH 1
+
+#include <paludis/dep_list_error.hh>
+
+namespace paludis
+{
+ /**
+ * Thrown if no entry in a || ( ) block is resolvable.
+ */
+ class NoResolvableOptionError : public DepListError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoResolvableOptionError() throw ();
+ };
+}
+
+#endif
diff --git a/paludis/no_such_package_error.cc b/paludis/no_such_package_error.cc
new file mode 100644
index 0000000..b43cd0c
--- /dev/null
+++ b/paludis/no_such_package_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "no_such_package_error.hh"
+
+using namespace paludis;
+
+NoSuchPackageError::NoSuchPackageError(const std::string & name) throw () :
+ PackageDatabaseLookupError("Could not find '" + name + "'")
+{
+}
+
diff --git a/paludis/no_such_package_error.hh b/paludis/no_such_package_error.hh
new file mode 100644
index 0000000..ca9d26e
--- /dev/null
+++ b/paludis/no_such_package_error.hh
@@ -0,0 +1,45 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_NO_SUCH_PACKAGE_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_NO_SUCH_PACKAGE_ERROR_HH 1
+
+#include <paludis/package_database_lookup_error.hh>
+
+/** \file
+ * Declaration for the NoSuchPackageError exception class.
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if there is no Package in a PackageDatabase with the given
+ * name.
+ */
+ class NoSuchPackageError : public PackageDatabaseLookupError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchPackageError(const std::string & name) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/no_such_repository_error.cc b/paludis/no_such_repository_error.cc
new file mode 100644
index 0000000..a3cf719
--- /dev/null
+++ b/paludis/no_such_repository_error.cc
@@ -0,0 +1,28 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "no_such_repository_error.hh"
+
+using namespace paludis;
+
+NoSuchRepositoryError::NoSuchRepositoryError(const std::string & name) throw () :
+ PackageDatabaseLookupError("Could not find repository '" + name + "'")
+{
+}
+
diff --git a/paludis/no_such_repository_error.hh b/paludis/no_such_repository_error.hh
new file mode 100644
index 0000000..acd3256
--- /dev/null
+++ b/paludis/no_such_repository_error.hh
@@ -0,0 +1,45 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_NO_SUCH_REPOSITORY_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_NO_SUCH_REPOSITORY_ERROR_HH 1
+
+#include <paludis/package_database_lookup_error.hh>
+
+/** \file
+ * Declaration for the NoSuchRepositoryError exception class.
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if there is no Repository in a RepositoryDatabase with the given
+ * name.
+ */
+ class NoSuchRepositoryError : public PackageDatabaseLookupError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchRepositoryError(const std::string & name) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/no_such_version_error.cc b/paludis/no_such_version_error.cc
new file mode 100644
index 0000000..bb81d75
--- /dev/null
+++ b/paludis/no_such_version_error.cc
@@ -0,0 +1,30 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "no_such_version_error.hh"
+#include "stringify.hh"
+
+using namespace paludis;
+
+NoSuchVersionError::NoSuchVersionError(const std::string & name,
+ const VersionSpec & version) throw () :
+ PackageDatabaseLookupError("No version of '" + name + "' named '" + stringify(version) + "'")
+{
+}
+
diff --git a/paludis/no_such_version_error.hh b/paludis/no_such_version_error.hh
new file mode 100644
index 0000000..7b99b16
--- /dev/null
+++ b/paludis/no_such_version_error.hh
@@ -0,0 +1,47 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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_NO_SUCH_VERSION_ERROR_HH
+#define PALUDIS_GUARD_PALUDIS_NO_SUCH_VERSION_ERROR_HH 1
+
+#include <paludis/package_database_lookup_error.hh>
+#include <paludis/version_spec.hh>
+
+/** \file
+ * Declaration for the NoSuchVersionError exception class.
+ */
+
+namespace paludis
+{
+ /**
+ * Thrown if there is no Version in a PackageDatabase with the given
+ * name.
+ */
+ class NoSuchVersionError : public PackageDatabaseLookupError
+ {
+ public:
+ /**
+ * Constructor.
+ */
+ NoSuchVersionError(const std::string & pkg_name,
+ const VersionSpec & version) throw ();
+ };
+}
+
+#endif
diff --git a/paludis/package_database.cc b/paludis/package_database.cc
new file mode 100644
index 0000000..acd876b
--- /dev/null
+++ b/paludis/package_database.cc
@@ -0,0 +1,207 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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 "package_database.hh"
+#include "no_such_package_error.hh"
+#include "no_such_repository_error.hh"
+#include "no_such_version_error.hh"
+#include "internal_error.hh"
+#include "duplicate_repository_error.hh"
+#include "ambiguous_package_name_error.hh"
+#include "package_dep_atom.hh"
+#include "indirect_iterator.hh"
+#include "stringify.hh"
+
+#include <list>
+#include <map>
+#include <set>
+
+using namespace paludis;
+
+namespace paludis
+{
+ /**
+ * Implementation data for a PackageDatabase.
+ */
+ template<>
+ struct Implementation<PackageDatabase> :
+ InternalCounted<Implementation<PackageDatabase> >
+ {
+ /**
+ * Our Repository instances.
+ */
+ std::list<Repository::ConstPointer> repositories;
+ };
+}
+PackageDatabase::PackageDatabase() :
+ PrivateImplementationPattern<PackageDatabase>(new Implementation<PackageDatabase>)
+{
+}
+
+PackageDatabase::~PackageDatabase()
+{
+}
+
+void
+PackageDatabase::add_repository(const Repository::ConstPointer r)
+{
+ Context c("When adding a repository named '" + stringify(r->name()) + "':");
+
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r_c(_implementation->repositories.begin()),
+ r_end(_implementation->repositories.end());
+ for ( ; r_c != r_end ; ++r_c)
+ if (r_c->name() == r->name())
+ throw DuplicateRepositoryError(stringify(r->name()));
+
+ _implementation->repositories.push_back(r);
+}
+
+VersionMetadata::ConstPointer
+PackageDatabase::fetch_metadata(const PackageDatabaseEntry & e) const
+{
+ const Repository::ConstPointer rr(fetch_repository(e.get<pde_repository>()));
+ if (! rr->has_category_named(e.get<pde_package>().get<qpn_category>()))
+ throw NoSuchPackageError(stringify(e.get<pde_package>()));
+ if (! rr->has_package_named(e.get<pde_package>()))
+ throw NoSuchPackageError(stringify(e.get<pde_package>()));
+ if (! rr->has_version(e.get<pde_package>(), e.get<pde_version>()))
+ throw NoSuchVersionError(stringify(e.get<pde_package>()), e.get<pde_version>());
+ return rr->version_metadata(e.get<pde_package>().get<qpn_category>(),
+ e.get<pde_package>().get<qpn_package>(), e.get<pde_version>());
+}
+
+Repository::ConstPointer
+PackageDatabase::fetch_repository(const RepositoryName & n) const
+{
+ std::list<Repository::ConstPointer>::const_iterator
+ r(_implementation->repositories.begin()),
+ r_end(_implementation->repositories.end());
+ for ( ; r != r_end ; ++r)
+ if ((*r)->name() == n)
+ return *r;
+
+ throw NoSuchRepositoryError(stringify(n));
+}
+
+QualifiedPackageName
+PackageDatabase::fetch_unique_qualified_package_name(
+ const PackageNamePart & p) const
+{
+ QualifiedPackageNameCollection::Pointer result(new QualifiedPackageNameCollection);
+
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r(_implementation->repositories.begin()),
+ r_end(_implementation->repositories.end());
+ for ( ; r != r_end ; ++r)
+ {
+ CategoryNamePartCollection::ConstPointer cats(r->category_names());
+ CategoryNamePartCollection::Iterator c(cats->begin()), c_end(cats->end());
+ for ( ; c != c_end ; ++c)
+ if (r->has_package_named(*c, p))
+ result->insert(QualifiedPackageName(*c, p));
+ }
+
+ if (result->empty())
+ throw NoSuchPackageError(stringify(p));
+ if (result->size() > 1)
+ throw AmbiguousPackageNameError(stringify(p), result->begin(), result->end());
+
+ return *(result->begin());
+}
+
+PackageDatabaseEntryCollection::Pointer
+PackageDatabase::query(const PackageDepAtom * const a) const
+{
+ PackageDatabaseEntryCollection::Pointer result(new PackageDatabaseEntryCollection);
+
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r(_implementation->repositories.begin()),
+ r_end(_implementation->repositories.end());
+ for ( ; r != r_end ; ++r)
+ {
+ if (! r->has_category_named(a->package().get<qpn_category>()))
+ continue;
+
+ if (! r->has_package_named(a->package()))
+ continue;
+
+ VersionSpecCollection::ConstPointer versions(r->version_specs(a->package()));
+ VersionSpecCollection::Iterator v(versions->begin()), v_end(versions->end());
+ for ( ; v != v_end ; ++v)
+ {
+ if (a->version_spec_ptr())
+ if (! ((*v).*(a->version_operator().as_version_spec_operator()))(*a->version_spec_ptr()))
+ continue;
+
+ /// \bug SLOT etc
+
+ if (! result->insert(PackageDatabaseEntry(a->package(), *v, r->name())))
+ ; /// \bug exception
+ }
+ }
+
+
+ return result;
+}
+
+const RepositoryName &
+PackageDatabase::better_repository(const RepositoryName & r1,
+ const RepositoryName & r2) const
+{
+ IndirectIterator<std::list<Repository::ConstPointer>::const_iterator, const Repository>
+ r(_implementation->repositories.begin()),
+ r_end(_implementation->repositories.end());
+ for ( ; r != r_end ; ++r)
+ {
+ if (r->name() == r1)
+ return r2;
+ else if (r->name() == r2)
+ return r1;
+ }
+
+ throw "TODO"; /// \bug
+}
+
+RepositoryName
+PackageDatabase::favourite_repository() const
+{
+ if (_implementation->repositories.empty())
+ return RepositoryName("unnamed");
+ else
+ return (*_implementation->repositories.begin())->name();
+}
+
+PackageDatabaseEntryCollection::Pointer
+PackageDatabase::query(PackageDepAtom::ConstPointer a) const
+{
+ return query(a.raw_pointer());
+}
+
+PackageDatabase::RepositoryIterator
+PackageDatabase::begin_repositories() const
+{
+ return _implementation->repositories.begin();
+}
+
+PackageDatabase::RepositoryIterator
+PackageDatabase::end_repositories() const
+{
+ return _implementation->repositories.end();
+}
diff --git a/paludis/package_database.hh b/paludis/package_database.hh
new file mode 100644
index 0000000..7fcdad2
--- /dev/null
+++ b/paludis/package_database.hh
@@ -0,0 +1,116 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2005, 2006 Ciaran McCreesh <ciaranm@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.
+ *