defaulting to standard lua string functions and making unicode ones available prefixed with a u (uchar, ulen, usub, ureverse); fixed event erroring being weird; fixed wrong case check order in kernel; fixed error when netsplitting a component from a computer; fixed localization for disk drive; config for name to provide when running command in command block; increased range of keyboards; adapter blocks re-use the same addresses for the blocks attached to them to avoid computers losing track of those nodes after reloading

This commit is contained in:
Florian Nücke 2013-10-19 15:55:59 +02:00
parent 87aa1f44a9
commit ccf53d6b85
20 changed files with 187 additions and 133 deletions

View File

@ -1,9 +1,10 @@
oc.block.Adapter.name=Adapter
oc.block.Computer.name=Computer
oc.block.DiskDrive.name=Diskettenlaufwerk
oc.block.Keyboard.name=Tastatur
oc.block.Screen.name=Bildschirm
oc.container.computer=Computer
oc.container.disk_drive=Diskettenlaufwerk
oc.container.Computer=Computer
oc.container.DiskDrive=Diskettenlaufwerk
oc.item.Disk.name=Diskette
oc.item.GraphicsCard.name=Grafikkarte
oc.item.HardDiskDrive2m.name=Festplatte (2MB)

View File

@ -1,9 +1,10 @@
oc.block.Adapter.name=Adapter
oc.block.Computer.name=Computer
oc.block.DiskDrive.name=Disk Drive
oc.block.Keyboard.name=Keyboard
oc.block.Screen.name=Screen
oc.container.computer=Computer
oc.container.disk_drive=Disk Drive
oc.container.Computer=Computer
oc.container.DiskDrive=Disk Drive
oc.item.Disk.name=Floppy Disk
oc.item.GraphicsCard.name=Graphics Card
oc.item.HardDiskDrive2m.name=Hard Disk Drive (2MB)

View File

@ -181,7 +181,7 @@ function driver.filesystem.isDirectory(path)
if node.fs and rest then
return send(node.fs, "fs.isDirectory", rest)
else
return not rest or rest:len() == 0
return not rest or rest:ulen() == 0
end
end
@ -339,12 +339,12 @@ function file:read(...)
local function readBytesOrChars(n)
local len, sub
if self.mode == "r" then
len = string.len
sub = string.sub
len = string.ulen
sub = string.usub
else
assert(self.mode == "rb")
len = rawlen
sub = string.bsub
sub = string.sub
end
local buffer = ""
repeat
@ -370,8 +370,8 @@ function file:read(...)
while true do
local l = self.buffer:find("\n", start, true)
if l then
local result = self.buffer:bsub(1, l + (chop and -1 or 0))
self.buffer = self.buffer:bsub(l + 1)
local result = self.buffer:sub(1, l + (chop and -1 or 0))
self.buffer = self.buffer:sub(l + 1)
return result
else
start = #self.buffer
@ -405,10 +405,10 @@ function file:read(...)
if type(format) == "number" then
return readBytesOrChars(format)
else
if type(format) ~= "string" or format:sub(1, 1) ~= "*" then
if type(format) ~= "string" or format:usub(1, 1) ~= "*" then
error("bad argument #" .. n .. " (invalid option)")
end
format = format:sub(2, 2)
format = format:usub(2, 2)
if format == "n" then
--[[ TODO ]]
error("not implemented")
@ -529,11 +529,11 @@ function file:write(...)
end
end
if l then
result, reason = self.stream:write(arg:bsub(1, l))
result, reason = self.stream:write(arg:sub(1, l))
if not result then
return nil, reason
end
arg = arg:bsub(l + 1)
arg = arg:sub(l + 1)
end
if #arg > self.bufferSize then
result, reason = self.stream:write(arg)

View File

