Skip to content

Commit c4fbd13

Browse files
authored
Merge pull request #58 from troughton/patch-2
Update StringConversions for Windows shell escaping
2 parents 2e45582 + ba9373b commit c4fbd13

File tree

1 file changed

+22
-10
lines changed

1 file changed

+22
-10
lines changed

Sources/TSCBasic/StringConversions.swift

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift.org open source project
33

4-
Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
4+
Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See http://swift.org/LICENSE.txt for license information
@@ -15,6 +15,11 @@
1515
///
1616
/// - Returns: True if shell escaping is not needed.
1717
private func inShellWhitelist(_ codeUnit: UInt8) -> Bool {
18+
#if os(Windows)
19+
if codeUnit == UInt8(ascii: "\\") {
20+
return true
21+
}
22+
#endif
1823
switch codeUnit {
1924
case UInt8(ascii: "a")...UInt8(ascii: "z"),
2025
UInt8(ascii: "A")...UInt8(ascii: "Z"),
@@ -38,7 +43,7 @@ private func inShellWhitelist(_ codeUnit: UInt8) -> Bool {
3843
extension String {
3944

4045
/// Creates a shell escaped string. If the string does not need escaping, returns the original string.
41-
/// Otherwise escapes using single quotes. For example:
46+
/// Otherwise escapes using single quotes on Unix and double quotes on Windows. For example:
4247
/// hello -> hello, hello$world -> 'hello$world', input A -> 'input A'
4348
///
4449
/// - Returns: Shell escaped string.
@@ -49,23 +54,30 @@ extension String {
4954
return self
5055
}
5156

52-
// If there are no single quotes then we can just wrap the string around single quotes.
53-
guard let singleQuotePos = utf8[pos...].firstIndex(of: UInt8(ascii: "'")) else {
54-
return "'" + self + "'"
57+
#if os(Windows)
58+
let quoteCharacter: Character = "\""
59+
let escapedQuoteCharacter = "\"\""
60+
#else
61+
let quoteCharacter: Character = "'"
62+
let escapedQuoteCharacter = "'\\''"
63+
#endif
64+
// If there are no quote characters then we can just wrap the string within the quotes.
65+
guard let quotePos = utf8[pos...].firstIndex(of: quoteCharacter.asciiValue!) else {
66+
return String(quoteCharacter) + self + String(quoteCharacter)
5567
}
5668

5769
// Otherwise iterate and escape all the single quotes.
58-
var newString = "'" + String(self[..<singleQuotePos])
70+
var newString = String(quoteCharacter) + String(self[..<quotePos])
5971

60-
for char in self[singleQuotePos...] {
61-
if char == "'" {
62-
newString += "'\\''"
72+
for char in self[quotePos...] {
73+
if char == quoteCharacter {
74+
newString += escapedQuoteCharacter
6375
} else {
6476
newString += String(char)
6577
}
6678
}
6779

68-
newString += "'"
80+
newString += String(quoteCharacter)
6981

7082
return newString
7183
}

0 commit comments

Comments
 (0)