[Debtags-commits] [svn] r1632 - in tagcoll/trunk: tagcoll tools

Enrico Zini enrico at costa.debian.org
Sat Mar 4 14:32:18 UTC 2006


Author: enrico
Date: Sat Mar  4 14:32:17 2006
New Revision: 1632

Added:
   tagcoll/trunk/tools/TagcollOptions.h
   tagcoll/trunk/tools/manpage.cc
Modified:
   tagcoll/trunk/tagcoll/Commandline.cc
   tagcoll/trunk/tagcoll/Commandline.h
   tagcoll/trunk/tools/Makefile.am
   tagcoll/trunk/tools/tagcoll.cc
Log:
Implemented manpage generation

Modified: tagcoll/trunk/tagcoll/Commandline.cc
==============================================================================
--- tagcoll/trunk/tagcoll/Commandline.cc	(original)
+++ tagcoll/trunk/tagcoll/Commandline.cc	Sat Mar  4 14:32:17 2006
@@ -1,4 +1,8 @@
 #include <tagcoll/Commandline.h>
+#include <config.h>
+#include <locale.h>
+#include <ctype.h>
+#include <set>
 
 using namespace std;
 
@@ -43,6 +47,22 @@
 		return string("--") + c + "=" + usage;
 }
 
+static string manfmtshort(char c, const std::string& usage)
+{
+	if (usage.empty())
+		return string("\\-") + c;
+	else
+		return string("\\-") + c + " \\fI" + usage + "\\fP";
+}
+
+static string manfmtlong(const std::string& c, const std::string& usage)
+{
+	if (usage.empty())
+		return string("\\-\\-") + c;
+	else
+		return string("\\-\\-") + c + "=\\fI" + usage + "\\fP";
+}
+
 const std::string& Option::fullUsage() const
 {
 	if (m_fullUsage.empty())
@@ -66,6 +86,27 @@
 	return m_fullUsage;
 }
 	
+std::string Option::fullUsageForMan() const
+{
+	string res;
+
+	for (vector<char>::const_iterator i = shortNames.begin();
+			i != shortNames.end(); i++)
+	{
+		if (!res.empty()) res += ", ";
+		res += manfmtshort(*i, usage);
+	}
+
+	for (vector<string>::const_iterator i = longNames.begin();
+			i != longNames.end(); i++)
+	{
+		if (!res.empty()) res += ", ";
+		res += manfmtlong(*i, usage);
+	}
+
+	return res;
+}
+	
 
 bool StringOption::parse(const char* str)
 {
@@ -520,6 +561,191 @@
 	out << endl;
 }
 
