Read all lines from stdin, Haxe command-line utility program

I want to read input lines from stdin, possibly piped from some other program like cat (just like a regular command-line utility that can go in a pipeline). I’ve come up with this:

class Main {
    public static function main() {
        var lines = Sys.stdin().readAll().toString().split("\n");
        // Then do something with them...
        //lines.whatev(...);
        for (line in lines) {
            Sys.println("> " + line);
        }
    }
}

and it works (I’m using the cpp target), but is that the customary way to do it in Haxe? For example:

  • .readAll() returns Bytes.toString() guesses the encoding?

  • maybe a platform-agnostic way to do .split("\n")? Or a .splitLines() function somewhere?

  • to read, could I instead be looping on a .readLine() call? Could you please provide an example?

Thanks!

Reading from stdin is similar in most languages – it’s represented as some kind of stream from which you can read bytes, or lines, or whatever. Sometimes you have the ability to read in a blocking vs non-blocking way.

Your example usage of readAll() seems fine – that’s one way to do it. But it maybe isn’t the most efficient way. It reads the whole blob up front, and then split() creates a new Array of Strings.

That’s probably why you typically see reading lines from stdin in a while loop, as you mentioned. You can also create an interactive CLI this way (or a game like Zork). You’ll also notice that the docs say it splits on “CR and/or LF bytes” - because of the different ways Win / *nix handle newlines. This is probably better if you’re expecting text. And again, more efficient to split it as you go.

Here’s a quick example of a readLine() while loop:

class Test {
  static function main() {
    var line:String;
    try while (true) {
      line = Sys.stdin().readLine();
      trace(' ---> "${ line }"');
    } catch (e:haxe.io.Eof) {
      trace('End of file, bye!');
    }
  }
}

You can either type into this (pressing CTRL-D is the *nix friendly way to end your input), or pipe into it, like you mentioned:

image

Note that -x is Haxe’s internal interpreter mode, which also supports the Sys api and is much faster to work with than cpp.

As for encoding, the readLine() doc doesn’t say, but if you look at the source, it uses bytes.toString() as well, so no difference from what you’ve done above.

Also, you may often see programmers get cryptic, doing the assignment in the while condition just to save a line:

  try while ( (line = Sys.stdin().readLine()) != null) { }

Happy coding!

-Jeff

2 Likes

Awesome. Thanks so much, Jeff!

I like that .readLine() doesn’t include the newline.

Thanks for the link to the source. I’ll check that first next time.

Looks like “-x” is maybe an older alias for --interp? But yes, thanks. I tend to use interp for quick checks like this, though in the end I like to make binary.