@@ -168,16 +168,28 @@ mod imp {
168
168
}
169
169
}
170
170
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]`.
171
184
#[ cfg( target_vendor = "apple" ) ]
172
185
mod imp {
173
186
use super :: Args ;
174
187
use crate :: ffi:: CStr ;
188
+ use crate :: os:: unix:: prelude:: * ;
175
189
176
190
pub unsafe fn init ( _argc : isize , _argv : * const * const u8 ) { }
177
191
178
- #[ cfg( target_os = "macos" ) ]
179
192
pub fn args ( ) -> Args {
180
- use crate :: os:: unix:: prelude:: * ;
181
193
extern "C" {
182
194
// These functions are in crt_externs.h.
183
195
fn _NSGetArgc ( ) -> * mut libc:: c_int ;
@@ -196,82 +208,6 @@ mod imp {
196
208
} ;
197
209
Args { iter : vec. into_iter ( ) }
198
210
}
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
- }
275
211
}
276
212
277
213
#[ cfg( any( target_os = "espidf" , target_os = "vita" ) ) ]
0 commit comments