mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-12 06:41:51 +09:00
working filesystem (tested: mkdir, open, file:writeLine/close, cp, mv, rm)
Former-commit-id: ce3fcae801291f770ed19dce4616b8ab61556f9b Former-commit-id: 999d637fac1c1c6a9ff855ebb8f7f37336519771
This commit is contained in:
390
src/net/torvald/terrarum/virtualcomputer/luaapi/Filesystem.kt
Normal file
390
src/net/torvald/terrarum/virtualcomputer/luaapi/Filesystem.kt
Normal file
@@ -0,0 +1,390 @@
|
||||
package net.torvald.terrarum.virtualcomputer.luaapi
|
||||
|
||||
import li.cil.repack.org.luaj.vm2.*
|
||||
import li.cil.repack.org.luaj.vm2.lib.OneArgFunction
|
||||
import li.cil.repack.org.luaj.vm2.lib.TwoArgFunction
|
||||
import li.cil.repack.org.luaj.vm2.lib.ZeroArgFunction
|
||||
import net.torvald.terrarum.Terrarum
|
||||
import net.torvald.terrarum.virtualcomputer.computer.BaseTerrarumComputer
|
||||
import java.io.*
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* computer directory:
|
||||
* .../computers/
|
||||
* media/hda/ -> .../computers/<uuid for the hda>/
|
||||
*
|
||||
* Created by minjaesong on 16-09-17.
|
||||
*/
|
||||
internal class Filesystem(globals: Globals, computer: BaseTerrarumComputer) {
|
||||
|
||||
init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["fs"] = LuaValue.tableOf()
|
||||
globals["fs"]["list"] = ListFiles(computer)
|
||||
globals["fs"]["exists"] = FileExists(computer)
|
||||
globals["fs"]["isDir"] = IsDirectory(computer)
|
||||
globals["fs"]["isReadOnly"] = IsReadOnly(computer)
|
||||
globals["fs"]["listFiles"] = ListFiles(computer)
|
||||
globals["fs"]["mkdir"] = Mkdir(computer)
|
||||
globals["fs"]["mv"] = Mv(computer)
|
||||
globals["fs"]["cp"] = Cp(computer)
|
||||
globals["fs"]["rm"] = Rm(computer)
|
||||
globals["fs"]["concat"] = ConcatPath(computer)
|
||||
globals["fs"]["open"] = OpenFile(computer)
|
||||
globals["fs"]["parent"] = GetParentDir(computer)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val isCaseInsensitive: Boolean
|
||||
get() {
|
||||
// TODO add: force case insensitive in config
|
||||
try {
|
||||
val uuid = UUID.randomUUID().toString()
|
||||
val lowerCase = File(Terrarum.currentSaveDir, uuid + "oc_rox")
|
||||
val upperCase = File(Terrarum.currentSaveDir, uuid + "OC_ROX")
|
||||
// This should NEVER happen but could also lead to VERY weird bugs, so we
|
||||
// make sure the files don't exist.
|
||||
lowerCase.exists() && lowerCase.delete()
|
||||
upperCase.exists() && upperCase.delete()
|
||||
lowerCase.createNewFile()
|
||||
val insensitive = upperCase.exists()
|
||||
lowerCase.delete()
|
||||
return insensitive
|
||||
}
|
||||
catch (e: IOException) {
|
||||
println("[Filesystem] Couldn't determine if file system is case sensitive, falling back to insensitive.")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Worst-case: we're on Windows or using a FAT32 partition mounted in *nix.
|
||||
// Note: we allow / as the path separator and expect all \s to be converted
|
||||
// accordingly before the path is passed to the file system.
|
||||
private val invalidChars = Regex("""[\\:*?"<>|]""") // original OC uses Set(); we use regex
|
||||
|
||||
fun isValidFilename(name: String) = !name.contains(invalidChars)
|
||||
|
||||
fun validatePath(path: String): String {
|
||||
if (!isValidFilename(path)) {
|
||||
throw IOException("path contains invalid characters")
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
/** actual directory: <appdata>/Saves/<savename>/computers/<drivename>/
|
||||
* directs media/ directory to /<uuid> directory
|
||||
*/
|
||||
fun BaseTerrarumComputer.getRealPath(luapath: LuaValue): String {
|
||||
// direct mounted paths to real path
|
||||
val computerDir = Terrarum.currentSaveDir.absolutePath + "/computers/"
|
||||
/* if not begins with "(/?)media/", direct to boot
|
||||
* else, to corresponding drives
|
||||
*
|
||||
* List of device names (these are auto-mounted. why? primitivism :p):
|
||||
* = hda - hdd: hard disks
|
||||
* = fd1 - fd4: floppy drives
|
||||
* = sda: whatever external drives, usually a CD
|
||||
* = boot: current boot device
|
||||
*/
|
||||
|
||||
// remove first '/' in path
|
||||
var path = luapath.checkjstring()
|
||||
if (path.startsWith('/')) path = path.substring(1)
|
||||
// replace '\' with '/'
|
||||
path.replace('\\', '/')
|
||||
|
||||
if (path.startsWith("media/")) {
|
||||
val device = path.substring(6, 9)
|
||||
val subPath = path.substring(9)
|
||||
return computerDir + this.computerValue.getAsString("device") + subPath
|
||||
}
|
||||
else {
|
||||
return computerDir + this.computerValue.getAsString("boot") + "/" + path
|
||||
}
|
||||
}
|
||||
|
||||
fun combinePath(base: String, local: String): String {
|
||||
return "$base$local".replace("//", "/").replace("\\\\", "\\")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cname == UUID of the drive
|
||||
*
|
||||
* actual directory: <appdata>/Saves/<savename>/computers/<drivename>/
|
||||
*/
|
||||
class ListFiles(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
val table = LuaTable()
|
||||
val file = File(computer.getRealPath(path))
|
||||
file.list().forEachIndexed { i, s -> table.insert(i, LuaValue.valueOf(s)) }
|
||||
return table
|
||||
}
|
||||
}
|
||||
|
||||
class FileExists(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).exists())
|
||||
}
|
||||
}
|
||||
|
||||
class IsDirectory(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).isDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
class IsFile(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).isFile)
|
||||
}
|
||||
}
|
||||
|
||||
class IsReadOnly(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(!File(computer.getRealPath(path)).canWrite())
|
||||
}
|
||||
}
|
||||
|
||||
/** we have 4GB file size limit */
|
||||
class GetSize(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).length().toInt())
|
||||
}
|
||||
}
|
||||
|
||||
// TODO class GetFreeSpace
|
||||
|
||||
/**
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Mkdir(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(File(computer.getRealPath(path)).mkdir())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* moves a directory, overwrites the target
|
||||
*/
|
||||
class Mv(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue): LuaValue {
|
||||
val fromFile = File(computer.getRealPath(from))
|
||||
fromFile.copyRecursively(
|
||||
File(computer.getRealPath(to)), overwrite = true
|
||||
)
|
||||
fromFile.deleteRecursively()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* copies a directory, overwrites the target
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Cp(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(from: LuaValue, to: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(
|
||||
File(computer.getRealPath(from)).copyRecursively(
|
||||
File(computer.getRealPath(to)), overwrite = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* difference with ComputerCraft: it returns boolean, true on successful.
|
||||
*/
|
||||
class Rm(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
return LuaValue.valueOf(
|
||||
File(computer.getRealPath(path)).deleteRecursively()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ConcatPath(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(base: LuaValue, local: LuaValue): LuaValue {
|
||||
val combinedPath = combinePath(base.checkjstring(), local.checkjstring())
|
||||
return LuaValue.valueOf(combinedPath)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mode: r, rb, w, wb, a, ab
|
||||
*
|
||||
* Difference: TEXT MODE assumes CP437 instead of UTF-8!
|
||||
*
|
||||
* When you have opened a file you must always close the file handle, or else data may not be saved.
|
||||
*
|
||||
* FILE class in CC:
|
||||
* (when you look thru them using file = fs.open("./test", "w")
|
||||
*
|
||||
* file = {
|
||||
* close = function()
|
||||
* -- write mode
|
||||
* write = function(string)
|
||||
* flush = function() -- write, keep the handle
|
||||
* writeLine = function(string) -- text mode
|
||||
* -- read mode
|
||||
* readLine = function() -- text mode
|
||||
* readAll = function()
|
||||
* -- binary read mode
|
||||
* read = function() -- read single byte. return: number or nil
|
||||
* -- binary write mode
|
||||
* write = function(byte)
|
||||
* writeBytes = function(string as bytearray)
|
||||
* }
|
||||
*/
|
||||
class OpenFile(val computer: BaseTerrarumComputer): TwoArgFunction() {
|
||||
override fun call(path: LuaValue, mode: LuaValue): LuaValue {
|
||||
val mode = mode.checkjstring().toLowerCase()
|
||||
val luaClass = LuaTable()
|
||||
val file = File(computer.getRealPath(path))
|
||||
|
||||
if (mode.contains("[aw]") && !file.canWrite())
|
||||
throw LuaError("Cannot open file for " +
|
||||
"${if (mode.startsWith('w')) "read" else "append"} mode" +
|
||||
": is readonly.")
|
||||
|
||||
when (mode) {
|
||||
"r" -> {
|
||||
val fr = FileReader(file)
|
||||
luaClass["close"] = FileClassClose(fr)
|
||||
luaClass["readLine"] = FileClassReadLine(fr)
|
||||
luaClass["readAll"] = FileClassReadAll(fr)
|
||||
}
|
||||
"rb" -> {
|
||||
val fis = FileInputStream(file)
|
||||
luaClass["close"] = FileClassClose(fis)
|
||||
luaClass["read"] = FileClassReadByte(fis)
|
||||
}
|
||||
"w", "a" -> {
|
||||
val fw = FileWriter(file, (mode.startsWith('a')))
|
||||
luaClass["close"] = FileClassClose(fw)
|
||||
luaClass["write"] = FileClassPrintText(fw)
|
||||
luaClass["writeLine"] = FileClassPrintlnText(fw)
|
||||
luaClass["flush"] = FileClassFlush(fw)
|
||||
}
|
||||
"wb", "ab" -> {
|
||||
val fos = FileOutputStream(file, (mode.startsWith('a')))
|
||||
luaClass["close"] = FileClassClose(fos)
|
||||
luaClass["write"] = FileClassWriteByte(fos)
|
||||
luaClass["writeBytes"] = FileClassWriteBytes(fos)
|
||||
luaClass["flush"] = FileClassFlush(fos)
|
||||
}
|
||||
}
|
||||
|
||||
return luaClass
|
||||
}
|
||||
}
|
||||
|
||||
class GetParentDir(val computer: BaseTerrarumComputer): OneArgFunction() {
|
||||
override fun call(path: LuaValue): LuaValue {
|
||||
var pathSB = StringBuilder(path.checkjstring())
|
||||
|
||||
// backward travel, drop chars until '/' has encountered
|
||||
while (!pathSB.endsWith('/') && !pathSB.endsWith('\\'))
|
||||
pathSB.deleteCharAt(pathSB.lastIndex - 1)
|
||||
|
||||
// drop trailing '/'
|
||||
if (pathSB.endsWith('/') || pathSB.endsWith('\\'))
|
||||
pathSB.deleteCharAt(pathSB.lastIndex - 1)
|
||||
|
||||
return LuaValue.valueOf(pathSB.toString())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
// OpenFile implementations //
|
||||
//////////////////////////////
|
||||
|
||||
private class FileClassClose(val fo: Any): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
if (fo is FileOutputStream)
|
||||
fo.close()
|
||||
else if (fo is FileWriter)
|
||||
fo.close()
|
||||
else if (fo is FileReader)
|
||||
fo.close()
|
||||
else if (fo is FileInputStream)
|
||||
fo.close()
|
||||
else
|
||||
throw IllegalArgumentException("Unacceptable file output: must be either Input/OutputStream or Reader/Writer.")
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteByte(val fos: FileOutputStream): OneArgFunction() {
|
||||
override fun call(byte: LuaValue): LuaValue {
|
||||
fos.write(byte.checkint())
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassWriteBytes(val fos: FileOutputStream): OneArgFunction() {
|
||||
override fun call(byteString: LuaValue): LuaValue {
|
||||
val byteString = byteString.checkjstring()
|
||||
val bytearr = ByteArray(byteString.length, { byteString[it].toByte() })
|
||||
fos.write(bytearr)
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintText(val fw: FileWriter): OneArgFunction() {
|
||||
override fun call(string: LuaValue): LuaValue {
|
||||
val text = string.checkjstring()
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassPrintlnText(val fw: FileWriter): OneArgFunction() {
|
||||
override fun call(string: LuaValue): LuaValue {
|
||||
val text = string.checkjstring() + "\n"
|
||||
fw.write(text)
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassFlush(val fo: Any): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
if (fo is FileOutputStream)
|
||||
fo.flush()
|
||||
else if (fo is FileWriter)
|
||||
fo.flush()
|
||||
else
|
||||
throw IllegalArgumentException("Unacceptable file output: must be either OutputStream or Writer.")
|
||||
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadByte(val fis: FileInputStream): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
val readByte = fis.read()
|
||||
return if (readByte == -1) LuaValue.NIL else LuaValue.valueOf(readByte)
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadAll(val fr: FileReader): ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(fr.readText())
|
||||
}
|
||||
}
|
||||
|
||||
private class FileClassReadLine(val fr: FileReader): ZeroArgFunction() {
|
||||
val scanner = Scanner(fr.readText()) // keeps the scanner status persistent
|
||||
|
||||
override fun call(): LuaValue {
|
||||
return if (scanner.hasNextLine()) LuaValue.valueOf(scanner.nextLine())
|
||||
else LuaValue.NIL
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.torvald.terrarum.virtualcomputer.luaapi
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-09-17.
|
||||
*/
|
||||
class FilesystemFactory {
|
||||
}
|
||||
96
src/net/torvald/terrarum/virtualcomputer/luaapi/Security.kt
Normal file
96
src/net/torvald/terrarum/virtualcomputer/luaapi/Security.kt
Normal file
@@ -0,0 +1,96 @@
|
||||
package net.torvald.terrarum.virtualcomputer.luaapi
|
||||
|
||||
import li.cil.repack.org.luaj.vm2.Globals
|
||||
import li.cil.repack.org.luaj.vm2.LuaValue
|
||||
import li.cil.repack.org.luaj.vm2.lib.OneArgFunction
|
||||
import net.torvald.terrarum.gameworld.toUint
|
||||
import org.apache.commons.codec.binary.Base64
|
||||
import org.apache.commons.codec.digest.DigestUtils
|
||||
import java.security.SecureRandom
|
||||
|
||||
/**
|
||||
* Created by minjaesong on 16-09-15.
|
||||
*/
|
||||
internal class Security(globals: Globals) {
|
||||
|
||||
init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["security"] = LuaValue.tableOf()
|
||||
globals["security"]["toSHA256"] = SHA256sum()
|
||||
globals["security"]["toSHA1"] = SHA1sum()
|
||||
globals["security"]["toMD5"] = MD5sum()
|
||||
globals["security"]["randomBytes"] = SecureRandomHex()
|
||||
globals["security"]["decodeBase64"] = DecodeBase64()
|
||||
globals["security"]["encodeBase64"] = EncodeBase64()
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class SHA256sum : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
val hashBytes = DigestUtils.sha256(p0.checkjstring())
|
||||
return LuaValue.valueOf(hashBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class SHA1sum: OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
val hashBytes = DigestUtils.sha1(p0.checkjstring())
|
||||
return LuaValue.valueOf(hashBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class MD5sum: OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
val hashBytes = DigestUtils.md5(p0.checkjstring())
|
||||
return LuaValue.valueOf(hashBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class SecureRandomHex: OneArgFunction() {
|
||||
override fun call(byteSize: LuaValue): LuaValue {
|
||||
val bytes = ByteArray(byteSize.checkint())
|
||||
SecureRandom().nextBytes(bytes)
|
||||
|
||||
return LuaValue.valueOf(bytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return String */
|
||||
class DecodeBase64: OneArgFunction() {
|
||||
override fun call(base64: LuaValue): LuaValue {
|
||||
val decodedBytes = Base64.decodeBase64(base64.checkjstring())
|
||||
return LuaValue.valueOf(decodedBytes.toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
/** @return byteArray as String */
|
||||
class EncodeBase64: OneArgFunction() {
|
||||
override fun call(inputString: LuaValue): LuaValue {
|
||||
val inputBytes = inputString.checkjstring().toByteArray(charset("UTF-8"))
|
||||
return LuaValue.valueOf(Base64.encodeBase64(inputBytes).toStringRepresentation())
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val hexLookup = charArrayOf(
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
||||
)
|
||||
|
||||
fun Byte.toHexString(): String {
|
||||
val bInt = this.toUint()
|
||||
return "${hexLookup[bInt.shr(8).and(0xf)]}${hexLookup[bInt.and(0xf)]}"
|
||||
}
|
||||
|
||||
/** essentially, 0xFC to 0xFC.toChar() */
|
||||
fun ByteArray.toStringRepresentation(): String {
|
||||
val sb = StringBuilder()
|
||||
for (b in this)
|
||||
sb.append(b.toChar())
|
||||
return sb.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
231
src/net/torvald/terrarum/virtualcomputer/luaapi/Term.kt
Normal file
231
src/net/torvald/terrarum/virtualcomputer/luaapi/Term.kt
Normal file
@@ -0,0 +1,231 @@
|
||||
package net.torvald.terrarum.virtualcomputer.luaapi
|
||||
|
||||
import li.cil.repack.org.luaj.vm2.*
|
||||
import li.cil.repack.org.luaj.vm2.lib.*
|
||||
import net.torvald.terrarum.virtualcomputer.terminal.Teletype
|
||||
import net.torvald.terrarum.virtualcomputer.terminal.Terminal
|
||||
|
||||
/**
|
||||
* APIs must have some extent of compatibility with ComputerCraft by dan200
|
||||
*
|
||||
* Created by minjaesong on 16-09-12.
|
||||
*/
|
||||
internal class Term(globals: Globals, term: Teletype) {
|
||||
|
||||
init {
|
||||
// load things. WARNING: THIS IS MANUAL!
|
||||
globals["term"] = LuaValue.tableOf()
|
||||
globals["term"]["write"] = Term.WriteString(term)
|
||||
globals["term"]["print"] = Term.PrintString(term)
|
||||
globals["term"]["newLine"] = Term.NewLine(term)
|
||||
globals["term"]["moveCursor"] = Term.MoveCursor(term) // TTY function
|
||||
globals["term"]["width"] = Term.GetWidth(term)
|
||||
globals["term"]["scroll"] = Term.Scroll(term)
|
||||
globals["term"]["isTeletype"] = Term.IsTeletype(term)
|
||||
|
||||
if (term is Terminal) {
|
||||
globals["term"]["emitRaw"] = Term.EmitRaw(term)
|
||||
globals["term"]["emit"] = Term.Emit(term)
|
||||
globals["term"]["resetColor"] = Term.ResetColour(term)
|
||||
globals["term"]["resetColour"] = Term.ResetColour(term)
|
||||
globals["term"]["clear"] = Term.Clear(term)
|
||||
globals["term"]["clearLine"] = Term.ClearLine(term)
|
||||
globals["term"]["moveCursor"] = Term.SetCursorPos(term)
|
||||
globals["term"]["getCursor"] = Term.GetCursorPos(term)
|
||||
globals["term"]["getX"] = Term.GetCursorX(term)
|
||||
globals["term"]["getY"] = Term.GetCursorY(term)
|
||||
globals["term"]["blink"] = Term.SetCursorBlink(term)
|
||||
globals["term"]["size"] = Term.GetSize(term)
|
||||
globals["term"]["isCol"] = Term.IsColour(term)
|
||||
globals["term"]["setForeCol"] = Term.SetForeColour(term)
|
||||
globals["term"]["setBackCol"] = Term.SetBackColour(term)
|
||||
globals["term"]["foreCol"] = Term.GetForeColour(term)
|
||||
globals["term"]["backCol"] = Term.GetBackColour(term)
|
||||
}
|
||||
}
|
||||
|
||||
class WriteString(val tty: Teletype) : LuaFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
if (tty is Terminal)
|
||||
tty.writeString(p0.checkjstring())
|
||||
else
|
||||
tty.writeChars(p0.checkjstring())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(s: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
|
||||
if (tty is Terminal)
|
||||
tty.writeString(s.checkjstring(), x.checkint(), y.checkint())
|
||||
else
|
||||
throw LuaError("couldn't move cursor; TTY is one-dimensional")
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class PrintString(val tty: Teletype) : LuaFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
if (tty is Terminal)
|
||||
tty.printString(p0.checkjstring())
|
||||
else
|
||||
tty.printChars(p0.checkjstring())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
|
||||
override fun call(s: LuaValue, x: LuaValue, y: LuaValue): LuaValue {
|
||||
if (tty is Terminal)
|
||||
tty.printString(s.checkjstring(), x.checkint(), y.checkint())
|
||||
else
|
||||
throw LuaError("couldn't move cursor; TTY is one-dimensional")
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class NewLine(val tty: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
tty.newLine()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class EmitRaw(val term: Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.emitChar(p0.checkint())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class Emit(val term: Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.emitChar(p0.checkint().toChar())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class ResetColour(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.resetColour()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class Clear(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.clear()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class ClearLine(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
term.clearLine()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setCursorPos(number x, number y) */
|
||||
class SetCursorPos(val term: Terminal) : TwoArgFunction() {
|
||||
override fun call(x: LuaValue, y: LuaValue): LuaValue {
|
||||
term.setCursor(x.checkint(), y.checkint())
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setCursorPos(number x) */
|
||||
class MoveCursor(val tty: Teletype) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
for (i in 1..p0.checkint())
|
||||
tty.printChar(' ')
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class GetCursorPos(val term: Terminal) : VarArgFunction() {
|
||||
override fun invoke(args: Varargs?): Varargs {
|
||||
val ret = arrayOf(LuaValue.valueOf(term.cursorX), LuaValue.valueOf(term.cursorY))
|
||||
return LuaValue.varargsOf(ret)
|
||||
}
|
||||
}
|
||||
|
||||
class GetCursorX(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.cursorX)
|
||||
}
|
||||
}
|
||||
|
||||
class GetCursorY(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.cursorY)
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setCursorBlink(boolean bool) */
|
||||
class SetCursorBlink(val term: Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.cursorBlink = p0.toboolean()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class GetSize(val term: Terminal) : VarArgFunction() {
|
||||
override fun invoke(args: Varargs?): Varargs {
|
||||
val ret = arrayOf(LuaValue.valueOf(term.width), LuaValue.valueOf(term.height))
|
||||
return LuaValue.varargsOf(ret)
|
||||
}
|
||||
}
|
||||
|
||||
class GetWidth(val tty: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(tty.width)
|
||||
}
|
||||
}
|
||||
|
||||
class IsColour(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.coloursCount > 4)
|
||||
}
|
||||
}
|
||||
|
||||
/** term.scroll(number n) */
|
||||
class Scroll(val tty: Teletype) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
if (tty is Terminal) tty.scroll(p0.checkint())
|
||||
else for (i in 1..p0.checkint()) tty.newLine()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setTextColor(number color) */
|
||||
class SetForeColour(val term: Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.foreColour = p0.checkint()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
/** term.setBackgroundColor(number color) */
|
||||
class SetBackColour(val term: Terminal) : OneArgFunction() {
|
||||
override fun call(p0: LuaValue): LuaValue {
|
||||
term.backColour = p0.checkint()
|
||||
return LuaValue.NONE
|
||||
}
|
||||
}
|
||||
|
||||
class GetForeColour(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.foreColour)
|
||||
}
|
||||
}
|
||||
|
||||
class GetBackColour(val term: Terminal) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(term.backColour)
|
||||
}
|
||||
}
|
||||
|
||||
class IsTeletype(val termInQuestion: Teletype) : ZeroArgFunction() {
|
||||
override fun call(): LuaValue {
|
||||
return LuaValue.valueOf(termInQuestion.coloursCount == 0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user