@@ -429,8 +429,15 @@ private struct UNIXPath: Path {
429429
430430 var dirname : String {
431431#if os(Windows)
432- let dir = string. deletingLastPathComponent
433- return dir == " " ? " . " : dir
432+ let fsr : UnsafePointer < Int8 > = string. fileSystemRepresentation
433+ defer { fsr. deallocate ( ) }
434+
435+ let path : String = String ( cString: fsr)
436+ return path. withCString ( encodedAs: UTF16 . self) {
437+ let data = UnsafeMutablePointer ( mutating: $0)
438+ PathCchRemoveFileSpec ( data, path. count)
439+ return String ( decodingCString: data, as: UTF16 . self)
440+ }
434441#else
435442 // FIXME: This method seems too complicated; it should be simplified,
436443 // if possible, and certainly optimized (using UTF8View).
@@ -459,6 +466,13 @@ private struct UNIXPath: Path {
459466 }
460467
461468 var basename : String {
469+ #if os(Windows)
470+ let path : String = self . string
471+ return path. withCString ( encodedAs: UTF16 . self) {
472+ PathStripPathW ( UnsafeMutablePointer ( mutating: $0) )
473+ return String ( decodingCString: $0, as: UTF16 . self)
474+ }
475+ #else
462476 // FIXME: This method seems too complicated; it should be simplified,
463477 // if possible, and certainly optimized (using UTF8View).
464478 // Check for a special case of the root directory.
@@ -475,13 +489,17 @@ private struct UNIXPath: Path {
475489 // Otherwise, it's the string from (but not including) the last path
476490 // separator.
477491 return String ( string. suffix ( from: string. index ( after: idx) ) )
492+ #endif
478493 }
479494
480495 // FIXME: We should investigate if it would be more efficient to instead
481496 // return a path component iterator that does all its work lazily, moving
482497 // from one path separator to the next on-demand.
483498 //
484499 var components : [ String ] {
500+ #if os(Windows)
501+ return string. components ( separatedBy: " \\ " ) . filter { !$0. isEmpty }
502+ #else
485503 // FIXME: This isn't particularly efficient; needs optimization, and
486504 // in fact, it might well be best to return a custom iterator so we
487505 // don't have to allocate everything up-front. It would be backed by
@@ -493,6 +511,7 @@ private struct UNIXPath: Path {
493511 } else {
494512 return components
495513 }
514+ #endif
496515 }
497516
498517 var parentDirectory : UNIXPath {
@@ -505,7 +524,11 @@ private struct UNIXPath: Path {
505524
506525 init ( normalizingAbsolutePath path: String ) {
507526 #if os(Windows)
508- self . init ( string: path. standardizingPath)
527+ var buffer : [ WCHAR ] = Array < WCHAR > ( repeating: 0 , count: Int ( MAX_PATH + 1 ) )
528+ _ = path. withCString ( encodedAs: UTF16 . self) {
529+ PathCanonicalizeW ( & buffer, $0)
530+ }
531+ self . init ( string: String ( decodingCString: buffer, as: UTF16 . self) )
509532 #else
510533 precondition ( path. first == " / " , " Failure normalizing \( path) , absolute paths should start with '/' " )
511534
@@ -571,7 +594,11 @@ private struct UNIXPath: Path {
571594
572595 init ( normalizingRelativePath path: String ) {
573596 #if os(Windows)
574- self . init ( string: path. standardizingPath)
597+ var buffer : [ WCHAR ] = Array < WCHAR > ( repeating: 0 , count: Int ( MAX_PATH + 1 ) )
598+ _ = path. replacingOccurrences ( of: " / " , with: " \\ " ) . withCString ( encodedAs: UTF16 . self) {
599+ PathCanonicalizeW ( & buffer, $0)
600+ }
601+ self . init ( string: String ( decodingCString: buffer, as: UTF16 . self) )
575602 #else
576603 precondition ( path. first != " / " )
577604
@@ -679,6 +706,15 @@ private struct UNIXPath: Path {
679706 }
680707
681708 func suffix( withDot: Bool ) -> String ? {
709+ #if os(Windows)
710+ let ext = self . string. withCString ( encodedAs: UTF16 . self) {
711+ PathFindExtensionW ( $0)
712+ }
713+ var result = String ( decodingCString: ext!, as: UTF16 . self)
714+ guard result. length > 0 else { return nil }
715+ if !withDot { result. removeFirst ( 1 ) }
716+ return result
717+ #else
682718 // FIXME: This method seems too complicated; it should be simplified,
683719 // if possible, and certainly optimized (using UTF8View).
684720 // Find the last path separator, if any.
@@ -700,9 +736,20 @@ private struct UNIXPath: Path {
700736 }
701737 // If we get this far, there is no suffix.
702738 return nil
739+ #endif
703740 }
704741
705742 func appending( component name: String ) -> UNIXPath {
743+ #if os(Windows)
744+ var result : PWSTR ?
745+ _ = string. withCString ( encodedAs: UTF16 . self) { root in
746+ name. withCString ( encodedAs: UTF16 . self) { path in
747+ PathAllocCombine ( root, path, ULONG ( PATHCCH_ALLOW_LONG_PATHS . rawValue) , & result)
748+ }
749+ }
750+ defer { LocalFree ( result) }
751+ return PathImpl ( string: String ( decodingCString: result!, as: UTF16 . self) )
752+ #else
706753 assert ( !name. contains ( " / " ) , " \( name) is invalid path component " )
707754
708755 // Handle pseudo paths.
@@ -720,9 +767,20 @@ private struct UNIXPath: Path {
720767 } else {
721768 return PathImpl ( string: string + " / " + name)
722769 }
770+ #endif
723771 }
724772
725773 func appending( relativePath: UNIXPath ) -> UNIXPath {
774+ #if os(Windows)
775+ var result : PWSTR ?
776+ _ = string. withCString ( encodedAs: UTF16 . self) { root in
777+ relativePath. string. withCString ( encodedAs: UTF16 . self) { path in
778+ PathAllocCombine ( root, path, ULONG ( PATHCCH_ALLOW_LONG_PATHS . rawValue) , & result)
779+ }
780+ }
781+ defer { LocalFree ( result) }
782+ return PathImpl ( string: String ( decodingCString: result!, as: UTF16 . self) )
783+ #else
726784 // Both paths are already normalized. The only case in which we have
727785 // to renormalize their concatenation is if the relative path starts
728786 // with a `..` path component.
@@ -748,6 +806,7 @@ private struct UNIXPath: Path {
748806 } else {
749807 return PathImpl ( string: newPathString)
750808 }
809+ #endif
751810 }
752811}
753812
@@ -795,7 +854,11 @@ extension AbsolutePath {
795854 // Special case, which is a plain path without `..` components. It
796855 // might be an empty path (when self and the base are equal).
797856 let relComps = pathComps. dropFirst ( baseComps. count)
857+ #if os(Windows)
858+ result = RelativePath ( relComps. joined ( separator: " \\ " ) )
859+ #else
798860 result = RelativePath ( relComps. joined ( separator: " / " ) )
861+ #endif
799862 } else {
800863 // General case, in which we might well need `..` components to go
801864 // "up" before we can go "down" the directory tree.
@@ -810,7 +873,11 @@ extension AbsolutePath {
810873 // `newBaseComps` followed by what remains in `newPathComps`.
811874 var relComps = Array ( repeating: " .. " , count: newBaseComps. count)
812875 relComps. append ( contentsOf: newPathComps)
876+ #if os(Windows)
877+ result = RelativePath ( relComps. joined ( separator: " \\ " ) )
878+ #else
813879 result = RelativePath ( relComps. joined ( separator: " / " ) )
880+ #endif
814881 }
815882 assert ( base. appending ( result) == self )
816883 return result
0 commit comments