// 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); function generateRandomHashStr(len) { let cs = 'qwfpgarstdzxcvbjluyhneiokmQWFPGARSTDZXCVBJLUYHNEIOKM'; let s = ''; for (let i = 0; i < len; i++) { s += cs[(Math.random()*cs.length)|0]; } return s; } // define TVDOS const _TVDOS = {}; _TVDOS.VERSION = "1.0"; _TVDOS.DRIVES = {}; // Object where key-value pair is : [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", KEYBOARD: "us_qwerty", PATH: "\\tvdos\\bin;\\tbas;\\home", PATHEXT: ".com;.bat;.js", HELPPATH: "\\tvdos\\help", OS_NAME: "Terrarum Virtual DOS", OS_VERSION: _TVDOS.VERSION }; Object.freeze(_TVDOS); /////////////////////////////////////////////////////////////////////////////// const 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]); return com.getStatusCode(port[0]); }; filesystem.getFileLen = (driveLetter) => { var port = filesystem._toPorts(driveLetter); com.sendMessage(port[0], "GETLEN"); 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 Number(com.pullMessage(port[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.readAllBytes = (driveLetter) => { var str = filesystem.readAll(driveLetter); var bytes = new Uint8Array(str.length); for (let i = 0; i < str.length; i++) { bytes[i] = str.charCodeAt(i); } return bytes; }; 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.writeBytes = (driveLetter, bytes) => { var string = String.fromCharCode.apply(null, bytes); // no spreading: has length limit filesystem.write(driveLetter, string); }; 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); /////////////////////////////////////////////////////////////////////////////// const input = {}; const inputwork = {}; inputwork.keymap = []; input.changeKeyLayout = function(name) { let res0 = filesystem.open("A",`tvdos/${name.toLowerCase()}.key`,"R"); if (res0 != 0 && inputwork.keymap.length == 0) throw new Error(`I/O Error ${res0} - A:\\tvdos\\${name.toLowerCase()}.key`); try { inputwork.keymap = eval(filesystem.readAll("A")); } catch (e) { printerrln(e); return -1; } } // load initial key layout input.changeKeyLayout(_TVDOS.variables.KEYBOARD || "us_qwerty"); // states to run the keyboard input inputwork.stroboTime = 4294967296*0; inputwork.stroboDelays = [0,250000000,0,25000000,0]; // 250ms, 25ms inputwork.stroboStatus = 0; // 0: first key, 1: waiting for initial delay, 2: repeating key, 3: waiting for repeat delay inputwork.oldKeys = []; inputwork.oldMouse = []; inputwork.repeatCount = 0; //inputwork.keyChanged = false; /** * callback: takes one argument of object which * [ , args ] * where: * "key_down", , , keycode0, keycode1 .. keycode7 * "key_change", , 0, keycode0, keycode1 .. keycode7 (remaining keys that are held down) * "mouse_down", pos-x, pos-y, 1 // yes there's only one mouse button :p * "mouse_up", pos-x, pos-y, 0 * "mouse_move", pos-x, pos-y,