Using termios in Swift

元气小坏坏 提交于 2020-08-23 06:13:38

问题


Now that we've reached Swift 2.0, I've decided to convert my, as yet unfinished, OS X app to Swift. Making progress but I've run into some issues with using termios and could use some clarification and advice.

The termios struct is treated as a struct in Swift, no surprise there, but what is surprising is that the array of control characters in the struct is now a tuple. I was expecting it to just be an array. As you might imagine it took me a while to figure this out. Working in a Playground if I do:

var settings:termios = termios()
print(settings)

then I get the correct details printed for the struct.

In Obj-C to set the control characters you would use, say,

cfmakeraw(&settings);
settings.c_cc[VMIN] = 1;

where VMIN is a #define equal to 16 in termios.h. In Swift I have to do

cfmakeraw(&settings)
settings.c_cc.16 = 1

which works, but is a bit more opaque. I would prefer to use something along the lines of

settings.c_cc.vim = 1

instead, but can't seem to find any documentation describing the Swift "version" of termios. Does anyone know if the tuple has pre-assigned names for it's elements, or if not, is there a way to assign names after the fact? Should I just create my own tuple with named elements and then assign it to settings.c_cc?

Interestingly, despite the fact that pre-processor directives are not supposed to work in Swift, if I do

print(VMIN)
print(VTIME)

then the correct values are printed and no compiler errors are produced. I'd be interested in any clarification or comments on that. Is it a bug?

The remaining issues have to do with further configuration of the termios.

The definition of cfsetspeed is given as

func cfsetspeed(_: UnsafeMutablePointer<termios>, _: speed_t) -> Int32

and speed_t is typedef'ed as an unsigned long. In Obj-C we'd do

cfsetspeed(&settings, B38400);

but since B38400 is a #define in termios.h we can no longer do that. Has Apple set up replacement global constants for things like this in Swift, and if so, can anyone tell me where they are documented. The alternative seems to be to just plug in the raw values and lose readability, or to create my own versions of the constants previously defined in termios.h. I'm happy to go that route if there isn't a better choice.


回答1:


Let's start with your second problem, which is easier to solve. B38400 is available in Swift, it just has the wrong type. So you have to convert it explicitly:

var settings = termios()
cfsetspeed(&settings, speed_t(B38400))

Your first problem has no "nice" solution that I know of. Fixed sized arrays are imported to Swift as tuples, and – as far as I know – you cannot address a tuple element with a variable.

However,Swift preserves the memory layout of structures imported from C, as confirmed by Apple engineer Joe Groff:. Therefore you can take the address of the tuple and “rebind” it to a pointer to the element type:

var settings = termios()
withUnsafeMutablePointer(to: &settings.c_cc) { (tuplePtr) -> Void in
    tuplePtr.withMemoryRebound(to: cc_t.self, capacity: MemoryLayout.size(ofValue: settings.c_cc)) {
        $0[Int(VMIN)] = 1
    }
}

(Code updated for Swift 4+.)



来源:https://stackoverflow.com/questions/31465943/using-termios-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!