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