Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read user input or stdin in Swift for Linux?

Tags:

linux

swift

How to read user input or character stream from standard input in Swift for Linux?

like image 431
masoud Avatar asked Dec 06 '15 10:12

masoud


2 Answers

readLine() works on Ubuntu 15:

[Readline] Returns Characters read from standard input through the end of the current line or until EOF is reached, or nil if EOF has already been reached.

Example:

print("\nEnter your name:\n")
if let name = readLine() {
    print("\nHello \(name)!\n")
}

ed@swiftux:~/Swift/Scripts$ ./testReadline

Enter your name:

Eric

Hello Eric!

readline() also works with | (the pipe):

ed@swiftux:~/Swift/Scripts$ echo "Mike" | ./testReadline

Enter your name:

Hello Mike!


I've also tried the classic way with NSFileHandle but it's not implemented yet:

fatal error: availableData is not yet implemented: file Foundation/NSObjCRuntime.swift

like image 77
Eric Aya Avatar answered Nov 03 '22 19:11

Eric Aya


If you import Glibc on Linux and Darwin.C on macOS, then you can read one line at a time using the getline function.

This requires a wee bit of c interop, but you can wrap it up to present a more Swifty interface. For instance, the following function returns a generator that iterates over lines read from a file stream:

#if os(Linux)
  import Glibc
#else
  import Darwin.C
#endif

func lineGenerator(file:UnsafeMutablePointer<FILE>) -> AnyIterator<String>
{
  return AnyIterator { () -> String? in
    var line:UnsafeMutablePointer<CChar>? = nil
    var linecap:Int = 0
    defer { free(line) }
    let charactersWritten = getline(&line, &linecap, file)

    if charactersWritten > 0 {
      guard let line = line else { return nil }
      return String(validatingUTF8: line)
    }
    else {
      return nil
    }
  }
}

This works on Swift 3. You can find a small swiftecho example project which exercises this from the command line.

like image 37
algal Avatar answered Nov 03 '22 20:11

algal