r3004 - in software/ui: . src

Enrico Zini enrico at alioth.debian.org
Wed Jun 20 11:18:50 UTC 2007


Author: enrico
Date: 2007-06-20 11:18:50 +0000 (Wed, 20 Jun 2007)
New Revision: 3004

Added:
   software/ui/Makefile.am
   software/ui/configure.ac
   software/ui/src/
   software/ui/src/Environment.cc
   software/ui/src/Environment.h
   software/ui/src/Environment.tcc
   software/ui/src/GamessOptions.h
   software/ui/src/Makefile.am
   software/ui/src/games.cc
   software/ui/src/manpage.cc
Log:
initial structure

Added: software/ui/Makefile.am
===================================================================
--- software/ui/Makefile.am	                        (rev 0)
+++ software/ui/Makefile.am	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,10 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = src .
+
+man_MANS = games.1
+
+games.1: src/manpage
+	tools/manpage gamse > $@ || rm $@
+
+EXTRA_DIST = $(man_MANS)

Added: software/ui/configure.ac
===================================================================
--- software/ui/configure.ac	                        (rev 0)
+++ software/ui/configure.ac	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,36 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(games, 0.1, [enrico at debian.org,little_miry at yahoo.es])
+AC_CONFIG_SRCDIR([configure.ac])
+AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE([foreign])
+
+dnl To use subdirs
+AC_PROG_MAKE_SET
+
+AC_LANG(C++)
+
+AC_GNU_SOURCE
+dnl AC_ISC_POSIX
+AC_PROG_CXX()
+AC_PROG_CXXCPP
+AM_PROG_CC_STDC
+AC_HEADER_STDC
+
+dnl Use libtool
+AM_PROG_LIBTOOL
+
+dnl Use wibble, tagcoll2 and pkg
+LIBWIBBLE_DEFS
+LIBTAGCOLL2_DEFS
+LIBEPT_DEFS
+
+dnl Look for apt-get
+AC_PATH_PROG(APTGET, apt-get, /usr/bin/apt-get)
+AC_SUBST(APTGET)
+AC_DEFINE_UNQUOTED(APTGET, "$APTGET", [Location of apt-get program])
+
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+])
+AC_OUTPUT

