Skip to content

Commit 7d02492

Browse files
authored
Merge pull request diffblue#5379 from danpoe/fixes/nondet-volatile-help-message
Fix format of nondet volatile command line help
2 parents 91a2257 + 8307fab commit 7d02492

File tree

9 files changed

+223
-9
lines changed

9 files changed

+223
-9
lines changed

src/goto-instrument/goto_instrument_parse_options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1799,7 +1799,7 @@ void goto_instrument_parse_optionst::help()
17991799
" --race-check add floating-point data race checks\n"
18001800
"\n"
18011801
"Semantic transformations:\n"
1802-
HELP_NONDET_VOLATILE
1802+
<< HELP_NONDET_VOLATILE <<
18031803
" --unwind <n> unwinds the loops <n> times\n"
18041804
" --unwindset L:B,... unwind loop L with a bound of B\n"
18051805
" --unwindset-file <file> read unwindset from file\n"

src/goto-instrument/nondet_volatile.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ class optionst;
2828
"(" NONDET_VOLATILE_MODEL_OPT "):"
2929

3030
#define HELP_NONDET_VOLATILE \
31-
" --" NONDET_VOLATILE_OPT " makes reads from volatile variables " \
32-
"non-deterministic\n" \
33-
" --" NONDET_VOLATILE_VARIABLE_OPT " <variable>\n" \
34-
" makes reads from given volatile variable " \
35-
"non-deterministic\n" \
36-
" --" NONDET_VOLATILE_MODEL_OPT "<variable>:<model>\n" \
37-
" models reads from given volatile variable " \
38-
"by a call to the given model"
31+
help_entry( \
32+
"--" NONDET_VOLATILE_OPT, \
33+
"makes reads from volatile variables non-deterministic") << \
34+
help_entry( \
35+
"--" NONDET_VOLATILE_VARIABLE_OPT " <variable>", \
36+
"makes reads from given volatile variable non-deterministic") << \
37+
help_entry( \
38+
"--" NONDET_VOLATILE_MODEL_OPT " <variable>:<model>", \
39+
"models reads from given volatile variable by a call to the given model")
3940
// clang-format on
4041

4142
void parse_nondet_volatile_options(const cmdlinet &cmdline, optionst &options);

src/util/parse_options.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Author: Daniel Kroening, [email protected]
99
#include "parse_options.h"
1010

1111
#include <algorithm>
12+
#include <cctype>
1213
#include <climits>
1314
#include <iostream>
1415

@@ -23,6 +24,7 @@ Author: Daniel Kroening, [email protected]
2324
#include "exception_utils.h"
2425
#include "exit_codes.h"
2526
#include "signal_catcher.h"
27+
#include "string_utils.h"
2628

2729
parse_options_baset::parse_options_baset(
2830
const std::string &_optstring,
@@ -151,3 +153,54 @@ banner_string(const std::string &front_end, const std::string &version)
151153

152154
return align_center_with_border(version_str);
153155
}
156+
157+
std::string help_entry(
158+
const std::string &option,
159+
const std::string &description,
160+
const std::size_t left_margin,
161+
const std::size_t width)
162+
{
163+
PRECONDITION(!option.empty());
164+
PRECONDITION(!std::isspace(option.front()));
165+
PRECONDITION(!std::isspace(option.back()));
166+
PRECONDITION(option.length() <= width);
167+
168+
PRECONDITION(!description.empty());
169+
PRECONDITION(!std::isspace(description.front()));
170+
PRECONDITION(!std::isspace(description.back()));
171+
172+
PRECONDITION(left_margin < width);
173+
174+
std::string result;
175+
176+
if(option.length() >= left_margin - 1)
177+
{
178+
result = " " + option + "\n";
179+
result += wrap_line(description, left_margin, width) + "\n";
180+
181+
return result;
182+
}
183+
184+
std::string padding(left_margin - option.length() - 1, ' ');
185+
result = " " + option + padding;
186+
187+
if(description.length() <= (width - left_margin))
188+
{
189+
return result + description + "\n";
190+
}
191+
192+
auto it = description.cbegin() + (width - left_margin);
193+
auto rit = std::reverse_iterator<decltype(it)>(it) - 1;
194+
195+
auto rit_space = std::find(rit, description.crend(), ' ');
196+
auto it_space = rit_space.base() - 1;
197+
CHECK_RETURN(*it_space == ' ');
198+
199+
result.append(description.cbegin(), it_space);
200+
result.append("\n");
201+
202+
result +=
203+
wrap_line(it_space + 1, description.cend(), left_margin, width) + "\n";
204+
205+
return result;
206+
}

