mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-03-11 21:51:50 +09:00
183 lines
6.2 KiB
Plaintext
183 lines
6.2 KiB
Plaintext
// define exceptions
|
|
function InterruptedException(m) {
|
|
this.message = m;
|
|
this.stack = (new Error()).stack;
|
|
};
|
|
InterruptedException.prototype = Object.create(Error.prototype);
|
|
InterruptedException.prototype.name = 'InterruptedException';
|
|
InterruptedException.prototype.constructor = InterruptedException;
|
|
function IllegalAccessException(m) {
|
|
this.message = m;
|
|
this.stack = (new Error()).stack;
|
|
};
|
|
IllegalAccessException.prototype = Object.create(Error.prototype);
|
|
IllegalAccessException.prototype.name = 'IllegalAccessException';
|
|
IllegalAccessException.prototype.constructor = IllegalAccessException;
|
|
class SIG {
|
|
constructor(name, number) {
|
|
this.name = "SIG" + name;
|
|
this.number = number|0;
|
|
}
|
|
}
|
|
const SIGTERM = new SIG("TERM",15);
|
|
const SIGSEGV = new SIG("SEGV",11)
|
|
// define TVDOS
|
|
var _TVDOS = {};
|
|
_TVDOS.VERSION = "1.0";
|
|
_TVDOS.DRIVES = {}; // Object where key-value pair is <drive-letter> : [serial-port, drive-number]
|
|
// actually figure out the drive letter association
|
|
// Drive A is always the device we're currently on
|
|
_TVDOS.DRIVES["A"] = _BIOS.FIRST_BOOTABLE_PORT;
|
|
//TODO
|
|
|
|
|
|
_TVDOS.getPath = function() {
|
|
return [''].concat(_TVDOS.variables.PATH.split(';'));
|
|
};
|
|
// initial values
|
|
_TVDOS.variables = {
|
|
DOSDIR: "\\tvdos",
|
|
LANG: "EN",
|
|
PATH: "\\tvdos\\bin;\\tbas;\\home",
|
|
PATHEXT: ".com;.bat;.js",
|
|
HELPPATH: "\\tvdos\\help",
|
|
OS_NAME: "Terrarum Virtual DOS",
|
|
OS_VERSION: _TVDOS.VERSION
|
|
};
|
|
Object.freeze(_TVDOS);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
var filesystem = {};
|
|
filesystem._toPorts = (driveLetter) => {
|
|
if (driveLetter.toUpperCase === undefined) {
|
|
throw Error("'"+driveLetter+"' (type: "+typeof driveLetter+") is not a valid drive letter");
|
|
}
|
|
var port = _TVDOS.DRIVES[driveLetter.toUpperCase()];
|
|
if (port === undefined) {
|
|
throw Error("Drive letter '" + driveLetter.toUpperCase() + "' does not exist");
|
|
}
|
|
return port
|
|
};
|
|
filesystem._close = (portNo) => {
|
|
com.sendMessage(portNo, "CLOSE");
|
|
};
|
|
filesystem._flush = (portNo) => {
|
|
com.sendMessage(portNo, "FLUSH");
|
|
};
|
|
// @return true if operation committed successfully, false if:
|
|
// - opening file with R-mode and target file does not exists
|
|
// throws if:
|
|
// - java.lang.NullPointerException if path is null
|
|
// - Error if operation mode is not "R", "W" nor "A"
|
|
filesystem.open = (driveLetter, path, operationMode) => {
|
|
var port = filesystem._toPorts(driveLetter);
|
|
|
|
filesystem._flush(port[0]); filesystem._close(port[0]);
|
|
|
|
var mode = operationMode.toUpperCase();
|
|
if (mode != "R" && mode != "W" && mode != "A") {
|
|
throw Error("Unknown file opening mode: " + mode);
|
|
}
|
|
|
|
com.sendMessage(port[0], "OPEN"+mode+'"'+path+'",'+port[1]);
|
|
var response = com.getStatusCode(port[0]);
|
|
return (response == 0);
|
|
};
|
|
// @return the entire contents of the file in String
|
|
filesystem.readAll = (driveLetter) => {
|
|
var port = filesystem._toPorts(driveLetter);
|
|
com.sendMessage(port[0], "READ");
|
|
var response = com.getStatusCode(port[0]);
|
|
if (135 == response) {
|
|
throw Error("File not opened");
|
|
}
|
|
if (response < 0 || response >= 128) {
|
|
throw Error("Reading a file failed with "+response);
|
|
}
|
|
return com.pullMessage(port[0]);
|
|
};
|
|
filesystem.write = (driveLetter, string) => {
|
|
var port = filesystem._toPorts(driveLetter);
|
|
com.sendMessage(port[0], "WRITE"+string.length);
|
|
var response = com.getStatusCode(port[0]);
|
|
if (135 == response) {
|
|
throw Error("File not opened");
|
|
}
|
|
if (response < 0 || response >= 128) {
|
|
throw Error("Writing a file failed with "+response);
|
|
}
|
|
com.sendMessage(port[0], string);
|
|
filesystem._flush(port[0]); filesystem._close(port[0]);
|
|
};
|
|
filesystem.isDirectory = (driveLetter) => {
|
|
var port = filesystem._toPorts(driveLetter);
|
|
com.sendMessage(port[0], "LISTFILES");
|
|
var response = com.getStatusCode(port[0]);
|
|
return (response === 0);
|
|
};
|
|
filesystem.mkDir = (driveLetter) => {
|
|
var port = filesystem._toPorts(driveLetter);
|
|
com.sendMessage(port[0], "MKDIR");
|
|
var response = com.getStatusCode(port[0]);
|
|
|
|
if (response < 0 || response >= 128) {
|
|
var status = com.getDeviceStatus(port[0]);
|
|
throw Error("Creating a directory failed with ("+response+"): "+status.message+"\n");
|
|
}
|
|
return (response === 0); // possible status codes: 0 (success), 1 (fail)
|
|
};
|
|
filesystem.touch = (driveLetter) => {
|
|
var port = filesystem._toPorts(driveLetter);
|
|
com.sendMessage(port[0], "TOUCH");
|
|
var response = com.getStatusCode(port[0]);
|
|
return (response === 0);
|
|
};
|
|
filesystem.mkFile = (driveLetter) => {
|
|
var port = filesystem._toPorts(driveLetter);
|
|
com.sendMessage(port[0], "MKFILE");
|
|
var response = com.getStatusCode(port[0]);
|
|
return (response === 0);
|
|
};
|
|
Object.freeze(filesystem);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// install other stuffs
|
|
filesystem.open("A", "tvdos/gl.js", "R");
|
|
var GL = eval(filesystem.readAll("A"));
|
|
|
|
// @param cmdsrc JS source code
|
|
// @param args arguments for the program, must be Array, and args[0] is always the name of the program, e.g.
|
|
// for command line 'echo foo bar', args[0] must be 'echo'
|
|
// @return status returned by the program
|
|
var execApp = (cmdsrc, args) => {
|
|
var execAppPrg = eval(
|
|
`var _appStub=function(exec_args){${cmdsrc}\n};_appStub`); // making 'exec_args' a app-level global
|
|
|
|
var status = 0;
|
|
|
|
try {
|
|
status = execAppPrg(args);
|
|
return status;
|
|
}
|
|
catch (e) {
|
|
serial.printerr(`app execution interrupted -- ${e}\n${e.stack || "(stack trace unavailable)"}`);
|
|
//serial.printerr(Object.entries(e));
|
|
if (e instanceof InterruptedException)
|
|
return SIGTERM;
|
|
else if (e instanceof IllegalAccessException || `${e}`.startsWith("net.torvald.tsvm.ErrorIllegalAccess"))
|
|
return SIGSEGV;
|
|
else
|
|
return (undefined == status) ? 0 : status;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Boot script
|
|
serial.println("TVDOS.SYS initialised, running boot script...");
|
|
var _G = {};
|
|
filesystem.open("A", "tvdos/bin/command.js", "R");
|
|
execApp(filesystem.readAll("A"), ["", "/c", "\\AUTOEXEC.BAT"]);
|