Skip to content

Commit 534eeac

Browse files
authored
Fix #1385 (#1390)
* Fix #1385 Fix for issue #1385 Ignore whitespace inside the quote Ignore quotes if seeking == Boundary.WordEnd Handle edge cases * Update CommandLineStringSplitter.cs Optimizing string operations
1 parent 7ed0823 commit 534eeac

File tree

2 files changed

+64
-54
lines changed

2 files changed

+64
-54
lines changed

src/System.CommandLine.Tests/Parsing/CommandLineStringSplitterTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,25 @@ public void It_handles_multiple_options_with_quoted_arguments()
7575
destination,
7676
"--verbose");
7777
}
78+
79+
[Fact]
80+
public void Internal_quotes_do_not_cause_string_to_be_split()
81+
{
82+
var commandLine = @"POST --raw='{""Id"":1,""Name"":""Alice""}'";
83+
84+
_splitter.Split(commandLine)
85+
.Should()
86+
.BeEquivalentTo("POST", "--raw='{Id:1,Name:Alice}'");
87+
}
88+
89+
[Fact]
90+
public void Internal_whitespaces_are_preserved_and_do_not_cause_string_to_be_split()
91+
{
92+
var commandLine = @"command --raw='{""Id"":1,""Movie Name"":""The Three Musketeers""}'";
93+
94+
_splitter.Split(commandLine)
95+
.Should()
96+
.BeEquivalentTo("command", "--raw='{Id:1,Movie Name:The Three Musketeers}'");
97+
}
7898
}
7999
}

src/System.CommandLine/Parsing/CommandLineStringSplitter.cs

Lines changed: 44 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ private enum Boundary
1313
{
1414
TokenStart,
1515
WordEnd,
16+
QuoteStart,
1617
QuoteEnd
1718
}
1819

@@ -25,52 +26,63 @@ public IEnumerable<string> Split(string commandLine)
2526
var pos = 0;
2627

2728
var seeking = Boundary.TokenStart;
28-
int? skipQuoteAtIndex = null;
29+
var seekingQuote = Boundary.QuoteStart;
2930

3031
while (pos < memory.Length)
3132
{
3233
var c = memory.Span[pos];
3334

3435
if (char.IsWhiteSpace(c))
3536
{
36-
switch (seeking)
37+
if (seekingQuote == Boundary.QuoteStart)
3738
{
38-
case Boundary.WordEnd:
39-
yield return CurrentToken();
40-
startTokenIndex = pos;
41-
seeking = Boundary.TokenStart;
42-
break;
43-
44-
case Boundary.TokenStart:
45-
startTokenIndex = pos;
46-
break;
47-
48-
case Boundary.QuoteEnd:
49-
break;
39+
switch (seeking)
40+
{
41+
case Boundary.WordEnd:
42+
yield return CurrentToken();
43+
startTokenIndex = pos;
44+
seeking = Boundary.TokenStart;
45+
break;
46+
47+
case Boundary.TokenStart:
48+
startTokenIndex = pos;
49+
break;
50+
}
5051
}
5152
}
5253
else if (c == '\"')
5354
{
54-
switch (seeking)
55+
if (seeking == Boundary.TokenStart)
5556
{
56-
case Boundary.QuoteEnd:
57-
yield return CurrentToken();
58-
startTokenIndex = pos;
59-
seeking = Boundary.TokenStart;
60-
break;
61-
62-
case Boundary.TokenStart:
63-
startTokenIndex = pos + 1;
64-
seeking = Boundary.QuoteEnd;
65-
break;
66-
67-
case Boundary.WordEnd:
68-
seeking = Boundary.QuoteEnd;
69-
skipQuoteAtIndex = pos;
70-
break;
57+
switch (seekingQuote)
58+
{
59+
case Boundary.QuoteEnd:
60+
yield return CurrentToken();
61+
startTokenIndex = pos;
62+
seekingQuote = Boundary.QuoteStart;
63+
break;
64+
65+
case Boundary.QuoteStart:
66+
startTokenIndex = pos + 1;
67+
seekingQuote = Boundary.QuoteEnd;
68+
break;
69+
}
70+
}
71+
else
72+
{
73+
switch (seekingQuote)
74+
{
75+
case Boundary.QuoteEnd:
76+
seekingQuote = Boundary.QuoteStart;
77+
break;
78+
79+
case Boundary.QuoteStart:
80+
seekingQuote = Boundary.QuoteEnd;
81+
break;
82+
}
7183
}
7284
}
73-
else if (seeking == Boundary.TokenStart)
85+
else if (seeking == Boundary.TokenStart && seekingQuote == Boundary.QuoteStart)
7486
{
7587
seeking = Boundary.WordEnd;
7688
startTokenIndex = pos;
@@ -95,29 +107,7 @@ public IEnumerable<string> Split(string commandLine)
95107

96108
string CurrentToken()
97109
{
98-
if (skipQuoteAtIndex is null)
99-
{
100-
return memory.Slice(
101-
startTokenIndex,
102-
IndexOfEndOfToken())
103-
.ToString();
104-
}
105-
else
106-
{
107-
var beforeQuote = memory.Slice(
108-
startTokenIndex,
109-
skipQuoteAtIndex.Value - startTokenIndex);
110-
111-
var indexOfCharAfterQuote = skipQuoteAtIndex.Value + 1;
112-
113-
var afterQuote = memory.Slice(
114-
indexOfCharAfterQuote,
115-
pos - skipQuoteAtIndex.Value - 1);
116-
117-
skipQuoteAtIndex = null;
118-
119-
return $"{beforeQuote}{afterQuote}";
120-
}
110+
return memory.Slice(startTokenIndex, IndexOfEndOfToken()).ToString().Replace("\"", "");
121111
}
122112

123113
int IndexOfEndOfToken() => pos - startTokenIndex;

0 commit comments

Comments
 (0)