aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Giannangeli <giann008@gmail.com>2017-05-03 13:27:49 +0200
committerBenoit Giannangeli <giann008@gmail.com>2017-05-03 13:27:49 +0200
commit5ac211f983cd628dfb95a6add7e5386071f4dada (patch)
tree887241157681d995d6fb5e54c4c3332f3cdb7afc
parent4e54f8371f376125a9cfdac3015ae2e0c3e2db73 (diff)
parent134f6bd221ad8880cb1b8514bb84e3b41d2b0d61 (diff)
downloadfengari-5ac211f983cd628dfb95a6add7e5386071f4dada.tar.gz
fengari-5ac211f983cd628dfb95a6add7e5386071f4dada.tar.bz2
fengari-5ac211f983cd628dfb95a6add7e5386071f4dada.zip
Merge remote-tracking branch 'daurnimator/iolib'
-rw-r--r--README.md14
-rw-r--r--src/liolib.js118
2 files changed, 125 insertions, 7 deletions
diff --git a/README.md b/README.md
index 9d7e70e..2c6cbba 100644
--- a/README.md
+++ b/README.md
@@ -25,9 +25,9 @@
- [x] os (~~`os.setlocale()`~~)
- [ ] Package
- [ ] io
- - [ ] `io.stdin`
- - [ ] `io.stdout`
- - [ ] `io.stderr`
+ - [x] `io.stdin`
+ - [x] `io.stdout`
+ - [x] `io.stderr`
- [ ] `io.flush()`
- [ ] `io.input()`
- [ ] `io.lines()`
@@ -37,16 +37,16 @@
- [ ] `io.read()`
- [ ] `io.tmpfile()`
- [ ] `io.type()`
- - [ ] `io.write()`
- - [ ] `io.close()`
+ - [x] `io.write()`
+ - [x] `io.close()`
- [ ] `file:flush()`
- [ ] `file:lines()`
- [ ] `file:read()`
- [ ] `file:read()`
- [ ] `file:setvbuf()`
- - [ ] `file:write()`
+ - [x] `file:write()`
- [ ] `file:__gc()`
- - [ ] `file:__tostring()`
+ - [x] `file:__tostring()`
- [ ] C API
- [x] ...
- [ ] lua_arith
diff --git a/src/liolib.js b/src/liolib.js
index 22dc2e8..2136755 100644
--- a/src/liolib.js
+++ b/src/liolib.js
@@ -1,12 +1,107 @@
"use strict";
+const assert = require('assert');
+const fs = require('fs');
+
const lua = require('./lua.js');
const lauxlib = require('./lauxlib.js');
+const IO_PREFIX = "_IO_";
+const IOPREF_LEN = IO_PREFIX.length;
+const IO_INPUT = lua.to_luastring(IO_PREFIX + "input");
+const IO_OUTPUT = lua.to_luastring(IO_PREFIX + "output");
+
+const tolstream = function(L) {
+ return lauxlib.luaL_checkudata(L, 1, lauxlib.LUA_FILEHANDLE);
+};
+
+const isclosed = function(p) {
+ return p.closef === null;
+};
+
+const f_tostring = function(L) {
+ let p = tolstream(L);
+ if (isclosed(p))
+ lua.lua_pushliteral(L, "file (closed)");
+ else
+ lua.lua_pushstring(L, lua.to_luastring(`file (${p.f.toString()})`));
+ return 1;
+};
+
+const tofile = function(L) {
+ let p = tolstream(L);
+ if (isclosed(p))
+ lauxlib.luaL_error(L, "attempt to use a closed file");
+ assert(p.f);
+ return p.f;
+};
+
+const newprefile = function(L) {
+ let p = lua.lua_newuserdata(L);
+ p.f = null;
+ p.closef = null;
+ lauxlib.luaL_setmetatable(L, lauxlib.LUA_FILEHANDLE);
+ return p;
+};
+
+const aux_close = function(L) {
+ let p = tolstream(L);
+ let cf = p.closef;
+ p.closef = null;
+ return cf(L);
+};
+
+const io_close = function(L) {
+ if (lua.lua_isnone(L, 1)) /* no argument? */
+ lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
+ tofile(L); /* make sure argument is an open stream */
+ return aux_close(L);
+};
+
+const getiofile = function(L, findex) {
+ lua.lua_getfield(L, lua.LUA_REGISTRYINDEX, findex);
+ let p = lua.lua_touserdata(L, -1);
+ if (isclosed(p))
+ lauxlib.luaL_error(L, lua.to_luastring(`standard ${lua.to_jsstring(findex.slice(IOPREF_LEN))} file is closed`));
+ return p.f;
+};
+
+const g_write = function(L, f, arg) {
+ let nargs = lua.lua_gettop(L) - arg;
+ let status = true;
+ let err;
+ for (; nargs--; arg++) {
+ let s = lauxlib.luaL_checklstring(L, arg);
+ try {
+ status = status && (fs.writeSync(f.fd, Uint8Array.from(s)) === s.length);
+ } catch (e) {
+ status = false;
+ err = e;
+ }
+ }
+ if (status) return 1; /* file handle already on stack top */
+ else return lauxlib.luaL_fileresult(L, status, null, err);
+};
+
+const io_write = function(L) {
+ return g_write(L, getiofile(L, IO_OUTPUT), 1);
+};
+
+const f_write = function(L) {
+ let f = tofile(L);
+ lua.lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */
+ return g_write(L, f, 2);
+};
+
const iolib = {
+ "close": io_close,
+ "write": io_write
};
const flib = {
+ "close": io_close,
+ "write": f_write,
+ "__tostring": f_tostring
};
const createmeta = function(L) {
@@ -17,9 +112,32 @@ const createmeta = function(L) {
lua.lua_pop(L, 1); /* pop new metatable */
};
+const io_noclose = function(L) {
+ let p = tolstream(L);
+ p.closef = io_noclose;
+ lua.lua_pushnil(L);
+ lua.lua_pushliteral(L, "cannot close standard file");
+ return 2;
+};
+
+const createstdfile = function(L, f, k, fname) {
+ let p = newprefile(L);
+ p.f = f;
+ p.closef = io_noclose;
+ if (k !== null) {
+ lua.lua_pushvalue(L, -1);
+ lua.lua_setfield(L, lua.LUA_REGISTRYINDEX, k); /* add file to registry */
+ }
+ lua.lua_setfield(L, -2, fname); /* add file to module */
+};
+
const luaopen_io = function(L) {
lauxlib.luaL_newlib(L, iolib);
createmeta(L);
+ /* create (and set) default files */
+ createstdfile(L, process.stdin, IO_INPUT, lua.to_luastring("stdin"));
+ createstdfile(L, process.stdout, IO_OUTPUT, lua.to_luastring("stdout"));
+ createstdfile(L, process.stderr, null, lua.to_luastring("stderr"));
return 1;
};