+static string toupper(const std::string& str)
+{
+	string res;
+	for (size_t i = 0; i < str.size(); i++)
+		res += ::toupper(str[i]);
+	return res;
+}
+
+static string man_date()
+{
+	time_t tnow = time(0);
+	struct tm* now = gmtime(&tnow);
+	char buf[20];
+	const char* oldlocale = setlocale(LC_TIME, "C");
+	string res(buf, strftime(buf, 20, "%B %d, %Y", now));
+	setlocale(LC_TIME, oldlocale);
+	return res;
+}
+
+void Help::outputManOption(std::ostream& out, const Option* o)
+{
+	out << ".TP" << endl;
+	out << ".B " << o->fullUsageForMan() << endl;
+	out << o->description << "." << endl;
+}
+
+void Help::outputMan(std::ostream& out, const CommandParser& cp, int section)
+{
+	std::map<std::string, OptionParser*> m_info;
+	
+	// Dig informations from cp
+	for(map<string, OptionParser*>::const_iterator i = cp.m_aliases.begin();
+			i != cp.m_aliases.end(); i++)
+	{
+		if (i->first == string())
+			continue;
+		map<string, OptionParser*>::iterator j = m_info.find(i->second->name());
+		if (j == m_info.end())
+			m_info[i->second->name()] = i->second;
+	}
+
+
+	// Manpage header
+	out << ".TH " << toupper(m_app) << " " << section << " \"" << man_date() << "\" \"" << m_ver << "\"" << endl;
+
+	out << ".SH NAME" << endl;
+	out << cp.name() << " \\- " << cp.description << endl;
+
+	out << ".SH SYNOPSIS" << endl;
+	out << m_app << " [options] " << cp.usage << endl;
+
+	out << ".SH DESCRIPTION" << endl;
+
+	out << ".SH COMMANDS" << endl;
+	out << "\\fB" << cp.name() << "\\fP always requires a non-switch argument, that indicates what is the operation that should be performed:" << endl;
+	for (map<string, OptionParser*>::const_iterator i = m_info.begin();
+			i != m_info.end(); i++)
+	{
+		out << ".TP" << endl;
+		out << "\\fB" << i->second->primaryAlias << "\\fP";
+
+		const vector<string>& v = i->second->aliases;
+		for (vector<string>::const_iterator j = v.begin(); j != v.end(); j++)
+			out << " or \\fB" << *j << "\\fP";
+		
+		out << " " << i->second->usage << endl;
+		out << ".br" << endl;
+		out << i->second->description << endl;
+	}
+
+	out << ".SH OPTIONS" << endl;
+
+	out << "This program follows the usual GNU command line syntax, with long options starting with two dashes (`\\-')." << endl << endl;
+	out << "Every one of the commands listed above has its own set of options.  To keep this manpage readable, all the options are presented together.  Please refer to \"\\fB" << cp.name() << "\\fP help \\fIcommand\\fP\" to see which options are accepted by a given command." << endl;
+
+	// Harvest merged option informations
+	set<OptionGroup*> groups;
+	vector<Option*> options;
+	for(map<string, OptionParser*>::const_iterator i = cp.m_aliases.begin();
+			i != cp.m_aliases.end(); i++)
+	{
+		if (i->first == string())
+			continue;
+		OptionParser& o = *i->second;
+
+		for (vector<OptionGroup*>::const_iterator i = o.m_groups.begin();
+				i != o.m_groups.end(); i++)
+			groups.insert(*i);
+		for (vector<Option*>::const_iterator j = o.m_options.begin();
+				j != o.m_options.end(); j++)
+			options.push_back(*j);
+	}
+
+	for (set<OptionGroup*>::const_iterator i = groups.begin();
+			i != groups.end(); i++)
+	{
+		if (!(*i)->description.empty())
+			out << endl << (*i)->description << ":" << endl;
+		for (vector<Option*>::const_iterator j = (*i)->options.begin();
+				j != (*i)->options.end(); ++j)
+			outputManOption(out, *j);
+		out << ".PP" << endl;
+	}
+
+	if (!options.empty())
+	{
+		out << endl;
+		out << "Other options:" << endl;
+		for (vector<Option*>::const_iterator j = options.begin();
+				j != options.end(); ++j)
+			outputManOption(out, *j);
+	}
+
+	out << ".SH AUTHOR" << endl;
+	out << "\\fB" << cp.name() << "\\fP is maintained by " << PACKAGE_BUGREPORT << "." << endl << endl;
+	out << "This manpage has been automatically generated by the " << m_app << " program." << endl;
+}
+
+#if 0
+void Help::outputMan(std::ostream& out, const OptionParser& o, int section)
+{
+	HelpWriter writer(out);
+
+	out << "Usage: " << m_app << " [options] " << o.primaryAlias << " [options] " << o.usage << endl;
+	out << endl;
+	if (!o.aliases.empty())
+	{
+		out << "Command aliases: ";
+		for (vector<string>::const_iterator i = o.aliases.begin();
+				i != o.aliases.end(); i++)
+			if (i == o.aliases.begin())
+				out << *i;
+			else
+				out << ", " << *i;
+		out << "." << endl;
+		out << endl;
+	}
+	writer.outstring("Description: " + o.description);
+
+	// Compute size of option display
+	size_t maxLeftCol = 0;
+	for (vector<OptionGroup*>::const_iterator i = o.m_groups.begin();
+			i != o.m_groups.end(); i++)
+		for (vector<Option*>::const_iterator j = (*i)->options.begin();
+				j != (*i)->options.end(); j++)
+		{
+			size_t w = (*j)->fullUsage().size();
+			if (w > maxLeftCol)
+				maxLeftCol = w;
+		}
+	for (vector<Option*>::const_iterator j = o.m_options.begin();
+			j != o.m_options.end(); j++)
+	{
+		size_t w = (*j)->fullUsage().size();
+		if (w > maxLeftCol)
+			maxLeftCol = w;
+	}
+
+	if (maxLeftCol)
+	{
+		// Output the options
+		out << endl;
+		out << "Options are:" << endl;
+		for (vector<OptionGroup*>::const_iterator i = o.m_groups.begin();
+				i != o.m_groups.end(); i++)
+		{
+			if (!(*i)->description.empty())
+				writer.outstring((*i)->description + ":");
+			for (vector<Option*>::const_iterator j = (*i)->options.begin();
+					j != (*i)->options.end(); j++)
+				writer.outlist(" " + (*j)->fullUsage(), maxLeftCol + 3, (*j)->description);
+		}
+		if (!o.m_options.empty())
+		{
+			out << endl;
+			writer.outstring("Other options:");
+			for (vector<Option*>::const_iterator j = o.m_options.begin();
+					j != o.m_options.end(); j++)
+				writer.outlist(" " + (*j)->fullUsage(), maxLeftCol + 3, (*j)->description);
+		}
+	}
+	out << endl;
+}
+#endif
+
 }
 }
 

