Skip to content
Snippets Groups Projects
Commit 9a8b2601 authored by George Nachman's avatar George Nachman
Browse files

Revamp command line parsing. Now it supports single quotes and has fewer bugs. Issue 5979

parent d5fd87dc
No related branches found
No related tags found
No related merge requests found
Loading
Loading
@@ -264,4 +264,165 @@
XCTAssertFalse([@"ABC" stringMatchesGlobPattern:@"a*x" caseSensitive:NO]);
}
 
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_Basic {
NSString *s = @"foo bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_BackslashEscapesMidlineSpace {
NSString *s = @"foo\\ bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_BackslashEscapesLeadingTrailingSpace {
NSString *s = @"\\ foo bar\\ ";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @" foo", @"bar " ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_BackslashEscapesSingleQuote {
NSString *s = @"foo\\' bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo'", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_BackslashEscapesDoubleQuote {
NSString *s = @"foo\\\" bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo\"", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_BackslashEscapesBackslash {
NSString *s = @"foo\\\\ bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo\\", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_CustomEscapes {
NSString *s = @"foo \\1";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{ @'1': @"bar" }];
NSArray<NSString *> *expected = @[ @"foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_QuotedCustomEscapes {
NSString *s = @"foo \"\\1\"";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{ @'1': @"bar" }];
NSArray<NSString *> *expected = @[ @"foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_DoubleQuotesWithSpace {
NSString *s = @"foo\" \"bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_DoubleQuotesWithSingleQuote {
NSString *s = @"foo\"'\"bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo'bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_DoubleQuotesWithEscapedDoubleQuote {
NSString *s = @"foo\"\\\"\"bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo\"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_SingleQuotesWithSpace {
NSString *s = @"foo' 'bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_SingleQuotesWithDoubleQuote {
NSString *s = @"foo'\"'bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo\"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_SingleQuotesWithEscapedSingleQuote {
NSString *s = @"foo'\\''bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo'bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_MismatchedDoubleQuotes {
NSString *s = @"foo\" bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_MismatchedSingleQuotes {
NSString *s = @"foo' bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_OrphanBackslash {
NSString *s = @"foo bar\\";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_ExpandTilde {
NSString *s = @"~/foo bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
XCTAssertEqual(actual.count, 2);
XCTAssertFalse([actual[0] hasPrefix:@"~"]);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_MidlineTilde {
NSString *s = @"fo~o bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"fo~o", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_EscapedTilde {
NSString *s = @"\\~/foo bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"~/foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_DoubleQuotedTilde {
NSString *s = @"\"~/foo\" bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"~/foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_SingleQuotedTilde {
NSString *s = @"'~/foo' bar";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"~/foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
- (void)testComponentsBySplittingStringWithQuotesAndBackslashEscaping_TrimSpace {
NSString *s = @" foo bar ";
NSArray<NSString *> *actual = [s componentsBySplittingStringWithQuotesAndBackslashEscaping:@{}];
NSArray<NSString *> *expected = @[ @"foo", @"bar" ];
XCTAssertEqualObjects(actual, expected);
}
@end
Loading
Loading
@@ -117,6 +117,8 @@ int decode_utf8_char(const unsigned char * restrict datap,
fromCharacterSet:(NSCharacterSet *)charSet
charsTakenFromPrefix:(int*)charsTakenFromPrefixPtr;
 
- (NSArray *)componentsBySplittingStringWithQuotesAndBackslashEscaping:(NSDictionary *)escapes;
// This handles a few kinds of URLs, after trimming whitespace from the beginning and end:
// 1. Well formed strings like:
// "http://example.com/foo?query#fragment"
Loading
Loading
Loading
Loading
@@ -157,11 +157,12 @@
- (NSArray *)componentsBySplittingStringWithQuotesAndBackslashEscaping:(NSDictionary *)escapes {
NSMutableArray *result = [NSMutableArray array];
 
int inQuotes = 0; // Are we inside double quotes?
BOOL inSingleQuotes = NO;
BOOL inDoubleQuotes = NO; // Are we inside double quotes?
BOOL escape = NO; // Should this char be escaped?
NSMutableString *currentValue = [NSMutableString string];
BOOL valueStarted = NO;
BOOL firstCharacterNotQuotedOrEscaped = NO;
BOOL isFirstCharacterOfWord = YES;
BOOL firstCharacterOfThisWordWasQuoted = YES;
 
for (NSInteger i = 0; i <= self.length; i++) {
unichar c;
Loading
Loading
@@ -174,6 +175,7 @@
} else {
// Signifies end-of-string.
c = 0;
escape = NO;
}
 
if (c == '\\' && !escape) {
Loading
Loading
@@ -182,7 +184,7 @@
}
 
if (escape) {
valueStarted = YES;
isFirstCharacterOfWord = NO;
escape = NO;
if (escapes[@(c)]) {
[currentValue appendString:escapes[@(c)]];
Loading
Loading
@@ -192,38 +194,43 @@
continue;
}
 
if (c == '"') {
inQuotes = !inQuotes;
valueStarted = YES;
if (c == '"' && !inSingleQuotes) {
inDoubleQuotes = !inDoubleQuotes;
isFirstCharacterOfWord = NO;
continue;
}
if (c == '\'' && !inDoubleQuotes) {
inSingleQuotes = !inSingleQuotes;
isFirstCharacterOfWord = NO;
continue;
}
if (c == 0) {
inQuotes = NO;
inSingleQuotes = NO;
inDoubleQuotes = NO;
}
 
// Treat end-of-string like whitespace.
BOOL isWhitespace = (c == 0 || iswspace(c));
 
if (!inQuotes && isWhitespace) {
if (valueStarted) {
if (firstCharacterNotQuotedOrEscaped) {
if (!inSingleQuotes && !inDoubleQuotes && isWhitespace) {
if (!isFirstCharacterOfWord) {
if (!firstCharacterOfThisWordWasQuoted) {
[result addObject:[currentValue stringByExpandingTildeInPath]];
} else {
[result addObject:currentValue];
}
currentValue = [NSMutableString string];
firstCharacterNotQuotedOrEscaped = NO;
valueStarted = NO;
firstCharacterOfThisWordWasQuoted = YES;
isFirstCharacterOfWord = YES;
}
// If !valueStarted, this char is meaningless whitespace.
// Ignore whitespace not in quotes or escaped.
continue;
}
 
if (!valueStarted) {
firstCharacterNotQuotedOrEscaped = !inQuotes;
if (isFirstCharacterOfWord) {
firstCharacterOfThisWordWasQuoted = inDoubleQuotes || inSingleQuotes;
isFirstCharacterOfWord = NO;
}
valueStarted = YES;
[currentValue appendFormat:@"%C", c];
}
 
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment