more coreutils

This commit is contained in:
minjaesong
2022-06-21 02:16:46 +09:00
parent d103373614
commit 371b80ca26
5 changed files with 243 additions and 58 deletions

View File

@@ -172,6 +172,12 @@ filesystem.mkFile = (driveLetter) => {
var response = com.getStatusCode(port[0]);
return (response === 0);
};
filesystem.delete = (driveLetter) => {
var port = filesystem._toPorts(driveLetter);
com.sendMessage(port[0], "DELETE");
var response = com.getStatusCode(port[0]);
return (response === 0);
};
Object.freeze(filesystem);
///////////////////////////////////////////////////////////////////////////////

View File

@@ -275,6 +275,16 @@ shell.coreutils = {
* but do instead:
* if (args[1] === undefined)
*/
cat: function(args) {
var pathstr = (args[1] !== undefined) ? args[1] : shell.getPwdString();
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);
},
cd: function(args) {
if (args[1] === undefined) {
println(CURRENT_DRIVE+":"+shell_pwd.join("/"));
@@ -286,10 +296,94 @@ shell.coreutils = {
// 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("CHDIR failed for '"+path.string+"'"); return dirOpenedStatus; } // 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;
},
cls: function(args) {
con.clear();
graphics.clearPixels(255);
graphics.clearPixels2(240);
},
cp: function(args) {
if (args[2] === undefined) {
printerrln("Syntax error")
return
}
else if (args[1] === undefined) {
printerrln(`Usage: ${args[0].toUpperCase()} SOURCE DEST`)
return
}
let path = shell.resolvePathInput(args[1])
let pathd = shell.resolvePathInput(args[2])
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
let bytes = filesystem.readAllBytes(CURRENT_DRIVE)
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) {
let monthNames = ["Spring", "Summer", "Autumn", "Winter"]
let dayNames = ["Mondag", "Tysdag", "Midtveke", "Torsdag", "Fredag", "Laurdag", "Sundag", "Verddag"]
let msec = sys.currentTimeInMills()
while (msec == 0) {
msec = sys.currentTimeInMills()
}
let secs = ((msec / 1000)|0) % 60
let timeInMinutes = ((msec / 60000)|0)
let mins = timeInMinutes % 60
let hours = ((timeInMinutes / 60)|0) % 24
let ordinalDay = ((timeInMinutes / (60*24))|0) % 120
let visualDay = (ordinalDay % 30) + 1
let months = ((timeInMinutes / (60*24*30))|0) % 4
let dayName = ordinalDay % 7 // 0 for Mondag
if (ordinalDay == 119) dayName = 7 // Verddag
let years = ((timeInMinutes / (60*24*30*120))|0) + 125
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();
// 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));
},
del: function(args) {
if (args[1] === undefined) {
printerrln("Syntax error");
return
}
var pathOpenedStatus = filesystem.open(CURRENT_DRIVE, args[1], 'R');
if (pathOpenedStatus != 0) { printerrln("File not found"); return pathOpenedStatus; }
return filesystem.delete(CURRENT_DRIVE)
},
echo: function(args) {
if (args[1] !== undefined) {
args.forEach(function(it,i) { if (i > 0) print(shell.replaceVarCall(it)+" ") });
}
println();
},
exit: function(args) {
cmdExit = true;
},
mkdir: function(args) {
if (args[1] === undefined) {
printerrln("Syntax error");
@@ -301,24 +395,7 @@ shell.coreutils = {
// check if path is valid
var dirOpenedStatus = filesystem.open(CURRENT_DRIVE, path.string, 'W');
var mkdird = filesystem.mkDir(CURRENT_DRIVE);
if (!mkdird) { printerrln("MKDIR failed for '"+path.string+"'"); return dirOpenedStatus; }
},
cls: function(args) {
con.clear();
graphics.clearPixels(255);
graphics.clearPixels2(240);
},
exit: function(args) {
cmdExit = true;
},
ver: function(args) {
println(welcome_text);
},
echo: function(args) {
if (args[1] !== undefined) {
args.forEach(function(it,i) { if (i > 0) print(shell.replaceVarCall(it)+" ") });
}
println();
if (!mkdird) { printerrln(`${args[0].toUpperCase()} failed for '${path.string}'`); return dirOpenedStatus; }
},
rem: function(args) {
return 0;
@@ -358,31 +435,21 @@ shell.coreutils = {
}
}
},
dir: function(args) {
var pathstr = (args[1] !== undefined) ? args[1] : shell.getPwdString();
// 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));
},
cat: function(args) {
var pathstr = (args[1] !== undefined) ? args[1] : shell.getPwdString();
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);
ver: function(args) {
println(welcome_text);
},
panic: function(args) {
throw Error("Panicking command.js")
}
};
shell.coreutils.chdir = shell.coreutils.cd;
// define command aliases here
shell.coreutils.chdir = shell.coreutils.cd
shell.coreutils.copy = shell.coreutils.cp
shell.coreutils.erase = shell.coreutils.del
shell.coreutils.rm = shell.coreutils.del
shell.coreutils.ls = shell.coreutils.dir
shell.coreutils.time = shell.coreutils.date
// end of command aliases
Object.freeze(shell.coreutils);
shell.stdio = {
out: {

View File

@@ -102,9 +102,8 @@ clockWidget.draw = function(charXoff, charYoff) {
con.move(1 + charYoff, 17 + charXoff);
print(clockWidget.monthNames[months]+" "+visualDay);
// print year and dayname
con.mvaddch(2 + charYoff, 17 + charXoff, 5);
con.move(2 + charYoff, 18 + charXoff);
print(years+" "+clockWidget.dayNames[dayName]);
con.move(2 + charYoff, 17 + charXoff);
print("\xE7"+years+" "+clockWidget.dayNames[dayName]);
};

View File

@@ -7,23 +7,43 @@ import java.io.OutputStream
/**
* Created by minjaesong on 2022-05-23.
*/
class SerialStdioHost(val hostVM: VM) : BlockTransferInterface(true, true) {
class SerialStdioHost(val runnerVM: VM) : BlockTransferInterface(true, true) {
/**
* - IDLE: Initial status
* - HOST: Usually the server computer
* - TERMINAL: Usually the user computer that connects to the host
* - PRINTSTREAM: When set, any received bytes will go into the monitor
* - INPUTSTREAM: When set, any received bytes will be handled internally (usually, when host sets the terminal to this mode, the host will interpret any data sent from the terminal as input by the human behind the terminal)
*/
enum class Mode {
IDLE, HOST, CLIENT, PRINTSTREAM, INPUTSTREAM
}
var otherVM: VM? = null
private var mode: Mode = Mode.IDLE
private var stream: Mode = Mode.IDLE
override fun attachDevice(device: BlockTransferInterface?) {
if (device !is SerialStdioHost) throw IllegalArgumentException("Other device is not SerialStdioHost: ${device?.javaClass?.canonicalName}")
super.attachDevice(device)
otherVM = device.hostVM
otherVM = device.runnerVM
}
private fun getOthersFirstGPU(): GraphicsAdapter? {
return otherVM!!.findPeribyType(VM.PERITYPE_GPU_AND_TERM)?.peripheral as? GraphicsAdapter
private fun getOthersFirstGPU(): GraphicsAdapter {
return otherVM!!.findPeribyType(VM.PERITYPE_GPU_AND_TERM)?.peripheral as GraphicsAdapter
}
private fun getHostsFirstGPU(): GraphicsAdapter {
return runnerVM.findPeribyType(VM.PERITYPE_GPU_AND_TERM)?.peripheral as GraphicsAdapter
}
// sends a byte to client's GPU
val out = object : OutputStream() {
override fun write(p0: Int) {
getOthersFirstGPU()?.writeOut(p0.toByte())
if ((recipient as SerialStdioHost).readyToBePossessed)
getOthersFirstGPU().writeOut(p0.toByte())
}
}
@@ -32,29 +52,34 @@ class SerialStdioHost(val hostVM: VM) : BlockTransferInterface(true, true) {
private val SGI_RESET = byteArrayOf(0x1B, 0x5B, 0x6D)
override fun write(p0: Int) {
getOthersFirstGPU()?.let { g ->
SGI_RED.forEach { g.writeOut(it) }
g.writeOut(p0.toByte())
SGI_RESET.forEach { g.writeOut(it) }
if ((recipient as SerialStdioHost).readyToBePossessed) {
getOthersFirstGPU().let { g ->
SGI_RED.forEach { g.writeOut(it) }
g.writeOut(p0.toByte())
SGI_RESET.forEach { g.writeOut(it) }
}
}
}
override fun write(p0: ByteArray) {
getOthersFirstGPU()?.let { g ->
SGI_RED.forEach { g.writeOut(it) }
p0.forEach { g.writeOut(it) }
SGI_RESET.forEach { g.writeOut(it) }
if ((recipient as SerialStdioHost).readyToBePossessed) {
getOthersFirstGPU().let { g ->
SGI_RED.forEach { g.writeOut(it) }
p0.forEach { g.writeOut(it) }
SGI_RESET.forEach { g.writeOut(it) }
}
}
}
}
// sends a byte from the client to the host
val `in` = object : InputStream() {
init {
otherVM?.getIO()?.mmio_write(38L, 1)
}
override fun read(): Int {
if (otherVM != null) {
if (otherVM != null && (recipient as SerialStdioHost).readyToBePossessed) {
var key: Byte
do {
Thread.sleep(4L) // if spinning rate is too fast, this function will fail.
@@ -77,13 +102,84 @@ class SerialStdioHost(val hostVM: VM) : BlockTransferInterface(true, true) {
TODO("Not yet implemented")
}
private var readyToBePossessed = false
/**
* Commands:
*
* - "LISTEN": when idle, sets the device to TERMINAL mode
* - "HOST": when idle, sets the device to HOST mode
* - \x14: hangs up the connection and routes stdio back to the TERMINAL's GraphicsAdapter
*
* // NOTE TO SELF: are these necessary?
*
* - \x11: tells TERMINAL to enter printstream mode (routes stdio to this device)
* - \x12: tells TERMINAL to enter datastream mode
* - \x13: tells TERMINAL to enter keyboard-read mode
*/
override fun writeoutImpl(inputData: ByteArray) {
TODO("Not yet implemented")
val inputString = inputData.trimNull().toString(VM.CHARSET)
if (mode == Mode.IDLE) {
if (inputString.startsWith("LISTEN")) {
mode = Mode.CLIENT
readyToBePossessed = true
}
else if (inputString.startsWith("HOST")) {
mode = Mode.HOST
hijackHostPrint()
hijackClientRead()
}
}
else {
if (mode == Mode.HOST) {
when (inputData[0]) {
DC_HUP -> {
releaseHostPrint()
releaseClientRead()
mode = Mode.IDLE
}
}
}
else if (mode == Mode.CLIENT) {
when (inputData[0]) {
DC_HUP -> {
mode = Mode.IDLE
readyToBePossessed = false
}
}
}
}
}
private fun hijackHostPrint() {
runnerVM.getPrintStream = { this.out }
runnerVM.getErrorStream = { this.err }
}
private fun hijackClientRead() {
otherVM!!.getInputStream = { this.`in` }
}
private fun releaseHostPrint() {
getHostsFirstGPU().let {
runnerVM.getPrintStream = { it.getPrintStream() }
runnerVM.getErrorStream = { it.getErrorStream() }
}
}
private fun releaseClientRead() {
otherVM!!.getInputStream = { getOthersFirstGPU().getInputStream() }
}
override fun hasNext(): Boolean {
TODO("Not yet implemented")
}
private companion object {
const val DC_PRINT = 0x11.toByte()
const val DC_DATA = 0x12.toByte()
const val DC_INPUT = 0x13.toByte()
const val DC_HUP = 0x14.toByte()
}
}

View File

@@ -215,6 +215,23 @@ class TestDiskDrive(private val vm: VM, private val driveNum: Int, theRootPath:
}
blockSendCount = 0
}
else if (inputString.startsWith("DELETE")) {
if (!fileOpen) {
statusCode = STATE_CODE_NO_FILE_OPENED
return
}
try {
file.delete()
}
catch (e: SecurityException) {
statusCode = STATE_CODE_SYSTEM_SECURITY_ERROR
return
}
catch (e1: IOException) {
statusCode = STATE_CODE_SYSTEM_IO_ERROR
return
}
}
else if (inputString.startsWith("LISTFILES")) {
// TODO temporary behaviour to ignore any arguments
resetBuf()