@@ -20,7 +20,50 @@ extension FilePath {
2020 self . init ( _platformString: platformString)
2121 }
2222
23- #if !os(Windows)
23+ /// Creates a file path by copying bytes from a null-terminated platform
24+ /// string.
25+ ///
26+ /// - Note It is a precondition that `platformString` must be null-terminated.
27+ /// The absence of a null byte will trigger a runtime error.
28+ ///
29+ /// - Parameter platformString: A null-terminated platform string.
30+ @inlinable
31+ @_alwaysEmitIntoClient
32+ public init ( platformString: [ CInterop . PlatformChar ] ) {
33+ guard let _ = platformString. firstIndex ( of: 0 ) else {
34+ fatalError (
35+ " input of FilePath.init(platformString:) must be null-terminated "
36+ )
37+ }
38+ self = platformString. withUnsafeBufferPointer {
39+ FilePath ( platformString: $0. baseAddress!)
40+ }
41+ }
42+
43+ @inlinable
44+ @_alwaysEmitIntoClient
45+ @available ( * , deprecated, message: " Use FilePath.init(_ scalar: Unicode.Scalar) " )
46+ public init ( platformString: inout CInterop . PlatformChar ) {
47+ guard platformString == 0 else {
48+ fatalError (
49+ " input of FilePath.init(platformString:) must be null-terminated "
50+ )
51+ }
52+ self = FilePath ( )
53+ }
54+
55+ @inlinable
56+ @_alwaysEmitIntoClient
57+ @available ( * , deprecated, message: " Use FilePath(_: String) to create a path from a String " )
58+ public init ( platformString: String ) {
59+ if let nullLoc = platformString. firstIndex ( of: " \0 " ) {
60+ self = FilePath ( String ( platformString [ ..< nullLoc] ) )
61+ } else {
62+ self = FilePath ( platformString)
63+ }
64+ }
65+
66+ #if !os(Windows)
2467 // Note: This function should have been opaque, but it shipped as
2568 // `@_alwaysEmitIntoClient` in macOS 12/iOS 15, and now it is stuck
2669 // this way forever. (Or until the language provides a way for us
@@ -81,6 +124,59 @@ extension FilePath.Component {
81124 self . init ( _platformString: platformString)
82125 }
83126
127+ /// Creates a file path component by copying bytes from a null-terminated
128+ /// platform string. It is a precondition that a null byte indicates the end of
129+ /// the string. The absence of a null byte will trigger a runtime error.
130+ ///
131+ /// Returns `nil` if `platformString` is empty, is a root, or has more than
132+ /// one component in it.
133+ ///
134+ /// - Note It is a precondition that `platformString` must be null-terminated.
135+ /// The absence of a null byte will trigger a runtime error.
136+ ///
137+ /// - Parameter platformString: A null-terminated platform string.
138+ @inlinable
139+ @_alwaysEmitIntoClient
140+ public init ? ( platformString: [ CInterop . PlatformChar ] ) {
141+ guard let _ = platformString. firstIndex ( of: 0 ) else {
142+ fatalError (
143+ " input of FilePath.Component.init?(platformString:) must be null-terminated "
144+ )
145+ }
146+ guard let component = platformString. withUnsafeBufferPointer ( {
147+ FilePath . Component ( platformString: $0. baseAddress!)
148+ } ) else {
149+ return nil
150+ }
151+ self = component
152+ }
153+
154+ @inlinable
155+ @_alwaysEmitIntoClient
156+ @available ( * , deprecated, message: " Use FilePath.Component.init(_ scalar: Unicode.Scalar) " )
157+ public init ? ( platformString: inout CInterop . PlatformChar ) {
158+ guard platformString == 0 else {
159+ fatalError (
160+ " input of FilePath.Component.init?(platformString:) must be null-terminated "
161+ )
162+ }
163+ return nil
164+ }
165+
166+ @inlinable
167+ @_alwaysEmitIntoClient
168+ @available ( * , deprecated, message: " Use FilePath.Component.init(_: String) " )
169+ public init ? ( platformString: String ) {
170+ let string : String
171+ if let nullLoc = platformString. firstIndex ( of: " \0 " ) {
172+ string = String ( platformString [ ..< nullLoc] )
173+ } else {
174+ string = platformString
175+ }
176+ guard let component = FilePath . Component ( string) else { return nil }
177+ self = component
178+ }
179+
84180 /// Calls the given closure with a pointer to the contents of the file path
85181 /// component, represented as a null-terminated platform string.
86182 ///
@@ -117,6 +213,58 @@ extension FilePath.Root {
117213 self . init ( _platformString: platformString)
118214 }
119215
216+ /// Creates a file path root by copying bytes from a null-terminated platform
217+ /// string. It is a precondition that a null byte indicates the end of
218+ /// the string. The absence of a null byte will trigger a runtime error.
219+ ///
220+ /// Returns `nil` if `platformString` is empty or is not a root.
221+ ///
222+ /// - Note It is a precondition that `platformString` must be null-terminated.
223+ /// The absence of a null byte will trigger a runtime error.
224+ ///
225+ /// - Parameter platformString: A null-terminated platform string.
226+ @inlinable
227+ @_alwaysEmitIntoClient
228+ public init ? ( platformString: [ CInterop . PlatformChar ] ) {
229+ guard let _ = platformString. firstIndex ( of: 0 ) else {
230+ fatalError (
231+ " input of FilePath.Root.init?(platformString:) must be null-terminated "
232+ )
233+ }
234+ guard let component = platformString. withUnsafeBufferPointer ( {
235+ FilePath . Root ( platformString: $0. baseAddress!)
236+ } ) else {
237+ return nil
238+ }
239+ self = component
240+ }
241+
242+ @inlinable
243+ @_alwaysEmitIntoClient
244+ @available ( * , deprecated, message: " Use FilePath.Root.init(_ scalar: Unicode.Scalar) " )
245+ public init ? ( platformString: inout CInterop . PlatformChar ) {
246+ guard platformString == 0 else {
247+ fatalError (
248+ " input of FilePath.Root.init?(platformString:) must be null-terminated "
249+ )
250+ }
251+ return nil
252+ }
253+
254+ @inlinable
255+ @_alwaysEmitIntoClient
256+ @available ( * , deprecated, message: " Use FilePath.Root.init(_: String) " )
257+ public init ? ( platformString: String ) {
258+ let string : String
259+ if let nullLoc = platformString. firstIndex ( of: " \0 " ) {
260+ string = String ( platformString [ ..< nullLoc] )
261+ } else {
262+ string = platformString
263+ }
264+ guard let root = FilePath . Root ( string) else { return nil }
265+ self = root
266+ }
267+
120268 /// Calls the given closure with a pointer to the contents of the file path
121269 /// root, represented as a null-terminated platform string.
122270 ///
@@ -169,7 +317,7 @@ extension FilePath.Component: ExpressibleByStringLiteral {
169317 public init ( stringLiteral: String ) {
170318 guard let s = FilePath . Component ( stringLiteral) else {
171319 // TODO: static assert
172- preconditionFailure ( """
320+ fatalError ( """
173321 FilePath.Component must be created from exactly one non-root component
174322 """ )
175323 }
@@ -193,7 +341,7 @@ extension FilePath.Root: ExpressibleByStringLiteral {
193341 public init ( stringLiteral: String ) {
194342 guard let s = FilePath . Root ( stringLiteral) else {
195343 // TODO: static assert
196- preconditionFailure ( """
344+ fatalError ( """
197345 FilePath.Root must be created from a root
198346 """ )
199347 }
@@ -426,10 +574,26 @@ extension String {
426574extension FilePath {
427575 /// For backwards compatibility only. This initializer is equivalent to
428576 /// the preferred `FilePath(platformString:)`.
577+ @available ( * , deprecated, renamed: " init(platformString:) " )
429578 public init ( cString: UnsafePointer < CChar > ) {
430579 self . init ( platformString: cString)
431580 }
432581
582+ @available ( * , deprecated, renamed: " init(platformString:) " )
583+ public init ( cString: [ CChar ] ) {
584+ self . init ( platformString: cString)
585+ }
586+
587+ @available ( * , deprecated, renamed: " init(platformString:) " )
588+ public init ( cString: inout CChar ) {
589+ self . init ( platformString: & cString)
590+ }
591+
592+ @available ( * , deprecated, renamed: " init(platformString:) " )
593+ public init ( cString: String ) {
594+ self . init ( platformString: cString)
595+ }
596+
433597 /// For backwards compatibility only. This function is equivalent to
434598 /// the preferred `withPlatformString`.
435599 public func withCString< Result> (
0 commit comments