@@ -16,6 +16,45 @@ import Darwin
16
16
import Glibc
17
17
#endif
18
18
19
+ func argumentNeedsQuoting( _ argument: String ) -> Bool {
20
+ if argument. isEmpty { return false }
21
+ let chars : Set < Character > = Set ( " \t \" &'()*<> \\ `^| \n " )
22
+ return argument. firstIndex ( where: { chars. contains ( $0) } ) != argument. endIndex
23
+ }
24
+
25
+ func quoteArgument( _ argument: String ) -> String {
26
+ #if os(Windows)
27
+ var unquoted : Substring = argument [ ... ]
28
+ var quoted : String = " \" "
29
+ while !unquoted. isEmpty {
30
+ guard let firstNonBS = unquoted. firstIndex ( where: { $0 != " \\ " } ) else {
31
+ // The rest of the string is backslashes. Escape all of them and exit.
32
+ ( 0 ..< ( 2 * unquoted. count) ) . forEach { _ in quoted += " \\ " }
33
+ break
34
+ }
35
+
36
+ let bsCount = unquoted. distance ( from: unquoted. startIndex, to: firstNonBS)
37
+ if unquoted [ firstNonBS] == " \" " {
38
+ // This is an embedded quote. Escape all preceding backslashes, then
39
+ // add one additional backslash to escape the quote.
40
+ ( 0 ..< ( 2 * bsCount + 1 ) ) . forEach { _ in quoted += " \\ " }
41
+ quoted += " \" "
42
+ } else {
43
+ // This is just a normal character. Don't escape any of the preceding
44
+ // backslashes, just append them as they are and then append the
45
+ // character.
46
+ ( 0 ..< bsCount) . forEach { _ in quoted += " \\ " }
47
+ quoted += " \( unquoted [ firstNonBS] ) "
48
+ }
49
+
50
+ unquoted = unquoted. dropFirst ( bsCount + 1 )
51
+ }
52
+ return quoted + " \" "
53
+ #else
54
+ return " ' " + argument + " ' "
55
+ #endif
56
+ }
57
+
19
58
#if canImport(Darwin) || os(Linux) || os(Android) || os(OpenBSD)
20
59
// Adapted from llvm::sys::commandLineFitsWithinSystemLimits.
21
60
func commandLineFitsWithinSystemLimits( path: String , args: [ String ] ) -> Bool {
@@ -49,45 +88,10 @@ func commandLineFitsWithinSystemLimits(path: String, args: [String]) -> Bool {
49
88
#elseif os(Windows)
50
89
func commandLineFitsWithinSystemLimits( path: String , args: [ String ] ) -> Bool {
51
90
func flattenWindowsCommandLine( _ arguments: [ String ] ) -> String {
52
- func argNeedsQuoting( _ argument: String ) -> Bool {
53
- if argument. isEmpty { return false }
54
- let chars : Set < Character > = Set ( " \t \" &'()*<> \\ `^| \n " )
55
- return argument. firstIndex ( where: { chars. contains ( $0) } ) != argument. endIndex
56
- }
57
-
58
- func quote( _ argument: String ) -> String {
59
- var unquoted : Substring = argument [ ... ]
60
- var quoted : String = " \" "
61
- while !unquoted. isEmpty {
62
- guard let firstNonBS = unquoted. firstIndex ( where: { $0 != " \\ " } ) else {
63
- // The rest of the string is backslashes. Escape all of them and exit.
64
- ( 0 ..< ( 2 * unquoted. count) ) . forEach { _ in quoted += " \\ " }
65
- break
66
- }
67
-
68
- let bsCount = unquoted. distance ( from: unquoted. startIndex, to: firstNonBS)
69
- if unquoted [ firstNonBS] == " \" " {
70
- // This is an embedded quote. Escape all preceding backslashes, then
71
- // add one additional backslash to escape the quote.
72
- ( 0 ..< ( 2 * bsCount + 1 ) ) . forEach { _ in quoted += " \\ " }
73
- quoted += " \" "
74
- } else {
75
- // This is just a normal character. Don't escape any of the preceding
76
- // backslashes, just append them as they are and then append the
77
- // character.
78
- ( 0 ..< bsCount) . forEach { _ in quoted += " \\ " }
79
- quoted += " \( unquoted [ firstNonBS] ) "
80
- }
81
-
82
- unquoted = unquoted. dropFirst ( bsCount + 1 )
83
- }
84
- return quoted + " \" "
85
- }
86
-
87
91
var quoted : String = " "
88
92
for arg in arguments {
89
- if argNeedsQuoting ( arg) {
90
- quoted += quote ( arg)
93
+ if argumentNeedsQuoting ( arg) {
94
+ quoted += quoteArgument ( arg)
91
95
} else {
92
96
quoted += arg
93
97
}
0 commit comments