@@ -168,16 +168,28 @@ mod imp {
168168 }
169169}
170170
171+ // Use `_NSGetArgc` and `_NSGetArgv` on Apple platforms.
172+ //
173+ // Even though these have underscores in their names, they've been available
174+ // since since the first versions of both macOS and iOS, and are declared in
175+ // the header `crt_externs.h`.
176+ //
177+ // NOTE: This header was added to the iOS 13.0 SDK, which has been the source
178+ // of a great deal of confusion in the past about the availability of these
179+ // APIs.
180+ //
181+ // NOTE(madsmtm): This has not strictly been verified to not cause App Store
182+ // rejections; if this is found to be the case, the previous implementation
183+ // of this used `[[NSProcessInfo processInfo] arguments]`.
171184#[ cfg( target_vendor = "apple" ) ]
172185mod imp {
173186 use super :: Args ;
174187 use crate :: ffi:: CStr ;
188+ use crate :: os:: unix:: prelude:: * ;
175189
176190 pub unsafe fn init ( _argc : isize , _argv : * const * const u8 ) { }
177191
178- #[ cfg( target_os = "macos" ) ]
179192 pub fn args ( ) -> Args {
180- use crate :: os:: unix:: prelude:: * ;
181193 extern "C" {
182194 // These functions are in crt_externs.h.
183195 fn _NSGetArgc ( ) -> * mut libc:: c_int ;
@@ -196,82 +208,6 @@ mod imp {
196208 } ;
197209 Args { iter : vec. into_iter ( ) }
198210 }
199-
200- // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
201- // and use underscores in their names - they're most probably
202- // are considered private and therefore should be avoided.
203- // Here is another way to get arguments using the Objective-C
204- // runtime.
205- //
206- // In general it looks like:
207- // res = Vec::new()
208- // let args = [[NSProcessInfo processInfo] arguments]
209- // for i in (0..[args count])
210- // res.push([args objectAtIndex:i])
211- // res
212- #[ cfg( not( target_os = "macos" ) ) ]
213- pub fn args ( ) -> Args {
214- use crate :: ffi:: { c_char, c_void, OsString } ;
215- use crate :: mem;
216- use crate :: str;
217-
218- type Sel = * const c_void ;
219- type NsId = * const c_void ;
220- type NSUInteger = usize ;
221-
222- extern "C" {
223- fn sel_registerName ( name : * const c_char ) -> Sel ;
224- fn objc_getClass ( class_name : * const c_char ) -> NsId ;
225-
226- // This must be transmuted to an appropriate function pointer type before being called.
227- fn objc_msgSend ( ) ;
228- }
229-
230- const MSG_SEND_PTR : unsafe extern "C" fn ( ) = objc_msgSend;
231- const MSG_SEND_NO_ARGUMENTS_RETURN_PTR : unsafe extern "C" fn ( NsId , Sel ) -> * const c_void =
232- unsafe { mem:: transmute ( MSG_SEND_PTR ) } ;
233- const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER : unsafe extern "C" fn (
234- NsId ,
235- Sel ,
236- ) -> NSUInteger = unsafe { mem:: transmute ( MSG_SEND_PTR ) } ;
237- const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR : unsafe extern "C" fn (
238- NsId ,
239- Sel ,
240- NSUInteger ,
241- )
242- -> * const c_void = unsafe { mem:: transmute ( MSG_SEND_PTR ) } ;
243-
244- let mut res = Vec :: new ( ) ;
245-
246- unsafe {
247- let process_info_sel = sel_registerName ( c"processInfo" . as_ptr ( ) ) ;
248- let arguments_sel = sel_registerName ( c"arguments" . as_ptr ( ) ) ;
249- let count_sel = sel_registerName ( c"count" . as_ptr ( ) ) ;
250- let object_at_index_sel = sel_registerName ( c"objectAtIndex:" . as_ptr ( ) ) ;
251- let utf8string_sel = sel_registerName ( c"UTF8String" . as_ptr ( ) ) ;
252-
253- let klass = objc_getClass ( c"NSProcessInfo" . as_ptr ( ) ) ;
254- // `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
255- let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR ( klass, process_info_sel) ;
256-
257- // `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
258- let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR ( info, arguments_sel) ;
259-
260- let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER ( args, count_sel) ;
261- for i in 0 ..cnt {
262- // `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
263- let ns_string =
264- MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR ( args, object_at_index_sel, i) ;
265- // The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
266- let utf_c_str: * const c_char =
267- MSG_SEND_NO_ARGUMENTS_RETURN_PTR ( ns_string, utf8string_sel) . cast ( ) ;
268- let bytes = CStr :: from_ptr ( utf_c_str) . to_bytes ( ) ;
269- res. push ( OsString :: from ( str:: from_utf8 ( bytes) . unwrap ( ) ) )
270- }
271- }
272-
273- Args { iter : res. into_iter ( ) }
274- }
275211}
276212
277213#[ cfg( any( target_os = "espidf" , target_os = "vita" ) ) ]
0 commit comments