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 | |
20 | namespace Poco { |
21 | namespace Util { |
22 | |
23 | |
24 | const int HelpFormatter::TAB_WIDTH = 4; |
25 | const int HelpFormatter::LINE_WIDTH = 78; |
26 | |
27 | |
28 | HelpFormatter::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 | |
41 | HelpFormatter::~HelpFormatter() |
42 | { |
43 | } |
44 | |
45 | |
46 | void HelpFormatter::setCommand(const std::string& command) |
47 | { |
48 | _command = command; |
49 | } |
50 | |
51 | |
52 | void HelpFormatter::setUsage(const std::string& usage) |
53 | { |
54 | _usage = usage; |
55 | } |
56 | |
57 | |
58 | void HelpFormatter::(const std::string& ) |
59 | { |
60 | _header = header; |
61 | } |
62 | |
63 | |
64 | void HelpFormatter::(const std::string& ) |
65 | { |
66 | _footer = footer; |
67 | } |
68 | |
69 | |
70 | void 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 | |
94 | void HelpFormatter::setWidth(int width) |
95 | { |
96 | poco_assert (width > 0); |
97 | |
98 | _width = width; |
99 | } |
100 | |
101 | |
102 | void HelpFormatter::setIndent(int indent) |
103 | { |
104 | poco_assert (indent >= 0 && indent < _width); |
105 | |
106 | _indent = indent; |
107 | } |
108 | |
109 | |
110 | void HelpFormatter::setAutoIndent() |
111 | { |
112 | _indent = calcIndent(); |
113 | } |
114 | |
115 | |
116 | void HelpFormatter::setUnixStyle(bool flag) |
117 | { |
118 | _unixStyle = flag; |
119 | } |
120 | |
121 | |
122 | int 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 | |
151 | void 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 | |
171 | void 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 | |
208 | void HelpFormatter::formatText(std::ostream& ostr, const std::string& text, int indent) const |
209 | { |
210 | formatText(ostr, text, indent, indent); |
211 | } |
212 | |
213 | |
214 | void 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 | |
256 | void 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 | |
269 | void 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 | |
276 | std::string HelpFormatter::shortPrefix() const |
277 | { |
278 | #if defined(POCO_OS_FAMILY_UNIX) |
279 | return "-" ; |
280 | #else |
281 | return _unixStyle ? "-" : "/" ; |
282 | #endif |
283 | } |
284 | |
285 | |
286 | std::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 | |