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("\\")) {
p = p.substring(0, p.length - 1)
}
serial.println(`TVDOSFileDescriptor input path: ${path0}, p = ${p}`)
this._driveLetter = p[0]
this._path = p.substring(2) // detaches A:
this._driverID = 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) => {
let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
com.sendMessage(portNo, "CLOSE")
com.sendMessage(portNo[0], "CLOSE")
}
_TVDOS.DRV.FS.SERIAL.flush = (fd) => {
let portNo = _TVDOS.DRV.FS.SERIAL._toPorts(fd.driveLetter)
com.sendMessage(portNo, "FLUSH")
com.sendMessage(portNo[0], "FLUSH")
}
_TVDOS.DRV.FS.SERIAL.getFileLen = (fd) => {
@@ -278,7 +278,7 @@ _TVDOS.DRV.FS.SERIAL.sread = (fd) => {
}
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 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.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)
for (let i = 0; i < str.length; 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.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)
com.sendMessage(port[0], "LISTFILES")
@@ -662,7 +662,7 @@ files.open = (fullpath) => {
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 driver = _TVDOS.DRIVEFS[driveLetter]
return new TVDOSFileDescriptor(fullpath, driver)

View File

@@ -238,34 +238,52 @@ shell.parse = function(input) {
return tokens;
}
/** @return fully resolved path, starting with '\' but not a drive letter */
shell.resolvePathInput = function(input) {
// replace revslashes into rslashes
var pathstr = input.replaceAll('\\','/');
var startsWithSlash = input.startsWith('/');
var newPwd = [];
// replace slashes
let pathstr0 = input.replaceAll('\\','/') // JS thinks '/' as a regex, so we're doing this to circumvent the issue
let pathstr = ''
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'
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 > newPwd = "+newPwd);
serial.println("command.js > resolvePathInput > ipwd = "+ipwd)
serial.println("command.js > resolvePathInput > newPwd = "+newPwd)
// process dots
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) {
newPwd.pop();
newPwd.pop()
}
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
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 = {
/* Args follow this format:
@@ -278,33 +296,34 @@ shell.coreutils = {
*/
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');
if (pathOpenedStatus != 0) { printerrln("File not found"); return pathOpenedStatus; }
let contents = filesystem.readAll(CURRENT_DRIVE);
// TODO just print out what's there
print(contents);
let file = files.open(resolvedPath.full)
if (!file.exists) { printerrln("File not found"); return 1 }
let contents = file.sread()
// TODO deal with pipes
print(contents)
file.close()
},
cd: function(args) {
if (args[1] === undefined) {
println(CURRENT_DRIVE+":"+shell_pwd.join("/"));
println(CURRENT_DRIVE+":"+shell_pwd.join("/"))
return
}
var path = shell.resolvePathInput(args[1])
if (DEBUG_PRINT) serial.println("command.js > cd > pathstr = "+path.string);
let path = shell.resolvePathInput(args[1])
if (DEBUG_PRINT) serial.println("command.js > cd > pathstr = "+path.string)
// check if path is valid
var dirOpenedStatus = filesystem.open(CURRENT_DRIVE, path.string, 'R');
var isDir = filesystem.isDirectory(CURRENT_DRIVE); // open a dir; if path is nonexistent, file won't actually be opened
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;
let file = files.open(path.full)
if (!file.isDirectory) { printerrln(`${args[0].toUpperCase()} failed for '${path.full}'`); return 1; } // if file is not opened, IO error code will be returned
shell_pwd = path.pwd
},
cls: function(args) {
con.clear();
graphics.clearPixels(255);
graphics.clearPixels2(240);
con.clear()
graphics.clearPixels(255)
graphics.clearPixels2(240)
},
cp: function(args) {
if (args[2] === undefined || args[1] === undefined) {
@@ -313,21 +332,18 @@ shell.coreutils = {
}
let path = shell.resolvePathInput(args[1])
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')
let isDir = filesystem.isDirectory(CURRENT_DRIVE)
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
serial.println(`[cp] source path: ${path.full}`)
serial.println(`[cp] dest path: ${pathd.full}`)
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())
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)
destFile.flush(); destFile.close(); sourceFile.close()
},
date: function(args) {
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')}`)
},
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
var pathOpenedStatus = filesystem.open(CURRENT_DRIVE, pathstr, 'R');
if (pathOpenedStatus != 0) { printerrln("File not found"); return pathOpenedStatus; }
var port = filesystem._toPorts(CURRENT_DRIVE)[0]
com.sendMessage(port, "LIST");
println(com.pullMessage(port));
println(`Current directory: ${currentDir.fullPath}`)
fileList.forEach(it => {
println(`${it.name.padEnd(termWidth / 2, ' ')}${it.size}`)
})
},
del: function(args) {
if (args[1] === undefined) {