1//
2// HelpFormatter.cpp
3//
4// Library: Util
5// Package: Options
6// Module: HelpFormatter
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Util/HelpFormatter.h"
16#include "Poco/Util/OptionSet.h"
17#include "Poco/Util/Option.h"
18
19
20namespace Poco {
21namespace Util {
22
23
24const int HelpFormatter::TAB_WIDTH = 4;
25const int HelpFormatter::LINE_WIDTH = 78;
26
27
28HelpFormatter::HelpFormatter(const OptionSet& options):
29 _options(options),
30 _width(LINE_WIDTH),
31 _indent(0),
32 _unixStyle(true)
33{
34#if !defined(POCO_OS_FAMILY_UNIX)
35 _unixStyle = false;
36#endif
37 _indent = calcIndent();
38}
39
40
41HelpFormatter::~HelpFormatter()
42{
43}
44
45
46void HelpFormatter::setCommand(const std::string& command)
47{
48 _command = command;
49}
50
51
52void HelpFormatter::setUsage(const std::string& usage)
53{
54 _usage = usage;
55}
56
57
58void HelpFormatter::setHeader(const std::string& header)
59{
60 _header = header;
61}
62
63
64void HelpFormatter::setFooter(const std::string& footer)
65{
66 _footer = footer;
67}
68
69
70void HelpFormatter::format(std::ostream& ostr) const
71{
72 ostr << "usage: " << _command;
73 if (!_usage.empty())
74 {
75 ostr << ' ';
76 formatText(ostr, _usage, (int) _command.length() + 1);
77 }
78 ostr << '\n';
79 if (!_header.empty())
80 {
81 formatText(ostr, _header, 0);
82 ostr << "\n\n";
83 }
84 formatOptions(ostr);
85 if (!_footer.empty())
86 {
87 ostr << '\n';
88 formatText(ostr, _footer, 0);
89 ostr << '\n';
90 }
91}
92
93
94void HelpFormatter::setWidth(int width)
95{
96 poco_assert (width > 0);
97
98 _width = width;
99}
100
101
102void HelpFormatter::setIndent(int indent)
103{
104 poco_assert (indent >= 0 && indent < _width);
105
106 _indent = indent;
107}
108
109
110void HelpFormatter::setAutoIndent()
111{
112 _indent = calcIndent();
113}
114
115
116void HelpFormatter::setUnixStyle(bool flag)
117{
118 _unixStyle = flag;
119}
120
121
122int HelpFormatter::calcIndent() const
123{
124 int indent = 0;
125 for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
126 {
127 int shortLen = (int) it->shortName().length();
128 int fullLen = (int) it->fullName().length();
129 int n = 0;
130 if (_unixStyle && shortLen > 0)
131 {
132 n += shortLen + (int) shortPrefix().length();
133 if (it->takesArgument())
134 n += (int) it->argumentName().length() + (it->argumentRequired() ? 0 : 2);
135 if (fullLen > 0) n += 2;
136 }
137 if (fullLen > 0)
138 {
139 n += fullLen + (int) longPrefix().length();
140 if (it->takesArgument())
141 n += 1 + (int) it->argumentName().length() + (it->argumentRequired() ? 0 : 2);
142 }
143 n += 2;
144 if (n > indent)
145 indent = n;
146 }
147 return indent;
148}
149
150
151void HelpFormatter::formatOptions(std::ostream& ostr) const
152{
153 int optWidth = calcIndent();
154 for (OptionSet::Iterator it = _options.begin(); it != _options.end(); ++it)
155 {
156 formatOption(ostr, *it, optWidth);
157 if (_indent < optWidth)
158 {
159 ostr << '\n' << std::string(_indent, ' ');
160 formatText(ostr, it->description(), _indent, _indent);
161 }
162 else
163 {
164 formatText(ostr, it->description(), _indent, optWidth);
165 }
166 ostr << '\n';
167 }
168}
169
170
171void HelpFormatter::formatOption(std::ostream& ostr, const Option& option, int width) const
172{
173 int shortLen = (int) option.shortName().length();
174 int fullLen = (int) option.fullName().length();
175
176 int n = 0;
177 if (_unixStyle && shortLen > 0)
178 {
179 ostr << shortPrefix() << option.shortName();
180 n += (int) shortPrefix().length() + (int) option.shortName().length();
181 if (option.takesArgument())
182 {
183 if (!option.argumentRequired()) { ostr << '['; ++n; }
184 ostr << option.argumentName();
185 n += (int) option.argumentName().length();
186 if (!option.argumentRequired()) { ostr << ']'; ++n; }
187 }
188 if (fullLen > 0) { ostr << ", "; n += 2; }
189 }
190 if (fullLen > 0)
191 {
192 ostr << longPrefix() << option.fullName();
193 n += (int) longPrefix().length() + (int) option.fullName().length();
194 if (option.takesArgument())
195 {
196 if (!option.argumentRequired()) { ostr << '['; ++n; }
197 ostr << '=';
198 ++n;
199 ostr << option.argumentName();
200 n += (int) option.argumentName().length();
201 if (!option.argumentRequired()) { ostr << ']'; ++n; }
202 }
203 }
204 while (n < width) { ostr << ' '; ++n; }
205}
206
207
208void HelpFormatter::formatText(std::ostream& ostr, const std::string& text, int indent) const
209{
210 formatText(ostr, text, indent, indent);
211}
212
213
214void HelpFormatter::formatText(std::ostream& ostr, const std::string& text, int indent, int firstIndent) const
215{
216 int pos = firstIndent;
217 int maxWordLen = _width - indent;
218 std::string word;
219 for (std::string::const_iterator it = text.begin(); it != text.end(); ++it)
220 {
221 if (*it == '\n')
222 {
223 clearWord(ostr, pos, word, indent);
224 ostr << '\n';
225 pos = 0;
226 while (pos < indent) { ostr << ' '; ++pos; }
227 }
228 else if (*it == '\t')
229 {
230 clearWord(ostr, pos, word, indent);
231 if (pos < _width) ++pos;
232 while (pos < _width && pos % TAB_WIDTH != 0)
233 {
234 ostr << ' ';
235 ++pos;
236 }
237 }
238 else if (*it == ' ')
239 {
240 clearWord(ostr, pos, word, indent);
241 if (pos < _width) { ostr << ' '; ++pos; }
242 }
243 else
244 {
245 if (word.length() == maxWordLen)
246 {
247 clearWord(ostr, pos, word, indent);
248 }
249 else word += *it;
250 }
251 }
252 clearWord(ostr, pos, word, indent);
253}
254
255
256void HelpFormatter::formatWord(std::ostream& ostr, int& pos, const std::string& word, int indent) const
257{
258 if (pos + word.length() > _width)
259 {
260 ostr << '\n';
261 pos = 0;
262 while (pos < indent) { ostr << ' '; ++pos; }
263 }
264 ostr << word;
265 pos += (int) word.length();
266}
267
268
269void HelpFormatter::clearWord(std::ostream& ostr, int& pos, std::string& word, int indent) const
270{
271 formatWord(ostr, pos, word, indent);
272 word.clear();
273}
274
275
276std::string HelpFormatter::shortPrefix() const
277{
278#if defined(POCO_OS_FAMILY_UNIX)
279 return "-";
280#else
281 return _unixStyle ? "-" : "/";
282#endif
283}
284
285
286std::string HelpFormatter::longPrefix() const
287{
288#if defined(POCO_OS_FAMILY_UNIX)
289 return "--";
290#else
291 return _unixStyle ? "--" : "/";
292#endif
293}
294
295
296} } // namespace Poco::Util
297