From 3b2870ec9cbad1ea3ad57b12bdfb4257044447bd Mon Sep 17 00:00:00 2001 From: minjaesong Date: Wed, 4 Nov 2020 14:33:27 +0900 Subject: [PATCH] impl of autoexec.bat (wip) --- assets/!BOOTSEC | 2 +- assets/AUTOEXEC.BAT | 2 + assets/tvdos/TVDOS.SYS | 18 +- assets/tvdos/command.js | 187 +++++++++++------- .../torvald/tsvm/peripheral/TestDiskDrive.kt | 21 +- 5 files changed, 138 insertions(+), 92 deletions(-) create mode 100644 assets/AUTOEXEC.BAT diff --git a/assets/!BOOTSEC b/assets/!BOOTSEC index 13336dc..27c2be4 100644 --- a/assets/!BOOTSEC +++ b/assets/!BOOTSEC @@ -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"); \ No newline at end of file +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"); \ No newline at end of file diff --git a/assets/AUTOEXEC.BAT b/assets/AUTOEXEC.BAT new file mode 100644 index 0000000..e3c62f0 --- /dev/null +++ b/assets/AUTOEXEC.BAT @@ -0,0 +1,2 @@ +echo "Hello, world!" +fsh \ No newline at end of file diff --git a/assets/tvdos/TVDOS.SYS b/assets/tvdos/TVDOS.SYS index 5baf03c..d1cdd57 100644 --- a/assets/tvdos/TVDOS.SYS +++ b/assets/tvdos/TVDOS.SYS @@ -10,7 +10,7 @@ _TVDOS.DRIVES["A"] = _BIOS.FIRST_BOOTABLE_PORT; _TVDOS.defaults = { path: [ - "/tvdos/bin" + "\\tvdos\\bin\\" ] }; Object.freeze(_TVDOS); @@ -31,8 +31,11 @@ filesystem._close = function(portNo) { filesystem._flush = function(portNo) { com.sendMessage(portNo, "FLUSH"); }; -// @return true if operation committed successfully, false otherwise; throws error -// if unknown mode or invalid drive letter was given +// @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 = function(driveLetter, path, operationMode) { let port = filesystem._toPorts(driveLetter); @@ -67,7 +70,8 @@ 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 +// @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) { let prg = eval("let _appStub=function(exec_args){"+cmdsrc+"};_appStub;"); // making 'exec_args' a app-level global return prg(args); @@ -78,8 +82,4 @@ var execApp = function(cmdsrc, args) { // Boot script filesystem.open("A", "tvdos/command.js", "R"); let cmdsrc = filesystem.readAll("A"); - -// app execution stub -execApp(cmdsrc); -//let sh = execApp(cmdsrc, [42]); -//println(sh.test); +execApp(cmdsrc, ["", "/c", "\\AUTOEXEC.BAT"]); diff --git a/assets/tvdos/command.js b/assets/tvdos/command.js index c64295c..7988981 100644 --- a/assets/tvdos/command.js +++ b/assets/tvdos/command.js @@ -6,25 +6,11 @@ let shell_pwd = []; const welcome_text = "TSVM Disk Operating System, version " + _TVDOS.VERSION; function print_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); + print(CURRENT_DRIVE + ":\\" + shell_pwd.join("\\") + PROMPT_TEXT); } function greet() { - con.color_pair(0,253); - //print(welcome_text + " ".repeat(_fsh.scrwidth - welcome_text.length)); - print(welcome_text + " ".repeat(80 - welcome_text.length)); - con.color_pair(239,255); - println(); + println(welcome_text); } @@ -129,77 +115,116 @@ Object.freeze(shell.coreutils); shell.execute = function(line) { if (line.size == 0) return; let tokens = shell.parse(line); - let cmd = tokens[0].toLowerCase(); - if (shell.coreutils[cmd] !== undefined) { - shell.coreutils[cmd](tokens); + let cmd = tokens[0]; + + 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 { - 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 + // ^[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 -let cmdHistoryScroll = 0; // 0 for outside-of-buffer, 1 for most recent -let cmdExit = false; -while (!cmdExit) { - print_prompt_text(); + greet(); - 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 key = con.getch(); + let cmdbuf = ""; - // printable chars - if (key >= 32 && key <= 126) { - let s = String.fromCharCode(key); - cmdbuf += s; - print(s); - } - // backspace - else if (key === 8 && cmdbuf.length > 0) { - cmdbuf = cmdbuf.substring(0, cmdbuf.length - 1); - print(String.fromCharCode(key)); - } - // enter - else if (key === 10 || key === 13) { - println(); - try { - shell.execute(cmdbuf); + while (true) { + let key = con.getch(); + + // printable chars + if (key >= 32 && key <= 126) { + let s = String.fromCharCode(key); + cmdbuf += s; + print(s); } - catch (e) { - printerrln(e); + // backspace + else if (key === 8 && cmdbuf.length > 0) { + cmdbuf = cmdbuf.substring(0, cmdbuf.length - 1); + print(String.fromCharCode(key)); } - finally { - if (cmdbuf.trim().length > 0) - cmdHistory.push(cmdbuf); + // enter + else if (key === 10 || key === 13) { + println(); + try { + shell.execute(cmdbuf); + } + catch (e) { + printerrln(e); + } + finally { + if (cmdbuf.trim().length > 0) + cmdHistory.push(cmdbuf); - cmdHistoryScroll = 0; - break; + cmdHistoryScroll = 0; + break; + } } - } - // up arrow - else if (key === 19 && cmdHistory.length > 0 && cmdHistoryScroll < cmdHistory.length) { - cmdHistoryScroll += 1; + // up arrow + else if (key === 19 && cmdHistory.length > 0 && cmdHistoryScroll < cmdHistory.length) { + 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 let x = 0; for (x = 0; x < cmdbuf.length; x++) print(String.fromCharCode(8)); @@ -207,13 +232,25 @@ while (!cmdExit) { // 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 = ""; + // down arrow + else if (key === 20) { + if (cmdHistoryScroll > 0) { + // 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); + + 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 = ""; + } } } } diff --git a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt index 6a00de5..be46c45 100644 --- a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt +++ b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt @@ -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() sb.addAll(msg[0].toByteArray().toTypedArray()) 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) if (inputString.startsWith("DEVRST\u0017")) { - println("[TestDiskDrive] Device Reset") + printdbg("Device Reset") //readModeLength = -1 fileOpen = false fileOpenMode = -1 @@ -144,14 +150,15 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc recipient?.writeout(composePositiveAns("Testtec Virtual Disk Drive")) else if (inputString.startsWith("OPENR\"") || inputString.startsWith("OPENW\"") || inputString.startsWith("OPENA\"")) { if (fileOpen) { + statusCode = STATE_CODE_FILE_ALREADY_OPENED return } - println("[TestDiskDrive] msg: $inputString, lastIndex: ${inputString.lastIndex}") + printdbg("msg: $inputString, lastIndex: ${inputString.lastIndex}") val openMode = inputString[4] - println("[TestDiskDrive] open mode: $openMode") + printdbg("open mode: $openMode") // split inputstring into path and optional drive-number // 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 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()) { - println("! file not found") + printdbg("! file not found") statusCode = STATE_CODE_FILE_NOT_FOUND return } @@ -314,7 +321,7 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc val paths = path.split('/') val newPaths = ArrayList() 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 == "..") { parentCount -= -1