@@ -22,8 +22,24 @@ import WinSDK
22
22
23
23
internal import _FoundationCShims
24
24
25
+ extension StringProtocol {
26
+ fileprivate func _standardizingSlashes( ) -> String {
27
+ #if os(Windows)
28
+ // The string functions below all assume that the path separator is a forward slash
29
+ // Standardize the path to use forward slashes before processing for consistency
30
+ return self . replacing ( . _backslash, with: . _slash)
31
+ #else
32
+ return String ( self )
33
+ #endif
34
+ }
35
+ }
36
+
25
37
extension String {
26
38
internal func deletingLastPathComponent( ) -> String {
39
+ _standardizingSlashes ( ) . _deletingLastPathComponent ( )
40
+ }
41
+
42
+ private func _deletingLastPathComponent( ) -> String {
27
43
let lastSlash = self . lastIndex { $0 == " / " }
28
44
guard let lastSlash else {
29
45
// No slash
@@ -50,6 +66,10 @@ extension String {
50
66
}
51
67
52
68
internal func appendingPathComponent( _ component: String ) -> String {
69
+ _standardizingSlashes ( ) . _appendingPathComponent ( component)
70
+ }
71
+
72
+ private func _appendingPathComponent( _ component: String ) -> String {
53
73
var result = self
54
74
if !component. isEmpty {
55
75
var needsSlash = true
@@ -103,6 +123,10 @@ extension String {
103
123
}
104
124
105
125
internal var lastPathComponent : String {
126
+ _standardizingSlashes ( ) . _lastPathComponent
127
+ }
128
+
129
+ private var _lastPathComponent : String {
106
130
let lastSlash = self . lastIndex { $0 == " / " }
107
131
guard let lastSlash else {
108
132
// No slash, just return self
@@ -170,11 +194,11 @@ extension String {
170
194
return false
171
195
}
172
196
if let lastDot = pathExtension. utf8. lastIndex ( of: UInt8 ( ascii: " . " ) ) {
173
- let beforeDot = pathExtension [ ..< lastDot] . unicodeScalars
174
- let afterDot = pathExtension [ pathExtension. index ( after: lastDot) ... ] . unicodeScalars
197
+ let beforeDot = pathExtension [ ..< lastDot] . _standardizingSlashes ( ) . unicodeScalars
198
+ let afterDot = pathExtension [ pathExtension. index ( after: lastDot) ... ] . _standardizingSlashes ( ) . unicodeScalars
175
199
return beforeDot. allSatisfy { $0 != " / " } && afterDot. allSatisfy { !String. invalidExtensionScalars. contains ( $0) }
176
200
} else {
177
- return pathExtension. unicodeScalars. allSatisfy { !String. invalidExtensionScalars. contains ( $0) }
201
+ return pathExtension. _standardizingSlashes ( ) . unicodeScalars. allSatisfy { !String. invalidExtensionScalars. contains ( $0) }
178
202
}
179
203
}
180
204
@@ -202,6 +226,10 @@ extension String {
202
226
}
203
227
204
228
internal func merging( relativePath: String ) -> String {
229
+ _standardizingSlashes ( ) . _merging ( relativePath: relativePath)
230
+ }
231
+
232
+ private func _merging( relativePath: String ) -> String {
205
233
guard relativePath. utf8. first != UInt8 ( ascii: " / " ) else {
206
234
return relativePath
207
235
}
@@ -212,6 +240,10 @@ extension String {
212
240
}
213
241
214
242
internal var removingDotSegments : String {
243
+ _standardizingSlashes ( ) . _removingDotSegments
244
+ }
245
+
246
+ private var _removingDotSegments : String {
215
247
let input = self . utf8
216
248
guard !input. isEmpty else {
217
249
return " "
@@ -440,18 +472,16 @@ extension String {
440
472
441
473
// From swift-corelibs-foundation's NSTemporaryDirectory. Internal for now, pending a better public API.
442
474
internal static var temporaryDirectoryPath : String {
443
- #if os(Windows)
444
- let validPathSeps : [ Character ] = [ " \\ " , " / " ]
445
- #else
446
- let validPathSeps : [ Character ] = [ " / " ]
447
- #endif
448
-
449
475
func normalizedPath( with path: String ) -> String {
450
- if validPathSeps. contains ( where: { path. hasSuffix ( String ( $0) ) } ) {
476
+ guard path. utf8. last != . _slash else {
477
+ return path
478
+ }
479
+ #if os(Windows)
480
+ guard path. utf8. last != . _backslash else {
451
481
return path
452
- } else {
453
- return path + String( validPathSeps. last!)
454
482
}
483
+ #endif
484
+ return path + " / "
455
485
}
456
486
#if os(Windows)
457
487
let cchLength : DWORD = GetTempPathW ( 0 , nil )
@@ -547,7 +577,7 @@ extension String {
547
577
static var NETWORK_PREFIX : String { #"\\"# }
548
578
549
579
private var _standardizingPath : String {
550
- var result = _transmutingCompressingSlashes ( ) . _droppingTrailingSlashes
580
+ var result = _standardizingSlashes ( ) . _transmutingCompressingSlashes ( ) . _droppingTrailingSlashes
551
581
let postNetStart = if result. starts ( with: String . NETWORK_PREFIX) {
552
582
result. firstIndex ( of: " / " ) ?? result. endIndex
553
583
} else {
@@ -558,7 +588,7 @@ extension String {
558
588
result = resolved
559
589
}
560
590
561
- result = result. removingDotSegments
591
+ result = result. _removingDotSegments
562
592
563
593
// Automounted paths need to be stripped for various flavors of paths
564
594
let exclusionList = [ " /Applications " , " /Library " , " /System " , " /Users " , " /Volumes " , " /bin " , " /cores " , " /dev " , " /opt " , " /private " , " /sbin " , " /usr " ]
@@ -584,6 +614,10 @@ extension String {
584
614
585
615
// _NSPathComponents
586
616
var pathComponents : [ String ] {
617
+ _standardizingSlashes ( ) . _pathComponents
618
+ }
619
+
620
+ private var _pathComponents : [ String ] {
587
621
var components = self . components ( separatedBy: " / " ) . filter { !$0. isEmpty }
588
622
if self . first == " / " {
589
623
components. insert ( " / " , at: 0 )
@@ -596,6 +630,10 @@ extension String {
596
630
597
631
#if !NO_FILESYSTEM
598
632
var abbreviatingWithTildeInPath : String {
633
+ _standardizingSlashes ( ) . _abbreviatingWithTildeInPath
634
+ }
635
+
636
+ private var _abbreviatingWithTildeInPath : String {
599
637
guard !self . isEmpty && self != " / " else { return self }
600
638
let homeDir = String . homeDirectoryPath ( )
601
639
guard self . starts ( with: homeDir) else { return self }
@@ -605,6 +643,10 @@ extension String {
605
643
}
606
644
607
645
var expandingTildeInPath : String {
646
+ _standardizingSlashes ( ) . _expandingTildeInPath
647
+ }
648
+
649
+ private var _expandingTildeInPath : String {
608
650
guard self . first == " ~ " else { return self }
609
651
var user : String ? = nil
610
652
let firstSlash = self . firstIndex ( of: " / " ) ?? self . endIndex
@@ -781,6 +823,7 @@ extension StringProtocol {
781
823
}
782
824
}
783
825
826
+ // Internal for testing purposes
784
827
internal func _hasDotDotComponent( ) -> Bool {
785
828
let input = self . utf8
786
829
guard input. count >= 2 else {
0 commit comments