@ -100,8 +100,6 @@ local sandbox = {
},
string = {
breverse = string.breverse,
bsub = string.bsub,
byte = string.byte,
char = string.char,
dump = string.dump,
@ -115,7 +113,11 @@ local sandbox = {
rep = string.rep,
reverse = string.reverse,
sub = string.sub,
upper = string.upper
upper = string.upper,
uchar = string.uchar,
ulen = string.ulen,
ureverse = string.breverse,
usub = string.bsub
},
table = {
@ -180,12 +182,12 @@ local function main(args)
debug.sethook(co, checkDeadline, "", 10000)
end
local result = table.pack(coroutine.resume(co, table.unpack(args, 1, args.n)))
if coroutine.status(co) == "dead" then
if not result[1] then
error(result[2] or "unknown error", 0)
elseif coroutine.status(co) == "dead" then
error("computer stopped unexpectedly", 0)
elseif result[1] then
args = table.pack(coroutine.yield(result[2])) -- system yielded value
else
error(result[2], 0)
args = table.pack(coroutine.yield(result[2])) -- system yielded value
end
end
end
@ -267,7 +269,8 @@ do
return debug.traceback(msg, 2)
end)
if not result then
print("Failed initializing driver '" .. name .. "': " .. reason)
print("Failed initializing driver '" .. name .. "': " ..
(reason or "unknown error"))
end
end
end

View File

@ -24,8 +24,18 @@ function component.primary(componentType, ...)
local args = table.pack(...)
if args.n > 0 then
checkArg(2, args[1], "string", "nil")
local address
if args[1] ~= nil then
for c in component.list(componentType) do
if c:usub(1, args[1]:ulen()) == args[1] then
address = c
break
end
end
assert(address, "no such component")
end
local wasAvailable = component.isAvailable(componentType)
primaries[componentType] = args[1]
primaries[componentType] = address
if not wasAvailable and component.isAvailable(componentType) then
event.fire("component_available", componentType)
elseif wasAvailable and not component.isAvailable(componentType) then
@ -45,6 +55,9 @@ end
-------------------------------------------------------------------------------
local function onComponentAdded(_, address)
if components[address] then
return false -- cancel this event, it is invalid
end
local componentType = driver.componentType(address)
components[address] = componentType
if not component.isAvailable(componentType) then
@ -53,16 +66,15 @@ local function onComponentAdded(_, address)
end
local function onComponentRemoved(_, address)
if not components[address] then
return false -- cancel this event, it is invalid
end
local componentType = component.type(address)
components[address] = nil
if primaries[componentType] == address then
component.primary(componentType, nil)
for address in component.list() do
if component.type(address) == componentType then
component.primary(componentType, address)
return
end
end
address = component.list(componentType)()
component.primary(componentType, address)
end
end

View File

@ -2,14 +2,18 @@ local listeners = {}
local weakListeners = {}
local timers = {}
local function listenersFor(name, weak)
local function listenersFor(name, weak, create)
checkArg(1, name, "string")
if weak then
weakListeners[name] = weakListeners[name] or setmetatable({}, {__mode = "v"})
return weakListeners[name]
if not weakListeners[name] and create then
weakListeners[name] = weakListeners[name] or setmetatable({}, {__mode = "v"})
end
return weakListeners[name] or {}
else
listeners[name] = listeners[name] or {}
return listeners[name]
if not listeners[name] and create then
listeners[name] = listeners[name] or {}
end
return listeners[name] or {}
end
end
@ -28,16 +32,20 @@ function event.fire(name, ...)
-- timer check (for example if we had no signal in event.wait()).
if name then
checkArg(1, name, "string")
for _, callback in ipairs(listenersFor(name, false)) do
local result, message = xpcall(callback, event.error, name, ...)
if not result and message then
error(message, 0)
end
local function copy(listA, listB)
local result = {}
for _, v in ipairs(listA) do table.insert(result, v) end
for _, v in ipairs(listB) do table.insert(result, v) end
return result
end
for _, callback in ipairs(listenersFor(name, true)) do
-- Copy the listener lists because they may be changed by callbacks.
local listeners = copy(listenersFor(name, false), listenersFor(name, true))
for _, callback in ipairs(listeners) do
local result, message = xpcall(callback, event.error, name, ...)
if not result and message then
if not result and message then -- only if handler returned something.
error(message, 0)
elseif result and message == false then
break
end
end
end
@ -50,7 +58,7 @@ function event.fire(name, ...)
end
for _, callback in ipairs(elapsed) do
local result, message = xpcall(callback, event.error)
if not result and message then
if not result and message then -- only if handler returned something.
error(message, 0)
end
end
@ -71,7 +79,7 @@ end
function event.listen(name, callback, weak)
checkArg(2, callback, "function")
local list = listenersFor(name, weak)
local list = listenersFor(name, weak, true)
for i = 1, #list do
if list[i] == callback then
return

View File

@ -28,9 +28,9 @@ local function onComponentAdded(_, address)
address ~= os.romAddress() and
address ~= os.tmpAddress()
then
local name = address:sub(1, 3)
local name = address:usub(1, 3)
repeat
name = address:sub(1, name:len() + 1)
name = address:usub(1, name:ulen() + 1)
until not fs.exists("/mnt/" .. name)
fs.mount(address, "/mnt/" .. name)
if isAutorunEnabled then

View File

@ -47,7 +47,7 @@ function term.cursorBlink(enabled)
if not cursorBlink then
cursorBlink = event.interval(0.5, toggleBlink)
cursorBlink.state = false
cursorBlink.solid = string.char(0x2588) -- 0x2588 is a solid block.
cursorBlink.solid = string.uchar(0x2588) -- 0x2588 is a solid block.
elseif cursorBlink.state then
toggleBlink()
end
@ -67,10 +67,10 @@ function term.cursorBlink(enabled)
stop()
end
elseif type(enabled) == "string" and
(not cursorBlink or enabled:sub(1, 1) ~= cursorBlink.alt)
(not cursorBlink or enabled:usub(1, 1) ~= cursorBlink.alt)
then
if enabled:len() > 0 then
start(enabled:sub(1, 1))
if enabled:ulen() > 0 then
start(enabled:usub(1, 1))
else
stop()
end
@ -85,63 +85,68 @@ function term.read(history)
table.insert(history, "")
local current = #history
local keys = driver.keyboard.keys
local start, y = term.cursor()
local start = term.cursor()
local cursor, scroll = 1, 0
local keyRepeat = nil
local result = nil
local function remove()
local x = start - 1 + cursor - scroll
local _, y = term.cursor()
local w = gpu.resolution()
gpu.copy(x + 1, y, w - x, 1, -1, 0)
local cursor = cursor + (w - x)
local char = history[current]:sub(cursor, cursor)
if char:len() == 0 then
local char = history[current]:usub(cursor, cursor)
if char:ulen() == 0 then
char = " "
end
gpu.set(w, y, char)
end
local function render()
local _, y = term.cursor()
local w = gpu.resolution()
local str = history[current]:sub(1 + scroll, 1 + scroll + w - (start - 1))
str = str .. string.rep(" ", (w - (start - 1)) - str:len())
local str = history[current]:usub(1 + scroll, 1 + scroll + w - (start - 1))
str = str .. string.rep(" ", (w - (start - 1)) - str:ulen())
gpu.set(start, y, str)
end
local function scrollEnd()
local w = gpu.resolution()
cursor = history[current]:len() + 1
cursor = history[current]:ulen() + 1
scroll = math.max(0, cursor - (w - (start - 1)))
render()
end
local function scrollLeft()
scroll = scroll - 1
local _, y = term.cursor()
local w = gpu.resolution()
gpu.copy(start, y, w - start - 1, 1, 1, 0)
local cursor = w - (start - 1) + scroll
local char = history[current]:sub(cursor, cursor)
if char:len() == 0 then
local char = history[current]:usub(cursor, cursor)
if char:ulen() == 0 then
char = " "
end
gpu.set(1, y, char)
end
local function scrollRight()
scroll = scroll + 1
local _, y = term.cursor()
local w = gpu.resolution()
gpu.copy(start + 1, y, w - start, 1, -1, 0)
local cursor = w - (start - 1) + scroll
local char = history[current]:sub(cursor, cursor)
if char:len() == 0 then
local char = history[current]:usub(cursor, cursor)
if char:ulen() == 0 then
char = " "
end
gpu.set(w, y, char)
end
local function update()
local _, y = term.cursor()
local w = gpu.resolution()
local cursor = cursor - 1
local x = start - 1 + cursor - scroll
if cursor < history[current]:len() then
if cursor < history[current]:ulen() then
gpu.copy(x, y, w - x, 1, 1, 0)
end
gpu.set(x, y, history[current]:sub(cursor, cursor))
gpu.set(x, y, history[current]:usub(cursor, cursor))
end
local function copyIfNecessary()
if current ~= #history then
@ -150,9 +155,10 @@ function term.read(history)
end
end
local function updateCursor()
local _, y = term.cursor()
term.cursor(start - 1 + cursor - scroll, y)
term.cursorBlink(cursor <= history[current]:len() and
history[current]:sub(cursor, cursor) or " ")
term.cursorBlink(cursor <= history[current]:ulen() and
history[current]:usub(cursor, cursor) or " ")
end
local function handleKeyPress(char, code)
if not term.isAvailable() then return end
@ -162,8 +168,8 @@ function term.read(history)
if code == keys.back then
if cursor > 1 then
copyIfNecessary()
history[current] = history[current]:sub(1, cursor - 2) ..
history[current]:sub(cursor)
history[current] = history[current]:usub(1, cursor - 2) ..
history[current]:usub(cursor)
cursor = cursor - 1
if cursor - scroll < 1 then
scrollLeft()
@ -172,13 +178,13 @@ function term.read(history)
end
cancel = cursor == 1
elseif code == keys.delete then
if cursor <= history[current]:len() then
if cursor <= history[current]:ulen() then
copyIfNecessary()
history[current] = history[current]:sub(1, cursor - 1) ..
history[current]:sub(cursor + 1)
history[current] = history[current]:usub(1, cursor - 1) ..
history[current]:usub(cursor + 1)
remove()
end
cancel = cursor == history[current]:len() + 1
cancel = cursor == history[current]:ulen() + 1
elseif code == keys.left then
if cursor > 1 then
cursor = cursor - 1
@ -188,13 +194,13 @@ function term.read(history)
end
cancel = cursor == 1
elseif code == keys.right then
if cursor < history[current]:len() + 1 then
if cursor < history[current]:ulen() + 1 then
cursor = cursor + 1
if cursor - scroll > w - (start - 1) then
scrollRight()
end
end
cancel = cursor == history[current]:len() + 1
cancel = cursor == history[current]:ulen() + 1
elseif code == keys.home then
if cursor > 1 then
cursor, scroll = 1, 0
@ -202,7 +208,7 @@ function term.read(history)
end
cancel = true
elseif code == keys["end"] then
if cursor < history[current]:len() + 1 then
if cursor < history[current]:ulen() + 1 then
scrollEnd()
end
cancel = true
@ -225,15 +231,15 @@ function term.read(history)
current = #history
end
result = history[current] .. "\n"
if history[current]:len() == 0 then
if history[current]:ulen() == 0 then
table.remove(history, current)
end
return true
elseif not keys.isControl(char) then
copyIfNecessary()
history[current] = history[current]:sub(1, cursor - 1) ..
string.char(char) ..
history[current]:sub(cursor)
history[current] = history[current]:usub(1, cursor - 1) ..
string.uchar(char) ..
history[current]:usub(cursor)
cursor = cursor + 1
update()
if cursor - scroll > w - (start - 1) then
@ -281,7 +287,7 @@ function term.read(history)
term.cursorBlink(false)
local l = value:find("\n", 1, true)
if l then
history[current] = history[current] .. value:sub(1, l - 1)
history[current] = history[current] .. value:usub(1, l - 1)
result = history[current] .. "\n"
else
history[current] = history[current] .. value
@ -312,7 +318,7 @@ end
function term.write(value, wrap)
value = tostring(value)
if value:len() == 0 or not term.isAvailable() then
if value:ulen() == 0 or not term.isAvailable() then
return
end
value = value:gsub("\t", " ")
@ -329,18 +335,18 @@ function term.write(value, wrap)
end
end
for line, nl in value:gmatch("([^\r\n]*)([\r\n]?)") do
while wrap and line:len() > w - cursorX + 1 do
local partial = line:sub(1, w - cursorX + 1)
line = line:sub(partial:len() + 1)
while wrap and line:ulen() > w - cursorX + 1 do
local partial = line:usub(1, w - cursorX + 1)
line = line:usub(partial:ulen() + 1)
gpu.set(cursorX, cursorY, partial)
cursorX = cursorX + partial:len()
cursorX = cursorX + partial:ulen()
checkCursor()
end
if line:len() > 0 then
if line:ulen() > 0 then
gpu.set(cursorX, cursorY, line)
cursorX = cursorX + line:len()
cursorX = cursorX + line:ulen()
end
if nl:len() == 1 then
if nl:ulen() == 1 then
cursorX = 1
cursorY = cursorY + 1
checkCursor()

View File

@ -24,6 +24,7 @@ object Config {
// ----------------------------------------------------------------------- //
var baseMemory = 0
var commandUser = "OpenComputers"
var fileCost = 512
var filesBuffered = true
var maxScreenHeight = 6
@ -83,6 +84,12 @@ object Config {
"global and applies to all computers!").
getInt(baseMemory)
commandUser = config.get("server", "commandUser", commandUser, "" +
"The user name to specify when executing a command via a command block. If\n" +
"you leave this empty it will use the address of the network node that sent\n" +
"the execution request - which will usually be a computer.").
getString
fileCost = config.get("server", "fileCost", fileCost, "" +
"The base 'cost' of a single file or directory on a limited file system,\n" +
"such as hard drives. When computing the used space we add this cost to\n" +

View File

@ -84,7 +84,7 @@ trait Component extends Node {
def canBeSeenBy(other: Node) = componentVisibility match {
case Visibility.None => false
case Visibility.Network => true
case Visibility.Neighbors => network.exists(_.neighbors(other).exists(_ == this))
case Visibility.Neighbors => other.network.exists(_.neighbors(other).exists(_ == this))
}
// ----------------------------------------------------------------------- //

View File

@ -9,7 +9,7 @@ class Computer(playerInventory: InventoryPlayer, val computer: tileentity.Comput
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
fontRenderer.drawString(
StatCollector.translateToLocal("oc.container.computer"),
StatCollector.translateToLocal("oc.container.Computer"),
8, 6, 0x404040)
}

View File

@ -9,7 +9,7 @@ class DiskDrive(playerInventory: InventoryPlayer, val drive: tileentity.DiskDriv
override def drawGuiContainerForegroundLayer(mouseX: Int, mouseY: Int) = {
super.drawGuiContainerForegroundLayer(mouseX, mouseY)
fontRenderer.drawString(
StatCollector.translateToLocal("oc.container.disk_drive"),
StatCollector.translateToLocal("oc.container.DiskDrive"),
8, 6, 0x404040)
}
}

View File

@ -9,10 +9,6 @@ class Keyboard(val parent: SpecialDelegator) extends SpecialDelegate {
val unlocalizedName = "Keyboard"
// ----------------------------------------------------------------------- //
// Tile entity
// ----------------------------------------------------------------------- //
override def hasTileEntity = true
override def createTileEntity(world: World, metadata: Int) = Some(new tileentity.Keyboard)

View File

@ -4,9 +4,9 @@ import dan200.computer.api.{ILuaContext, IComputerAccess, IPeripheral}
import li.cil.oc.api
import li.cil.oc.api.network.{Message, Visibility, Node}
import li.cil.oc.server.driver
import net.minecraft.nbt.{NBTTagString, NBTTagList, NBTTagCompound}
import net.minecraftforge.common.ForgeDirection
import scala.collection.mutable
import net.minecraft.nbt.NBTTagCompound
class Adapter extends Rotatable with Node with IPeripheral {
val name = "adapter"
@ -15,6 +15,8 @@ class Adapter extends Rotatable with Node with IPeripheral {
private val blocks = Array.fill[Option[(Node, api.driver.Block)]](6)(None)
private val blocksAddresses = Array.fill[String](6)(java.util.UUID.randomUUID.toString)
private val computers = mutable.ArrayBuffer.empty[IComputerAccess]
private val openPorts = mutable.Map.empty[IComputerAccess, mutable.Set[Int]]
@ -52,12 +54,14 @@ class Adapter extends Rotatable with Node with IPeripheral {
// This is... odd.
network.foreach(_.disconnect(this, node))
val newNode = newDriver.node(worldObj, x, y, z)
newNode.address = Some(blocksAddresses(d.ordinal()))
network.foreach(_.connect(this, newNode))
blocks(d.ordinal()) = Some((newNode, newDriver))
} // else: the more things change, the more they stay the same.
case _ =>
// A challenger appears.
val node = newDriver.node(worldObj, x, y, z)
node.address = Some(blocksAddresses(d.ordinal()))
network.foreach(_.connect(this, node))
blocks(d.ordinal()) = Some((node, newDriver))
}
@ -75,14 +79,29 @@ class Adapter extends Rotatable with Node with IPeripheral {
override def readFromNBT(nbt: NBTTagCompound) {
super.readFromNBT(nbt)
load(nbt.getCompoundTag("node"))
val addressesNbt = nbt.getTagList("addresses")
(0 until (addressesNbt.tagCount min blocksAddresses.length)).
map(addressesNbt.tagAt).
map(_.asInstanceOf[NBTTagString].data).
zipWithIndex.
foreach {
case (a, i) => blocksAddresses(i) = a
}
}
override def writeToNBT(nbt: NBTTagCompound) {
super.writeToNBT(nbt)
val nodeNbt = new NBTTagCompound
val nodeNbt = new NBTTagCompound()
save(nodeNbt)
nbt.setCompoundTag("node", nodeNbt)
val addressesNbt = new NBTTagList()
for (i <- 0 until blocksAddresses.length) {
addressesNbt.appendTag(new NBTTagString(null, blocksAddresses(i)))
}
nbt.setTag("addresses", addressesNbt)
}
// ----------------------------------------------------------------------- //

View File

@ -88,7 +88,7 @@ class Computer(isClient: Boolean) extends Rotatable with component.Computer.Envi
// ----------------------------------------------------------------------- //
def getInvName = "oc.container.computer"
def getInvName = "oc.container.Computer"
def getSizeInventory = 8

View File

@ -46,7 +46,7 @@ class DiskDrive extends Rotatable with Component with ComponentInventory {
// ----------------------------------------------------------------------- //
def getInvName = "oc.container.disk_drive"
def getInvName = "oc.container.DiskDrive"
def getSizeInventory = 1

View File

@ -44,5 +44,5 @@ class Keyboard extends Rotatable with Component {
}
def isUseableByPlayer(p: Player) = worldObj.getBlockTileEntity(xCoord, yCoord, zCoord) == this &&
p.asInstanceOf[EntityPlayer].getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 16
p.asInstanceOf[EntityPlayer].getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5) < 64
}

View File

@ -1,5 +1,6 @@
package li.cil.oc.server.component
import li.cil.oc.Config
import li.cil.oc.api.network.{Component, Message, Visibility}
import net.minecraft.tileentity.TileEntityCommandBlock
@ -19,7 +20,11 @@ class CommandBlock(entity: TileEntityCommandBlock) extends Component {
entity.worldObj.markBlockForUpdate(entity.xCoord, entity.yCoord, entity.zCoord)
result(true)
case Array() if message.name == "command.run" =>
entity.setCommandSenderName(message.source.address.get)
val name = if (Config.commandUser != null && !Config.commandUser.trim.isEmpty)
Config.commandUser.trim
else
message.source.address.get
entity.setCommandSenderName(name)
result(entity.executeCommandOnPowered(entity.worldObj) != 0)
case _ => None
}

View File

@ -606,8 +606,13 @@ class Computer(val owner: Computer.Environment) extends Persistable with Runnabl
lua.pushScalaFunction(lua => {
owner.network.fold(None: Option[Node])(_.node(lua.checkString(1))) match {
case None => 0
case Some(node) => lua.pushString(node.name); 1
case Some(node: Component) if node.canBeSeenBy(this.owner) =>
lua.pushString(node.name)
1
case None =>
lua.pushNil()
lua.pushString("invalid address")
2
}
})
lua.setGlobal("nodeName")
@ -865,7 +870,10 @@ object Computer {
message.data match {
case Array() if message.name == "system.disconnect" && computer.isRunning =>
message.source match {
case node: Component if node.canBeSeenBy(this) =>
case node: Component =>
// This is also generated for components that were never added,
// because the node has already been removed from the network at
// this point, so we cannot check for visibility anymore.
computer.signal("component_removed", message.source.address.get); None
case _ => None
}

View File

@ -142,10 +142,6 @@ object LuaStateFactory {
state.setGlobal("dofile")
state.pushNil()
state.setGlobal("loadfile")
state.pushNil()
state.setGlobal("module")
state.pushNil()
state.setGlobal("require")
// Push a couple of functions that override original Lua API functions or
// that add new functionality to it.
@ -218,20 +214,6 @@ object LuaStateFactory {
// Provide some better Unicode support.
state.getGlobal("string")
// Rename stuff for binary functionality, to allow byte-wise operations
// operations on the string.
state.getField(-1, "sub")
state.setField(-2, "bsub")
state.getField(-1, "reverse")
state.setField(-2, "breverse")
state.pushScalaFunction(lua => {
lua.pushString(String.valueOf((1 to lua.getTop).map(lua.checkInteger).map(_.toChar).toArray))
1
})
state.setField(-2, "char")
// TODO find (probably not necessary?)
// TODO format (probably not necessary?)
@ -240,11 +222,7 @@ object LuaStateFactory {
// TODO gsub (probably not necessary?)
state.pushScalaFunction(lua => {
lua.pushInteger(lua.checkString(1).length)
1
})
state.setField(-2, "len")
// TODO match (probably not necessary?)
state.pushScalaFunction(lua => {
lua.pushString(lua.checkString(1).toLowerCase)
@ -252,13 +230,29 @@ object LuaStateFactory {
})
state.setField(-2, "lower")
// TODO match (probably not necessary?)
state.pushScalaFunction(lua => {
lua.pushString(lua.checkString(1).toUpperCase)
1
})
state.setField(-2, "upper")
state.pushScalaFunction(lua => {
lua.pushString(String.valueOf((1 to lua.getTop).map(lua.checkInteger).map(_.toChar).toArray))
1
})
state.setField(-2, "uchar")
state.pushScalaFunction(lua => {
lua.pushInteger(lua.checkString(1).length)
1
})
state.setField(-2, "ulen")
state.pushScalaFunction(lua => {
lua.pushString(lua.checkString(1).reverse)
1
})
state.setField(-2, "reverse")
state.setField(-2, "ureverse")
state.pushScalaFunction(lua => {
val string = lua.checkString(1)
@ -276,13 +270,7 @@ object LuaStateFactory {
else lua.pushString(string.substring(start, end))
1
})
state.setField(-2, "sub")
state.pushScalaFunction(lua => {
lua.pushString(lua.checkString(1).toUpperCase)
1
})
state.setField(-2, "upper")
state.setField(-2, "usub")
// Pop the string table.
state.pop(1)