Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Providing stdin to an emscripten HTML program?

I have a C program that takes one argument (a char array / string) via command line and also reads from stdin. I've compiled it to JavaScript using emscripten. This was successful and I can run it just like the normal C program using node.js:

emcc -O2 translate.c
node translate.js "foo" < bar.txt

As you can see, I'm providing the string "foo" as an argument and the contents of bar.txt as stdin. Now I want this to be a self-contained HTML file.

By changing the output to HTML:

emcc -O2 translate.c -o trans.html

I provide the argument by adding arguments: ['foo'], to the definitions in var Module. This works as expected, the program receives the argument correctly.

Now, how do I provide the stdin input to this program? I don't need to do this dynamically. It would be fine to just declare a string somewhere in the HTML with the required stdin content.

like image 562
turbo Avatar asked Oct 02 '15 16:10

turbo


1 Answers

A way would be to use the Emscripten Filesystem API, for example by calling FS.init in the Module preRun function, passing custom functions to be used for standard input, output and error.

var Module = {
  preRun: function() {
    function stdin() {
      // Return ASCII code of character, or null if no input
    }

    function stdout(asciiCode) {
      // Do something with the asciiCode
    }

    function stderr(asciiCode) {
      // Do something with the asciiCode
    }

    FS.init(stdin, stdout, stderr);
  }
};

The functions are quite low-level: they each deal with one character at a time as an ASCII code. If you have strings you want to pass in, you would have to iterate over the characters of the string yourself. I suspect charCodeAt would be helpful. To output strings from stdout or stderr, then I suspect fromCharCode would be helpful.

Example (not very well tested!) implementations using each are below.

var input = "This is from the standard input\n";
var i = 0;
var Module = {
  preRun: function() {
    function stdin() {
      if (i < res.length) {
        var code = input.charCodeAt(i);
        ++i;
        return code;
      } else {
        return null;
      }
    }

    var stdoutBuffer = "";
    function stdout(code) {
      if (code === "\n".charCodeAt(0) && stdoutBuffer !== "") {
        console.log(stdoutBuffer);
        stdoutBuffer = "";
      } else {
        stdoutBuffer += String.fromCharCode(code);
      }
    }

    var stderrBuffer = "";
    function stderr(code) {
      if (code === "\n".charCodeAt(0) && stderrBuffer !== "") {
        console.log(stderrBuffer);
        stderrBuffer = "";
      } else {
        stderrBuffer += String.fromCharCode(code);
      }
    }

    FS.init(stdin, stdout, stderr);
  }
};
like image 108
Michal Charemza Avatar answered Oct 05 '22 22:10

Michal Charemza