Dribbler
Dribbler

Reputation: 4681

How can I use getopt with command line arguments in Swift 3?

I'm trying to use getopt with command line arguments in Swift 3. I have from Michele Dall'Agata's nice stackoverflow contribution:

let pattern = "abc:"
var buffer = Array( pattern.utf8 ).map { Int8($0) }

When I then use this code:

let option = Int( getopt( CommandLine.argc, CommandLine.arguments, buffer ) )

I get this error:

Cannot convert value of type '[String]' to expected argument type 'UnsafePointer<UnsafeMutablePointer<Int8>?>!'

for CommandLine.arguments, which I am trying to use as argv. Does anyone know the proper syntax for the 2nd argument for getopt? Thanks in advance!

Upvotes: 3

Views: 1791

Answers (2)

Martin R
Martin R

Reputation: 539815

@Hamish already answered the question and explained how to pass CommandLine.unsafeArgv to getopt() in Swift (and why).

Here is a complete self-contained example how a typical getopt loop can be implemented in Swift 3:

var aFlag = false
var bFlag = false
var cValue: String?

while case let option = getopt(CommandLine.argc, CommandLine.unsafeArgv, "abc:"), option != -1 {
    switch UnicodeScalar(CUnsignedChar(option)) {
    case "a":
        aFlag = true
    case "b":
        bFlag = true
    case "c":
        cValue = String(cString: optarg)
    default:
        fatalError("Unknown option")
    }
}

print(aFlag, bFlag, cValue ?? "?")

Remarks:

  • You can pass a Swift string (here: "abc:") directly to a C function expecting a (constant) C string, the compiler will automatically generate a temporary UTF-8 representation.
  • getopt() return either -1 (if the argument list is exhausted) or an unsigned char converted to an int. Therefore it is safe to convert the return value to CUnsignedChar (which is UInt8 in Swift).
  • while is used (abused?) with pattern matching plus an additional boolean condition to implement the typical C pattern

    while ((option = getopt(argc, argv, "abc:")) != -1) { ... }
    

    in Swift.

Upvotes: 8

Hamish
Hamish

Reputation: 80821

CommandLine.arguments gives you a friendly Swift [String] of the arguments passed – however you're looking to send the arguments straight back to C. Therefore you can simply use CommandLine.unsafeArgv instead, which will give you the actual raw value of argv passed to your program.

let option = Int( getopt( CommandLine.argc, CommandLine.unsafeArgv, buffer ) )

Upvotes: 6

Related Questions