Modified: tagcoll/trunk/tagcoll/Commandline.h
==============================================================================
--- tagcoll/trunk/tagcoll/Commandline.h	(original)
+++ tagcoll/trunk/tagcoll/Commandline.h	Sat Mar  4 14:32:17 2006
@@ -93,6 +93,7 @@
 
 	/// Return a full usage message including all the aliases for this option
 	const std::string& fullUsage() const;
+	std::string fullUsageForMan() const;
 
 	std::vector<char> shortNames;
 	std::vector<std::string> longNames;
@@ -278,6 +279,10 @@
 	void outputVersion(std::ostream& out);
 	void outputHelp(std::ostream& out, const CommandParser& cp);
 	void outputHelp(std::ostream& out, const OptionParser& cp);
+
+	void outputManOption(std::ostream& out, const Option* o);
+	void outputMan(std::ostream& out, const CommandParser& cp, int section);
+	//void outputMan(std::ostream& out, const OptionParser& cp, int section);
 };
 
 }

Modified: tagcoll/trunk/tools/Makefile.am
==============================================================================
--- tagcoll/trunk/tools/Makefile.am	(original)
+++ tagcoll/trunk/tools/Makefile.am	Sat Mar  4 14:32:17 2006
@@ -1,8 +1,9 @@
 ## Process this file with automake to produce Makefile.in
 
 bin_PROGRAMS = tagcoll taggrep tagidx
+noinst_PROGRAMS = manpage
 
-tagcoll_SOURCES = tagcoll.cc CommandlineParser.cc
+tagcoll_SOURCES = tagcoll.cc
 tagcoll_LDADD = ../tagcoll/libtagcoll.la ../tagcoll/tagexpr/libtagexpr.la
 
 taggrep_SOURCES = taggrep.cc CommandlineParser.cc
@@ -11,6 +12,9 @@
 tagidx_SOURCES = tagidx.cc CommandlineParser.cc
 tagidx_LDADD = ../tagcoll/libtagcoll.la ../tagcoll/tagexpr/libtagexpr.la
 
+manpage_SOURCES = manpage.cc
+manpage_LDADD = ../tagcoll/libtagcoll.la ../tagcoll/tagexpr/libtagexpr.la
+
 INCLUDES = -I$(top_srcdir)
 
-EXTRA_DIST = CommandlineParser.h Index.h
+EXTRA_DIST = CommandlineParser.h

Modified: tagcoll/trunk/tools/tagcoll.cc
==============================================================================
--- tagcoll/trunk/tools/tagcoll.cc	(original)
+++ tagcoll/trunk/tools/tagcoll.cc	Sat Mar  4 14:32:17 2006
@@ -62,296 +62,11 @@
 #include <algorithm>
 #include <iostream>
 
+#include "TagcollOptions.h"
+
 using namespace std;
 using namespace Tagcoll;
 
