@@ -50,36 +50,53 @@ extension String {
5050 public func spm_shellEscaped( ) -> String {
5151
5252 // If all the characters in the string are in the allow list then no need to escape.
53- guard let pos = utf8. firstIndex ( where: { !inShellAllowlist( $0) } ) else {
53+ guard utf8. contains ( where: { !inShellAllowlist( $0) } ) else {
5454 return self
5555 }
5656
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)
67- }
57+ #if os(Windows)
58+ var quoted = " \" "
59+ var unquoted = self . unicodeScalars
60+ while !unquoted. isEmpty {
61+ guard let firstNonBackslash = unquoted. firstIndex ( where: { $0 != " \\ " } ) else {
62+ let backslashCount = unquoted. count
63+ quoted. append ( String ( repeating: " \\ " , count: backslashCount * 2 ) )
64+ break
65+ }
66+ let backslashCount = unquoted. distance (
67+ from: unquoted. startIndex, to: firstNonBackslash)
68+ if unquoted [ firstNonBackslash] == " \" " {
69+ quoted. append ( String ( repeating: " \\ " , count: backslashCount * 2 + 1 ) )
70+ } else {
71+ quoted. append ( String ( repeating: " \\ " , count: backslashCount) )
72+ }
73+ quoted. append ( String ( unquoted [ firstNonBackslash] ) )
74+ unquoted. removeFirst ( backslashCount + 1 )
75+ }
76+ quoted. append ( " \" " )
77+ return quoted
78+ #else
79+ let quoteCharacter : Character = " ' "
80+ let escapedQuoteCharacter = " ' \\ '' "
81+ // If there are no quote characters then we can just wrap the string within the quotes.
82+ guard let quotePos = utf8. firstIndex ( of: quoteCharacter. asciiValue!) else {
83+ return String ( quoteCharacter) + self + String( quoteCharacter)
84+ }
6885
69- // Otherwise iterate and escape all the single quotes.
70- var newString = String ( quoteCharacter) + String( self [ ..< quotePos] )
86+ // Otherwise iterate and escape all the single quotes.
87+ var newString = String ( quoteCharacter) + String( self [ ..< quotePos] )
7188
72- for char in self [ quotePos... ] {
73- if char == quoteCharacter {
74- newString += escapedQuoteCharacter
75- } else {
76- newString += String ( char)
89+ for char in self [ quotePos... ] {
90+ if char == quoteCharacter {
91+ newString += escapedQuoteCharacter
92+ } else {
93+ newString += String ( char)
94+ }
7795 }
78- }
79-
80- newString += String ( quoteCharacter)
8196
82- return newString
97+ newString += String ( quoteCharacter)
98+ return newString
99+ #endif
83100 }
84101
85102 /// Shell escapes the current string. This method is mutating version of shellEscaped().
0 commit comments