mirror of
https://github.com/curioustorvald/tsvm.git
synced 2026-06-12 23:54:04 +09:00
impl of autoexec.bat (wip)
This commit is contained in:
@@ -1 +1 @@
|
|||||||
let p=_BIOS.FIRST_BOOTABLE_PORT;com.sendMessage(p[0], "DEVRST\x17");com.sendMessage(p[0],'OPENR"tvdos/TVDOS.SYS",'+p[1]);let r=com.getStatusCode(p[0]);if(0==r)if(com.sendMessage(p[0],"READ"),r=com.getStatusCode([0]),0==r){let g=com.pullMessage(p[0]);eval(g)}else println("I/O Error");else println("TVDOS.SYS not found");println("Shutting down...");println("It is now safe to turn off the power");
|
let p=_BIOS.FIRST_BOOTABLE_PORT;com.sendMessage(p[0],"DEVRST\x17");com.sendMessage(p[0],'OPENR"tvdos/TVDOS.SYS",'+p[1]);let r=com.getStatusCode(p[0]);if(0==r)if(com.sendMessage(p[0],"READ"),r=com.getStatusCode([0]),0==r){let g=com.pullMessage(p[0]);eval(g)}else println("I/O Error");else println("TVDOS.SYS not found");println("Shutting down...");println("It is now safe to turn off the power");
|
||||||
2
assets/AUTOEXEC.BAT
Normal file
2
assets/AUTOEXEC.BAT
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
echo "Hello, world!"
|
||||||
|
fsh
|
||||||
@@ -10,7 +10,7 @@ _TVDOS.DRIVES["A"] = _BIOS.FIRST_BOOTABLE_PORT;
|
|||||||
|
|
||||||
_TVDOS.defaults = {
|
_TVDOS.defaults = {
|
||||||
path: [
|
path: [
|
||||||
"/tvdos/bin"
|
"\\tvdos\\bin\\"
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
Object.freeze(_TVDOS);
|
Object.freeze(_TVDOS);
|
||||||
@@ -31,8 +31,11 @@ filesystem._close = function(portNo) {
|
|||||||
filesystem._flush = function(portNo) {
|
filesystem._flush = function(portNo) {
|
||||||
com.sendMessage(portNo, "FLUSH");
|
com.sendMessage(portNo, "FLUSH");
|
||||||
};
|
};
|
||||||
// @return true if operation committed successfully, false otherwise; throws error
|
// @return true if operation committed successfully, false if:
|
||||||
// if unknown mode or invalid drive letter was given
|
// - 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 = function(driveLetter, path, operationMode) {
|
filesystem.open = function(driveLetter, path, operationMode) {
|
||||||
let port = filesystem._toPorts(driveLetter);
|
let port = filesystem._toPorts(driveLetter);
|
||||||
|
|
||||||
@@ -67,7 +70,8 @@ filesystem.open("A", "tvdos/gl.js", "R");
|
|||||||
var GL = eval(filesystem.readAll("A"));
|
var GL = eval(filesystem.readAll("A"));
|
||||||
|
|
||||||
// @param cmdsrc JS source code
|
// @param cmdsrc JS source code
|
||||||
// @param args arguments for the program, must be Array
|
// @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'
|
||||||
var execApp = function(cmdsrc, args) {
|
var execApp = function(cmdsrc, args) {
|
||||||
let prg = eval("let _appStub=function(exec_args){"+cmdsrc+"};_appStub;"); // making 'exec_args' a app-level global
|
let prg = eval("let _appStub=function(exec_args){"+cmdsrc+"};_appStub;"); // making 'exec_args' a app-level global
|
||||||
return prg(args);
|
return prg(args);
|
||||||
@@ -78,8 +82,4 @@ var execApp = function(cmdsrc, args) {
|
|||||||
// Boot script
|
// Boot script
|
||||||
filesystem.open("A", "tvdos/command.js", "R");
|
filesystem.open("A", "tvdos/command.js", "R");
|
||||||
let cmdsrc = filesystem.readAll("A");
|
let cmdsrc = filesystem.readAll("A");
|
||||||
|
execApp(cmdsrc, ["", "/c", "\\AUTOEXEC.BAT"]);
|
||||||
// app execution stub
|
|
||||||
execApp(cmdsrc);
|
|
||||||
//let sh = execApp(cmdsrc, [42]);
|
|
||||||
//println(sh.test);
|
|
||||||
|
|||||||
@@ -6,25 +6,11 @@ let shell_pwd = [];
|
|||||||
const welcome_text = "TSVM Disk Operating System, version " + _TVDOS.VERSION;
|
const welcome_text = "TSVM Disk Operating System, version " + _TVDOS.VERSION;
|
||||||
|
|
||||||
function print_prompt_text() {
|
function print_prompt_text() {
|
||||||
//print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT);
|
print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT);
|
||||||
con.color_pair(239,161);
|
|
||||||
print(" "+CURRENT_DRIVE+":");
|
|
||||||
con.color_pair(161,253);
|
|
||||||
con.addch(16);
|
|
||||||
con.color_pair(0,253);
|
|
||||||
print(" \\"+shell_pwd.join("\\")+" ");
|
|
||||||
con.color_pair(253,255);
|
|
||||||
con.addch(16);
|
|
||||||
con.addch(32);
|
|
||||||
con.color_pair(239,255);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function greet() {
|
function greet() {
|
||||||
con.color_pair(0,253);
|
println(welcome_text);
|
||||||
//print(welcome_text + " ".repeat(_fsh.scrwidth - welcome_text.length));
|
|
||||||
print(welcome_text + " ".repeat(80 - welcome_text.length));
|
|
||||||
con.color_pair(239,255);
|
|
||||||
println();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -129,77 +115,116 @@ Object.freeze(shell.coreutils);
|
|||||||
shell.execute = function(line) {
|
shell.execute = function(line) {
|
||||||
if (line.size == 0) return;
|
if (line.size == 0) return;
|
||||||
let tokens = shell.parse(line);
|
let tokens = shell.parse(line);
|
||||||
let cmd = tokens[0].toLowerCase();
|
let cmd = tokens[0];
|
||||||
if (shell.coreutils[cmd] !== undefined) {
|
|
||||||
shell.coreutils[cmd](tokens);
|
if (shell.coreutils[cmd.toLowerCase()] !== undefined) {
|
||||||
|
let retval = shell.coreutils[cmd.toLowerCase()](tokens);
|
||||||
|
return retval|0; // return value of undefined will cast into 0
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printerrln('Bad command or filename: "'+cmd+'"');
|
// search through PATH for execution
|
||||||
|
|
||||||
|
let fileExists = false;
|
||||||
|
let searchDir = (cmd.startsWith("\\")) ? [""] : ["\\"+shell_pwd.join("\\")].concat(_TVDOS.defaults.path);
|
||||||
|
|
||||||
|
searchDir.forEach(function(it) { serial.println("Searchdir: "+it); });
|
||||||
|
|
||||||
|
for (let i = 0; i < searchDir.length; i++) {
|
||||||
|
let path = (searchDir[i] + cmd).substring(1); // without substring, this will always prepend revslash
|
||||||
|
if (filesystem.open(CURRENT_DRIVE, path, "R")) {
|
||||||
|
fileExists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fileExists) {
|
||||||
|
printerrln('Bad command or filename: "'+cmd+'"');
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let prg = filesystem.readAll(CURRENT_DRIVE);
|
||||||
|
let extension = undefined;
|
||||||
|
// get proper extension
|
||||||
|
let dotSepTokens = cmd.split('.');
|
||||||
|
if (dotSepTokens.length > 1) extension = dotSepTokens[dotSepTokens.length - 1].toUpperCase();
|
||||||
|
|
||||||
|
if ("BAT" == extension) {
|
||||||
|
// parse and run as batch file
|
||||||
|
let lines = prg.split('\n').filter(function(it) { return it.length > 0; });
|
||||||
|
lines.forEach(function(it) { println("Batch: " + it) }); // TODO
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return execApp(prg, tokens)|0; // return value of undefined will cast into 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (exec_args !== undefined) return Object.freeze(shell);
|
Object.freeze(shell);
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
println("Starting TVDOS...");
|
|
||||||
|
|
||||||
greet();
|
if (exec_args !== undefined) {
|
||||||
|
// command /c <commands>
|
||||||
|
// ^[0] ^[1] ^[2]
|
||||||
|
if (exec_args[1].toLowerCase() == "/c") {
|
||||||
|
if (exec_args[2] == "") return 0; // no commands were given, just exit successfully
|
||||||
|
return shell.execute(exec_args[2]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printerrln("Invalid switch: "+exec_args[1]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println("Starting TVDOS...");
|
||||||
|
|
||||||
let cmdHistory = []; // zeroth element is the oldest
|
greet();
|
||||||
let cmdHistoryScroll = 0; // 0 for outside-of-buffer, 1 for most recent
|
|
||||||
let cmdExit = false;
|
|
||||||
while (!cmdExit) {
|
|
||||||
print_prompt_text();
|
|
||||||
|
|
||||||
let cmdbuf = "";
|
let cmdHistory = []; // zeroth element is the oldest
|
||||||
|
let cmdHistoryScroll = 0; // 0 for outside-of-buffer, 1 for most recent
|
||||||
|
let cmdExit = false;
|
||||||
|
while (!cmdExit) {
|
||||||
|
print_prompt_text();
|
||||||
|
|
||||||
while (true) {
|
let cmdbuf = "";
|
||||||
let key = con.getch();
|
|
||||||
|
|
||||||
// printable chars
|
while (true) {
|
||||||
if (key >= 32 && key <= 126) {
|
let key = con.getch();
|
||||||
let s = String.fromCharCode(key);
|
|
||||||
cmdbuf += s;
|
// printable chars
|
||||||
print(s);
|
if (key >= 32 && key <= 126) {
|
||||||
}
|
let s = String.fromCharCode(key);
|
||||||
// backspace
|
cmdbuf += s;
|
||||||
else if (key === 8 && cmdbuf.length > 0) {
|
print(s);
|
||||||
cmdbuf = cmdbuf.substring(0, cmdbuf.length - 1);
|
|
||||||
print(String.fromCharCode(key));
|
|
||||||
}
|
|
||||||
// enter
|
|
||||||
else if (key === 10 || key === 13) {
|
|
||||||
println();
|
|
||||||
try {
|
|
||||||
shell.execute(cmdbuf);
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
// backspace
|
||||||
printerrln(e);
|
else if (key === 8 && cmdbuf.length > 0) {
|
||||||
|
cmdbuf = cmdbuf.substring(0, cmdbuf.length - 1);
|
||||||
|
print(String.fromCharCode(key));
|
||||||
}
|
}
|
||||||
finally {
|
// enter
|
||||||
if (cmdbuf.trim().length > 0)
|
else if (key === 10 || key === 13) {
|
||||||
cmdHistory.push(cmdbuf);
|
println();
|
||||||
|
try {
|
||||||
|
shell.execute(cmdbuf);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
printerrln(e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (cmdbuf.trim().length > 0)
|
||||||
|
cmdHistory.push(cmdbuf);
|
||||||
|
|
||||||
cmdHistoryScroll = 0;
|
cmdHistoryScroll = 0;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
// up arrow
|
||||||
// up arrow
|
else if (key === 19 && cmdHistory.length > 0 && cmdHistoryScroll < cmdHistory.length) {
|
||||||
else if (key === 19 && cmdHistory.length > 0 && cmdHistoryScroll < cmdHistory.length) {
|
cmdHistoryScroll += 1;
|
||||||
cmdHistoryScroll += 1;
|
|
||||||
|
|
||||||
// back the cursor in order to type new cmd
|
|
||||||
let x = 0;
|
|
||||||
for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8));
|
|
||||||
cmdbuf = cmdHistory[cmdHistory.length - cmdHistoryScroll];
|
|
||||||
// re-type the new command
|
|
||||||
print(cmdbuf);
|
|
||||||
|
|
||||||
}
|
|
||||||
// down arrow
|
|
||||||
else if (key === 20) {
|
|
||||||
if (cmdHistoryScroll > 0) {
|
|
||||||
// back the cursor in order to type new cmd
|
// back the cursor in order to type new cmd
|
||||||
let x = 0;
|
let x = 0;
|
||||||
for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8));
|
for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8));
|
||||||
@@ -207,13 +232,25 @@ while (!cmdExit) {
|
|||||||
// re-type the new command
|
// re-type the new command
|
||||||
print(cmdbuf);
|
print(cmdbuf);
|
||||||
|
|
||||||
cmdHistoryScroll -= 1;
|
|
||||||
}
|
}
|
||||||
else {
|
// down arrow
|
||||||
// back the cursor in order to type new cmd
|
else if (key === 20) {
|
||||||
let x = 0;
|
if (cmdHistoryScroll > 0) {
|
||||||
for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8));
|
// back the cursor in order to type new cmd
|
||||||
cmdbuf = "";
|
let x = 0;
|
||||||
|
for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8));
|
||||||
|
cmdbuf = cmdHistory[cmdHistory.length - cmdHistoryScroll];
|
||||||
|
// re-type the new command
|
||||||
|
print(cmdbuf);
|
||||||
|
|
||||||
|
cmdHistoryScroll -= 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// back the cursor in order to type new cmd
|
||||||
|
let x = 0;
|
||||||
|
for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8));
|
||||||
|
cmdbuf = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,13 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun composePositiveAns(vararg msg: String): ByteArray {
|
private val DBGPRN = true
|
||||||
|
|
||||||
|
private fun printdbg(msg: Any) {
|
||||||
|
if (DBGPRN) println("[TestDiskDrive] $msg")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun composePositiveAns(vararg msg: String): ByteArray {
|
||||||
val sb = ArrayList<Byte>()
|
val sb = ArrayList<Byte>()
|
||||||
sb.addAll(msg[0].toByteArray().toTypedArray())
|
sb.addAll(msg[0].toByteArray().toTypedArray())
|
||||||
for (k in 1 until msg.size) {
|
for (k in 1 until msg.size) {
|
||||||
@@ -126,7 +132,7 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc
|
|||||||
val inputString = inputData.trimNull().toString(VM.CHARSET)
|
val inputString = inputData.trimNull().toString(VM.CHARSET)
|
||||||
|
|
||||||
if (inputString.startsWith("DEVRST\u0017")) {
|
if (inputString.startsWith("DEVRST\u0017")) {
|
||||||
println("[TestDiskDrive] Device Reset")
|
printdbg("Device Reset")
|
||||||
//readModeLength = -1
|
//readModeLength = -1
|
||||||
fileOpen = false
|
fileOpen = false
|
||||||
fileOpenMode = -1
|
fileOpenMode = -1
|
||||||
@@ -144,14 +150,15 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc
|
|||||||
recipient?.writeout(composePositiveAns("Testtec Virtual Disk Drive"))
|
recipient?.writeout(composePositiveAns("Testtec Virtual Disk Drive"))
|
||||||
else if (inputString.startsWith("OPENR\"") || inputString.startsWith("OPENW\"") || inputString.startsWith("OPENA\"")) {
|
else if (inputString.startsWith("OPENR\"") || inputString.startsWith("OPENW\"") || inputString.startsWith("OPENA\"")) {
|
||||||
if (fileOpen) {
|
if (fileOpen) {
|
||||||
|
|
||||||
statusCode = STATE_CODE_FILE_ALREADY_OPENED
|
statusCode = STATE_CODE_FILE_ALREADY_OPENED
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
println("[TestDiskDrive] msg: $inputString, lastIndex: ${inputString.lastIndex}")
|
printdbg("msg: $inputString, lastIndex: ${inputString.lastIndex}")
|
||||||
|
|
||||||
val openMode = inputString[4]
|
val openMode = inputString[4]
|
||||||
println("[TestDiskDrive] open mode: $openMode")
|
printdbg("open mode: $openMode")
|
||||||
// split inputstring into path and optional drive-number
|
// split inputstring into path and optional drive-number
|
||||||
|
|
||||||
// get position of latest delimeter (comma)
|
// get position of latest delimeter (comma)
|
||||||
@@ -172,10 +179,10 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc
|
|||||||
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
// TODO driveNum is for disk drives that may have two or more slots built; for testing purposes we'll ignore it
|
||||||
|
|
||||||
file = File(rootPath, filePath)
|
file = File(rootPath, filePath)
|
||||||
println("[TestDiskDrive] file path: ${file.canonicalPath}, drive num: $driveNum")
|
printdbg("file path: ${file.canonicalPath}, drive num: $driveNum")
|
||||||
|
|
||||||
if (openMode == 'R' && !file.exists()) {
|
if (openMode == 'R' && !file.exists()) {
|
||||||
println("! file not found")
|
printdbg("! file not found")
|
||||||
statusCode = STATE_CODE_FILE_NOT_FOUND
|
statusCode = STATE_CODE_FILE_NOT_FOUND
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -314,7 +321,7 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc
|
|||||||
val paths = path.split('/')
|
val paths = path.split('/')
|
||||||
val newPaths = ArrayList<String>()
|
val newPaths = ArrayList<String>()
|
||||||
paths.forEach {
|
paths.forEach {
|
||||||
if (it.isBlank() || it.isEmpty()) throw IllegalArgumentException("Path cannot contain whitespaces")
|
if (it.isBlank() || it.isEmpty()) throw IllegalArgumentException("Path cannot contain whitespaces: $paths")
|
||||||
|
|
||||||
if (it == "..") {
|
if (it == "..") {
|
||||||
parentCount -= -1
|
parentCount -= -1
|
||||||
|
|||||||
Reference in New Issue
Block a user