-namespace Tagcoll {
-namespace commandline {
-
-struct CommandlineParser : public CommandParser
-{
-	struct HelpGroup : public OptionGroup
-	{
-		BoolOption* help;
-		BoolOption* version;
-
-		HelpGroup()
-		{
-			add(help = new BoolOption("help", 'h', "help"));
-			add(version = new BoolOption("version", 'V', "version"));
-			help->shortNames.push_back('?');
-			help->description = "show commandline help";
-			version->description = "show program version";
-		}
-		~HelpGroup()
-		{
-			delete help;
-		}
-	} helpGroup;
-
-	struct InputGroup : public OptionGroup
-	{
-		ExistingFileOption* derived;
-		ExistingFileOption* extimpl;
-		ExistingFileOption* rename;
-		ExistingFileOption* patch;
-		StringOption* rmunfaceted;
-		StringOption* rmtags;
-
-		InputGroup()
-		{
-			add(derived		= new ExistingFileOption("derived-tags-from", 'e', "derived"));
-			add(extimpl		= new ExistingFileOption("extimpl", 'i', "implications-from"));
-			add(rename		= new ExistingFileOption("rename", 'r', "rename-from"));
-			add(patch		= new ExistingFileOption("patch", 'p', "patch-with"));
-			add(rmunfaceted	= new StringOption("rmunfaceted", 0, "remove-unfaceted"));
-			add(rmtags		= new StringOption("rmtags", 0, "remove-tags"));
-
-			derived->description = "expand derived tags using the given list";
-			extimpl->description = "use an external list of implications";
-			rename->description = "rename tags using the given mapping list";
-			patch->description = "apply patches from the given tag patch file";
-			patch->longNames.push_back("patch");
-			rmunfaceted->description = "while parsing, remove all tags with no facet part";
-			rmtags->usage = "<expression>";
-			rmtags->description = "while parsing, remove all tags matching the given tag expression";
-		}
-		~InputGroup()
-		{
-			delete derived; delete extimpl; delete rename; delete patch;
-			delete rmunfaceted; delete rmtags;
-		}
-	} inputGroup;
-
-	struct OutputGroup : public OptionGroup
-	{
-		BoolOption* group;
-		BoolOption* redundant;
-		
-		OutputGroup()
-		{
-			add(group		= new BoolOption("group", 'g', "group"));
-			add(redundant	= new BoolOption("redundant", 0, "redundant"));
-			group->description = "group items with the same tagset in the output collection";
-			group->longNames.push_back("group-items");
-			redundant->description = "when implications are provided, expand them explicitly in the output";
-		}
-		~OutputGroup()
-		{
-			delete group;
-			delete redundant;
-		}
-	} outputGroup;
-
-	struct HierarchyGroup : public OptionGroup
-	{
-		IntOption* flatten;
-		IntOption* filter;
-
-		HierarchyGroup()
-		{
-			add(flatten = new IntOption("flatten", 0, "flatten-threshold"));
-			add(filter = new IntOption("filter", 'f', "filter"));
-
-			flatten->description = "set the number of total items below which a branch is flattened when using the \"hierarchy\" command (defaults to 0, meaning \"don't flatten\")";
-			filter->description = "filter out the tags with cardinality less than the given value (defaults to not filter; currently only works when building hierarchies)";
-		}
-
-		~HierarchyGroup()
-		{
-			delete flatten;
-			delete filter;
-		}
-	} hierarchyGroup;
-
-	struct Generic : public OptionParser
-	{
-		Generic(CommandlineParser* cp) : OptionParser("")
-		{
-			add(&cp->helpGroup);
-		}
-	} generic;
-	struct Help : public OptionParser
-	{
-		Help(CommandlineParser* cp) : OptionParser("help")
-		{
-			usage = "[command]";
-			description = "print help informations";
-		}
-	} help;
-	struct Copy : public OptionParser
-	{
-		Copy(CommandlineParser* cp) : OptionParser("copy")
-		{
-			usage = "[files...]";
-			description = "output the collection";
-			add(&cp->inputGroup);
-			add(&cp->outputGroup);
-			add(&cp->helpGroup);
-			aliases.push_back("cat");
-		}
-	} copy;
-	struct Reverse : public OptionParser
-	{
-		StringOption* untaggedTag;
-
-		Reverse(CommandlineParser* cp) : OptionParser("reverse")
-		{
-			add(untaggedTag = new StringOption("untagged-tag", 0, "untagged-tag"));
-			untaggedTag->usage = "<tag>";
-			untaggedTag->description = "set item name to use for associating untagged items when using the \"reverse\" command.  If not specified, untagged items are not included in the output";
-				
-			usage = "[files...]";
-			description = "\"reverse\" the collection, outputting one with items associated to tags";
-			add(&cp->helpGroup);
-		}
-		~Reverse()
-		{
-			delete untaggedTag;
-		}
-	} reverse;
-	struct Diff : public OptionParser
-	{
-		Diff(CommandlineParser* cp) : OptionParser("diff")
-		{
-			usage = "<file1> <file2>";
-			description = "output a tag patch file with the differences between two files";
-			add(&cp->helpGroup);
-		}
-	} diff;
-	struct Related : public OptionParser
-	{
-		IntOption* distance;
-		
-		Related(CommandlineParser* cp) : OptionParser("related")
-		{
-			add(distance = new IntOption("distance", 'd', "distance"));
-			distance->description = "set the maximum distance to use for the \"related\" command (defaults to 0)";
-			
-			usage = "<item> [files...]";
-			description = "print a list of items related to the given one";
-			add(&cp->helpGroup);
-		}
-		~Related()
-		{
-			delete distance;
-		}
-	} related;
-	struct Implications : public OptionParser
-	{
-		Implications(CommandlineParser* cp) : OptionParser("implications")
-		{
-			usage = "[files...]";
-			description = "compute a list of tag implications";
-			add(&cp->helpGroup);
-		}
-	} implications;
-	struct Hierarchy : public OptionParser
-	{
-		Hierarchy(CommandlineParser* cp) : OptionParser("hierarchy")
-		{
-			usage = "[files...]";
-			description = "build a smart hierarchy with the collection data";
-			add(&cp->hierarchyGroup);
-			add(&cp->helpGroup);
-		}
-	} hierarchy;
-	struct CleanHierarchy : public OptionParser
-	{
-		CleanHierarchy(CommandlineParser* cp) : OptionParser("cleanhierarchy")
-		{
-			usage = "[files...]";
-			description = "build a cleaned smart hierarchy with the collection data";
-			add(&cp->hierarchyGroup);
-			add(&cp->helpGroup);
-		}
-	} cleanhierarchy;
-	struct FindSpecials : public OptionParser
-	{
-		FindSpecials(CommandlineParser* cp) : OptionParser("findspecials")
-		{
-			usage = "[files...]";
-			description =
-				"generate a smart hierarchy and print, for each toplevel tag, "
-				"what are the items that make it toplevel instead of going below "
-				"another tag";
-			add(&cp->hierarchyGroup);
-			add(&cp->helpGroup);
-		}
-	} findspecials;
-	struct Grep : public OptionParser
-	{
-		Grep(CommandlineParser* cp) : OptionParser("grep")
-		{
-			usage = "<expression> [files...]";
-			description = "output the collection of tags that match the given tag expression";
-			add(&cp->helpGroup);
-		}
-	} grep;
-	struct Items : public OptionParser
-	{
-		Items(CommandlineParser* cp) : OptionParser("items")
-		{
-			usage = "[files...]";
-			description = "output only the items of the input collection";
-			add(&cp->helpGroup);
-		}
-	} items;
-
-	arglist args;
-
-	CommandlineParser(int argc, const char* argv[]) : CommandParser("main"),
-		generic(this),
-		help(this), copy(this), reverse(this), diff(this), related(this), implications(this),
-		hierarchy(this), cleanhierarchy(this), findspecials(this), grep(this), items(this)
-	{
-		add(generic);
-		add(help);
-		add(copy);
-		add(reverse);
-		add(diff);
-		add(related);
-		add(implications);
-		add(hierarchy);
-		add(cleanhierarchy);
-		add(findspecials);
-		add(grep);
-		add(items);
-
-		usage = "<command> [options and arguments]";
-		description = "Perform various operations on a tagged collection";
-
-		for (int i = 1; i < argc; i++)
-			args.push_back(argv[i]);
-	}
-
-	arglist parse()
-	{
-		parseList(args);
-		if (!lastCommand())
-			throw commandline::BadOption("could not understand the command to execute");
-		return args;
-	}
-
-	bool hasNext() const { return !args.empty(); }
-	string next()
-	{
-		if (args.empty())
-			return string();
-		string res(*args.begin());
-		args.erase(args.begin());
-		return res;
-	}
-
-#if 0
-		//opts.add("verbose", 'v', "verbose", "enable verbose output");
-		//opts.add("debug", 0, "debug", "enable debugging output (including verbose output)");
-#endif
-};
-
-}
-}
-
 
 bool isdir(const std::string& file)
 {
@@ -583,7 +298,7 @@
 	FilterTagsByExpression<string, string> filterByExpression;
 
 public:
-	Reader(commandline::CommandlineParser& opts)
+	Reader(commandline::TagcollOptions& opts)
 		: addImplied(implications), removeImplied(implications),
 		  addDerived(derivedTags), removeDerived(derivedTags),
 		  unfacetedRemover("::"), filterByExpression("")
@@ -654,7 +369,7 @@
 		filters.setConsumer(cons);
 		readCollection(file, filters);
 	}
-	void output(commandline::CommandlineParser& opts, Consumer<string, string>& cons)
+	void output(commandline::TagcollOptions& opts, Consumer<string, string>& cons)
 	{
 		if (opts.hasNext())
 			while (opts.hasNext())
@@ -714,7 +429,7 @@
 	}
 
 public:
-	Writer(commandline::CommandlineParser& opts)
+	Writer(commandline::TagcollOptions& opts)
 		: output(conv, conv, stdout), grouper(0)
 	{
 		if (opts.outputGroup.group->boolValue())
@@ -733,10 +448,10 @@
 
 int main(int argc, const char* argv[])
 {
-	commandline::CommandlineParser opts(argc, argv);
+	commandline::TagcollOptions opts;
 
 	try {
-		opts.parse();
+		opts.parse(argc, argv);
 
 		Reader reader(opts);
 		



More information about the Debtags-commits mailing list