command.js: WIP rewriting coreutils to use new filesystem

This commit is contained in:
minjaesong
2022-08-18 00:19:49 +09:00
parent 1e9f4f17c8
commit 01e7ead7fa
2 changed files with 72 additions and 57 deletions

View File

@@ -83,11 +83,11 @@ class TVDOSFileDescriptor {
while (p.endsWith("\\")) { while (p.endsWith("\\")) {
p = p.substring(0, p.length - 1) p = p.substring(0, p.length - 1)
} }
serial.println(`TVDOSFileDescriptor input path: ${path0}, p = ${p}`)
this._driveLetter = p[0] this._driveLetter = p[0]
this._path = p.substring(2) // detaches A: this._path = p.substring(2) // detaches A:
this._driverID = driverID this._driverID = driverID
this._driver = _TVDOS.DRV.FS[driverID] this._driver = _TVDOS.DRV.FS[driverID]
serial.println(`TVDOSFileDescriptor input path: ${path0}, p = ${p}, driveLetter = ${this._driveLetter}, path = ${this._path}`)
} }
} }
@@ -241,11 +241,11 @@ _TVDOS.DRV.FS.SERIAL._flush = (portNo) => {
} }
_TVDOS.DRV.FS.SERIAL.close = (fd) => { _TVDOS.DRV.FS.SERIAL.close = (fd) => {
let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
com.sendMessage(portNo, "CLOSE") com.sendMessage(portNo[0], "CLOSE")
} }
_TVDOS.DRV.FS.SERIAL.flush = (fd) => { _TVDOS.DRV.FS.SERIAL.flush = (fd) => {
let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
com.sendMessage(portNo, "FLUSH") com.sendMessage(portNo[0], "FLUSH")
} }
_TVDOS.DRV.FS.SERIAL.getFileLen = (fd) => { _TVDOS.DRV.FS.SERIAL.getFileLen = (fd) => {
@@ -278,7 +278,7 @@ _TVDOS.DRV.FS.SERIAL.sread = (fd) => {
} }
return com.pullMessage(port[0]) return com.pullMessage(port[0])
} }
_TVDOS.DRV.FS.SERIAL.swrite = (fd, str) => { _TVDOS.DRV.FS.SERIAL.swrite = (fd, string) => {
let rrrr = _TVDOS.DRV.FS.SERIAL._openw(fd); if (rrrr != 0) throw Error("Writing a file failed with "+rrrr) let rrrr = _TVDOS.DRV.FS.SERIAL._openw(fd); if (rrrr != 0) throw Error("Writing a file failed with "+rrrr)
let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
@@ -294,7 +294,7 @@ _TVDOS.DRV.FS.SERIAL.swrite = (fd, str) => {
_TVDOS.DRV.FS.SERIAL._flush(port[0]);_TVDOS.DRV.FS.SERIAL._close(port[0]) _TVDOS.DRV.FS.SERIAL._flush(port[0]);_TVDOS.DRV.FS.SERIAL._close(port[0])
} }
_TVDOS.DRV.FS.SERIAL.bread = (fd) => { _TVDOS.DRV.FS.SERIAL.bread = (fd) => {
let str = _TVDOS.DRV.FS.SERIAL.sread(fd.driveLetter) let str = _TVDOS.DRV.FS.SERIAL.sread(fd)
let bytes = new Uint8Array(str.length) let bytes = new Uint8Array(str.length)
for (let i = 0; i < str.length; i++) { for (let i = 0; i < str.length; i++) {
bytes[i] = str.charCodeAt(i) bytes[i] = str.charCodeAt(i)
@@ -306,7 +306,7 @@ _TVDOS.DRV.FS.SERIAL.bwrite = (fd, bytes) => { // pwrite replaces DMA.ramToCom
_TVDOS.DRV.FS.SERIAL.swrite(fd, string) _TVDOS.DRV.FS.SERIAL.swrite(fd, string)
} }
_TVDOS.DRV.FS.SERIAL.isDirectory = (fd) => { _TVDOS.DRV.FS.SERIAL.isDirectory = (fd) => {
if (129 == _TVDOS.DRV.FS.SERIAL._openr(fd)) throw Error(`No such file: ${fd.path}`) if (129 == _TVDOS.DRV.FS.SERIAL._openr(fd)) return false // file not exists
let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter) let port = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
com.sendMessage(port[0], "LISTFILES") com.sendMessage(port[0], "LISTFILES")
@@ -662,7 +662,7 @@ files.open = (fullpath) => {
return new TVDOSFileDescriptor(fullpath.toUpperCase()) return new TVDOSFileDescriptor(fullpath.toUpperCase())
} }
if (fullpath[2] != '/' && fullpath[2] != '\\') throw Error("Expected full path with drive letter") if (fullpath[2] != '/' && fullpath[2] != '\\') throw Error("Expected full path with drive letter, got " + fullpath)
let driveLetter = fullpath[0].toUpperCase() let driveLetter = fullpath[0].toUpperCase()
let driver = _TVDOS.DRIVEFS[driveLetter] let driver = _TVDOS.DRIVEFS[driveLetter]
return new TVDOSFileDescriptor(fullpath, driver) return new TVDOSFileDescriptor(fullpath, driver)

View File

@@ -238,34 +238,52 @@ shell.parse = function(input) {
return tokens; return tokens;
} }
/** @return fully resolved path, starting with '\' but not a drive letter */
shell.resolvePathInput = function(input) { shell.resolvePathInput = function(input) {
// replace revslashes into rslashes // replace slashes
var pathstr = input.replaceAll('\\','/'); let pathstr0 = input.replaceAll('\\','/') // JS thinks '/' as a regex, so we're doing this to circumvent the issue
var startsWithSlash = input.startsWith('/'); let pathstr = ''
var newPwd = []; let driveLetter = CURRENT_DRIVE
// if input has no drive letter?
if (pathstr0[2] != '/' && pathstr0[2] != '\\') {
pathstr = pathstr0
}
else {
pathstr = pathstr0.substring(2)
driveLetter = pathstr0[0].toUpperCase()
}
serial.println("command.js > resolvePathInput > sanitised input: "+pathstr)
let startsWithSlash = pathstr.startsWith('/')
let newPwd = []
serial.println("command.js > resolvePathInput > path starts with slash: "+startsWithSlash)
// split them into an array while filtering empty elements except for the root 'head' // split them into an array while filtering empty elements except for the root 'head'
var ipwd = (startsWithSlash ? [""] : shell_pwd).concat(pathstr.split("/").filter(function(it) { return (it.length > 0); })); let ipwd = (startsWithSlash ? [""] : shell_pwd).concat(pathstr.split("/").filter(function(it) { return (it.length > 0); }))
serial.println("command.js > resolvePathInput > ipwd = "+ipwd); serial.println("command.js > resolvePathInput > ipwd = "+ipwd)
serial.println("command.js > resolvePathInput > newPwd = "+newPwd); serial.println("command.js > resolvePathInput > newPwd = "+newPwd)
// process dots // process dots
ipwd.forEach(function(it) { ipwd.forEach(function(it) {
serial.println("command.js > resolvePathInput > ipwd.forEach > it = "+it); serial.println("command.js > resolvePathInput > ipwd.forEach > it = "+it)
if (it === ".." && newPwd[1] !== undefined) { if (it === ".." && newPwd[1] !== undefined) {
newPwd.pop(); newPwd.pop()
} }
else if (it !== ".." && it !== ".") { else if (it !== ".." && it !== ".") {
newPwd.push(it); newPwd.push(it)
} }
serial.println("command.js > resolvePathInput > newPwd = "+newPwd); serial.println("command.js > resolvePathInput > newPwd = "+newPwd)
}); })
// construct new pathstr from pwd arr so it will be sanitised // construct new pathstr from pwd arr so it will be sanitised
pathstr = newPwd.join('/').substring(1); pathstr = '\\' + newPwd.join('\\').substring(1) // dirty hack to make sure slash is prepended even if newPwd is one elem long
return { string: pathstr, pwd: newPwd }; return { string: pathstr, pwd: newPwd, drive: driveLetter, full: `${driveLetter}:${pathstr}` }
} }
shell.coreutils = { shell.coreutils = {
/* Args follow this format: /* Args follow this format:
@@ -278,33 +296,34 @@ shell.coreutils = {
*/ */
cat: function(args) { cat: function(args) {
var pathstr = (args[1] !== undefined) ? args[1] : shell.getPwdString(); let pathstr = (args[1] !== undefined) ? args[1] : shell.getPwdString()
let resolvedPath = shell.resolvePathInput(pathstr)
var pathOpenedStatus = filesystem.open(CURRENT_DRIVE, pathstr, 'R'); let file = files.open(resolvedPath.full)
if (pathOpenedStatus != 0) { printerrln("File not found"); return pathOpenedStatus; }
let contents = filesystem.readAll(CURRENT_DRIVE); if (!file.exists) { printerrln("File not found"); return 1 }
// TODO just print out what's there let contents = file.sread()
print(contents); // TODO deal with pipes
print(contents)
file.close()
}, },
cd: function(args) { cd: function(args) {
if (args[1] === undefined) { if (args[1] === undefined) {
println(CURRENT_DRIVE+":"+shell_pwd.join("/")); println(CURRENT_DRIVE+":"+shell_pwd.join("/"))
return return
} }
var path = shell.resolvePathInput(args[1]) let path = shell.resolvePathInput(args[1])
if (DEBUG_PRINT) serial.println("command.js > cd > pathstr = "+path.string); if (DEBUG_PRINT) serial.println("command.js > cd > pathstr = "+path.string)
// check if path is valid // check if path is valid
var dirOpenedStatus = filesystem.open(CURRENT_DRIVE, path.string, 'R'); let file = files.open(path.full)
var isDir = filesystem.isDirectory(CURRENT_DRIVE); // open a dir; if path is nonexistent, file won't actually be opened if (!file.isDirectory) { printerrln(`${args[0].toUpperCase()} failed for '${path.full}'`); return 1; } // if file is not opened, IO error code will be returned
if (!isDir) { printerrln(`${args[0].toUpperCase()} failed for '${path.string}'`); return dirOpenedStatus; } // if file is not opened, IO error code will be returned shell_pwd = path.pwd
shell_pwd = path.pwd;
}, },
cls: function(args) { cls: function(args) {
con.clear(); con.clear()
graphics.clearPixels(255); graphics.clearPixels(255)
graphics.clearPixels2(240); graphics.clearPixels2(240)
}, },
cp: function(args) { cp: function(args) {
if (args[2] === undefined || args[1] === undefined) { if (args[2] === undefined || args[1] === undefined) {
@@ -313,21 +332,18 @@ shell.coreutils = {
} }
let path = shell.resolvePathInput(args[1]) let path = shell.resolvePathInput(args[1])
let pathd = shell.resolvePathInput(args[2]) let pathd = shell.resolvePathInput(args[2])
let sourceFile = files.open(path.full)
let destFile = files.open(pathd.full)
let dirOpenedStatus = filesystem.open(CURRENT_DRIVE, path.string, 'R') serial.println(`[cp] source path: ${path.full}`)
let isDir = filesystem.isDirectory(CURRENT_DRIVE) serial.println(`[cp] dest path: ${pathd.full}`)
if (isDir || dirOpenedStatus != 0) { printerrln(`${args[0].toUpperCase()} failed for '${path.string}'`); return dirOpenedStatus; } // if file is directory or failed to open, IO error code will be returned
if (sourceFile.isDirectory || !sourceFile.exists) { printerrln(`${args[0].toUpperCase()} failed for '${sourceFile.fullPath}'`); return 1 } // if file is directory or failed to open, IO error code will be returned
if (destFile.isDirectory) { printerrln(`${args[0].toUpperCase()} failed for '${destFile.fullPath}'`); return 1 } // if file is directory or failed to open, IO error code will be returned
let bytes = filesystem.readAllBytes(CURRENT_DRIVE) destFile.bwrite(sourceFile.bread())
destFile.flush(); destFile.close(); sourceFile.close()
dirOpenedStatus = filesystem.open(CURRENT_DRIVE, pathd.string, 'W')
isDir = filesystem.isDirectory(CURRENT_DRIVE)
if (isDir || dirOpenedStatus != 0) { printerrln(`${args[0].toUpperCase()} failed for '${pathd.string}'`); return dirOpenedStatus; } // if file is directory or failed to open, IO error code will be returned
filesystem.writeBytes(CURRENT_DRIVE, bytes)
}, },
date: function(args) { date: function(args) {
let monthNames = ["Spring", "Summer", "Autumn", "Winter"] let monthNames = ["Spring", "Summer", "Autumn", "Winter"]
@@ -352,15 +368,14 @@ shell.coreutils = {
println(`\xE7${years} ${monthNames[months]} ${visualDay} ${dayNames[dayName]}, ${(''+hours).padStart(2,'0')}:${(''+mins).padStart(2,'0')}:${(''+secs).padStart(2,'0')}`) println(`\xE7${years} ${monthNames[months]} ${visualDay} ${dayNames[dayName]}, ${(''+hours).padStart(2,'0')}:${(''+mins).padStart(2,'0')}:${(''+secs).padStart(2,'0')}`)
}, },
dir: function(args) { dir: function(args) {
var pathstr = (args[1] !== undefined) ? args[1] : shell.getPwdString(); let currentPath = (args[1] !== undefined) ? args[1] : shell.getPwdString()
let currentDir = files.open(`${CURRENT_DRIVE}:\\${currentPath}`)
let fileList = currentDir.list()
// check if path is valid println(`Current directory: ${currentDir.fullPath}`)
var pathOpenedStatus = filesystem.open(CURRENT_DRIVE, pathstr, 'R'); fileList.forEach(it => {
if (pathOpenedStatus != 0) { printerrln("File not found"); return pathOpenedStatus; } println(`${it.name.padEnd(termWidth / 2, ' ')}${it.size}`)
})
var port = filesystem._toPorts(CURRENT_DRIVE)[0]
com.sendMessage(port, "LIST");
println(com.pullMessage(port));
}, },
del: function(args) { del: function(args) {
if (args[1] === undefined) { if (args[1] === undefined) {