Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix OutOfMemoryException caused by description text.

	* src/NDesk.Options/NDesk.Options/Options.cs: Viktor Lundgren reported
	  that Option.Description text of `"aaa." . "a" x 64` (that is, "aaa."
	  followed by 64 "a"s) would cause GetLines() to go into an infinite
	  loop and (eventually) die from an OutOfMemoryException.  Oops.
	  Fix this, simplify the logic, and turn GetLines() into an
	  IEnumerable<string>.
	* src/NDesk.Options/Test/NDesk.Options/OptionSetTest.cs: Add tests for
	  line breaking.
  • Loading branch information...
commit d6b6f26be105d3d972b7b11823f785743df177cc 1 parent a5b66ef
@jonpryor jonpryor authored
View
69 src/NDesk.Options/NDesk.Options/Options.cs
@@ -919,12 +919,13 @@ public void WriteOptionDescriptions (TextWriter o)
o.Write (new string (' ', OptionWidth));
}
- List<string> lines = GetLines (localizer (GetDescription (p.Description)));
- o.WriteLine (lines [0]);
+ bool indent = false;
string prefix = new string (' ', OptionWidth+2);
- for (int i = 1; i < lines.Count; ++i) {
- o.Write (prefix);
- o.WriteLine (lines [i]);
+ foreach (string line in GetLines (localizer (GetDescription (p.Description)))) {
+ if (indent)
+ o.Write (prefix);
+ o.WriteLine (line);
+ indent = true;
}
}
}
@@ -1052,56 +1053,44 @@ private static string GetDescription (string description)
return sb.ToString ();
}
- private static List<string> GetLines (string description)
+ private static IEnumerable<string> GetLines (string description)
{
- List<string> lines = new List<string> ();
if (string.IsNullOrEmpty (description)) {
- lines.Add (string.Empty);
- return lines;
+ yield return string.Empty;
+ yield break;
}
- int length = 80 - OptionWidth - 2;
+ int length = 80 - OptionWidth - 1;
int start = 0, end;
do {
end = GetLineEnd (start, length, description);
- bool cont = false;
- if (end < description.Length) {
- char c = description [end];
- if (c == '-' || (char.IsWhiteSpace (c) && c != '\n'))
- ++end;
- else if (c != '\n') {
- cont = true;
- --end;
- }
- }
- lines.Add (description.Substring (start, end - start));
- if (cont) {
- lines [lines.Count-1] += "-";
- }
+ char c = description [end-1];
+ if (char.IsWhiteSpace (c))
+ --end;
+ bool writeContinuation = end != description.Length && !IsEolChar (c);
+ string line = description.Substring (start, end - start) +
+ (writeContinuation ? "-" : "");
+ yield return line;
start = end;
- if (start < description.Length && description [start] == '\n')
+ if (char.IsWhiteSpace (c))
++start;
+ length = 80 - OptionWidth - 2 - 1;
} while (end < description.Length);
- return lines;
+ }
+
+ private static bool IsEolChar (char c)
+ {
+ return !char.IsLetterOrDigit (c);
}
private static int GetLineEnd (int start, int length, string description)
{
int end = System.Math.Min (start + length, description.Length);
int sep = -1;
- for (int i = start; i < end; ++i) {
- switch (description [i]) {
- case ' ':
- case '\t':
- case '\v':
- case '-':
- case ',':
- case '.':
- case ';':
- sep = i;
- break;
- case '\n':
- return i;
- }
+ for (int i = start+1; i < end; ++i) {
+ if (description [i] == '\n')
+ return i+1;
+ if (IsEolChar (description [i]))
+ sep = i+1;
}
if (sep == -1 || end == description.Length)
return end;
View
20 src/NDesk.Options/Test/NDesk.Options/OptionSetTest.cs
@@ -291,6 +291,15 @@ public void WriteOptionDescriptions ()
{ "long-desc2",
"IWantThisDescriptionToBreakInsideAWordGeneratingAutoWordHyphenation.",
v => {} },
+ { "long-desc3",
+ "OnlyOnePeriod.AndNoWhitespaceShouldBeSupportedEvenWithLongDescriptions",
+ v => {} },
+ { "long-desc4",
+ "Lots of spaces in the middle 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 and more until the end.",
+ v => {} },
+ { "long-desc5",
+ "Lots of spaces in the middle - . - . - . - . - . - . - . - and more until the end.",
+ v => {} },
{ "h|?|help", "show help text", v => {} },
{ "version", "output version information and exit", v => {} },
{ "<>", v => {} },
@@ -311,8 +320,15 @@ public void WriteOptionDescriptions ()
expected.WriteLine (" break-on-hyphen. Also, a list:");
expected.WriteLine (" item 1");
expected.WriteLine (" item 2");
- expected.WriteLine (" --long-desc2 IWantThisDescriptionToBreakInsideAWordGenerating-");
- expected.WriteLine (" AutoWordHyphenation.");
+ expected.WriteLine (" --long-desc2 IWantThisDescriptionToBreakInsideAWordGeneratingAu-");
+ expected.WriteLine (" toWordHyphenation.");
+ expected.WriteLine (" --long-desc3 OnlyOnePeriod.");
+ expected.WriteLine (" AndNoWhitespaceShouldBeSupportedEvenWithLongDesc-");
+ expected.WriteLine (" riptions");
+ expected.WriteLine (" --long-desc4 Lots of spaces in the middle 1 2 3 4 5 6 7 8 9 0");
+ expected.WriteLine (" 1 2 3 4 5 and more until the end.");
+ expected.WriteLine (" --long-desc5 Lots of spaces in the middle - . - . - . - . - . -");
+ expected.WriteLine (" . - . - and more until the end.");
expected.WriteLine (" -h, -?, --help show help text");
expected.WriteLine (" --version output version information and exit");
Please sign in to comment.
Something went wrong with that request. Please try again.