src/util/parse_options.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,10 @@ banner_string(const std::string &front_end, const std::string &version);
5858
/// ```
5959
std::string align_center_with_border(const std::string &text);
6060

61+
std::string help_entry(
62+
const std::string &option,
63+
const std::string &description,
64+
const std::size_t left_margin = 30,
65+
const std::size_t width = 80);
66+
6167
#endif // CPROVER_UTIL_PARSE_OPTIONS_H

src/util/string_utils.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,75 @@ std::string capitalize(const std::string &str)
174174
capitalized[0] = toupper(capitalized[0]);
175175
return capitalized;
176176
}
177+
178+
std::string wrap_line(
179+
const std::string &line,
180+
const std::size_t left_margin,
181+
const std::size_t width)
182+
{
183+
return wrap_line(line.cbegin(), line.cend(), left_margin, width);
184+
}
185+
186+
std::string wrap_line(
187+
std::string::const_iterator left,
188+
std::string::const_iterator right,
189+
const std::size_t left_margin,
190+
const std::size_t width)
191+
{
192+
PRECONDITION(left_margin < width);
193+
194+
const std::size_t column_width = width - left_margin;
195+
const std::string margin(left_margin, ' ');
196+
197+
auto distance = std::distance(left, right);
198+
CHECK_RETURN(distance > 0);
199+
200+
std::string result;
201+
202+
if(static_cast<std::size_t>(distance) <= column_width)
203+
{
204+
result.append(margin);
205+
result.append(left, right);
206+
207+
return result;
208+
}
209+
210+
auto it_line_begin = left;
211+
212+
do
213+
{
214+
// points to the first character past the current column
215+
auto it = it_line_begin + column_width;
216+
217+
auto rit_r = std::reverse_iterator<decltype(it)>(it) - 1;
218+
auto rit_l = rit_r + column_width;
219+
220+
auto rit_space = std::find(rit_r, rit_l, ' ');
221+
222+
if(rit_space != rit_l)
223+
{
224+
auto it_space = rit_space.base() - 1;
225+
CHECK_RETURN(*it_space == ' ');
226+
227+
result.append(margin);
228+
result.append(it_line_begin, it_space);
229+
result.append("\n");
230+
231+
it_line_begin = it_space + 1;
232+
}
233+
else
234+
{
235+
// we have not found a space, thus cannot wrap this line
236+
result.clear();
237+
result.append(left, right);
238+
239+
return result;
240+
}
241+
} while(static_cast<std::size_t>(std::distance(it_line_begin, right)) >
242+
column_width);
243+
244+
result.append(margin);
245+
result.append(it_line_begin, right);
246+
247+
return result;
248+
}

src/util/string_utils.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,44 @@ std::string escape(const std::string &);
108108
/// \return string with non-alphanumeric characters escaped
109109
std::string escape_non_alnum(const std::string &to_escape);
110110

