// Simulate handles.
// When implementing new handles, remember that passed strings may be thunks,
// and so need to be evaluated before use.
function jsNewHandle(init, read, write, flush, close, seek, tell) {
var h = {
read: read || function() {},
write: write || function() {},
seek: seek || function() {},
tell: tell || function() {},
close: close || function() {},
flush: flush || function() {}
};
init.call(h);
return h;
}
function jsReadHandle(h, len) {return h.read(len);}
function jsWriteHandle(h, str) {return h.write(str);}
function jsFlushHandle(h) {return h.flush();}
function jsCloseHandle(h) {return h.close();}
function jsMkConWriter(op) {
return function(str) {
str = E(str);
var lines = (this.buf + str).split('\n');
for(var i = 0; i < lines.length-1; ++i) {
op.call(console, lines[i]);
}
this.buf = lines[lines.length-1];
}
}
function jsMkStdout() {
return jsNewHandle(
function() {this.buf = '';},
function(_) {return '';},
jsMkConWriter(console.log),
function() {console.log(this.buf); this.buf = '';}
);
}
function jsMkStderr() {
return jsNewHandle(
function() {this.buf = '';},
function(_) {return '';},
jsMkConWriter(console.warn),
function() {console.warn(this.buf); this.buf = '';}
);
}
function jsMkStdin() {
return jsNewHandle(
function() {this.buf = '';},
function(len) {
while(this.buf.length < len) {
this.buf += prompt('[stdin]') + '\n';
}
var ret = this.buf.substr(0, len);
this.buf = this.buf.substr(len);
return ret;
}
);
}