diff --git a/assets/tbas/basic.js b/assets/tbas/basic.js index c90c2bb..fe6df17 100644 --- a/assets/tbas/basic.js +++ b/assets/tbas/basic.js @@ -317,8 +317,7 @@ basicInterpreterStatus.builtin = { if (seps[llll - 1] == ",") print("\t"); } - var resolvedargs = resolve(args[llll]); - if (resolvedargs === undefined) resolvedargs = ""; + var resolvedargs = resolve(args[llll]) || ""; if (args[llll].type == "number") print(" "+resolvedargs+" "); diff --git a/assets/tvdos/TVDOS.SYS b/assets/tvdos/TVDOS.SYS index a551f3b..11f6b78 100644 --- a/assets/tvdos/TVDOS.SYS +++ b/assets/tvdos/TVDOS.SYS @@ -27,6 +27,9 @@ Object.freeze(_TVDOS); var filesystem = {}; filesystem._toPorts = function(driveLetter) { + if (driveLetter.toUpperCase === undefined) { + throw Error("'"+driveLetter+"' (type: "+typeof driveLetter+") is not a valid drive letter"); + } let port = _TVDOS.DRIVES[driveLetter.toUpperCase()]; if (port === undefined) { throw Error("Drive letter '" + driveLetter.toUpperCase() + "' does not exist"); @@ -76,9 +79,8 @@ filesystem.isDirectory = function(driveLetter) { let port = filesystem._toPorts(driveLetter); com.sendMessage(port[0], "LISTFILES"); let response = com.getStatusCode(port[0]); - return (response === 0); -} +}; filesystem.mkDir = function(driveLetter) { let port = filesystem._toPorts(driveLetter); com.sendMessage(port[0], "MKDIR"); @@ -89,7 +91,19 @@ filesystem.mkDir = function(driveLetter) { throw Error("Creating a directory failed with ("+response+"): "+status.message+"\n"); } return (response === 0); // possible status codes: 0 (success), 1 (fail) -} +}; +filesystem.touch = function(driveLetter) { + let port = filesystem._toPorts(driveLetter); + com.sendMessage(port[0], "TOUCH"); + let response = com.getStatusCode(port[0]); + return (response === 0); +}; +filesystem.mkFile = function(driveLetter) { + let port = filesystem._toPorts(driveLetter); + com.sendMessage(port[0], "MKFILE"); + let response = com.getStatusCode(port[0]); + return (response === 0); +}; Object.freeze(filesystem); /////////////////////////////////////////////////////////////////////////////// @@ -110,6 +124,7 @@ var execApp = function(cmdsrc, args) { // Boot script serial.println("TVDOS.SYS initialised, running boot script..."); +var _G = {}; filesystem.open("A", "tvdos/bin/command.js", "R"); let cmdsrc = filesystem.readAll("A"); execApp(cmdsrc, ["", "/c", "\\AUTOEXEC.BAT"]); diff --git a/assets/tvdos/bin/command.js b/assets/tvdos/bin/command.js index 0c5b604..e3c7070 100644 --- a/assets/tvdos/bin/command.js +++ b/assets/tvdos/bin/command.js @@ -52,6 +52,8 @@ function trimStartRevSlash(s) { } let shell = {}; +shell.getPwd = function() { return shell_pwd; } +shell.getCurrentDrive = function() { return CURRENT_DRIVE; } // example input: echo "the string" > subdir\test.txt shell.parse = function(input) { let tokens = []; @@ -122,8 +124,7 @@ shell.parse = function(input) { return tokens; } - -function resolvePathInput(input) { +shell.resolvePathInput = function(input) { // replace slashes into revslashes let pathstr = input.replaceAll('/','\\\\'); let startsWithSlash = input.startsWith('\\'); @@ -166,7 +167,7 @@ shell.coreutils = { println(CURRENT_DRIVE+":"+shell_pwd.join("\\")); return } - let path = resolvePathInput(args[1]) + let path = shell.resolvePathInput(args[1]) if (DEBUG_PRINT) serial.println("command.js > cd > pathstr = "+path.string); // check if path is valid @@ -181,7 +182,7 @@ shell.coreutils = { printerrln("Syntax error"); return } - let path = resolvePathInput(args[1]) + let path = shell.resolvePathInput(args[1]) if (DEBUG_PRINT) serial.println("command.js > mkdir > pathstr = "+path.string); // check if path is valid @@ -320,6 +321,7 @@ shell.execute = function(line) { } }; Object.freeze(shell); +_G.shell = shell; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/assets/tvdos/bin/touch.js b/assets/tvdos/bin/touch.js new file mode 100644 index 0000000..3081a8a --- /dev/null +++ b/assets/tvdos/bin/touch.js @@ -0,0 +1,30 @@ +if (exec_args[1] === undefined) { + println("TOUCH - TVDOS file date and time setting utility"); + println() + println("SYNOPSIS") + println(" TOUCH [/C] path") + println() + println("/C = don't create files that do not already exist") + return 1; +} + +let path = _G.shell.resolvePathInput(exec_args[2] || exec_args[1]).string; +let driveLetter = _G.shell.getCurrentDrive(); +let noNewFile = (exec_args[1] == "/c" || exec_args[1] == "/C"); +let fileOpened = filesystem.open(driveLetter, path, "W"); +if (!fileOpened) { + printerrln("TOUCH: Can't open "+driveLetter+":\\"+path+" due to IO error"); + return 1; +} + +if (!noNewFile) { + filesystem.mkFile(driveLetter); +} + +let touched = filesystem.touch(driveLetter); +if (!touched) { + printerrln("TOUCH: Can't touch "+driveLetter+":\\"+path+" due to IO error"); + return 1; +} + +return 0; \ No newline at end of file diff --git a/src/net/torvald/tsvm/peripheral/IOSpace.kt b/src/net/torvald/tsvm/peripheral/IOSpace.kt index b3bda14..3cf0d81 100644 --- a/src/net/torvald/tsvm/peripheral/IOSpace.kt +++ b/src/net/torvald/tsvm/peripheral/IOSpace.kt @@ -40,7 +40,7 @@ class IOSpace(val vm: VM) : PeriBase, InputProcessor { init { blockTransferPorts[1].attachDevice(TestFunctionGenerator()) - blockTransferPorts[0].attachDevice(TestDiskDrive(0, File("assets/"))) + blockTransferPorts[0].attachDevice(TestDiskDrive(vm, 0, File("assets/"))) } private fun composeBlockTransferStatus(portno: Int): Int { diff --git a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt index 3b477c5..929ad4f 100644 --- a/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt +++ b/src/net/torvald/tsvm/peripheral/TestDiskDrive.kt @@ -1,13 +1,14 @@ package net.torvald.tsvm.peripheral import net.torvald.tsvm.VM +import net.torvald.tsvm.VMJSR223Delegate import java.io.ByteArrayOutputStream import java.io.File import java.io.FileInputStream import java.io.IOException import java.util.* -class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : BlockTransferInterface(false, true) { +class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath: File? = null) : BlockTransferInterface(false, true) { companion object { const val STATE_CODE_STANDBY = 0 @@ -306,7 +307,7 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc } else if (inputString.startsWith("MKDIR")) { if (!fileOpen) { - statusCode = STATE_CODE_FILE_NOT_FOUND + statusCode = STATE_CODE_NO_FILE_OPENED return } if (fileOpenMode < 1) { @@ -321,9 +322,51 @@ class TestDiskDrive(private val driveNum: Int, theRootPath: File? = null) : Bloc statusCode = STATE_CODE_SYSTEM_SECURITY_ERROR } } + else if (inputString.startsWith("MKFILE")) { + if (!fileOpen) { + statusCode = STATE_CODE_NO_FILE_OPENED + return + } + if (fileOpenMode < 1) { + statusCode = STATE_CODE_OPERATION_NOT_PERMITTED + return + } + try { + val f1 = file.createNewFile() + statusCode = if (f1) STATE_CODE_STANDBY else STATE_CODE_OPERATION_FAILED + return + } + catch (e: IOException) { + statusCode = STATE_CODE_SYSTEM_IO_ERROR + } + catch (e1: SecurityException) { + statusCode = STATE_CODE_SYSTEM_SECURITY_ERROR + } + } + else if (inputString.startsWith("TOUCH")) { + if (!fileOpen) { + statusCode = STATE_CODE_NO_FILE_OPENED + return + } + if (fileOpenMode < 1) { + statusCode = STATE_CODE_OPERATION_NOT_PERMITTED + return + } + try { + val f1 = file.setLastModified(vm.worldInterface.currentTimeInMills()) + statusCode = if (f1) STATE_CODE_STANDBY else STATE_CODE_OPERATION_FAILED + return + } + catch (e: IOException) { + statusCode = STATE_CODE_SYSTEM_IO_ERROR + } + catch (e1: SecurityException) { + statusCode = STATE_CODE_SYSTEM_SECURITY_ERROR + } + } else if (inputString.startsWith("WRITE")) { if (!fileOpen) { - statusCode = STATE_CODE_FILE_NOT_FOUND + statusCode = STATE_CODE_NO_FILE_OPENED return } if (fileOpenMode < 0) {