what I'm trying to achieve here is getting the ioctl number for ejecting a disk, which I already do in my Bridging Header:
#define DKIOCEJECT _IO('d', 21)
NSUInteger IOEJECT = DKIOCEJECT;
...and that indeed does work for creating an ioctl
request, what I'm trying to do is just that but in Swift rather than having to use a Bridging Header
In C, I'd usually put something like this to get an ioctl
number:
#define DKIOCEJECT _IO('d', 21)
The above would usually return an ioctl
number, How can I do something similar but in Swift?
Here are all the preprocessor macros:
#define _IO(g, n) _IOC(IOC_VOID, (g), (n), 0)
#define _IOC(inout, group, num, len) \ (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */
define IOC_VOID (__uint32_t)0x20000000
CodePudding user response:
Given that the _IO
macro resolves to a single integer constant, we can follow the preprocessor's logic to reimplement it:
#define DKIOCEJECT _IO('d', 21)
#define _IO(g, n) _IOC(IOC_VOID, (g), (n), 0)
#define _IOC(inout, group, num, len) (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
#define IOC_VOID (unsigned long)0x20000000
#define IOCPARM_MASK 0x1fff
Therefore....
DKIOCEJECT == _IO(g: 'd', n: 21)
== _IOC(IOC_VOID, ('d'), (21), 0)
== (IOC_VOID | ((0 & IOCPARM_MASK) << 16) | (('d') << 8) | (21))
== ( 0x20000000 | (0 << 16) | (('d') << 8) | (21) )
== ( 0x20000000 | 0 | (0x64 << 8) | 21 )
== ( 0x20000000 | 0x6400 | 0x15 )
== 0x20006415
// For reference:
'd' == 0x64 // asciitable.com
21 == 0x15
In Swift as a constant from a literal:
enum MyIoctrlNumbers {
static let DKIOCEJECT: UInt = 0x20006415
}
Swift doesn't support C -style constexpr
-expressions, but if you're okay with a runtime-generated static
value, then try this:
import Foundation
func getIoctrlNumber( group: Character, n: UInt ) -> UInt {
let IOC_VOID: UInt = 0x20000000;
let g : UInt = UInt( UInt( group.asciiValue! ) << 8 );
return IOC_VOID | g | n;
}
let asInt = getIoctrlNumber( group: "d", n: 21 );
let asDec = String( asInt, radix: 10 );
let asHex = String( asInt, radix: 16 );
print( "DKIOCEJECT == " asDec );
print( "DKIOCEJECT == 0x" asHex );
Gives me this output:
Swift version 5.5.1 (swift-5.5.1-RELEASE) 02:11:39 4s
Target: x86_64-unknown-linux-gnu
DKIOCEJECT == 536896533
DKIOCEJECT == 0x20006415
Apparently Swift does let you populate an enum
's values with runtime-init static
values (not just consts/literals!), so you could have it like so:
enum MyIoctrlNumbers {
static let DKIOCEJECT: UInt = getIoctrlNumber( group: "d", n: 21 );
static let ANOTHER : Uint = getIoctrlNumber( group: "e", n: 22 );
}
and this works fine:
print( "DKIOCEJECT == " String( MyIoctrlNumbers.DKIOCEJECT, radix: 10 ));
print( "DKIOCEJECT == 0x" String( MyIoctrlNumbers.DKIOCEJECT, radix: 16 ) );
Gives me this output:
Swift version 5.5.1 (swift-5.5.1-RELEASE) 02:13:31 6s
Target: x86_64-unknown-linux-gnu
DKIOCEJECT == 536896533
DKIOCEJECT == 0x20006415