tclap 1.4.0
DocBookOutput.h
Go to the documentation of this file.
1// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
2
3/******************************************************************************
4 *
5 * file: DocBookOutput.h
6 *
7 * Copyright (c) 2004, Michael E. Smoot
8 * Copyright (c) 2017, Google LLC
9 * All rights reserved.
10 *
11 * See the file COPYING in the top directory of this distribution for
12 * more information.
13 *
14 * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 *****************************************************************************/
23
24#ifndef TCLAP_DOC_BOOK_OUTPUT_H
25#define TCLAP_DOC_BOOK_OUTPUT_H
26
27#include <tclap/Arg.h>
28#include <tclap/ArgGroup.h>
30#include <tclap/CmdLineOutput.h>
31
32#include <algorithm>
33#include <iostream>
34#include <list>
35#include <string>
36#include <vector>
37
38namespace TCLAP {
39
45public:
51 virtual void usage(CmdLineInterface &c);
52
58 virtual void version(CmdLineInterface &c);
59
66 virtual void failure(CmdLineInterface &c, ArgException &e);
67
69
70protected:
71 // Escape raw data once, at the XML output boundary (text and attributes).
72 static std::string escapeXml(const std::string &text) {
73 std::string result;
74 for (std::string::const_iterator it = text.begin(); it != text.end(); ++it) {
75 switch (*it) {
76 case '&': result += "&amp;"; break;
77 case '<': result += "&lt;"; break;
78 case '>': result += "&gt;"; break;
79 case '\"': result += "&quot;"; break;
80 case '\'': result += "&apos;"; break;
81 default: result += *it; break;
82 }
83 }
84 return result;
85 }
86
87 static std::string valueLabel(const Arg &arg) {
88 const std::string id = arg.shortID();
89 const std::string label = arg.getFlag().empty()
90 ? arg.nameStartString() + arg.getName()
91 : arg.flagStartString() + arg.getFlag();
92 const std::string::size_type labelStart = id.find(label);
93 if (labelStart != std::string::npos) {
94 const std::string::size_type open = labelStart + label.size() + 1;
95 const std::string::size_type close = id.rfind('>');
96 if (open < id.size() && id[open] == '<' &&
97 close != std::string::npos && close > open)
98 return id.substr(open + 1, close - open - 1);
99 }
100 return id; // Custom IDs without the usual value wrapper.
101 }
102
109 void substituteSpecialChars(std::string &s, char r,
110 const std::string &x) const;
111 void removeChar(std::string &s, char r) const;
112
113 void printShortGroup(const ArgGroup &group, bool labelsOnly);
114 static bool hasVisiblePositional(const ArgGroup &group) {
115 for (ArgGroup::const_iterator it = group.begin(); it != group.end(); ++it)
116 if (!(*it)->hasLabel() && (*it)->visibleInHelp()) return true;
117 return false;
118 }
119
120 void printShortArg(Arg *it, bool required);
121 void printLongArg(const ArgGroup &it) const;
122
124
125private:
126 void _printSynopsis(CmdLineInterface &cmd,
127 const std::list<ArgGroup *> &groups,
128 const std::string &programName);
129 static ArgGroup *_findArgGroup(const std::list<ArgGroup *> &groups,
130 const Arg *arg);
131 void _printLongEntry(Arg &arg, bool forceRequired) const;
132 void _printAliasTerms(const Arg &arg) const;
133 void _printValuePlaceholder(const Arg &arg) const;
134};
135
137 std::cout << _cmd.getVersion() << std::endl;
138}
139
140namespace internal {
141inline const char *GroupChoice(const ArgGroup &group) {
142 if (!group.showAsGroup()) {
143 return "plain";
144 }
145
146 if (group.isRequired()) {
147 return "req";
148 }
149
150 return "opt";
151}
152} // namespace internal
153
154inline void DocBookOutput::printShortGroup(const ArgGroup &group, bool labelsOnly) {
155 int visible = 0;
156 for (ArgGroup::const_iterator it = group.begin(); it != group.end(); ++it)
157 if ((*it)->visibleInHelp() && (!labelsOnly || (*it)->hasLabel())) ++visible;
158 if (visible > 1)
159 std::cout << "<group choice='" << internal::GroupChoice(group) << "'>\n";
160 for (ArgGroup::const_iterator it = group.begin(); it != group.end(); ++it) {
161 Arg *arg = *it;
162 if (!arg->visibleInHelp() || (labelsOnly && !arg->hasLabel())) continue;
163 printShortArg(arg, arg->isRequired() || (visible == 1 && group.isRequired()));
164 }
165 if (visible > 1) std::cout << "</group>\n";
166}
167
169 std::list<ArgGroup *> argSets = _cmd.getArgGroups();
170 std::string progName = _cmd.getProgramName();
171 std::string xversion = _cmd.getVersion();
172 theDelimiter = _cmd.getDelimiter();
173
174 std::cout << "<?xml version='1.0'?>\n";
175 std::cout
176 << "<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"\n";
177 std::cout
178 << "\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">\n\n";
179
180 std::cout << "<refentry>\n";
181
182 std::cout << "<refmeta>\n";
183 std::cout << "<refentrytitle>" << escapeXml(progName) << "</refentrytitle>\n";
184 std::cout << "<manvolnum>1</manvolnum>\n";
185 std::cout << "</refmeta>\n";
186
187 std::cout << "<refnamediv>\n";
188 std::cout << "<refname>" << escapeXml(progName) << "</refname>\n";
189 std::cout << "<refpurpose>" << escapeXml(_cmd.getMessage()) << "</refpurpose>\n";
190 std::cout << "</refnamediv>\n";
191
192 _printSynopsis(_cmd, argSets, progName);
193
194 std::cout << "<refsect1>\n";
195 std::cout << "<title>Description</title>\n";
196 std::cout << "<para>\n";
197 std::cout << escapeXml(_cmd.getMessage()) << '\n';
198 std::cout << "</para>\n";
199 std::cout << "</refsect1>\n";
200
201 std::cout << "<refsect1>\n";
202 std::cout << "<title>Options</title>\n";
203
204 std::cout << "<variablelist>\n";
205
206 for (std::list<ArgGroup *>::iterator sit = argSets.begin();
207 sit != argSets.end(); ++sit) {
208 printLongArg(**sit);
209 }
210
211 std::cout << "</variablelist>\n";
212 std::cout << "</refsect1>\n";
213
214 std::cout << "<refsect1>\n";
215 std::cout << "<title>Version</title>\n";
216 std::cout << "<para>\n";
217 std::cout << escapeXml(xversion) << '\n';
218 std::cout << "</para>\n";
219 std::cout << "</refsect1>\n";
220
221 std::cout << "</refentry>" << std::endl;
222}
223
224inline void DocBookOutput::_printSynopsis(CmdLineInterface &cmd,
225 const std::list<ArgGroup *> &groups,
226 const std::string &programName) {
227 std::cout << "<refsynopsisdiv>\n";
228 std::cout << "<cmdsynopsis>\n";
229
230 std::cout << "<command>" << escapeXml(programName) << "</command>\n";
231
232 for (std::list<ArgGroup *>::const_iterator it = groups.begin();
233 it != groups.end(); ++it) {
234 const ArgGroup &group = **it;
235 if (group.isExclusive() && hasVisiblePositional(group)) continue;
236 printShortGroup(group, true);
237 }
238 const std::list<Arg *> operands = cmd.getArgList();
239 std::list<ArgGroup *> shown;
240 for (ArgListIterator it = operands.begin(); it != operands.end(); ++it) {
241 Arg *arg = *it;
242 if (arg->hasLabel() || !arg->visibleInHelp()) continue;
243 ArgGroup *owner = _findArgGroup(groups, arg);
244 if (owner && owner->isExclusive()) {
245 if (std::find(shown.begin(), shown.end(), owner) == shown.end()) {
246 printShortGroup(*owner, false);
247 shown.push_back(owner);
248 }
249 } else {
250 printShortArg(arg, arg->isRequired());
251 }
252 }
253
254 std::cout << "</cmdsynopsis>\n";
255 std::cout << "</refsynopsisdiv>\n";
256}
257
258inline ArgGroup *DocBookOutput::_findArgGroup(
259 const std::list<ArgGroup *> &groups, const Arg *arg) {
260 for (std::list<ArgGroup *>::const_iterator group = groups.begin();
261 group != groups.end(); ++group)
262 if (std::find((*group)->begin(), (*group)->end(), arg) !=
263 (*group)->end())
264 return *group;
265 return NULL;
266}
267
269 static_cast<void>(_cmd); // unused
270 std::cout << e.what() << std::endl;
271 throw ExitException(1);
272}
273
274inline void DocBookOutput::substituteSpecialChars(std::string &s, char r,
275 const std::string &x) const {
276 size_t p;
277 while ((p = s.find_first_of(r)) != std::string::npos) {
278 s.erase(p, 1);
279 s.insert(p, x);
280 }
281}
282
283inline void DocBookOutput::removeChar(std::string &s, char r) const {
284 size_t p;
285 while ((p = s.find_first_of(r)) != std::string::npos) {
286 s.erase(p, 1);
287 }
288}
289
290inline void DocBookOutput::printShortArg(Arg *a, bool required) {
291
292 std::string choice = "opt";
293 if (required) {
294 choice = "plain";
295 }
296
297 std::cout << "<arg choice='" << choice << '\'';
298 if (a->acceptsMultipleValues()) std::cout << " rep='repeat'";
299
300 std::cout << '>';
301 if (!a->hasLabel()) {
302 std::cout << "<replaceable>" << escapeXml(a->getName())
303 << "</replaceable></arg>" << std::endl;
304 return;
305 }
306
307 if (!a->getFlag().empty())
308 std::cout << escapeXml(std::string(1, a->flagStartChar()) + a->getFlag());
309 else
310 std::cout << escapeXml(a->nameStartString() + a->getName());
311 if (a->isValueRequired()) {
312 _printValuePlaceholder(*a);
313 }
314 std::cout << "</arg>" << std::endl;
315}
316
317inline void DocBookOutput::printLongArg(const ArgGroup &group) const {
318
319 bool forceRequired = group.isRequired() && CountVisibleArgs(group) == 1;
320 for (ArgGroup::const_iterator it = group.begin(); it != group.end(); ++it) {
321 Arg &a = **it;
322 if (!a.visibleInHelp()) {
323 continue;
324 }
325 _printLongEntry(a, forceRequired);
326 }
327}
328
329inline void DocBookOutput::_printLongEntry(Arg &a, bool forceRequired) const {
330 std::string desc = a.getDescription(forceRequired || a.isRequired());
331
332 std::cout << "<varlistentry>\n";
333 if (!a.hasLabel()) {
334 std::cout << "<term><replaceable>" << escapeXml(a.getName())
335 << "</replaceable></term>\n<listitem><para>"
336 << escapeXml(desc) << "</para></listitem>\n</varlistentry>"
337 << std::endl;
338 return;
339 }
340
341 if (!a.getFlag().empty()) {
342 std::cout << "<term>\n";
343 std::cout << "<option>";
344 std::cout << escapeXml(std::string(1, a.flagStartChar()) + a.getFlag());
345 std::cout << "</option>\n";
346 std::cout << "</term>\n";
347 }
348
349 std::cout << "<term>\n";
350 std::cout << "<option>";
351 std::cout << escapeXml(a.nameStartString() + a.getName());
352 if (a.isValueRequired()) {
353 _printValuePlaceholder(a);
354 }
355
356 std::cout << "</option>\n";
357 std::cout << "</term>\n";
358
359 _printAliasTerms(a);
360
361 std::cout << "<listitem>\n";
362 std::cout << "<para>\n";
363 std::cout << escapeXml(desc) << '\n';
364 std::cout << "</para>\n";
365 std::cout << "</listitem>\n";
366
367 std::cout << "</varlistentry>" << std::endl;
368}
369
370inline void DocBookOutput::_printAliasTerms(const Arg &a) const {
371 for (std::vector<ArgAlias>::const_iterator alias = a.aliases().begin();
372 alias != a.aliases().end(); ++alias) {
373 for (int spelling = 0; spelling < 2; ++spelling) {
374 const std::string &label =
375 spelling == 0 ? alias->flag : alias->name;
376 if (label.empty()) continue;
377 std::cout << "<term><option>"
378 << escapeXml((spelling == 0 ? a.flagStartString()
379 : a.nameStartString()) +
380 label);
381 if (a.isValueRequired())
382 std::cout << escapeXml(std::string(1, theDelimiter))
383 << "<replaceable>" << escapeXml(valueLabel(a))
384 << "</replaceable>";
385 std::cout << "</option></term>\n";
386 }
387 }
388}
389
390inline void DocBookOutput::_printValuePlaceholder(const Arg &arg) const {
391 const std::string label = valueLabel(arg);
392 std::cout << escapeXml(std::string(1, theDelimiter));
393 std::cout << "<replaceable>" << escapeXml(label) << "</replaceable>";
394}
395
396} // namespace TCLAP
397#endif // TCLAP_DOC_BOOK_OUTPUT_H
A simple class that defines and argument exception.
const char * what() const
Returns the arg id and error text.
ArgGroup is the base class for implementing groups of arguments that are mutually exclusive (it repla...
Definition ArgGroup.h:41
virtual bool isExclusive() const =0
Returns true if this argument group is exclusive.
iterator begin()
Definition ArgGroup.h:110
Container::const_iterator const_iterator
Definition ArgGroup.h:47
iterator end()
Definition ArgGroup.h:111
virtual bool showAsGroup() const
If arguments in this group should show up as grouped in help.
Definition ArgGroup.h:105
virtual bool isRequired() const =0
Returns true if this argument group is required.
A virtual base class that defines the essential data for all arguments.
Definition Arg.h:66
static const std::string nameStartString()
Definition Arg.h:275
const std::string & getFlag() const
Returns the argument flag.
Definition Arg.h:743
bool isValueRequired() const
Indicates whether a value must be specified for argument.
Definition Arg.h:749
static char flagStartChar()
Definition Arg.h:256
const std::string & getName() const
Returns the argument name.
Definition Arg.h:745
std::string getDescription() const
Returns the argument description.
Definition Arg.h:328
virtual bool acceptsMultipleValues()
Use by output classes to determine whether an Arg accepts multiple values.
Definition Arg.h:815
virtual bool hasLabel() const
Definition Arg.h:445
virtual bool visibleInHelp() const
Returns true if this Arg is visible in the help output.
Definition Arg.h:443
virtual bool isRequired() const
Indicates whether the argument is required.
Definition Arg.h:747
virtual std::string shortID(const std::string &valueId="val") const
Returns a short ID for the usage.
Definition Arg.h:568
static const std::string flagStartString()
Definition Arg.h:266
The base class that manages the command line definition and passes along the parsing to the appropria...
virtual std::string getVersion() const =0
Returns the version string.
virtual std::string getMessage() const =0
Returns the message string.
virtual std::string getProgramName() const =0
Returns the program name string.
virtual std::list< ArgGroup * > getArgGroups()=0
Returns the list of ArgGroups.
virtual char getDelimiter() const =0
Returns the delimiter string.
virtual std::list< Arg * > getArgList() const =0
The interface that any output object must implement.
A class that generates DocBook output for usage() method for the given CmdLine and its Args.
void printLongArg(const ArgGroup &it) const
static std::string valueLabel(const Arg &arg)
virtual void version(CmdLineInterface &c)
Prints the version to stdout.
void substituteSpecialChars(std::string &s, char r, const std::string &x) const
Substitutes the char r for string x in string s.
static std::string escapeXml(const std::string &text)
virtual void failure(CmdLineInterface &c, ArgException &e)
Prints (to stderr) an error message, short usage Can be overridden to produce alternative behavior.
void printShortArg(Arg *it, bool required)
void removeChar(std::string &s, char r) const
void printShortGroup(const ArgGroup &group, bool labelsOnly)
static bool hasVisiblePositional(const ArgGroup &group)
virtual void usage(CmdLineInterface &c)
Prints the usage to stdout.
Thrown when TCLAP thinks the program should exit.
Definition Arg.h:52
int CountVisibleArgs(const ArgGroup &g)
Definition ArgGroup.h:246
std::list< Arg * >::const_iterator ArgListIterator
Typedef of an Arg list iterator.
Definition Arg.h:451