Added: software/ui/src/Environment.cc
===================================================================
--- software/ui/src/Environment.cc	                        (rev 0)
+++ software/ui/src/Environment.cc	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,115 @@
+/*
+ * Common environment for many program parts
+ *
+ * Copyright (C) 2003--2007  Enrico Zini <enrico at debian.org>
+ *
+ * This program 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.
+ *
+ * This program 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 "Environment.h"
+
+#include <ept/apt/apt.h>
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>	// isatty
+
+#include <cstdlib>
+
+using namespace std;
+
+static Environment* instance = 0;
+
+Environment& Environment::get() throw ()
+{
+	if (instance == 0)
+		instance = new Environment;
+
+	return *instance;
+}
+
+// Initialize the environment with default values
+Environment::Environment() throw ()
+	: m_apt(0), m_debtags(0), _verbose(false), _debug(false) {}
+
+void Environment::init(bool editable)
+{
+	m_apt = new ept::apt::Apt;
+	m_debtags = new ept::debtags::Debtags(editable);
+}
+
+void fatal_error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
+{
+	fprintf(stderr, "debtags: ");
+	va_list ap;
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+	exit(1);
+}
+
+void error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+}
+
+void warning(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+}
+
+void verbose(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
+{
+	if (Environment::get().verbose())
+	{
+		va_list ap;
+		va_start(ap, fmt);
+		vfprintf(stderr, fmt, ap);
+		va_end(ap);
+	}
+}
+
+void debug(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
+{
+	if (Environment::get().debug())
+	{
+		va_list ap;
+		va_start(ap, fmt);
+		vfprintf(stderr, fmt, ap);
+		va_end(ap);
+	}
+}
+
+void feedback(const char* fmt, ...) throw() ATTR_PRINTF(1, 2)
+{
+	if (isatty(1))
+	{
+		va_list ap;
+		va_start(ap, fmt);
+		vfprintf(stdout, fmt, ap);
+		va_end(ap);
+	}
+}
+
+
+
+// vim:set ts=4 sw=4:

Added: software/ui/src/Environment.h
===================================================================
--- software/ui/src/Environment.h	                        (rev 0)
+++ software/ui/src/Environment.h	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,104 @@
+#ifndef DEBTAGS_ENVIRONMENT_H
+#define DEBTAGS_ENVIRONMENT_H
+
+/*
+ * Common environment for many program parts
+ *
+ * Copyright (C) 2003--2007  Enrico Zini <enrico at debian.org>
+ *
+ * This program 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.
+ *
+ * This program 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 <ept/debtags/debtags.h>
+#include <string>
+
+namespace ept {
+namespace apt {
+class Apt;
+}
+}
+
+class Environment
+{
+protected:
+	/// Apt data provider
+	ept::apt::Apt* m_apt;
+
+	/// Debtags data provider
+	ept::debtags::Debtags* m_debtags;
+
+	// True when operations should be verbose
+	bool _verbose;
+
+	// True when operations should be very verbose
+	bool _debug;
+
+	Environment() throw ();
+		
+public:
+	static Environment& get() throw ();
+
+	/**
+	 * Initialise the data providers.
+	 *
+	 * This method must be called before they can be accessed.
+	 */
+	void init(bool editable = false);
+
+	/// Access the apt data provider
+	ept::apt::Apt& apt() { return *m_apt; }
+
+	/// Access the debtags data provider
+	ept::debtags::Debtags& debtags() { return *m_debtags; }
+
+	/// Access the tag vocabulary
+	ept::debtags::Vocabulary& voc() { return m_debtags->vocabulary(); }
+
+	// Accessor methods
+
+	bool verbose() const throw () { return _verbose; }
+	bool verbose(bool verbose) throw () { return _verbose = verbose; }
+
+	bool debug() const throw () { return _debug; }
+	bool debug(bool debug) throw ()
+	{
+		// Debug implies verbose
+		if (debug)
+			_verbose = true;
+		return _debug = debug;
+	}
+};
+
+// Commodity output functions
+
+#ifndef ATTR_PRINTF
+ #ifdef GCC
+  #define ATTR_PRINTF(string, first) __attribute__((format (printf, string, first)))
+ #else
+  #define ATTR_PRINTF(string, first)
+ #endif
+#endif
+
+void fatal_error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
+void error(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
+void warning(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
+void verbose(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
+void debug(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
+void feedback(const char* fmt, ...) throw() ATTR_PRINTF(1, 2);
+
+static inline Environment& env() { return Environment::get(); }
+
+// vim:set ts=4 sw=4:
+#endif

Added: software/ui/src/Environment.tcc
===================================================================
--- software/ui/src/Environment.tcc	                        (rev 0)
+++ software/ui/src/Environment.tcc	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,67 @@
+/*
+ * debtags - Implement package tags support for Debian
+ *
+ * Copyright (C) 2003--2007  Enrico Zini <enrico at debian.org>
+ *
+ * This program 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.
+ *
+ * This program 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 DEBTAGS_ENVIRONMENT_TCC
+#define DEBTAGS_ENVIRONMENT_TCC
+
+#include "Environment.h"
+
+#include <pkg/debtags/maint/serializer.h>
+
+#include <tagcoll/input/stdio.h>
+#include <tagcoll/TextFormat.h>
+
+
+template<typename OUT>
+void Environment::readCollection(const string& file, const OUT& out)
+{
+	if (file == "-")
+	{
+		input::Stdio input(stdin, "<stdin>");
+		textformat::parse(input,
+				pkg::debtags::stringToInt(pkgid, voc(),
+					pkg::debtags::intToPkg(pkgid, voc(), out)));
+	}
+	else
+	{
+		input::Stdio input(file);
+		textformat::parse(input,
+				pkg::debtags::stringToInt(pkgid, voc(),
+					pkg::debtags::intToPkg(pkgid, voc(), out)));
+	}
+}
+
+template<typename OUT>
+void Environment::readCollectionRaw(const string& file, const OUT& out)
+{
+	if (file == "-")
+	{
+		input::Stdio input(stdin, "<stdin>");
+		textformat::parse(input, out);
+	}
+	else
+	{
+		input::Stdio input(file);
+		textformat::parse(input, out);
+	}
+}
+
+#endif
+// vim:set ts=4 sw=4:

Added: software/ui/src/GamessOptions.h
===================================================================
--- software/ui/src/GamessOptions.h	                        (rev 0)
+++ software/ui/src/GamessOptions.h	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,243 @@
+#ifndef DEBTAGS_OPTIONS_H
+#define DEBTAGS_OPTIONS_H
+
+/*
+ * Commandline parser for tagcoll
+ *
+ * Copyright (C) 2003,2004,2005,2006  Enrico Zini
+ * 
+ * This program 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.
+ * 
+ * This program 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 <wibble/commandline/parser.h>
+
+namespace wibble {
+namespace commandline {
+
+struct DebtagsOptions : public StandardParserWithMandatoryCommand
+{
+public:
+	BoolOption* out_quiet;
+	BoolOption* out_verbose;
+
+	BoolOption* out_names;
+	BoolOption* out_debug;
+	BoolOption* out_facets;
+	BoolOption* out_short;
+	BoolOption* out_full;
+
+	BoolOption* match_invert;
+
+	BoolOption* misc_local;
+	BoolOption* misc_reindex;
+	IntOption* misc_distance;
+	StringOption* misc_vocfile;
+
+	BoolOption* smse_reltags;
+	BoolOption* smse_disctags;
+
+	Engine* update;
+	Engine* selfcheck;
+	Engine* check;
+	Engine* tagcat;
+	Engine* tagshow;
+	Engine* tagsearch;
+	Engine* show;
+	Engine* related;
+	Engine* cat;
+	Engine* dumpavail;
+	Engine* search;
+	Engine* grep;
+	Engine* install;
+	Engine* diff;
+	Engine* maintainers;
+	Engine* tag;
+	Engine* submit;
+	Engine* todo;
+	Engine* score;
+	Engine* stats;
+	Engine* todoreport;
+	Engine* smartsearch;
+	Engine* vocfilter;
+
+	DebtagsOptions() 
+		: StandardParserWithMandatoryCommand("debtags", VERSION, 1, "enrico at enricozini.org")
+	{
+		usage = "<command> [options and arguments]";
+		description = "Commandline interface to access and manipulate Debian Package Tags";
+
+		out_verbose = add<BoolOption>("verbose", 'v', "verbose", "",
+						"enable verbose output");
+		out_debug = add<BoolOption>("debug", 0, "debug", "",
+						"enable debugging output (including verbose output)");
+
+		// Create the collection output group
+		OptionGroup* collOutputOpts = createGroup("Options controlling transformations of tag data on output");
+		out_names = collOutputOpts->add<BoolOption>("names", 0, "names", "",
+						"output only the names of the packages");
+		out_quiet = collOutputOpts->add<BoolOption>("quiet", 'q', "quiet", "",
+						"do not write anything to standard output");
+		out_facets = collOutputOpts->add<BoolOption>("facets", 0, "facets", "",
+						"output only the names of the facets (mainly used for computing statistics)");
+
+		// Create the package output group
+		OptionGroup* pkgOutputOpts = createGroup("Options controlling transformations of package data on output");
+		pkgOutputOpts->add(out_names);
+		pkgOutputOpts->add(out_quiet);
+		out_short = pkgOutputOpts->add<BoolOption>("short", 0, "short", "",
+						"output the names of the packages, plus a short description");
+		out_full = pkgOutputOpts->add<BoolOption>("full", 0, "full", "",
+						"output the full record of package data");
+
+		// Create the matching options group
+		OptionGroup* matchOpts = createGroup("Options controlling matching of packages");
+		match_invert = matchOpts->add<BoolOption>("invert", 'i', "invert", "",
+				"invert the match, selecting non-matching items");
+
+		update = addEngine("update", "",
+			"updates the package tag database (requires root)",
+			"Collect package tag data from the sources listed in "
+			"/etc/debtags/sources.list, then regenerate the debtags "
+			"tag database and main index.\n"
+			"It needs to be run as root");
+		misc_local = update->add<BoolOption>("local", 0, "local", "",
+			"do not download files when performing an update");
+		misc_reindex = update->add<BoolOption>("reindex", 0, "reindex", "",
+			"do not download any file, just do reindexing if needed");
+
+		selfcheck = addEngine("selfcheck", "",
+			"perform a series of internal self checks using the current tag data");
+
+		check = addEngine("check", "<file>", 
+			"check that all the tags in the given tagged collection are present "
+			"in the tag vocabulary.  Checks the main database if no file is "
+			"specified");
+
+		tagcat = addEngine("tagcat", "", "output the tag vocabulary");
+
+		tagshow = addEngine("tagshow", "", 
+			"show the vocabulary informations about a tag");
+
+		tagsearch = addEngine("tagsearch", "<string [string [string ...]]>",
+			"show a summary of all tags whose data contains the given strings");
+
+		show = addEngine("show", "<pkg>",
+			"show informations about a package, like apt-cache show does, but "
+			"adding the tag informations from the debtags index");
+
+		related = addEngine("related", "<pkg1[,pkg2[,pkg3...]]>",
+			"show packages related to the given one(s)",
+			"Output a list of the packages that are related to the given package or list of packages.  "
+			"If more than one package are to be specified, separate them with commas.\n"
+			"The --distance option can be used to control how closely related the output "
+			"packages should be from the package(s) specified.");
+		related->examples = "debtags related mutt,mozilla-browser";
+		misc_distance = related->add<IntOption>("distance", 'd', "distance", "distance",
+			"set the maximum distance to use for the \"related\" command (defaults to 0)");
+			
+		cat = addEngine("cat", "", "output the full package tag database");
+		cat->add(matchOpts);
+		cat->add(collOutputOpts);
+
+		dumpavail = addEngine("dumpavail", "[tag expression]",
+			"output the full package database");
+		dumpavail->add(matchOpts);
+		dumpavail->add(pkgOutputOpts);
+
+		search = addEngine("search", "<tag expression>",
+			"output the names and descriptions of the packages that match"
+			" the given tag expression");
+		search->add(matchOpts);
+		search->add(pkgOutputOpts);
+
+		grep = addEngine("grep", "<tag expression>",
+			"output the lines of the full package tag database that match"
+			" the given tag expression");
+		grep->add(matchOpts);
+		grep->add(collOutputOpts);
+
+		install = addEngine("install", "<tag expression>",
+			"apt-get install the packages that match the given tag expression",
+			"Invokes apt-get install with the names of the packages matched "
+			"by the given tag expression.  If you want to see what packages "
+			"would be installed you can use debtags search, as "
+			"debtags install just calls apt-get install on all "
+			"the results of an equivalent debtags search.  Please note "
+			"that debtags install is just a prototype feature useful "
+			"for experimenting in some environments like Custom Debian "
+			"Distributions.  For this reason it is suggested that you "
+			"use debtags just as a way to find packages, and "
+			"proper package managers as the way to install them");
+		install->add(matchOpts);
+
+		diff = addEngine("diff", "[filename]",
+			"create a tag patch between the current tag database and the tag"
+			"collection [filename].  Standard input is used if filename is not specified");
+		diff->aliases.push_back("mkpatch");
+
+		maintainers = addEngine("maintainers", "", 
+			"create a tagged collection of maintainers and the tags of the"
+			"packages they maintain");
+		maintainers->add(collOutputOpts);
+
+		tag = addEngine("tag", "{add|rm|ls} <package> [tags...]",
+			"view and edit the tags for a package",
+			"General manipulation of tags, useful for automation in scripts.\n"
+			"It can be used in three ways:\n"
+			"tag add <package> <tags...> will add the tags to the given package\n"
+			"tag rm <package> <tags...> will remove the tags from the given package\n"
+			"tag ls <package> will output the names of the tags of the given package");
+
+		submit = addEngine("submit", "[patch]",
+			"mail the given patch file to the central tag repository."
+			"If [patch] is omitted, mail the local tag modifications.");
+
+		todo = addEngine("todo", "", 
+			"print a list of the installed packages that are not yet tagged");
+		todo->add(pkgOutputOpts);
+
+		score = addEngine("score", "", 
+			"score uninstalled packages according to how often their tags "
+			"appear in the packages that are installed already");
+
+		stats = addEngine("stats", "",
+			"print statistics about Debtags");
+
+		todoreport = addEngine("todoreport", "", 
+			"print a report of packages needing work");
+
+		smartsearch = addEngine("smartsearch", "<word [word1 [+tag [-tag1 ...]]]>",
+			"Perform a keyword search integrated with related packages.\n"
+			"A + prefix indicates a wanted tag.  A - prefix indicates "
+			"an unwanted tag.  Other words indicate keywords to search.\n"
+			"Remember to use '--' before unwanted tags to avoid to have "
+			"them interpreted as commandline switches.\n");
+		smse_reltags = smartsearch->add<BoolOption>("relevant", 0, "relevant", "",
+			"only print the tag names sorted by increasing relevance");
+		smse_disctags = smartsearch->add<BoolOption>("discriminant", 0, "discriminant", "",
+			"only print the tag names sorted by increasing discriminance");
+
+		vocfilter = addEngine("vocfilter", "tagfile", 
+			"filter out the tags that are not found in the given vocabulary file");
+		misc_vocfile = vocfilter->add<StringOption>("vocabulary", 0, "vocabulary", "file",
+			"vocabulary file to use instead of the current debtags vocabulary");
+	}
+};
+
+}
+}
+
+// vim:set ts=4 sw=4:
+#endif

Added: software/ui/src/Makefile.am
===================================================================
--- software/ui/src/Makefile.am	                        (rev 0)
+++ software/ui/src/Makefile.am	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,16 @@
+## Process this file with automake to produce Makefile.in
+
+bin_PROGRAMS = games
+noinst_PROGRAMS = manpage
+
+games_SOURCES = \
+	Environment.cc \
+	games.cc
+games_LDADD = $(LIBEPT_LIBS)
+
+manpage_SOURCES = manpage.cc
+manpage_LDADD = $(LIBEPT_LIBS)
+
+INCLUDES = -I.. $(LIBEPT_CFLAGS)
+
+EXTRA_DIST = GamesOptions.h Environment.h

Added: software/ui/src/games.cc
===================================================================
--- software/ui/src/games.cc	                        (rev 0)
+++ software/ui/src/games.cc	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,821 @@
+/*
+ * debtags - Implement package tags support for Debian
+ *
+ * Copyright (C) 2003--2006  Enrico Zini <enrico at debian.org>
+ *
+ * This program 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.
+ *
+ * This program 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#define APPNAME PACKAGE_NAME
+#else
+#warning No config.h found: using fallback values
+#define APPNAME __FILE__
+#define PACKAGE_VERSION "unknown"
+#endif
+
+#include <tagcoll/input/stdio.h>
+#include <tagcoll/stream/filters.h>
+#include <tagcoll/expression.h>
+#include <tagcoll/TextFormat.h>
+#include <tagcoll/SmartHierarchy.h>
+#include <tagcoll/coll/simple.h>
+#include <tagcoll/utils/set.h>
+//#include <tagcoll/experiments.h>
+
+#include "Environment.h"
+#include "DebtagsOptions.h"
+#include "Printer.h"
+#include "nullstream.h"
+//#include "Ept.h"
+#include "SmartSearcher.h"
+
+#include <ept/apt/packagerecord.h>
+#include <ept/debtags/expression.h>
+#include <ept/debtags/maint/vocabularymerger.h>
+#include <ept/debtags/maint/path.h>
+#include <ept/debtags/maint/vocabularyindexer.h>
+#include <ept/debtags/maint/debtagsindexer.h>
+#if 0
+#include <ept/cache/debtags/update.h>
+//#include <apt-pkg/configuration.h>
+#endif
+
+#include <wibble/sys/fs.h>
+
+#include <errno.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>	// umask
+#include <sys/stat.h>	// umask
+
+namespace std {
+
+template<typename TAG, typename _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& out, const std::set<TAG>& tags)
+{
+	for (typename std::set<TAG>::const_iterator i = tags.begin();
+			i != tags.end(); i++)
+		if (i == tags.begin())
+			out << i->fullname();
+		else
+			out << ", " << i->fullname();
+	return out;
+}
+
+template<typename TAG, typename _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& out, const wibble::Singleton<TAG>& tags)
+{
+	out << *tags.begin();
+	return out;
+}
+
+template<typename TAG, typename _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>& out, const wibble::Empty<TAG>&)
+{
+	return out;
+}
+
+}
+
+using namespace std;
+using namespace ept;
+using namespace ept::debtags;
+using namespace ept::apt;
+using namespace ept::textsearch;
+
+int main(int argc, const char* argv[])
+{
+	wibble::commandline::DebtagsOptions opts;
+
+	try {
+		// Install the handler for unexpected exceptions
+		wibble::exception::InstallUnexpected installUnexpected;
+
+		if (opts.parse(argc, argv))
+			return 0;
+
+		if (opts.out_verbose->boolValue())
+			::Environment::get().verbose(true);
+
+		if (opts.out_debug->boolValue())
+			::Environment::get().debug(true);
+
+		if (opts.foundCommand() == opts.selfcheck)
+		{
+			env().init();
+			Vocabulary& voc = env().voc();
+			Apt& apt = env().apt();
+
+			// ensure that all facets are readable
+			std::set<Facet> facets = voc.facets();
+			for (std::set<Facet>::const_iterator i = facets.begin(); i != facets.end(); i++)
+			{
+				cout << "Checking facet " << i->name(string("<invalid name>")) << "..." << endl;
+				i->name(string("foo"));
+				i->shortDescription(string("foo"));
+				i->longDescription(string("foo"));
+				i->tags();
+			}
+
+			// ensure that all tags are readable
+			std::set<Tag> tags = voc.tags();
+			for (std::set<Tag>::const_iterator i = tags.begin(); i != tags.end(); i++)
+			{
+				cout << "Checking tag " << i->fullname(string("<invalid name>")) << "..." << endl;
+				i->name(string("foo"));
+				i->fullname(string("foo"));
+				i->shortDescription(string("foo"));
+				i->longDescription(string("foo"));
+			}
+
+			// ensure that all packages that declare they are readable, are readable
+			for (Apt::iterator i = apt.begin(); i != apt.end(); ++i)
+			{
+				cout << "Checking package " << *i << "..." << endl;
+				//if (i->isValid())
+				//{
+				//	i->shortDescription(string("foo"));
+				//	i->longDescription(string("foo"));
+				//	//i->tags(std::set<Tag>());
+				//}
+			}
+			
+			for (std::set<Facet>::const_iterator i = facets.begin();
+					i != facets.end(); i++)
+			{
+				if (!voc.hasFacet(i->name()))
+					cerr << "Vocabulary is not sure about having facet " << i->name() << endl;
+
+				std::set<Tag> tags = i->tags();
+				for (std::set<Tag>::const_iterator j = tags.begin();
+						j != tags.end(); j++)
+					if (!voc.hasTag(j->fullname()))
+						cerr << "Vocabulary is not sure about having tag " << j->fullname() << endl;
+			}
+			return 0;
+		}
+		// Output the full package tag database
+		else if (opts.foundCommand() == opts.cat)
+		{
+			env().init();
+			Debtags& debtags = env().debtags();
+			int count = 0;
+
+			auto_ptr<CollPrinter> printer;
+
+			if (opts.out_names->boolValue())
+				printer.reset(new CollPrinter(CollPrinter::NAME, count));
+			else if (opts.out_facets->boolValue())
+				printer.reset(new CollPrinter(CollPrinter::FACETS, count));
+			else if (opts.out_quiet->boolValue())
+				printer.reset(new CollPrinter(CollPrinter::QUIET, count));
+			else 
+				printer.reset(new CollPrinter(CollPrinter::TAGS, count));
+
+			if (opts.hasNext())
+			{
+				debtags.output(expressionFilter(opts.next(), opts.match_invert->boolValue(), *printer));
+			} else
+				debtags.output(*printer);
+
+			return count > 0 ? 0 : 1;
+		}
+		// Output the full package database
+		else if (opts.foundCommand() == opts.dumpavail)
+		{
+			env().init();
+			int count = 0;
+
+			auto_ptr<PackagePrinter> printer;
+			if (opts.out_names->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::NAME, count));
+			else if (opts.out_short->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::SHORT, count));
+			else if (opts.out_quiet->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::QUIET, count));
+			else 
+				printer.reset(new PackagePrinter(PackagePrinter::FULL, count));
+
+			if (opts.hasNext())
+			{
+				env().debtags().output(expressionFilter(opts.next(), opts.match_invert->boolValue(), *printer));
+			} else {
+				// If there is no expression filter, dump from the Apt database
+				Apt& apt = env().apt();
+				PackageRecord record;
+				for (Apt::record_iterator i = apt.recordBegin();
+						i != apt.recordEnd(); ++i)
+				{
+					record.scan(*i);
+					*printer = record;
+				}
+			}
+
+			return count > 0 ? 0 : 1;
+		}
+		// search [-v] <tag expression>\n"
+		// Output the names and description of the packages that match\n"
+		// the given tag expression\n"
+		else if (opts.foundCommand() == opts.search)
+		{
+			env().init();
+			// TODO: complain if no expression found
+			int count = 0;
+
+			auto_ptr<PackagePrinter> printer;
+			if (opts.out_names->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::NAME, count));
+			else if (opts.out_full->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::FULL, count));
+			else if (opts.out_quiet->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::QUIET, count));
+			else 
+				printer.reset(new PackagePrinter(PackagePrinter::SHORT, count));
+
+			if (opts.hasNext())
+			{
+				env().debtags().output(expressionFilter(opts.next(), opts.match_invert->boolValue(), *printer));
+			} else
+				env().debtags().output(*printer);
+
+			return count > 0 ? 0 : 1;
+		}
+		// grep [-v] [-q] <tag expression>
+		// Output the lines of the full package tag database that match the
+		// given tag expression
+		else if (opts.foundCommand() == opts.grep)
+		{
+			env().init();
+			// TODO: complain if no expression found
+			Debtags& debtags = env().debtags();
+			int count = 0;
+
+			auto_ptr<CollPrinter> printer;
+
+			if (opts.out_names->boolValue())
+				printer.reset(new CollPrinter(CollPrinter::NAME, count));
+			else if (opts.out_facets->boolValue())
+				printer.reset(new CollPrinter(CollPrinter::FACETS, count));
+			else if (opts.out_quiet->boolValue())
+				printer.reset(new CollPrinter(CollPrinter::QUIET, count));
+			else 
+				printer.reset(new CollPrinter(CollPrinter::TAGS, count));
+
+			if (opts.hasNext())
+			{
+				debtags.output(expressionFilter(opts.next(), opts.match_invert->boolValue(), *printer));
+			} else
+				debtags.output(*printer);
+
+			return count > 0 ? 0 : 1;
+		}
+		// tagcat
+		// Output the entire tag vocabulary
+		else if (opts.foundCommand() == opts.tagcat)
+		{
+			env().init();
+			Vocabulary& voc = env().voc();
+
+			std::set<Facet> facets = voc.facets();
+			for (std::set<Facet>::const_iterator i = facets.begin();
+					i != facets.end(); i++)
+			{
+				printVocabularyItem(*i);
+
+				std::set<Tag> tags = i->tags();
+				for (std::set<Tag>::const_iterator j = tags.begin();
+						j != tags.end(); j++)
+					printVocabularyItem(*j);
+			}
+			return 0;
+		}
+		// tagshow <tag>
+		// Show the vocabulary informations about a tag
+		else if (opts.foundCommand() == opts.tagshow)
+		{
+			env().init();
+			string tag = opts.next();
+
+			Tag t = env().voc().tagByName(tag);
+			if (!t.valid())
+			{
+				verbose("Tag `%s' was not found in tag vocabulary\n", tag.c_str());
+				return 1;
+			}
+			else
+			{
+				printVocabularyItem(t);
+				return 0;
+			}
+		}
+		// tagsearch <pattern [pattern [pattern [...]]]>
+		// Show a summary of all tags matching the given patterns
+		else if (opts.foundCommand() == opts.tagsearch)
+		{
+			env().init();
+			SubstringTagMatcher match;
+
+			// Get the patterns to be matched
+			bool empty;
+			while (opts.hasNext())
+			{
+				string pattern = opts.next();
+				match.add(pattern);
+				empty = false;
+			}
+
+			if (empty)
+			{
+				error("No patterns given in commandline\n");
+				return 1;
+			}
+
+			int matched = 0;
+
+			std::set<Facet> facets = env().voc().facets();
+			for (std::set<Facet>::const_iterator i = facets.begin();
+					i != facets.end(); i++)
+			{
+				if (match(*i))
+				{
+					matched++;
+					printShortVocabularyItem(*i);
+				}
+
+				std::set<Tag> tags = i->tags();
+				for (std::set<Tag>::const_iterator j = tags.begin();
+						j != tags.end(); j++)
+					if (match(*j))
+					{
+						matched++;
+						printShortVocabularyItem(*j);
+					}
+			}
+
+			return matched > 0 ? 0 : 1;
+		}
+		// show <pkg>
+		// Call apt-cache show <pkg>, but add tag informations to the output.\n"
+		else if (opts.foundCommand() == opts.show)
+		{
+			env().init();
+			while (opts.hasNext())
+			{
+				string name = opts.next();
+
+				if (env().apt().isValid(name))
+				{
+					PackagePrinter printer(PackagePrinter::FULL);
+					printer = name;
+					return 0;
+				} else {
+					verbose("Package %s not found", name.c_str());
+					return 1;
+				}
+			}
+		}
+		// related <pkg1[,pkg2[,pkg2,[...]]]>
+		// Show packages related to the specified ones
+		else if (opts.foundCommand() == opts.related)
+		{
+			env().init();
+			using namespace wibble::operators;
+
+			int maxdist = 0;
+			if (opts.misc_distance->boolValue())
+				maxdist = opts.misc_distance->intValue();
+			string pkg = opts.next();
+
+			// Split the items on commas
+			string splititem;
+			std::set<string> splititems;
+			for (string::const_iterator c = pkg.begin(); c != pkg.end(); c++)
+				if (*c == ',')
+				{
+					if (env().apt().isValid(splititem))
+					{
+						splititems.insert(splititem);
+					} else {
+						error("Item \"%s\" does not exist in the collection\n", splititem.c_str());
+						return 1;
+					}
+					splititem = string();
+				} else
+					splititem += *c;
+			if (env().apt().isValid(splititem))
+			{
+				splititems.insert(splititem);
+			} else {
+				error("Item \"%s\" does not exist in the collection\n", splititem.c_str());
+				return 1;
+			}
+
+			// Get the tagset as the intersection of the tagsets of all input items
+			std::set<string>::const_iterator i = splititems.begin();
+			std::set<Tag> ts = env().debtags().getTagsOfItem(*i);
+			for (++i; i != splititems.end(); i++)
+				ts &= env().debtags().getTagsOfItem(*i);
+
+			if (ts.empty())
+			{
+				if (splititems.size() > 1)
+					fprintf(stderr, "The packages %s are unrelated: cannot find a barycenter to start computing relationships from.\n", pkg.c_str());
+				else
+					fprintf(stderr, "The package %s has no tags attached.\n", pkg.c_str());
+				return 1;
+			}
+
+			std::set<string> related(env().debtags().getRelatedItems(ts, maxdist) - splititems);
+
+			int count = 0;
+
+			auto_ptr<PackagePrinter> printer;
+			if (opts.out_names->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::NAME, count));
+			else if (opts.out_full->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::FULL, count));
+			else if (opts.out_quiet->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::QUIET, count));
+			else 
+				printer.reset(new PackagePrinter(PackagePrinter::SHORT, count));
+
+			for (std::set<string>::const_iterator i = related.begin();
+					i != related.end(); ++i)
+			{
+				**printer = *i;
+				++*printer;
+			}
+
+			if (count > 50 && maxdist == 0 && isatty(1))
+			{
+				string tags;
+				for (std::set<Tag>::const_iterator i = ts.begin();
+						i != ts.end(); i++)
+					if (i == ts.begin())
+						tags += i->fullname();
+					else
+						tags += "%2C" + i->fullname();
+				feedback("\nIt seems that this set of packages lacks tag information that could help to better distinguish package similarities.\nYou can help providing better tagging: just point your browser to http://debian.vitavonni.de/packagebrowser/?tags=%s\n", tags.c_str());
+			}
+			return 0;
+		}
+		// maintainers
+		// Create a tagged collection of maintainers and the tags of the
+		// packages they maintain
+		else if (opts.foundCommand() == opts.maintainers)
+		{
+			env().init();
+			// Gather maintainer informations
+			coll::Simple<string, string> maints;
+			env().debtags().output(packageToMaint(inserter(maints)));
+
+			// Print them out
+			maints.output(textformat::StdioWriter(stdout));
+		}
+		// tag
+		//   tag [add <package> <tags...>\n"
+		//   tag [rm  <package> <tags...>\n"
+		//   tag [ls  <package>\n"
+		//                View and edit the tags for a package\n");
+		else if (opts.foundCommand() == opts.tag)
+		{
+			std::string cmd = opts.next();
+
+			if (cmd == "add" || cmd == "rm")
+			{
+				env().init(true);
+
+				string pkg = opts.next();
+				if (!env().apt().isValid(pkg))
+				{
+					error("Package %s not found\n", pkg.c_str());
+					return 1;
+				}
+
+				std::set<Tag> tagset;
+				while (opts.hasNext())
+				{
+					string tag = opts.next();
+					Tag t = env().voc().tagByName(tag);
+					if (t)
+						tagset.insert(t);
+					else
+						error("Tag '%s' not found: ignored\n", tag.c_str());
+				}
+
+				if (!tagset.empty())
+				{
+					PatchList<string, Tag> change;
+					if (cmd == "add")
+						change.addPatch(Patch<string, Tag>(pkg, tagset, std::set<Tag>()));
+					else
+						change.addPatch(Patch<string, Tag>(pkg, std::set<Tag>(), tagset));
+					env().debtags().applyChange(change);
+					env().debtags().savePatch();
+				} else
+					verbose("No tags to add\n");
+			}
+			else if (cmd == "ls")
+			{
+				env().init();
+				string pkg = opts.next();
+				if (env().apt().isValid(pkg))
+				{
+					std::set<Tag> ts = env().debtags().getTagsOfItem(pkg);
+					for (std::set<Tag>::const_iterator i = ts.begin();
+							i != ts.end(); i++)
+						cout << i->fullname() << endl;
+					return 0;
+				} else {
+					verbose("Package %s not found", pkg.c_str());
+					return 1;
+				}
+			}
+			else
+				throw wibble::exception::Consistency("parsing the 'tag' subcommand", "command " + cmd + " is not valid working with tags");
+		}
+		// submit
+		// Mail the local updates to the tag database to the central tag
+		// repository
+		else if (opts.foundCommand() == opts.submit)
+		{
+			env().init();
+			if (opts.hasNext())
+			{
+				input::Stdio in(opts.next());
+				PatchList<string, string> patch;
+				textformat::parsePatch(in, inserter(patch));
+				env().debtags().sendPatch(patch);
+			}
+			else
+				env().debtags().sendPatch();
+		}
+		// todo
+		// Print a list of the installed packages that are not yet tagged
+		else if (opts.foundCommand() == opts.todo)
+		{
+			env().init();
+			int count = 0;
+
+			auto_ptr<PackagePrinter> printer;
+			if (opts.out_names->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::NAME, count));
+			else if (opts.out_full->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::FULL, count));
+			else if (opts.out_quiet->boolValue())
+				printer.reset(new PackagePrinter(PackagePrinter::QUIET, count));
+			else 
+				printer.reset(new PackagePrinter(PackagePrinter::SHORT, count));
+
+			env().debtags().output(todoFilter(*printer));
+
+			return count > 0 ? 0 : 1;
+		}
+		// stats
+		// Print statistics about Debtags
+		else if (opts.foundCommand() == opts.stats)
+		{
+			env().init();
+			int pkgCount = env().apt().size();
+			printf("Total count of packages: %d\n", pkgCount);
+
+			Stats stats;
+			env().debtags().outputPatched(StatsCollector(stats));
+
+			printf("Total count of packages (according to APT): %d\n", pkgCount);
+			printf("Total count of packages (according to Debtags): %d\n", stats.seen);
+
+			printf("Number of facets: %zi\n", env().voc().facets().size());
+			printf("Number of tags: %zi\n", env().voc().tags().size());
+
+#if 0
+			// Copied from Debtags class: compute the toplevel facets
+			// TODO: use Debtags instead of Environment throughout all Debtags
+			CardinalityStore<entity::Package, Facet> coll;
+			TagToFacet<entity::Package> tagStripper(coll);
+			debtags.outputPatched(tagStripper);
+			Facet f;
+			SmartHierarchyNode<entity::Package, Facet> node(f, coll, 0);
+			printf("Number of automatically computed toplevel facets: %d\n", node.size());
+#endif
+
+//			printf("Number of packages with special::completely-tagged tags: %d (%.1f%%)\n",
+//					stats.complete, (float)stats.complete*100/stats.seen);
+			printf("Number of packages with tags, but no special::not-yet-tagged tags: %d (%.1f%%)\n",
+					stats.tagged, (float)stats.tagged*100/stats.seen);
+			printf("Number of packages with special::not-yet-tagged tags: %d (%.1f%%)\n",
+					stats.nyt, (float)stats.nyt*100/stats.seen);
+			printf("Number of packages with only special::not-yet-tagged tags: %d (%.1f%%)\n",
+					stats.onlynyt, (float)stats.onlynyt*100/stats.seen);
+			printf("Number of packages with no tags: %d (%.1f%%)\n",
+					stats.notags, (float)stats.notags*100/stats.seen);
+
+		}
+		// check <file>
+		// Check that all the tags in the given tagged collection are
+		// present in the tag vocabulary.  Checks the main database if no
+		// file is specified
+		else if (opts.foundCommand() == opts.check)
+		{
+			env().init();
+			if (!opts.hasNext())
+				throw wibble::exception::BadOption("you should specify the file with the collection to check");
+
+			string file = opts.next();
+
+			VocabularyCheck results;
+			readCollection(file, VocabularyChecker(env().voc(), results));
+
+			if (results.missing_count > 0)
+			{
+				results.report(cout);
+				return 1;
+			}
+			else
+				return 0;
+		}
+		// score
+		// Score uninstalled packages according to how often their tags
+		// appear in the packages that are installed already
+		else if (opts.foundCommand() == opts.score)
+		{
+			env().init();
+			// Compute package scores
+			PackageScore score;
+			env().debtags().outputPatched(PackageScorer(score));
+
+			// Print the results
+			score.output(env().debtags(), cout);
+		}
+		// mkpatch [filename]
+		// Create a tag patch between the current tag database and the tag
+		// collection [filename]
+		else if (opts.foundCommand() == opts.diff)
+		{
+			env().init();
+			string file = opts.next();
+
+			coll::Simple<string, Tag> coll;
+			env().debtags().outputSystem(file, inserter(coll));
+
+			PatchList<string, Tag> newpatches;
+			newpatches.addPatch(env().debtags(), coll);
+
+			textformat::outputPatch(serPackage, serTag, newpatches, stdout);
+		}
+		// ssearch <word [word1 [word2 ...]]>
+		// Perform a keyword search integrated with related packages
+		else if (opts.foundCommand() == opts.smartsearch)
+		{
+			env().init();
+			if (!opts.hasNext())
+				throw wibble::exception::BadOption("you should specify one pattern to search");
+
+			string keywords;
+			while (opts.hasNext())
+				if (keywords.empty())
+					keywords = opts.next();
+				else
+					keywords += " " + opts.next();
+
+			SmartSearcher searcher(keywords);
+
+			if (opts.smse_reltags->boolValue())
+				searcher.outputRelevantTags();
+			else if (opts.smse_disctags->boolValue())
+				searcher.outputDiscriminantTags();
+			else {
+				searcher.interact();
+			}
+		}
+		// update
+		// Updates the package tag database (requires root)
+		else if (opts.foundCommand() == opts.update)
+		{
+			using namespace wibble::sys;
+
+			verbose("System source directory: %s\n", Path::debtagsSourceDir().c_str());
+			verbose("User source directory: %s\n", Path::debtagsUserSourceDir().c_str());
+
+			if (!opts.misc_reindex->boolValue())
+			{
+				// Run the fetcher to acquire new data
+				string fetcher = SCRIPTDIR "/fetch";
+				if (!fs::access(fetcher, X_OK))
+					warning("Fetch script %s does not exist or is not executable: skipping acquiring of new data\n", fetcher.c_str());
+				else {
+					if (opts.out_verbose->boolValue())
+						fetcher += " --verbose";
+					if (opts.misc_local->boolValue())
+						fetcher += " --local";
+					if (system(fetcher.c_str()) != 0)
+						throw wibble::exception::Consistency("acquiring new data", "fetcher command " + fetcher + " failed");
+				}
+			}
+
+
+			// Access the indexes to trigger a rebuild
+			//typedef ept::t::cache::debtags::IndexManager<> IndexManager;
+			std::string a, b;
+
+			//auto_ptr<Ept> ept = debtagsInit();
+			env().init();
+
+			VocabularyIndexer::obtainWorkingVocabulary(a, b);
+			verbose("Vocabulary: %s\n", a.c_str());
+			verbose("Vocabulary index: %s\n", b.c_str());
+
+			DebtagsIndexer::obtainWorkingDebtags(env().voc(), a, b);
+			verbose("Tag database: %s\n", a.c_str());
+			verbose("Tag database index: %s\n", b.c_str());
+
+			//mode_t prev_umask = umask(022);
+			//umask(prev_umask);
+		}
+		else if (opts.foundCommand() == opts.vocfilter)
+		{
+			env().init();
+			if (!opts.hasNext())
+				throw wibble::exception::BadOption("you should specify the file with the collection to check");
+
+			string file = opts.next();
+
+			if (opts.misc_vocfile->boolValue())
+			{
+				VocabularyMerger vm;
+				input::Stdio input(opts.misc_vocfile->stringValue());
+				vm.read(input);
+				readCollection(file, vocabularyFilter(vm, textformat::OstreamWriter(cout)));
+			}
+			else
+				readCollection(file, vocabularyFilter(env().voc(), textformat::OstreamWriter(cout)));
+		}
+#if 0
+		// todoreport
+		// Print a report of packages needing work
+		else if (opts.foundCommand() == opts.todoreport)
+		{
+			debtagsInit();
+			wantTagDatabase();
+
+			unsigned int itemsPerGroup = 0;
+			if (opts.hasNext())
+				itemsPerGroup = atoi(opts.next().c_str());
+
+			ReportMaker rm(itemsPerGroup);
+			rm.printReport();
+
+		}
+#endif
+#if 0
+		// install [-v] [-q] <tag expression>
+		// apt-get install the packages that match the given tag expression
+		else if (opts.foundCommand() == opts.install)
+		{
+			component::PackageTags& debtags = debtagsInit();
+			wantTagDatabase();
+			Installer installer;
+
+			Searcher searcher(debtags, &installer);
+			string expression = opts.next();
+
+			searcher.output(expression, opts.matchGroup.invert->boolValue());
+
+			return 1;
+		}
+#endif
+		else
+			throw wibble::exception::BadOption(string("unhandled command ") +
+						(opts.foundCommand() ? opts.foundCommand()->name() : "(null)"));
+
+		return 0;
+	} catch (wibble::exception::BadOption& e) {
+		cerr << e.desc() << endl;
+		opts.outputHelp(cerr);
+		return 1;
+	} catch (std::exception& e) {
+		cerr << e.what() << endl;
+		return 1;
+	}
+}
+
+#include <ept/debtags/debtags.tcc>
+#include <tagcoll/coll/simple.tcc>
+#include <tagcoll/coll/fast.tcc>
+#include <tagcoll/TextFormat.tcc>
+
+// vim:set ts=4 sw=4:

Added: software/ui/src/manpage.cc
===================================================================
--- software/ui/src/manpage.cc	                        (rev 0)
+++ software/ui/src/manpage.cc	2007-06-20 11:18:50 UTC (rev 3004)
@@ -0,0 +1,60 @@
+/*
+ * tagged collection - Experimental programs to test and study tagged collections
+ *
+ * Copyright (C) 2003,2004,2005,2006  Enrico Zini
+ * 
+ * This program 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.
+ * 
+ * This program 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.h>
+#include <wibble/commandline/doc.h>
+#include "DebtagsOptions.h"
+#include <iostream>
+
+using namespace std;
+
+int main(int argc, const char* argv[])
+{
+	try {
+		if (argc == 1)
+			throw wibble::exception::BadOption("no arguments provided");
+
+		string cmd(argv[1]);
+		string hooks(argc > 2 ? argv[2] : "");
+
+		if (cmd == "debtags")
+		{
+			wibble::commandline::DebtagsOptions opts;
+			wibble::commandline::Manpage help("debtags", VERSION, 1, "enrico at enricozini.org");
+			if (!hooks.empty())
+				help.readHooks(hooks);
+			help.output(cout, opts);
+		}
+		else
+			throw wibble::exception::BadOption("unknown command " + cmd);
+
+		return 0;
+	} catch (wibble::exception::BadOption& e) {
+		cerr << e.desc() << endl << endl;
+		cerr << "Usage: manpage <command>" << endl << endl;
+		cerr << "Supported commands are: debtags" << endl;
+		return 1;
+	} catch (std::exception& e) {
+		cerr << e.what() << endl;
+		return 1;
+	}
+}
+
+// vim:set ts=4 sw=4:




More information about the Pkg-games-commits mailing list