111+
/// Wrap line at spaces to not extend past the right margin, and include given
112+
/// padding with spaces to the left
113+
///
114+
/// The given string should not contain any newlines.
115+
///
116+
/// \param line: line to wrap, should not contain newlines
117+
/// \param left_margin: each line will be padded to the left with `left_margin`
118+
/// spaces
119+
/// \param width: width of the resulting text, i.e., right margin
120+
/// \return resulting string such that each line has length less or equal to
121+
/// `width`, and each line includes `left_margin` spaces to the left; if the
122+
/// given line cannot be wrapped (i.e., it cannot be broken up at spaces such
123+
/// that every resulting line fits within the margin), the given line is
124+
/// returned unchanged
125+
std::string wrap_line(
126+
const std::string &line,
127+
const std::size_t left_margin = 0,
128+
const std::size_t width = 80);
129+
130+
/// Wrap line at spaces to not extend past the right margin, and include given
131+
/// padding with spaces to the left
132+
///
133+
/// The given string should not contain any newlines.
134+
///
135+
/// \param left: iterator to beginning of string
136+
/// \param right: iterator to end of string
137+
/// \param left_margin: each line will be padded to the left with `left_margin`
138+
/// spaces
139+
/// \param width: width of the resulting text, i.e., right margin
140+
/// \return resulting string such that each line has length less or equal to
141+
/// `width`, and each line includes `left_margin` spaces to the left; if the
142+
/// given line cannot be wrapped (i.e., it cannot be broken up at spaces such
143+
/// that every resulting line fits within the margin), the given line is
144+
/// returned unchanged
145+
std::string wrap_line(
146+
const std::string::const_iterator left,
147+
const std::string::const_iterator right,
148+
const std::size_t left_margin = 0,
149+
const std::size_t width = 80);
150+
111151
#endif

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ SRC += analyses/ai/ai.cpp \
117117
util/string_utils/join_string.cpp \
118118
util/string_utils/split_string.cpp \
119119
util/string_utils/strip_string.cpp \
120+
util/string_utils/wrap_line.cpp \
120121
util/symbol_table.cpp \
121122
util/symbol.cpp \
122123
util/unicode.cpp \

unit/util/parse_options.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,12 @@ TEST_CASE("align_center_with_border", "[core][util]")
1515
align_center_with_border("test-text") ==
1616
"* * test-text * *");
1717
}
18+
19+
TEST_CASE("help_entry", "[core][util]")
20+
{
21+
REQUIRE(help_entry("--abc", "xyz", 8, 12) == " --abc xyz\n");
22+
REQUIRE(help_entry("--abc", "xxxx x", 8, 12) == " --abc xxxx\n x\n");
23+
REQUIRE(help_entry("--abc", "xx xx", 8, 12) == " --abc xx\n xx\n");
24+
REQUIRE(help_entry("--abcdef", "xyz", 8, 12) == " --abcdef\n xyz\n");
25+
REQUIRE(help_entry("--abcdefg", "xyz", 8, 12) == " --abcdefg\n xyz\n");
26+
}

unit/util/string_utils/wrap_line.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/// Author: Daniel Poetzl
2+
3+
/// \file Tests for wrap_line()
4+
5+
#include <testing-utils/use_catch.h>
6+
#include <util/string_utils.h>
7+
8+
TEST_CASE("Wrap line", "[core][util]")
9+
{
10+
SECTION("Wrap without margin")
11+
{
12+
REQUIRE(wrap_line("x", 0, 1) == "x");
13+
REQUIRE(wrap_line("x x", 0, 1) == "x\nx");
14+
REQUIRE(wrap_line("x x x", 0, 1) == "x\nx\nx");
15+
16+
REQUIRE(wrap_line("x x", 0, 2) == "x\nx");
17+
REQUIRE(wrap_line("xx xx xx", 0, 4) == "xx\nxx\nxx");
18+
19+
REQUIRE(wrap_line("xx", 0, 1) == "xx");
20+
}
21+
22+
SECTION("Wrap with margin")
23+
{
24+
REQUIRE(wrap_line("x", 1, 2) == " x");
25+
REQUIRE(wrap_line("x x", 1, 2) == " x\n x");
26+
REQUIRE(wrap_line("x x x", 1, 2) == " x\n x\n x");
27+
28+
REQUIRE(wrap_line("x", 2, 3) == " x");
29+
30+
REQUIRE(wrap_line("xx", 1, 2) == "xx");
31+
}
32+
}

0 commit comments

Comments
 (0)