summaryrefslogtreecommitdiff
path: root/libraries/base/jsbits/base.js
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2022-02-10 08:24:24 +0000
committerSylvain Henry <sylvain@haskus.fr>2022-11-29 09:44:31 +0100
commitcc25d52e0f65d54c052908c7d91d5946342ab88a (patch)
tree0f35764ee3b9b0451ac999b64d2db9fa074fa3dd /libraries/base/jsbits/base.js
parentdef47dd32491311289bff26230b664c895f178cc (diff)
downloadhaskell-cc25d52e0f65d54c052908c7d91d5946342ab88a.tar.gz
Add Javascript backend
Add JS backend adapted from the GHCJS project by Luite Stegeman. Some features haven't been ported or implemented yet. Tests for these features have been disabled with an associated gitlab ticket. Bump array submodule Work funded by IOG. Co-authored-by: Jeffrey Young <jeffrey.young@iohk.io> Co-authored-by: Luite Stegeman <stegeman@gmail.com> Co-authored-by: Josh Meredith <joshmeredith2008@gmail.com>
Diffstat (limited to 'libraries/base/jsbits/base.js')
-rw-r--r--libraries/base/jsbits/base.js839
1 files changed, 839 insertions, 0 deletions
diff --git a/libraries/base/jsbits/base.js b/libraries/base/jsbits/base.js
new file mode 100644
index 0000000000..dd491bac00
--- /dev/null
+++ b/libraries/base/jsbits/base.js
@@ -0,0 +1,839 @@
+//#OPTIONS: CPP
+#include "HsBaseConfig.h"
+
+// #define GHCJS_TRACE_IO 1
+
+#ifdef GHCJS_TRACE_IO
+function h$logIO() { h$log.apply(h$log, arguments); }
+#define TRACE_IO(args...) h$logIO(args)
+#else
+#define TRACE_IO(args...)
+#endif
+
+function h$base_access(file, file_off, mode, c) {
+ TRACE_IO("base_access")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.stat(fd, function(err, fs) {
+ if(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ } else {
+ c(mode & fs.mode); // fixme is this ok?
+ }
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+
+function h$base_chmod(file, file_off, mode, c) {
+ TRACE_IO("base_chmod")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.chmod(h$decodeUtf8z(file, file_off), mode, function(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+
+function h$base_close(fd, c) {
+ TRACE_IO("base_close fd: " + fd)
+ var fdo = h$base_fds[fd];
+ if(fdo) {
+ delete h$base_fds[fd];
+ if(--fdo.refs < 1) {
+ TRACE_IO("base_close: closing underlying fd")
+ if(fdo.close) {
+ fdo.close(fd, fdo, c);
+ } else {
+ c(0);
+ }
+ } else {
+ TRACE_IO("base_close: remaining references, not closing underlying fd")
+ c(0);
+ }
+ } else {
+ TRACE_IO("base_close: file descriptor not found, already closed?")
+ h$errno = CONST_EINVAL;
+ c(-1);
+ }
+}
+
+function h$base_dup(fd, c) {
+ // h$log("h$base_dup al: " + arguments.length);
+ h$base_dup2(fd, h$base_fdN--, c);
+}
+
+function h$base_dup2(fd, new_fd, c) {
+ TRACE_IO("base_dup2 " + fd + " " + new_fd)
+ // if(new_fd >= 0 && new_fd <= 2) {
+
+ // }
+ // h$log("h$base_dup2 al: " + arguments.length);
+ // if(fd >= 0 && fd < 2) {
+ // h$errno = CONST_EINVAL;
+ // c(-1);
+ // fixme make sure it can't be called again!
+ // return;
+ // } // && new_fd )
+
+ /* Fixme:
+ The two descriptors do not share file descriptor flags
+ (the close-on-exec flag). The close-on-exec flag
+ (FD_CLOEXEC; see fcntl(2)) for the duplicate descriptor is off.
+ */
+ var fdo = h$base_fds[fd];
+ if(!fdo) {
+ TRACE_IO("file descriptor not found")
+ h$errno = CONST_EINVAL;
+ c(-1);
+ } else {
+ var new_fdo = h$base_fds[new_fd];
+ function f() {
+ h$base_fds[new_fd] = fdo;
+ fdo.refs++;
+ c(new_fd);
+ }
+ if(new_fdo) {
+ TRACE_IO("closing existing fd")
+ h$base_close(new_fd, f);
+ } else {
+ f();
+ } // h$new_fdo.close();
+ }
+}
+
+function h$base_fstat(fd, stat, stat_off, c) {
+ TRACE_IO("base_stat")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.fstat(fd, function(err, fs) {
+ if(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ } else {
+ h$base_fillStat(fs, stat, stat_off);
+ c(0);
+ }
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+
+function h$base_isatty(fd) {
+ TRACE_IO("base_isatty " + fd)
+ // return 1; // fixme debug
+ var fdo = h$base_fds[fd];
+ if(fdo && typeof fdo.isatty !== 'undefined') {
+ if(typeof fdo.isatty === 'function') return fdo.isatty() ? 1 : 0;
+ return fdo.isatty ? 1 : 0;
+ }
+ return 0;
+}
+
+
+#define TWO_PWR_32_DBL_ 0x100000000
+#define TWO_PWR_63_DBL_ 0x8000000000000000
+#define CLOSEST_FLOAT_NUMBER(h,l) (((h)*TWO_PWR_32_DBL_) + ((l)>>>0))
+
+/**
+ * Returns a 64-bit represention of the given number.
+ * NaN will be returned as zero.
+ * Infinity is converted to max value and
+ * -Infinity to min value.
+ * @param {f} The number in question.
+ * @param {c} the continuation taking high and low bits
+ */
+function h$long_from_number(f,c) {
+ if (f > 0) {
+ if (f >= TWO_PWR_63_DBL_) {
+ // return max value
+ return c(0x7FFFFFFF,0xFFFFFFFF);
+ }
+ return c(f / TWO_PWR_32_DBL_, f);
+ } else if (f < 0) {
+ if (f <= -TWO_PWR_63_DBL_) {
+ // return min value
+ return c(0x80000000,0);
+ }
+ var h = -f / TWO_PWR_32_DBL_;
+ var l = -f;
+ // negate h l
+ var nl = (~l + 1) | 0;
+ var nh = (~h + !nl) | 0;
+ return c(nh,nl);
+ } else {
+ // NaN or 0.
+ return c(0,0);
+ }
+}
+
+function h$base_lseek(fd, pos_h, pos_l, whence, c) {
+ TRACE_IO("base_lseek")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ var p = CLOSEST_FLOAT_NUMBER(pos_h,pos_l);
+ var o = h$base_fds[fd];
+ if(!o) {
+ h$errno = CONST_BADF;
+ c(-1,-1);
+ } else {
+ switch(whence) {
+ case 0: /* SET */
+ o.pos = p;
+ c(pos_h, pos_l);
+ break;
+ case 1: /* CUR */
+ o.pos += p;
+ h$long_from_number(o.pos,c);
+ break;
+ case 2: /* END */
+ h$fs.fstat(fd, function(err, fs) {
+ if(err) {
+ h$setErrno(err);
+ c(-1,-1);
+ } else {
+ o.pos = fs.size + p;
+ h$long_from_number(o.pos,c);
+ }
+ });
+ break;
+ default:
+ h$errno = CONST_EINVAL;
+ c(-1,-1);
+ }
+ }
+ } else {
+#endif
+ h$unsupported();
+ c(-1, -1);
+#ifndef GHCJS_BROWSER
+ }
+#endif
+}
+
+function h$base_lstat(file, file_off, stat, stat_off, c) {
+ TRACE_IO("base_lstat")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.lstat(h$decodeUtf8z(file, file_off), function(err, fs) {
+ if(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ } else {
+ h$base_fillStat(fs, stat, stat_off);
+ c(0);
+ }
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+function h$base_open(file, file_off, how, mode, c) {
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ var flags, off;
+ var fp = h$decodeUtf8z(file, file_off);
+ TRACE_IO("base_open: " + fp)
+ var acc = how & h$base_o_accmode;
+ // passing a number lets node.js use it directly as the flags (undocumented)
+ if(acc === h$base_o_rdonly) {
+ flags = h$processConstants['fs']['O_RDONLY'];
+ } else if(acc === h$base_o_wronly) {
+ flags = h$processConstants['fs']['O_WRONLY'];
+ } else { // r+w
+ flags = h$processConstants['fs']['O_RDWR'];
+ }
+ off = (how & h$base_o_append) ? -1 : 0;
+ flags = flags | ((how & h$base_o_trunc) ? h$processConstants['fs']['O_TRUNC'] : 0)
+ | ((how & h$base_o_creat) ? h$processConstants['fs']['O_CREAT'] : 0)
+ | ((how & h$base_o_excl) ? h$processConstants['fs']['O_EXCL'] : 0)
+ | ((how & h$base_o_append) ? h$processConstants['fs']['O_APPEND'] : 0);
+ h$fs.open(fp, flags, mode, function(err, fd) {
+ if(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ } else {
+ var f = function(p) {
+ h$base_fds[fd] = { read: h$base_readFile
+ , write: h$base_writeFile
+ , close: h$base_closeFile
+ , fd: fd
+ , pos: p
+ , refs: 1
+ };
+ TRACE_IO("base_open: " + fp + " -> " + fd)
+ c(fd);
+ }
+ if(off === -1) {
+ h$fs.stat(fp, function(err, fs) {
+ if(err) h$handleErrnoC(err, -1, 0, c); else f(fs.size);
+ });
+ } else {
+ f(0);
+ }
+ }
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+function h$base_read(fd, buf, buf_off, n, c) {
+ TRACE_IO("base_read: " + fd)
+ var fdo = h$base_fds[fd];
+ if(fdo && fdo.read) {
+ fdo.read(fd, fdo, buf, buf_off, n, c);
+ } else {
+ h$fs.read(fd, buf.u8, buf_off, n, null, function(err, bytesRead, buf0) {
+ h$handleErrnoC(err, -1, bytesRead, c);
+ });
+ }
+}
+function h$base_stat(file, file_off, stat, stat_off, c) {
+ TRACE_IO("base_stat")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.stat(h$decodeUtf8z(file, file_off), function(err, fs) {
+ if(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ } else {
+ h$base_fillStat(fs, stat, stat_off);
+ c(0);
+ }
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+function h$base_umask(mode) {
+ TRACE_IO("base_umask: " + mode)
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) return process.umask(mode);
+#endif
+ return 0;
+}
+
+function h$base_write(fd, buf, buf_off, n, c) {
+// fd: file descriptor number
+// buf: buffer to write
+// buf_off: offset in the buffer
+// n: number of bytes to write
+// c: continuation
+ TRACE_IO("base_write: " + fd)
+
+ var fdo = h$base_fds[fd];
+
+ if(fdo && fdo.write) {
+ fdo.write(fd, fdo, buf, buf_off, n, c);
+ } else {
+ h$fs.write(fd, buf.u8, buf_off, n, function(err, bytesWritten, buf0) {
+ h$handleErrnoC(err, -1, bytesWritten, c);
+ });
+ }
+}
+
+function h$base_ftruncate(fd, pos_h, pos_l, c) {
+ TRACE_IO("base_ftruncate")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.ftruncate(fd, CLOSEST_FLOAT_NUMBER(pos_h,pos_l), function(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+function h$base_unlink(file, file_off, c) {
+ TRACE_IO("base_unlink")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.unlink(h$decodeUtf8z(file, file_off), function(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+function h$base_getpid() {
+ TRACE_IO("base_getpid")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) return process.pid;
+#endif
+ return 0;
+}
+function h$base_link(file1, file1_off, file2, file2_off, c) {
+ TRACE_IO("base_link")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.link(h$decodeUtf8z(file1, file1_off), h$decodeUtf8z(file2, file2_off), function(err) {
+ h$handleErrnoC(err, -1, 0, c);
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+function h$base_mkfifo(file, file_off, mode, c) {
+ throw "h$base_mkfifo";
+}
+function h$base_sigemptyset(sigset, sigset_off) {
+ return 0;
+ // throw "h$base_sigemptyset";
+}
+function h$base_sigaddset(sigset, sigset_off, sig) {
+ return 0;
+ // throw "h$base_sigaddset";
+}
+function h$base_sigprocmask(sig, sigset1, sigset1_off, sigset2, sigset2_off) {
+ return 0;
+ // throw "h$base_sigprocmask";
+}
+function h$base_tcgetattr(attr, termios, termios_off) {
+ return 0;
+}
+function h$base_tcsetattr(attr, val, termios, termios_off) {
+ return 0;
+}
+function h$base_utime(file, file_off, timbuf, timbuf_off, c) {
+ TRACE_IO("base_utime")
+#ifndef GHCJS_BROWSER
+ if(h$isNode()) {
+ h$fs.fstat(h$decodeUtf8z(file, file_off), function(err, fs) {
+ if(err) {
+ h$handleErrnoC(err, 0, -1, c); // fixme
+ } else {
+ h$long_from_number(fs.atime.getTime(), (h,l) => {
+ timbuf.i3[0] = h;
+ timbuf.i3[1] = l;
+ });
+ h$long_from_number(fs.mtime.getTime(), (h,l) => {
+ timbuf.i3[2] = h;
+ timbuf.i3[3] = l;
+ });
+ h$long_from_number(fs.ctime.getTime(), (h,l) => {
+ timbuf.i3[4] = h;
+ timbuf.i3[5] = l;
+ });
+ c(0);
+ }
+ });
+ } else
+#endif
+ h$unsupported(-1, c);
+}
+function h$base_waitpid(pid, stat, stat_off, options, c) {
+ throw "h$base_waitpid";
+}
+/** @const */ var h$base_o_rdonly = 0x00000;
+/** @const */ var h$base_o_wronly = 0x00001;
+/** @const */ var h$base_o_rdwr = 0x00002;
+/** @const */ var h$base_o_accmode = 0x00003;
+/** @const */ var h$base_o_append = 0x00008;
+/** @const */ var h$base_o_creat = 0x00200;
+/** @const */ var h$base_o_trunc = 0x00400;
+/** @const */ var h$base_o_excl = 0x00800;
+/** @const */ var h$base_o_noctty = 0x20000;
+/** @const */ var h$base_o_nonblock = 0x00004;
+/** @const */ var h$base_o_binary = 0x00000;
+
+function h$base_c_s_isreg(mode) {
+ return 1;
+}
+function h$base_c_s_ischr(mode) {
+ return 0;
+}
+function h$base_c_s_isblk(mode) {
+ return 0;
+}
+function h$base_c_s_isdir(mode) {
+ return 0; // fixme
+}
+function h$base_c_s_isfifo(mode) {
+ return 0;
+}
+
+#ifndef GHCJS_BROWSER
+function h$base_fillStat(fs, b, off) {
+ if(off%4) throw "h$base_fillStat: not aligned";
+ var o = off>>2;
+ b.i3[o+0] = fs.mode;
+ h$long_from_number(fs.size, (h,l) => {
+ b.i3[o+1] = h;
+ b.i3[o+2] = l;
+ });
+
+ b.i3[o+3] = 0; // fixme
+ b.i3[o+4] = 0; // fixme
+ b.i3[o+5] = fs.dev;
+ h$long_from_number(fs.ino, (h,l) => {
+ b.i3[o+6] = h;
+ b.i3[o+7] = l;
+ });
+ b.i3[o+8] = fs.uid;
+ b.i3[o+9] = fs.gid;
+}
+#endif
+
+// [mode,size1,size2,mtime1,mtime2,dev,ino1,ino2,uid,gid] all 32 bit
+/** @const */ var h$base_sizeof_stat = 40;
+
+function h$base_st_mtime(stat, stat_off) {
+ RETURN_UBX_TUP2(stat.i3[(stat_off>>2)+3], stat.i3[(stat_off>>2)+4]);
+}
+
+function h$base_st_size(stat, stat_off) {
+ RETURN_UBX_TUP2(stat.i3[(stat_off>>2)+1], stat.i3[(stat_off>>2)+2]);
+}
+
+function h$base_st_mode(stat, stat_off) {
+ return stat.i3[stat_off>>2];
+}
+
+function h$base_st_dev(stat, stat_off) {
+ return stat.i3[(stat_off>>2)+5];
+}
+
+function h$base_st_ino(stat, stat_off) {
+ RETURN_UBX_TUP2(stat.i3[(stat_off>>2)+6], stat.i3[(stat_off>>2)+7]);
+}
+
+/** @const */ var h$base_echo = 1;
+/** @const */ var h$base_tcsanow = 2;
+/** @const */ var h$base_icanon = 4;
+/** @const */ var h$base_vmin = 8;
+/** @const */ var h$base_vtime = 16;
+/** @const */ var h$base_sigttou = 0;
+/** @const */ var h$base_sig_block = 0;
+/** @const */ var h$base_sig_setmask = 0;
+/** @const */ var h$base_f_getfl = 0;
+/** @const */ var h$base_f_setfl = 0;
+/** @const */ var h$base_f_setfd = 0;
+/** @const */ var h$base_fd_cloexec = 0;
+/** @const */ var h$base_sizeof_termios = 4;
+/** @const */ var h$base_sizeof_sigset_t = 4;
+
+function h$base_lflag(termios, termios_off) {
+ return 0;
+}
+
+function h$base_poke_lflag(termios, termios_off, flag) {
+ return 0;
+}
+
+function h$base_ptr_c_cc(termios, termios_off) {
+ RETURN_UBX_TUP2(h$newByteArray(8), 0);
+}
+
+/** @const */ var h$base_default_buffer_size = 32768;
+
+function h$base_c_s_issock(mode) {
+ return 0; // fixme
+}
+
+/** @const */ var h$base_SEEK_SET = 0;
+/** @const */ var h$base_SEEK_CUR = 1;
+/** @const */ var h$base_SEEK_END = 2;
+
+function h$base_set_saved_termios(a, b, c) {
+ RETURN_UBX_TUP2(null, 0);
+}
+
+function h$base_get_saved_termios(r) {
+ RETURN_UBX_TUP2(null, 0);
+}
+
+// fixme
+function h$lockFile(fd, dev, ino, for_writing) {
+ TRACE_IO("lockFile:" + fd)
+ return 0;
+}
+function h$unlockFile(fd) {
+ TRACE_IO("unlockFile:" + fd)
+ return 0;
+}
+
+
+
+// engine-dependent setup
+var h$base_readStdin , h$base_writeStderr, h$base_writeStdout;
+var h$base_isattyStdin = false, h$base_isattyStdout = false, h$base_isattyStderr = false;
+var h$base_closeStdin = null, h$base_closeStderr = null, h$base_closeStdout = null;
+var h$base_readFile, h$base_writeFile, h$base_closeFile;
+#ifndef GHCJS_BROWSER
+var h$base_stdin_waiting = new h$Queue();
+var h$base_stdin_chunk = { buf: null
+ , pos: 0
+ , processing: false
+ };
+var h$base_stdin_eof = false;
+var h$base_process_stdin = function() {
+ var c = h$base_stdin_chunk;
+ var q = h$base_stdin_waiting;
+ if(!q.length() || c.processing) return;
+ c.processing = true;
+ if(!c.buf) { c.pos = 0; c.buf = process.stdin.read(); }
+ while(c.buf && q.length()) {
+ var x = q.dequeue();
+ var n = Math.min(c.buf.length - c.pos, x.n);
+ for(var i=0;i<n;i++) {
+ x.buf.u8[i+x.off] = c.buf[c.pos+i];
+ }
+ c.pos += n;
+ x.c(n);
+ if(c.pos >= c.buf.length) c.buf = null;
+ if(!c.buf && q.length()) { c.pos = 0; c.buf = process.stdin.read(); }
+ }
+ while(h$base_stdin_eof && q.length()) q.dequeue().c(0);
+ c.processing = false;
+}
+
+if(h$isNode()) {
+ h$base_closeFile = function(fd, fdo, c) {
+ TRACE_IO("base_closeFile: " + fd + " (" + fdo.fd + ")")
+ var real_fd = typeof fdo.fd === 'number' ? fdo.fd : fd;
+ h$fs.close(real_fd, function(err) {
+ delete h$base_fds[fd];
+ h$handleErrnoC(err, -1, 0, c);
+ });
+ }
+
+ h$base_readFile = function(fd, fdo, buf, buf_offset, n, c) {
+ var pos = typeof fdo.pos === 'number' ? fdo.pos : null;
+ TRACE_IO("base_readFile: " + fd + " (" + fdo.fd + ") " + pos + " " + buf_offset + " " + n)
+ var real_fd = typeof fdo.fd === 'number' ? fdo.fd : fd;
+ h$fs.read(real_fd, Buffer.alloc(n), 0, n, pos, function(err, bytesRead, nbuf) {
+ if(err) {
+ h$setErrno(err);
+ c(-1);
+ } else {
+ for(var i=bytesRead-1;i>=0;i--) buf.u8[buf_offset+i] = nbuf[i];
+ if(typeof fdo.pos === 'number') fdo.pos += bytesRead;
+ c(bytesRead);
+ }
+ });
+ }
+
+ h$base_readStdin = function(fd, fdo, buf, buf_offset, n, c) {
+ TRACE_IO("read stdin")
+ h$base_stdin_waiting.enqueue({buf: buf, off: buf_offset, n: n, c: c});
+ h$base_process_stdin();
+ }
+
+ h$base_closeStdin = function(fd, fdo, c) {
+ TRACE_IO("close stdin")
+ // process.stdin.close(); fixme
+ c(0);
+ }
+
+ h$base_writeFile = function(fd, fdo, buf, buf_offset, n, c) {
+ var pos = typeof fdo.pos === 'number' ? fdo.pos : null;
+ TRACE_IO("base_writeFile: " + fd + " (" + fdo.fd + ") " + pos + " " + buf_offset + " " + n)
+ var nbuf = Buffer.alloc(n);
+ for(var i=0;i<n;i++) nbuf[i] = buf.u8[i+buf_offset];
+ var real_fd = typeof fdo.fd === 'number' ? fdo.fd : fd;
+ if(typeof fdo.pos === 'number') fdo.pos += n;
+ h$fs.write(real_fd, nbuf, 0, n, pos, function(err, bytesWritten) {
+ TRACE_IO("written file: " + fd + " (" + fdo.fd + ")")
+ if(err) {
+ h$setErrno(err);
+ if(typeof fdo.pos === 'number') fdo.pos -= n;
+ if(h$errno === CONST_EAGAIN)
+ setTimeout(function() { h$base_writeFile(fd, fdo, buf, buf_offset, n, c); }, 20);
+ else c(-1);
+ } else {
+ if(typeof fdo.pos === 'number') fdo.pos += bytesWritten - n;
+ c(bytesWritten);
+ }
+ });
+ }
+
+ h$base_writeStdout = function(fd, fdo, buf, buf_offset, n, c) {
+ TRACE_IO("write stdout")
+ h$base_writeFile(1, fdo, buf, buf_offset, n, c);
+ }
+
+ h$base_closeStdout = function(fd, fdo, c) {
+ TRACE_IO("close stdout")
+ // not actually closed, fixme?
+ c(0);
+ }
+
+ h$base_writeStderr = function(fd, fdo, buf, buf_offset, n, c) {
+ TRACE_IO("write stderr")
+ h$base_writeFile(2, fdo, buf, buf_offset, n, c);
+ }
+
+ h$base_closeStderr = function(fd, fdo, c) {
+ TRACE_IO("close stderr")
+ // not actually closed, fixme?
+ c(0);
+ }
+
+ process.stdin.on('readable', h$base_process_stdin);
+ process.stdin.on('end', function() { h$base_stdin_eof = true; h$base_process_stdin(); });
+
+ h$base_isattyStdin = function() { return process.stdin.isTTY; };
+ h$base_isattyStdout = function() { return process.stdout.isTTY; };
+ h$base_isattyStderr = function() { return process.stderr.isTTY; };
+
+} else if (h$isJsShell()) {
+ h$base_readStdin = function(fd, fdo, buf, buf_offset, n, c) {
+ c(0);
+ }
+ h$base_writeStdout = function(fd, fdo, buf, buf_offset, n, c) {
+ putstr(h$decodeUtf8(buf, n, buf_offset));
+ c(n);
+ }
+ h$base_writeStderr = function(fd, fdo, buf, buf_offset, n, c) {
+ printErr(h$decodeUtf8(buf, n, buf_offset));
+ c(n);
+ }
+} else if(h$isJsCore()) {
+ h$base_readStdin = function(fd, fdo, buf, buf_offset, n, c) {
+ c(0);
+ }
+ var h$base_stdoutLeftover = { f: print, val: null };
+ var h$base_stderrLeftover = { f: debug, val: null };
+ var h$base_writeWithLeftover = function(buf, n, buf_offset, c, lo) {
+ var lines = h$decodeUtf8(buf, n, buf_offset).split(/\r?\n/);
+ if(lines.length === 1) {
+ if(lines[0].length) {
+ if(lo.val !== null) lo.val += lines[0];
+ else lo.val = lines[0];
+ }
+ } else {
+ lo.f(((lo.val !== null) ? lo.val : '') + lines[0]);
+ for(var i=1;i<lines.length-1;i++) lo.f(lines[i]);
+ if(lines[lines.length-1].length) lo.val = lines[lines.length-1];
+ else lo.val = null;
+ }
+ c(n);
+ }
+ h$base_writeStdout = function(fd, fdo, buf, buf_offset, n, c) {
+ h$base_writeWithLeftover(buf, n, buf_offset, c, h$base_stdoutLeftover);
+ }
+ h$base_writeStderr = function(fd, fdo, buf, buf_offset, n, c) {
+ // writing to stderr not supported, write to stdout
+ h$base_writeWithLeftover(buf, n, buf_offset, c, h$base_stderrLeftover);
+ }
+} else { // browser / fallback
+#endif
+ h$base_readStdin = function(fd, fdo, buf, buf_offset, n, c) {
+ c(0);
+ }
+ h$base_writeStdout = function(fd, fdo, buf, buf_offset, n, c) {
+ console.log(h$decodeUtf8(buf, n, buf_offset));
+ c(n);
+ }
+ h$base_writeStderr = function(fd, fdo, buf, buf_offset, n, c) {
+ console.log(h$decodeUtf8(buf, n, buf_offset));
+ c(n);
+ }
+#ifndef GHCJS_BROWSER
+}
+#endif
+
+var h$base_stdin_fd =
+ { read: h$base_readStdin
+ , close: h$base_closeStdin
+ , isatty: h$base_isattyStdin
+ , refs: 1
+ };
+var h$base_stdout_fd =
+ { write: h$base_writeStdout
+ , close: h$base_closeStdout
+ , isatty: h$base_isattyStdout
+ , refs: 1
+ };
+var h$base_stderr_fd =
+ { write: h$base_writeStderr
+ , close: h$base_closeStderr
+ , isatty: h$base_isattyStderr
+ , refs: 1
+ };
+
+var h$base_fdN = -2; // negative file descriptors are 'virtual', -1 is already used to indicated error
+var h$base_fds = [h$base_stdin_fd, h$base_stdout_fd, h$base_stderr_fd];
+
+function h$shutdownHaskellAndExit(code, fast) {
+#ifndef GHCJS_BROWSER
+#ifdef GHCJS_LOG_BUFFER
+ if(h$isNode()) console.log(h$logBuffer);
+ if(h$isJsShell() || h$isJsCore()) print(h$logBuffer);
+#endif
+#endif
+ h$exitProcess(code);
+}
+
+// RAND_MAX = 32767
+function h$rand() {
+ return (32768 * Math.random()) & 32767;
+}
+
+// SIGUSR1, SIGTERM, SIGINT, SIGPIPE, SIGHUP, SIGTERM, SIGINT
+// SIGBREAK, SIGWINCH, SIGKILL, SIGSTOP, SIGBUS, SIGFPE
+// SIGSEGV, SIGILL
+
+// returns old action code
+function h$stg_sig_install(sigNo, actionCode, sigSet_d, sigSet_o) {
+ // XXX dummy implementation
+ return 0;
+}
+
+const h$putchar_buf = h$newByteArray(1);
+
+function h$putchar(c) {
+ h$putchar_buf.u8[0] = c;
+ h$base_write(1, h$putchar_buf, 0, 1, null);
+ return h$errno;
+}
+
+function h$__hscore_set_errno(n) {
+ h$errno = n;
+}
+
+/*******************************************
+ * Directory API
+ *******************************************/
+
+function h$opendir(path) {
+ if(!h$isNode()) {
+ throw "h$opendir unsupported";
+ }
+
+ const d = fs.opendirSync(h$decodeUtf8z(path,0));
+ RETURN_UBX_TUP2(d,0);
+}
+
+function h$closedir(d,o) {
+ if(!h$isNode()) {
+ throw "h$closedir unsupported";
+ }
+ d.closeSync();
+ return 0;
+}
+
+function h$readdir(d,o) {
+ if(!h$isNode()) {
+ throw "h$readdir unsupported";
+ }
+ const c = d.readSync();
+ RETURN_UBX_TUP2(c,0);
+}
+
+function h$__hscore_readdir(d,o,dst_a,dst_o) {
+ if(!h$isNode()) {
+ throw "h$readdir unsupported";
+ }
+ const e = d.readSync();
+
+ if (!dst_a.arr) dst_a.arr = [];
+ dst_a.arr[dst_o*2] = [e,0];
+ return 0;
+}
+
+function h$__hscore_free_dirent(a,o) {
+}
+
+function h$__hscore_d_name(a,o) {
+ RETURN_UBX_TUP2(h$encodeModifiedUtf8(a.name),0);
+}