From 568c8829db2f886921c7592cadbadbf4241127b6 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Sun, 27 Apr 2014 16:48:07 +1000 Subject: Centralise the PACKAGE_* stuff, move our libraries to lib, and shuffle stuff to suit. --- libraries/LSL.lua | 870 ------------------------- libraries/LumbrJack.c | 85 --- libraries/LumbrJack.h | 38 -- libraries/Runnr.c | 318 ---------- libraries/Runnr.h | 15 - libraries/build.lua | 24 - libraries/skang.lua | 1686 ------------------------------------------------- 7 files changed, 3036 deletions(-) delete mode 100644 libraries/LSL.lua delete mode 100644 libraries/LumbrJack.c delete mode 100644 libraries/LumbrJack.h delete mode 100644 libraries/Runnr.c delete mode 100644 libraries/Runnr.h delete mode 100755 libraries/build.lua delete mode 100644 libraries/skang.lua (limited to 'libraries') diff --git a/libraries/LSL.lua b/libraries/LSL.lua deleted file mode 100644 index 662c880..0000000 --- a/libraries/LSL.lua +++ /dev/null @@ -1,870 +0,0 @@ --- A module of LSL stuffs. - --- Using a module means it gets compiled each time? Maybe not if I can use bytecode files. Perhaps LuaJIT caches these? --- Does not seem to be slowing it down noticably, but that might change once the stubs are filled out. - --- Use it like this - --- local _LSL = require 'LSL' - ---[[ From http://lua-users.org/wiki/LuaModuleFunctionCritiqued -A related note on C code: The luaL_register [9] function in C is -somewhat analogous to the module function in Lua, so luaL_register -shares similar problems, at least when a non-NULL libname is used. -Furthermore, the luaL_newmetatable/luaL_getmetatable/luaL_checkudata -functions use a C string as a key into the global registry. This poses -some potential for name conflicts--either because the modules were -written by different people or because they are different versions of -the same module loaded simultaneously. To address this, one may instead -use a lightuserdata (pointer to variable of static linkage to ensure -global uniqueness) for this key or store the metatable as an -upvalue--either way is a bit more efficient and less error prone. -]] - --- http://www.lua.org/pil/15.4.html looks useful. --- http://www.lua.org/pil/15.5.html the last part about autoloading functions might be useful. - - -local LSL = {}; -local SID = ""; -local scriptName = ""; -local running = true -local paused = false -local currentState = {} -local detectedGroups = {} -local detectedGrabs = {} -local detectedKeys = {} -local detectedLinkNumbers = {} -local detectedNames = {} -local detectedOwners = {} -local detectedPoss = {} -local detectedRots = {} -local detectedTouchBinormals = {} -local detectedTouchFaces = {} -local detectedTouchNormals = {} -local detectedTouchPoss = {} -local detectedTouchSTs = {} -local detectedTouchUVs = {} -local detectedTypes = {} -local detectedVels = {} -local waitAndProcess - - --- Debugging aids - --- Functions to print tables. -local print_table, print_table_start - -function print_table_start(table, space, name) - print(space .. name .. ": "); - print(space .. "{"); - print_table(table, space .. " "); - print(space .. "}"); -end - -function print_table(table, space) - for k, v in pairs(table) do - if type(v) == "table" then - print_table_start(v, space, k); - elseif type(v) == "string" then - print(space .. k .. ': "' .. v .. '";') - else - print(space .. k .. ": " .. v .. ";") - end - end -end - -function msg(...) - print(SID, ...) -- The comma adds a tab, fancy that. B-) -end - - --- Stuff called from the wire protocol has to be global, but I think this means just global to this file. - -events = {} - -function start() paused = false end -function stop() paused = true end -function quit() running = false end - -function events.detectedGroups(list) detectedGroups = list end -function events.detectedGrabs(list) detectedGrabs = list end -function events.detectedKeys(list) detectedKeys = list end -function events.detectedLinkNumbers(list) detectedLinkNumbers = list end -function events.detectedNames(list) detectedNames = list end -function events.detectedOwners(list) detectedOwners = list end -function events.detectedPoss(list) detectedPoss = list end -function events.detectedRots(list) detectedRots = list end -function events.detectedTouchBinormals(list) detectedTouchBinormals = list end -function events.detectedTouchFaces(list) detectedTouchFaces = list end -function events.detectedTouchNormals(list) detectedTouchNormals = list end -function events.detectedTouchPoss(list) detectedTouchPoss = list end -function events.detectedTouchSTs(list) detectedTouchSTs = list end -function events.detectedTouchUVs(list) detectedTouchUVs = list end -function events.detectedTypes(list) detectedTypes = list end -function events.detectedVels(list) detectedVels = list end - -function events.detectsClear() - detectedGroups = {} - detectedGrabs = {} - detectedKeys = {} - detectedLinkNumbers = {} - detectedNames = {} - detectedOwners = {} - detectedPoss = {} - detectedRots = {} - detectedTouchBinormals = {} - detectedTouchFaces = {} - detectedTouchNormals = {} - detectedTouchPoss = {} - detectedTouchSTs = {} - detectedTouchUVs = {} - detectedTypes = {} - detectedVels = {} -end - -function events.at_rot_target(tnum, targetrot, ourrot) if nil ~= currentState.at_rot_target then currentState.at_rot_target(tnum, targetrot, ourrot) end events.detectsClear() end -function events.at_target(tnum, targetpos, ourpos) if nil ~= currentState.at_target then currentState.at_target(tnum, targetpos, ourpos) end events.detectsClear() end -function events.attach(id) if nil ~= currentState.attach then currentState.attach(id) end events.detectsClear() end -function events.changed(change) if nil ~= currentState.changed then currentState.changed(change) end events.detectsClear() end -function events.collision_start(num_detected) if nil ~= currentState.collision_start then currentState.collision_start(num_detected) end events.detectsClear() end -function events.collision(num_detected) if nil ~= currentState.collision then currentState.collision(num_detected) end events.detectsClear() end -function events.collision_end(num_detected) if nil ~= currentState.collision_end then currentState.collision_end(num_detected) end events.detectsClear() end -function events.control(id, held, changed) if nil ~= currentState.control then currentState.control(id, held, changed) end events.detectsClear() end -function events.dataserver(queryid, data) if nil ~= currentState.dataserver then currentState.dataserver(queryid, data) end events.detectsClear() end -function events.email(Time, address, subj, message, num_left) if nil ~= currentState.email then currentState.email(Time, address, subj, message, num_left) end events.detectsClear() end -function events.http_request(request_id, status, metadata, body) if nil ~= currentState.http_request then currentState.http_request(request_id, status, metadata, body) end events.detectsClear() end -function events.http_response(request_id, status, metadata, body) if nil ~= currentState.http_response then currentState.http_response(request_id, status, metadata, body) end events.detectsClear() end -function events.land_collision_start(pos) if nil ~= currentState.land_collision_start then currentState.land_collision_start(pos) end events.detectsClear() end -function events.land_collision(pos) if nil ~= currentState.land_collision then currentState.land_collision(pos) end events.detectsClear() end -function events.land_collision_end(pos) if nil ~= currentState.land_collision_end then currentState.land_collision_end(pos) end events.detectsClear() end -function events.link_message(sender_num, num, str, id) if nil ~= currentState.link_message then currentState.link_message(sender_num, num, str, id) end events.detectsClear() end -function events.listen(channel, name, id, message) if nil ~= currentState.listen then currentState.listen(channel, name, id, message) end events.detectsClear() end -function events.money(id, amount) if nil ~= currentState.money then currentState.money(id, amount) end events.detectsClear() end -function events.moving_start() if nil ~= currentState.moving_start then currentState.moving_start() end events.detectsClear() end -function events.moving_end() if nil ~= currentState.moving_end then currentState.moving_end() end events.detectsClear() end -function events.no_sensor() if nil ~= currentState.no_sensor then currentState.no_sensor() end events.detectsClear() end -function events.not_at_rot_target() if nil ~= currentState.not_at_rot_target then currentState.not_at_rot_target() end events.detectsClear() end -function events.not_at_target() if nil ~= currentState.not_at_target then currentState.not_at_target() end events.detectsClear() end -function events.object_rez(id) if nil ~= currentState.object_rez then currentState.object_rez() end events.detectsClear() end -function events.on_rez(start_param) if nil ~= currentState.on_rezz then currentState.on_rez(start_param) end events.detectsClear() end -function events.remote_data(event_type, channel, message_id, sender, idata, sdata) if nil ~= currentState.remote_data then currentState.remote_data(event_type, channel, message_id, sender, idata, sdata) end events.detectsClear() end -function events.run_time_permissions(perm) if nil ~= currentState.run_time_permisions then currentState.run_time_permissions(perm) end events.detectsClear() end -function events.sensor(num_detected) if nil ~= currentState.sensor then currentState.sensor(num_detected) end events.detectsClear() end -function events.state_entry() if nil ~= currentState.state_entry then currentState.state_entry() end events.detectsClear() end -function events.state_exit() if nil ~= currentState.state_exit then currentState.state_exit() end events.detectsClear() end -function events.timer() if nil ~= currentState.timer then currentState.timer() end events.detectsClear() end -function events.touch_start(num_detected) if nil ~= currentState.touch_start then currentState.touch_start(num_detected) end events.detectsClear() end -function events.touch(num_detected) if nil ~= currentState.touch then currentState.touch(num_detected) end events.detectsClear() end -function events.touch_end(num_detected) if nil ~= currentState.touch_end then currentState.touch_end(num_detected) end events.detectsClear() end -function events.transaction_result(id, success, data) if nil ~= currentState.transaction_result then currentState.transaction_result(id, success, data) end events.detectsClear() end - - --- LSL function and constant creation stuff. - -local args2string -- Pre declare this. -local functions = {} -local mt = {} - -local function value2string(value, Type) - local temp = "" - - if "float" == Type then temp = temp .. value - elseif "integer" == Type then temp = temp .. value - elseif "key" == Type then temp = "\"" .. value .. "\"" - elseif "list" == Type then temp = "[" .. args2string(true, unpack(value)) .. "]" - elseif "table" == Type then temp = "[" .. args2string(true, unpack(value)) .. "]" - elseif "string" == Type then temp = "\"" .. value .. "\"" - elseif "rotation" == Type then temp = "<" .. value.x .. ", " .. value.y .. ", " .. value.z .. ", " .. value.s .. ">" - elseif "vector" == Type then temp = "<" .. value.x .. ", " .. value.y .. ", " .. value.z .. ">" - else - temp = temp .. value - end - return temp -end - -function args2string(doType, ...) - local temp = "" - local first = true - - for j,w in ipairs( {...} ) do - if first then first = false else temp = temp .. ", " end - if doType then - temp = temp .. value2string(w, type(w)) - else - temp = temp .. w - end - end - return temp -end - -function mt.callAndReturn(name, ...) - luaproc.sendback(name .. "(" .. args2string(true, ...) .. ")") -end - -function mt.callAndWait(name, ...) - mt.callAndReturn(name, ...); - -- Eventually a sendForth() is called, which should end up passing through SendToChannel(). - -- Wait for the result, which should be a Lua value as a string. - return waitAndProcess(true) -end - -local function newConst(Type, name, value) - LSL[name] = value - return { Type = Type, name = name } -end - -local function newFunc(Type, name, ... ) - functions[name] = { Type = Type, args = {...} } - if "" == Type then - LSL[name] = function(...) mt.callAndReturn(name, ... ) end - else - LSL[name] = function(...) return mt.callAndWait(name, ... ) end - end -end - - --- LSL constants. - -local constants = -{ - newConst("float", "PI", 3.14159265358979323846264338327950), - newConst("float", "PI_BY_TWO", LSL.PI / 2), -- 1.57079632679489661923132169163975 - newConst("float", "TWO_PI", LSL.PI * 2), -- 6.28318530717958647692528676655900 - newConst("float", "DEG_TO_RAD", LSL.PI / 180.0), -- 0.01745329252 - newConst("float", "RAD_TO_DEG", 180.0 / LSL.PI), -- 57.2957795131 - newConst("float", "SQRT2", 1.4142135623730950488016887242097), - - newConst("integer", "CHANGED_INVENTORY", 0x001), - newConst("integer", "CHANGED_COLOR", 0x002), - newConst("integer", "CHANGED_SHAPE", 0x004), - newConst("integer", "CHANGED_SCALE", 0x008), - newConst("integer", "CHANGED_TEXTURE", 0x010), - newConst("integer", "CHANGED_LINK", 0x020), - newConst("integer", "CHANGED_ALLOWED_DROP", 0x040), - newConst("integer", "CHANGED_OWNER", 0x080), - newConst("integer", "CHANGED_REGION", 0x100), - newConst("integer", "CHANGED_TELEPORT", 0x200), - newConst("integer", "CHANGED_REGION_START", 0x400), - newConst("integer", "CHANGED_MEDIA", 0x800), - - newConst("integer", "DEBUG_CHANNEL", 2147483647), - newConst("integer", "PUBLIC_CHANNEL", 0), - - newConst("integer", "INVENTORY_ALL", -1), - newConst("integer", "INVENTORY_NONE", -1), - newConst("integer", "INVENTORY_TEXTURE", 0), - newConst("integer", "INVENTORY_SOUND", 1), - newConst("integer", "INVENTORY_LANDMARK", 3), - newConst("integer", "INVENTORY_CLOTHING", 5), - newConst("integer", "INVENTORY_OBJECT", 6), - newConst("integer", "INVENTORY_NOTECARD", 7), - newConst("integer", "INVENTORY_SCRIPT", 10), - newConst("integer", "INVENTORY_BODYPART", 13), - newConst("integer", "INVENTORY_ANIMATION", 20), - newConst("integer", "INVENTORY_GESTURE", 21), - - newConst("integer", "ALL_SIDES", -1), - newConst("integer", "LINK_SET", -1), - newConst("integer", "LINK_ROOT", 1), - newConst("integer", "LINK_ALL_OTHERS", -2), - newConst("integer", "LINK_ALL_CHILDREN", -3), - newConst("integer", "LINK_THIS", -4), - - newConst("integer", "PERM_ALL", 0x7FFFFFFF), - newConst("integer", "PERM_COPY", 0x00008000), - newConst("integer", "PERM_MODIFY", 0x00004000), - newConst("integer", "PERM_MOVE", 0x00080000), - newConst("integer", "PERM_TRANSFER", 0x00002000), - newConst("integer", "MASK_BASE", 0), - newConst("integer", "MASK_OWNER", 1), - newConst("integer", "MASK_GROUP", 2), - newConst("integer", "MASK_EVERYONE", 3), - newConst("integer", "MASK_NEXT", 4), - newConst("integer", "PERMISSION_DEBIT", 0x0002), - newConst("integer", "PERMISSION_TAKE_CONTROLS", 0x0004), - newConst("integer", "PERMISSION_TRIGGER_ANIMATION", 0x0010), - newConst("integer", "PERMISSION_ATTACH", 0x0020), - newConst("integer", "PERMISSION_CHANGE_LINKS", 0x0080), - newConst("integer", "PERMISSION_TRACK_CAMERA", 0x0400), - newConst("integer", "PERMISSION_CONTRAL_CAMERA", 0x0800), - - newConst("integer", "AGENT", 0x01), - newConst("integer", "ACTIVE", 0x02), - newConst("integer", "PASSIVE", 0x04), - newConst("integer", "SCRIPTED", 0x08), - - newConst("integer", "OBJECT_UNKNOWN_DETAIL", -1), - - newConst("integer", "PRIM_BUMP_SHINY", 19), - newConst("integer", "PRIM_COLOR", 18), - newConst("integer", "PRIM_FLEXIBLE", 21), - newConst("integer", "PRIM_FULLBRIGHT", 20), - newConst("integer", "PRIM_GLOW", 25), - newConst("integer", "PRIM_MATERIAL", 2), - newConst("integer", "PRIM_PHANTOM", 5), - newConst("integer", "PRIM_PHYSICS", 3), - newConst("integer", "PRIM_POINT_LIGHT", 23), - newConst("integer", "PRIM_POSITION", 6), - newConst("integer", "PRIM_ROTATION", 8), - newConst("integer", "PRIM_SIZE", 7), - newConst("integer", "PRIM_TEMP_ON_REZ", 4), - newConst("integer", "PRIM_TYPE", 9), - newConst("integer", "PRIM_TYPE_OLD", 1), - newConst("integer", "PRIM_TEXGEN", 22), - newConst("integer", "PRIM_TEXTURE", 17), - newConst("integer", "PRIM_TEXT", 26), - - newConst("integer", "PRIM_BUMP_NONE", 0), - newConst("integer", "PRIM_BUMP_BRIGHT", 1), - newConst("integer", "PRIM_BUMP_DARK", 2), - newConst("integer", "PRIM_BUMP_WOOD", 3), - newConst("integer", "PRIM_BUMP_BARK", 4), - newConst("integer", "PRIM_BUMP_BRICKS", 5), - newConst("integer", "PRIM_BUMP_CHECKER", 6), - newConst("integer", "PRIM_BUMP_CONCRETE", 7), - newConst("integer", "PRIM_BUMP_TILE", 8), - newConst("integer", "PRIM_BUMP_STONE", 9), - newConst("integer", "PRIM_BUMP_DISKS", 10), - newConst("integer", "PRIM_BUMP_GRAVEL", 11), - newConst("integer", "PRIM_BUMP_BLOBS", 12), - newConst("integer", "PRIM_BUMP_SIDING", 13), - newConst("integer", "PRIM_BUMP_LARGETILE", 14), - newConst("integer", "PRIM_BUMP_STUCCO", 15), - newConst("integer", "PRIM_BUMP_SUCTION", 16), - newConst("integer", "PRIM_BUMP_WEAVE", 17), - - newConst("integer", "PRIM_HOLE_DEFAULT", 0), - newConst("integer", "PRIM_HOLE_CIRCLE", 16), - newConst("integer", "PRIM_HOLE_SQUARE", 32), - newConst("integer", "PRIM_HOLE_TRIANGLE", 48), - - newConst("integer", "PRIM_MATERIAL_STONE", 0), - newConst("integer", "PRIM_MATERIAL_METAL", 1), - newConst("integer", "PRIM_MATERIAL_GLASS", 2), - newConst("integer", "PRIM_MATERIAL_WOOD", 3), - newConst("integer", "PRIM_MATERIAL_FLESH", 4), - newConst("integer", "PRIM_MATERIAL_PLASTIC", 5), - newConst("integer", "PRIM_MATERIAL_RUBBER", 6), - newConst("integer", "PRIM_MATERIAL_LIGHT", 7), - - newConst("integer", "PRIM_SCULPT_TYPE_SPHERE", 1), - newConst("integer", "PRIM_SCULPT_TYPE_TORUS", 2), - newConst("integer", "PRIM_SCULPT_TYPE_PLANE", 3), - newConst("integer", "PRIM_SCULPT_TYPE_CYLINDER", 4), - newConst("integer", "PRIM_SCULPT_TYPE_MESH", 5), - newConst("integer", "PRIM_SCULPT_TYPE_MIMESH", 6), - - newConst("integer", "PRIM_SHINY_NONE", 0), - newConst("integer", "PRIM_SHINY_LOW", 1), - newConst("integer", "PRIM_SHINY_MEDIUM", 2), - newConst("integer", "PRIM_SHINY_HIGH", 3), - - newConst("integer", "PRIM_TYPE_BOX", 0), - newConst("integer", "PRIM_TYPE_CYLINDER", 1), - newConst("integer", "PRIM_TYPE_PRISM", 2), - newConst("integer", "PRIM_TYPE_SPHERE", 3), - newConst("integer", "PRIM_TYPE_TORUS", 4), - newConst("integer", "PRIM_TYPE_TUBE", 5), - newConst("integer", "PRIM_TYPE_RING", 6), - newConst("integer", "PRIM_TYPE_SCULPT", 7), - - newConst("integer", "STRING_TRIM", 3), - newConst("integer", "STRING_TRIM_HEAD", 1), - newConst("integer", "STRING_TRIM_TAIL", 2), - - newConst("integer", "TRUE", 1), - newConst("integer", "FALSE", 0), - - newConst("integer", "TOUCH_INVALID_FACE", 0x7FFFFFFF), - newConst("vector", "TOUCH_INVALID_TEXCOORD", {x=-1.0, y=-1.0, z=0.0}), - newConst("vector", "TOUCH_INVALID_VECTOR", {x=0.0, y=0.0, z=0.0}), - - newConst("integer", "TYPE_INTEGER", 1), - newConst("integer", "TYPE_FLOAT", 2), - newConst("integer", "TYPE_STRING", 3), - newConst("integer", "TYPE_KEY", 4), - newConst("integer", "TYPE_VECTOR", 5), - newConst("integer", "TYPE_ROTATION", 6), - newConst("integer", "TYPE_INVALID", 0), - - newConst("string", "NULL_KEY", "00000000-0000-0000-0000-000000000000"), - newConst("string", "EOF", "\\n\\n\\n"), -- Corner case, dealt with later. - - newConst("rotation", "ZERO_ROTATION", {x=0.0, y=0.0, z=0.0, s=1.0}), - newConst("vector", "ZERO_VECTOR", {x=0.0, y=0.0, z=0.0}), - --- TODO - Temporary dummy variables to get vector and rotation thingies to work for now. - - newConst("float", "s", 1.0), - newConst("float", "x", 0.0), - newConst("float", "y", 0.0), - newConst("float", "z", 0.0), -} - --- ll*() function definitions - --- LSL avatar functions -newFunc("key", "llAvatarOnSitTarget") -newFunc("list", "llGetAnimationList", "key id") -newFunc("integer", "llGetPermissions") -newFunc("key", "llGetPermissionsKey") -newFunc("string", "llKey2Name", "key avatar") -newFunc("", "llRequestPermissions", "key avatar", "integer perms") -newFunc("integer", "llSameGroup", "key avatar") -newFunc("", "llStartAnimation", "string anim") -newFunc("", "llStopAnimation", "string anim") -newFunc("", "llUnSit", "key avatar") - --- LSL collision / detect / sensor functions -newFunc("integer", "llDetectedGroup", "integer index") -newFunc("vector", "llDetectedGrab", "integer index") -newFunc("key", "llDetectedKey", "integer index") -newFunc("integer", "llDetectedLinkNumber", "integer index") -newFunc("string", "llDetectedName", "integer index") -newFunc("key", "llDetectedOwner", "integer index") -newFunc("vector", "llDetectedPos", "integer index") -newFunc("rotation", "llDetectedRot", "integer index") -newFunc("vector", "llDetectedTouchBinormal", "integer index") -newFunc("integer", "llDetectedTouchFace", "integer index") -newFunc("vector", "llDetectedTouchNormal", "integer index") -newFunc("vector", "llDetectedTouchPos", "integer index") -newFunc("vector", "llDetectedTouchST", "integer index") -newFunc("vector", "llDetectedTouchUV", "integer index") -newFunc("integer", "llDetectedType", "integer index") -newFunc("vector", "llDetectedVel", "integer index") - - --- LSL communications functions -newFunc("", "llDialog", "key avatar", "string caption", "list arseBackwardsMenu", "integer channel") -newFunc("integer", "llListen", "integer channel", "string name", "key id", "string msg") -newFunc("", "llListenRemove", "integer handle") -newFunc("", "llOwnerSay", "string text") -newFunc("", "llSay", "integer channel", "string text") -newFunc("", "llShout", "integer channel", "string text") -newFunc("", "llWhisper", "integer channel", "string text") -newFunc("", "llMessageLinked", "integer link", "integer num", "string text", "key aKey") - --- LSL inventory functions. -newFunc("string", "llGetInventoryName", "integer Type", "integer index") -newFunc("integer", "llGetInventoryNumber", "integer Type") -newFunc("integer", "llGetInventoryType", "string name") -newFunc("key", "llGetNotecardLine", "string name", "integer index") -newFunc("", "llRezAtRoot", "string name", "vector position", "vector velocity", "rotation rot", "integer channel") -newFunc("", "llRezObject", "string name", "vector position", "vector velocity", "rotation rot", "integer channel") - --- LSL list functions. -newFunc("list", "llCSV2List", "string text") -newFunc("list", "llDeleteSubList", "list l", "integer start", "integer End") -newFunc("string", "llDumpList2String", "list l", "string separator") -newFunc("integer", "llGetListLength", "list l") -newFunc("string", "llList2CSV", "list l") -newFunc("float", "llList2Float", "list l", "integer index") -newFunc("integer", "llList2Integer", "list l", "integer index") -newFunc("key", "llList2Key", "list l", "integer index") -newFunc("list", "llList2List", "list l", "integer start", "integer End") -newFunc("string", "llList2String", "list l", "integer index") -newFunc("rotation", "llList2Rotation", "list l", "integer index") -newFunc("vector", "llList2Vector", "list l", "integer index") -newFunc("integer", "llListFindList", "list l", "list l1") -newFunc("list", "llListInsertList", "list l", "list l1", "integer index") -newFunc("list", "llListReplaceList", "list l", "list part", "integer start", "integer End") -newFunc("list", "llListSort", "list l", "integer stride", "integer ascending") -newFunc("list", "llParseString2List", "string In", "list l", "list l1") -newFunc("list", "llParseStringKeepNulls", "string In", "list l", "list l1") - --- LSL math functions -newFunc("rotation", "llEuler2Rot", "vector vec") -newFunc("float", "llFrand", "float max") -newFunc("float", "llPow", "float number", "float places") -newFunc("vector", "llRot2Euler", "rotation rot") -newFunc("integer", "llRound", "float number") - --- LSL media functions -newFunc("", "llPlaySound", "string name", "float volume") - --- LSL object / prim functions -newFunc("", "llDie") -newFunc("key", "llGetKey") -newFunc("integer", "llGetLinkNumber") -newFunc("string", "llGetObjectDesc") -newFunc("string", "llGetObjectName") -newFunc("key", "llGetOwner") -newFunc("", "llSetObjectDesc", "string text") -newFunc("", "llSetObjectName", "string text") -newFunc("", "llSetPrimitiveParams", "list params") -newFunc("", "llSetSitText", "string text") -newFunc("", "llSetText", "string text", "vector colour", "float alpha") -newFunc("", "llSitTarget", "vector pos", "rotation rot") - --- LSL rotation / scaling / translation functions -newFunc("vector", "llGetPos") -newFunc("rotation", "llGetRot") -newFunc("", "llSetPos", "vector pos") -newFunc("", "llSetRot", "rotation rot") -newFunc("", "llSetScale", "vector scale") - --- LSL script functions -newFunc("integer", "llGetFreeMemory") -newFunc("string", "llGetScriptName") -newFunc("", "llResetOtherScript", "string name") -newFunc("", "llResetScript") -newFunc("", "llSetScriptState", "string name", "integer running") - --- LSL string functions -newFunc("string", "llGetSubString", "string text", "integer start", "integer End") -newFunc("integer", "llStringLength", "string text") -newFunc("string", "llStringTrim", "string text", "integer type") -newFunc("integer", "llSubStringIndex", "string text", "string sub") - --- LSL texture functions -newFunc("float", "llGetAlpha", "integer side") -newFunc("", "llSetAlpha", "float alpha", "integer side") -newFunc("", "llSetColor", "vector colour", "integer side") - --- LSL time functions -newFunc("float", "llGetTime") -newFunc("", "llResetTime") -newFunc("", "llSetTimerEvent", "float seconds") -newFunc("float", "llSleep", "float seconds") -- Faked return type, it actually does not return anything. This forces it to wait. Actually fully implements llSleep(). B-) - - --- TODO - fake this for now. -function --[[integer]] LSL.llGetInventoryType(--[[string]] name) return LSL.INVENTORY_SCRIPT end; - - --- LSL collision / detect / sensor functions -function --[[integer]] LSL.llDetectedGroup( --[[integer]] index) return detectedGroups [index + 1] or false end -function --[[vector]] LSL.llDetectedGrab( --[[integer]] index) return detectedGrabs [index + 1] or LSL.ZERO_VECTOR end -function --[[key]] LSL.llDetectedKey( --[[integer]] index) return detectedKeys [index + 1] or LSL.NULL_KEY end -- LL says "returns empty key" which is "", but LSL Wiki says NULL_KEY -function --[[integer]] LSL.llDetectedLinkNumber( --[[integer]] index) return detectedLinkNumbers [index + 1] or 0 end -function --[[string]] LSL.llDetectedName( --[[integer]] index) return detectedNames [index + 1] or "" end -- LL says it returns NULL_KEY, LSL Wiki says an empty string. Apparently there used to be an exploit for creating multi kb names, normally they are 255 characters. -function --[[key]] LSL.llDetectedOwner( --[[integer]] index) return detectedOwners [index + 1] or LSL.NULL_KEY end -- LL says "returns empty key" which is "", but LSL Wiki says NULL_KEY -function --[[vector]] LSL.llDetectedPos( --[[integer]] index) return detectedPoss [index + 1] or LSL.ZERO_VECTOR end -function --[[rotation]] LSL.llDetectedRot( --[[integer]] index) return detectedRots [index + 1] or LSL.ZERO_ROTATION end -function --[[vector]] LSL.llDetectedTouchBinormal( --[[integer]] index) return detectedTouchBinormals [index + 1] or LSL.TOUCH_INVALID_VECTOR end -function --[[integer]] LSL.llDetectedTouchFace( --[[integer]] index) return detectedTouchFaces [index + 1] or LSL.TOUCH_INVALID_FACE end -function --[[vector]] LSL.llDetectedTouchNormal( --[[integer]] index) return detectedTouchNormals [index + 1] or LSL.TOUCH_INVALID_VECTOR end -function --[[vector]] LSL.llDetectedTouchPos( --[[integer]] index) return detectedTouchPoss [index + 1] or LSL.TOUCH_INVALID_VECTOR end -function --[[vector]] LSL.llDetectedTouchST( --[[integer]] index) return detectedTouchSTs [index + 1] or LSL.TOUCH_INVALID_TEXCOORD end -function --[[vector]] LSL.llDetectedTouchUV( --[[integer]] index) return detectedTouchUVs [index + 1] or LSL.TOUCH_INVALID_TEXCOORD end -function --[[integer]] LSL.llDetectedType( --[[integer]] index) return detectedTypes [index + 1] or 0 end -function --[[vector]] LSL.llDetectedVel( --[[integer]] index) return detectedVels [index + 1] or LSL.ZERO_VECTOR end - - --- LSL list functions. - ---function --[[list]] LSL.llCSV2List(--[[string]] text) return {} end; -function --[[list]] LSL.llDeleteSubList(--[[list]] l,--[[integer]] start,--[[integer]] eNd) - local result = {} - local x = 1 - - -- Deal with the impedance mismatch. - start = start + 1 - eNd = eNd + 1 - for i = 1,#l do - if i < start then result[x] = l[i]; x = x + 1 - elseif i > eNd then result[x] = l[i]; x = x + 1 - end - end - - return result -end - -function --[[string]] LSL.llDumpList2String(--[[list]] l, --[[string]] separator) - local result = "" - for i = 1,#l do - if "" ~= result then result = result .. separator end - result = result .. l[i] - end - return result -end - -function --[[integer]] LSL.llGetListLength(--[[list]] l) - return #l -end - -function --[[string]] LSL.llList2CSV(--[[list]] l) - return LSL.llDumpList2String(l, ",") -end - -function --[[float]] LSL.llList2Float(--[[list]] l,--[[integer]] index) - local result = tonumber(l[index]) - if nil == result then result = 0.0 end - return result -end - -function --[[integer]] LSL.llList2Integer(--[[list]] l,--[[integer]] index) - local result = tonumber(l[index+1]) - if nil == result then result = 0 end - return result -end - -function --[[key]] LSL.llList2Key(--[[list]] l,--[[integer]] index) - local result = l[index+1] - if result then return "" .. result else return LSL.NULL_KEY end -end - -function --[[list]] LSL.llList2List(--[[list]] l,--[[integer]] start,--[[integer]] eNd) - local result = {} - local x = 1 - - --[[ TODO - -Using negative numbers for start and/or end causes the index to count backwards from the length of the list, so 0, -1 would capture the entire list. -If start is larger than end the list returned is the exclusion of the entries, so 6, 4 would give the entire list except for the 5th entry. - ]] - - -- Deal with the impedance mismatch. - start = start + 1 - eNd = eNd + 1 - for i = 1,#l do - if i >= start then result[x] = l[i]; x = x + 1 - elseif i <= eNd then result[x] = l[i]; x = x + 1 - end - end - - return result -end - -function --[[string]] LSL.llList2String(--[[list]] l,--[[integer]] index) - local result = l[index+1] - if result then return "" .. result else return "" end -end - -function --[[rotation]] LSL.llList2Rotation(--[[list]] l,--[[integer]] index) - local result = l[index+1] - if nil == result then result = LSL.ZERO_ROTATION end - -- TODO - check if it's not an actual rotation, then return LSS.ZERO_ROTATION - return result -end - -function --[[vector]] LSL.llList2Vector(--[[list]] l,--[[integer]] index) - local result = l[index+1] - if nil == result then result = LSL.ZERO_VECTOR end - -- TODO - check if it's not an actual rotation, then return LSS.ZERO_VECTOR - return result -end - ---function --[[integer]] LSL.llListFindList(--[[list]] l, --[[list]] l1) return 0 end; -function --[[list]] LSL.llListInsertList(--[[list]] l, --[[list]] l1,--[[integer]] index) - local result = {} - local x = 1 - local y - for i = 1,index do - result[x] = l[i] - x = x + 1 - end - y = x - for i = 1,#ll do - result[x] = ll[i] - x = x + 1 - end - for i = y,#l do - result[x] = l[i] - x = x + 1 - end - return result -end - -function --[[list]] LSL.llListReplaceList(--[[list]] l, --[[list]] part,--[[integer]] start,--[[integer]] eNd) - local result = {} - local x = 1 - local y - for i = 1,index do - result[x] = l[i] - x = x + 1 - end - for i = 1,#part do - result[x] = part[i] - x = x + 1 - end - for i = index,#l do - result[x] = l[i] - x = x + 1 - end - return result -end - -function --[[list]] LSL.llListSort(--[[list]] l,--[[integer]] stride,--[[integer]] ascending) - local result = {} - - -- TODO - Deal with stride and ascending. - for i = 1,#l do - result[x] = l[i]; x = x + 1 - end - table.sort(result) - - return result -end - ---function --[[list]] LSL.llParseString2List(--[[string]] In, --[[list]] l, --[[list]] l1) return {} end; ---function --[[list]] LSL.llParseStringKeepNulls(--[[string]] In, --[[list]] l, --[[list]] l1) return {} end; - - --- LSL script functions - -function --[[string]] LSL.llGetScriptName() - return scriptName -end - - --- LSL string functions - -function --[[string]] LSL.llGetSubString(--[[string]] text, --[[integer]] start, --[[integer]] End) - -- Deal with the impedance mismatch. - if 0 <= start then start = start + 1 end - if 0 <= End then End = End + 1 end --- TODO - If start is larger than end the substring is the exclusion of the entries, so 6,4 would give the entire string except for the 5th character. - return string.sub(text, start, End) -end - -function --[[integer]] LSL.llSubStringIndex(--[[string]] text, --[[string]] sub) - local start, End = string.find(text, sub, 1, true) - - if nil == start then return -1 else return start - 1 end -end - - --- Crements stuff. - -function LSL.preDecrement(name) _G[name] = _G[name] - 1; return _G[name]; end; -function LSL.preIncrement(name) _G[name] = _G[name] + 1; return _G[name]; end; -function LSL.postDecrement(name) local temp = _G[name]; _G[name] = _G[name] - 1; return temp; end; -function LSL.postIncrement(name) local temp = _G[name]; _G[name] = _G[name] + 1; return temp; end; - - --- State stuff - -function LSL.stateChange(x) - if currentState ~= x then -- Changing to the same state is a NOP. - -- TODO - Should clear out pending events, except timer() - -- Also forget about any event setup that needs setting up via some ll*() function, except timer(). - if nil ~= currentState.state_exit then - currentState.state_exit(); - end - currentState = x; - --[[ Never return to the current states event handler. In theory. lol - Notably, it's not actually legal to do a state change from a function, only from handlers. - There is a hack though, but it's unsupported, so I don't have to worry about it so much. - - Write out "state new;" as "return _LSL.stateChange(newState);", with stateChange() returning new.state_entry()) which will force two tail calls. - - The caller of stateChange() might be a function rather than an event handler. - Which will return to the event handler (possibly via other nested function calls) as if the state never changed. - http://lslwiki.net/lslwiki/wakka.php?wakka=FunctionStateChangeHack seems to imply that this is exactly what LSL does. - Soooo, this might actually work perfectly. - Except for one minor quirk, as that page shows - only the top level function's state sticks, unless the handler does one to, then the handlers one overrides things. - Which I can probably ignore anyway, as this entire calling states within functions thing is an unsupported hack. - ]] - if nil ~= currentState.state_entry then - return currentState.state_entry(); - end - end -end; - -function LSL.mainLoop(sid, name, x) - local status, errorMsg - local result - - SID = sid - scriptName = name - LSL.EOF = "\n\n\n" -- Fix this up now. - - LSL.stateChange(x); - waitAndProcess(false) - msg("Script quitting.") -end - -function waitAndProcess(returnWanted) - local Type = "event" - - if returnWanted then Type = "result" end - while running do - local message = luaproc.receive(SID) - if message then - -- TODO - should we be discarding return values while paused? I don't think so, so we need to process those, - if paused then - if "start()" == message then paused = false end - else - result, errorMsg = loadstring(message) -- "The environment of the returned function is the global environment." Though normally, a function inherits it's environment from the function creating it. Which is what we want. lol - if nil == result then - msg("Not a valid " .. Type .. ": " .. message .. " ERROR MESSAGE: " .. errorMsg) - else - -- Set the functions environment to ours, for the protection of the script, coz loadstring sets it to the global environment instead. - -- TODO - On the other hand, we will need the global environment when we call event handlers. So we should probably stash it around here somewhere. - -- Meh, seems to be working fine as it is. - setfenv(result, getfenv(1)) - status, result = pcall(result) - if not status then - msg("Error from " .. Type .. ": " .. message .. " ERROR MESSAGE: " .. result) - elseif result then - -- Check if we are waiting for a return, and got it. - if returnWanted and string.match(message, "^return ") then - return result - end - -- Otherwise, just run it and keep looping. - status, errorMsg = luaproc.send(sid, result) - if not status then - msg("Error sending results from " .. Type .. ": " .. message .. " ERROR MESSAGE: " .. errorMsg) - end - end - end - end - end - end -end - --- Typecasting stuff. - -function LSL.floatTypecast(x) - local temp = tonumber(x) - if nil == temp then temp = 0 end - return temp; -end - -function LSL.integerTypecast(x) - local temp = tonumber(x) - if nil == temp then temp = 0 end - return temp; -end - -function LSL.keyTypecast(x) - return "" .. x; -end - -function LSL.listTypecast(x) - return {x}; -end - -function LSL.rotationTypecast(x) - return x; -end - -function LSL.stringTypecast(x) - return "" .. x; -end - -function LSL.vectorTypecast(x) - return x; -end - - --- Called at compiler set up time, to produce the constants.lsl file. -function LSL.gimmeLSL() - for i,v in ipairs(constants) do - local value = LSL[v.name] - - print(v.Type .. " " .. v.name .. " = " .. value2string(value, v.Type) .. ";") - end - - for k in pairs(functions) do - local v = functions[k] - if nil == v.args then - print(v.Type .. " " .. k .. "(){}") - else - print(v.Type .. " " .. k .. "(" .. args2string(false, unpack(v.args)) .. "){}") - end - end -end - - -return LSL; diff --git a/libraries/LumbrJack.c b/libraries/LumbrJack.c deleted file mode 100644 index 084d916..0000000 --- a/libraries/LumbrJack.c +++ /dev/null @@ -1,85 +0,0 @@ -/* LumbrJack - a logging library that wraps Eina logging. - -*/ - - -#include "LumbrJack.h" - - -static char dateTime[DATE_TIME_LEN]; - -static void _ggg_log_print_cb(const Eina_Log_Domain *d, Eina_Log_Level level, const char *file, const char *fnc, int line, const char *fmt, void *data, va_list args) -{ - FILE *f = data; - char dt[DATE_TIME_LEN + 1]; - char fileTab[256], funcTab[256]; - - getDateTime(NULL, dt, NULL); - dt[19] = '\0'; - if (12 > strlen(file)) - snprintf(fileTab, sizeof(fileTab), "%s\t\t", file); - else - snprintf(fileTab, sizeof(fileTab), "%s\t", file); - snprintf(funcTab, sizeof(funcTab), "\t%s", fnc); - fprintf(f, "%s ", dt); - if (f == stderr) - eina_log_print_cb_stderr(d, level, fileTab, funcTab, line, fmt, data, args); - else if (f == stdout) - eina_log_print_cb_stdout(d, level, fileTab, funcTab, line, fmt, data, args); - fflush(f); -} - -int loggingStartup(char *name, int logDom) -{ - if (logDom < 0) - { - logDom = eina_log_domain_register(name, NULL); - if (logDom < 0) - { - EINA_LOG_CRIT("could not register log domain '%s'", name); - return logDom; - } - } - eina_log_level_set(EINA_LOG_LEVEL_DBG); - eina_log_domain_level_set(name, EINA_LOG_LEVEL_DBG); - eina_log_print_cb_set(_ggg_log_print_cb, stderr); - - // Shut up the excess debugging shit from EFL. - eina_log_domain_level_set("eo", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("eldbus", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("eet", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("ecore", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("ecore_audio", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("ecore_con", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("ecore_evas", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("ecore_input_evas", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("ecore_input_evas", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("ecore_system_upower", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("eio", EINA_LOG_LEVEL_WARN); - eina_log_domain_level_set("evas_main", EINA_LOG_LEVEL_WARN); - - return logDom; -} - -char *getDateTime(struct tm **nowOut, char *dateOut, time_t *timeOut) -{ - struct tm *newTime; - time_t szClock; - char *date = dateTime; - - // Get time in seconds - time(&szClock); - // Convert time to struct tm form - newTime = localtime(&szClock); - - if (nowOut) - *nowOut = newTime; - if (dateOut) - date = dateOut; - if (timeOut) - *timeOut = szClock; - - // format - strftime(date, DATE_TIME_LEN, "%d/%m/%Y %H:%M:%S\r", newTime); - return (dateTime); -} diff --git a/libraries/LumbrJack.h b/libraries/LumbrJack.h deleted file mode 100644 index 4a3290c..0000000 --- a/libraries/LumbrJack.h +++ /dev/null @@ -1,38 +0,0 @@ - -#include -#include - -#include - - -#define PC(...) EINA_LOG_DOM_CRIT(ourGlobals->logDom, __VA_ARGS__) -#define PE(...) EINA_LOG_DOM_ERR(ourGlobals->logDom, __VA_ARGS__) -#define PW(...) EINA_LOG_DOM_WARN(ourGlobals->logDom, __VA_ARGS__) -#define PD(...) EINA_LOG_DOM_DBG(ourGlobals->logDom, __VA_ARGS__) -#define PI(...) EINA_LOG_DOM_INFO(ourGlobals->logDom, __VA_ARGS__) - -#define PCm(...) EINA_LOG_DOM_CRIT(ourGlobals.logDom, __VA_ARGS__) -#define PEm(...) EINA_LOG_DOM_ERR(ourGlobals.logDom, __VA_ARGS__) -#define PWm(...) EINA_LOG_DOM_WARN(ourGlobals.logDom, __VA_ARGS__) -#define PDm(...) EINA_LOG_DOM_DBG(ourGlobals.logDom, __VA_ARGS__) -#define PIm(...) EINA_LOG_DOM_INFO(ourGlobals.logDom, __VA_ARGS__) - -#define D() PD("DEBUG") - - -// "01:03:52 01-01-1973\n\0" -#define DATE_TIME_LEN 21 - - -#ifndef FALSE -// NEVER change this -typedef enum -{ - FALSE = 0, - TRUE = 1 -} boolean; -#endif - - -int loggingStartup(char *name, int logDom); -char *getDateTime(struct tm **nowOut, char *dateOut, time_t *tiemOut); diff --git a/libraries/Runnr.c b/libraries/Runnr.c deleted file mode 100644 index a24e7f5..0000000 --- a/libraries/Runnr.c +++ /dev/null @@ -1,318 +0,0 @@ -/* Runnr - a library that deals with running Lua scripts. - -*/ - - -#include "Runnr.h" - - -void dumpStack(lua_State *L, int i) -{ - int type = lua_type(L, i); - - switch (type) - { - case LUA_TNONE : printf("Stack %d is empty\n", i); break; - case LUA_TNIL : printf("Stack %d is a nil\n", i); break; - case LUA_TBOOLEAN : printf("Stack %d is a boolean - %d\n", i, lua_toboolean(L, i)); break; - case LUA_TNUMBER : printf("Stack %d is a number\n - %f", i, lua_tonumber(L, i)); break; - case LUA_TSTRING : printf("Stack %d is a string - %s\n", i, lua_tostring(L, i)); break; - case LUA_TFUNCTION : printf("Stack %d is a function\n", i); break; - case LUA_TTHREAD : printf("Stack %d is a thread\n", i); break; - case LUA_TTABLE : - { - int j; - - printf("Stack %d is a table", i); - lua_getfield(L, i, "_NAME"); - j = lua_gettop(L); - if (lua_isstring(L, j)) - printf(" - %s", lua_tostring(L, j)); - lua_pop(L, 1); - printf("\n"); - break; - } - case LUA_TUSERDATA : printf("Stack %d is a userdata\n", i); break; - case LUA_TLIGHTUSERDATA : printf("Stack %d is a light userdata\n", i); break; - default : printf("Stack %d is unknown\n", i); break; - } -} - - -// These are what the various symbols are for each type - -// int % -// num # -// str $ -// bool ! -// C func & -// table.field @ Expects an integer and a string. -// nil ~ -// table {} Starts and stops filling up a new table. -// ( Just syntax sugar for call. -// call ) Expects an integer, the number of results left after the call. -// FIXME: Still to do, if we ever use them - -// stack = Get a value from the stack, expects a stack index. -// userdata + -// lightuserdata * -// thread ^ - -static char *_push_name(lua_State *L, char *q, int *idx) // Stack usage [-0, +1, e or m] -{ - char *p = q; - char temp = '\0'; - - // A simplistic scan through an identifier, it's wrong, but it's quick, - // and we don't mind that it's wrong, coz this is only internal. - while (isalnum((int)*q)) - q++; - temp = *q; - *q = '\0'; - if (*idx > 0) - lua_getfield(L, *idx, p); // Stack usage [-0, +1, e] - else - { - if (p != q) - lua_pushstring(L, p); // Stack usage [-0, +1, m] - else - { - lua_pushnumber(L, (lua_Number) (0 - (*idx))); - (*idx)--; - } - } - *q = temp; - - return q; -} - -int pull_lua(lua_State *L, int i, char *params, ...) // Stack usage - - // if i is a table - // [-n, +n, e] - // else - // [-0, +0, -] -{ - va_list vl; - char *f = strdup(params); - char *p = f; - int n = 0, j = i, count = 0; - Eina_Bool table = EINA_FALSE; - - if (!f) return -1; - va_start(vl, params); - - if (lua_istable(L, i)) // Stack usage [-0, +0, -] - { - j = -1; - table = EINA_TRUE; - } - - while (*p) - { - char *q; - Eina_Bool get = EINA_TRUE; - - while (isspace((int)*p)) - p++; - q = p + 1; - switch (*p) - { - case '%': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, e] - if (lua_isnumber(L, j)) // Stack usage [-0, +0, -] - { - int *v = va_arg(vl, int *); - *v = lua_tointeger(L, j); // Stack usage [-0, +0, -] - n++; - } - break; - } - case '#': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, e] - if (lua_isnumber(L, j)) // Stack usage [-0, +0, -] - { - double *v = va_arg(vl, double *); - *v = lua_tonumber(L, j); // Stack usage [-0, +0, -] - n++; - } - break; - } - case '$': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, e] - if (lua_isstring(L, j)) // Stack usage [-0, +0, -] - { - char **v = va_arg(vl, char **); - size_t len; - char *temp = (char *) lua_tolstring(L, j, &len); // Stack usage [-0, +0, m] - - len++; // Cater for the null at the end. - *v = malloc(len); - if (*v) - { - memcpy(*v, temp, len); - n++; - } - } - break; - } - case '!': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, e] - if (lua_isboolean(L, j)) // Stack usage [-0, +0, -] - { - int *v = va_arg(vl, int *); - *v = lua_toboolean(L, j); // Stack usage [-0, +0, -] - n++; - } - break; - } - default: - { - get = EINA_FALSE; - break; - } - } - - if (get) - { - if (table) - { - // If this is a table, then we pushed a value on the stack, pop it off. - lua_pop(L, 1); // Stack usage [-n, +0, -] - } - else - j++; - count++; - } - p = q; - } - - va_end(vl); - free(f); - if (count > n) - n = 0; - else if (table) - n = 1; - return n; -} - -int push_lua(lua_State *L, char *params, ...) // Stack usage [-0, +n, em] -{ - va_list vl; - char *f = strdup(params); - char *p = f; - int n = 0, table = 0, i = -1; - - if (!f) return -1; - - va_start(vl, params); - - while (*p) - { - char *q; - Eina_Bool set = EINA_TRUE; - - while (isspace((int)*p)) - p++; - q = p + 1; - switch (*p) - { - case '%': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_pushinteger(L, va_arg(vl, int)); // Stack usage [-0, +1, -] - break; - } - case '#': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_pushnumber(L, va_arg(vl, double)); // Stack usage [-0, +1, -] - break; - } - case '$': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_pushstring(L, va_arg(vl, char *)); // Stack usage [-0, +1, m] - break; - } - case '!': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_pushboolean(L, va_arg(vl, int)); // Stack usage [-0, +1, -] - break; - } - case '=': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_pushvalue(L, va_arg(vl, int)); // Stack usage [-0, +1, -] - break; - } - case '@': - { - int tabl = va_arg(vl, int); - char *field = va_arg(vl, char *); - - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_getfield(L, tabl, field); // Stack usage [-0, +1, e] - break; - } - case '&': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_pushcfunction(L, va_arg(vl, void *)); // Stack usage [-0, +1, m] - break; - } - case '~': - { - if (table) q = _push_name(L, q, &i); // Stack usage [-0, +1, m] - lua_pushnil(L); // Stack usage [-0, +1, -] - break; - } - case '(': // Just syntax sugar. - { - set = EINA_FALSE; - break; - } - case ')': - { - lua_call(L, n - 1, va_arg(vl, int)); - n = 0; - set = EINA_FALSE; - break; - } - case '{': - { - lua_newtable(L); - table++; - n++; - set = EINA_FALSE; - break; - } - case '}': - { - table--; - set = EINA_FALSE; - break; - } - default: - { - set = EINA_FALSE; - break; - } - } - - if (set) - { - if (table > 0) - lua_settable(L, -3); // Stack usage [-2, +0, e] - else - n++; - } - p = q; - } - - va_end(vl); - free(f); - return n; -} diff --git a/libraries/Runnr.h b/libraries/Runnr.h deleted file mode 100644 index dc720ff..0000000 --- a/libraries/Runnr.h +++ /dev/null @@ -1,15 +0,0 @@ - -#include -#include - -#include - -#include -#include -#include -#include - - -void dumpStack(lua_State *L, int i); -int pull_lua(lua_State *L, int i, char *params, ...); -int push_lua(lua_State *L, char *params, ...); diff --git a/libraries/build.lua b/libraries/build.lua deleted file mode 100755 index 8b48b70..0000000 --- a/libraries/build.lua +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env lua - -local dir = ... - -if 'nil' == type(dir) then - local build, err = loadfile('../build.lua') - if build then - setfenv(build, getfenv(2)) - build('') - else - print("ERROR - " .. err) - end - dir = workingDir -end - -LDFLAGS = '-L ' .. dir .. ' ' .. LDFLAGS - -removeFiles(dir, {'LumbrJack.o', 'libLumbrJack.so', 'Runnr.o', 'libRunnr.so'}) - -runCommand('C libraries', dir, 'gcc ' .. CFLAGS .. ' -fPIC -c LumbrJack.c') -runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' -shared -Wl,-soname,libLumbrJack.so -o libLumbrJack.so LumbrJack.o') - -runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' -fPIC -c Runnr.c') -runCommand(nil, dir, 'gcc ' .. CFLAGS .. ' -shared -Wl,-soname,libRunnr.so -o libRunnr.so Runnr.o') diff --git a/libraries/skang.lua b/libraries/skang.lua deleted file mode 100644 index 23549c3..0000000 --- a/libraries/skang.lua +++ /dev/null @@ -1,1686 +0,0 @@ ---[[ TODO - This should be in C, but so far development has been quite rapid doing it in Lua. - -C will let us - - Actually do the widget stuff. - Slap meta tables on all value types. - Which lets us put the meta table on the variable, instead of on the table, which I think is cleaner. - Figure out the directory separator. - Network stuff. No need to look at Lua socket stuff, we have Ecore_Con. - Database stuff. No need to look at Lua SQL stuff, we have esskyuehl. Maybe. - - Actually, we could have the best of both worlds, since it is currently a C / Lua hybrid. B-) -]] - - ---[[ Skang package - -In here should live all the internals of matrix-RAD that don't -specifically relate to widgets. This would include the "window" though. - -skang.module(Evas) -skang.module(Elementary) -skang.skang('some/skang/file.skang') - -This package is also what "apps" that use the system should "inherit" -from, in the same way matrix-RAD apps did. Skang "apps" could be Lua -modules. They could also be C code, like the extantz modules are likely -to be. Skang "apps" would automatically be associated with skang files -of the same name. - -For a .skang file, the skang command (written in C) would strip off the -first line, add the two implied lines, then run it as Lua. The -skang.load() command would do the same. So that skang C comand would -just pass the file name to skang.load() in this library. B-) - -The old skang argument types are - - -{"name", "java.lang.String"}, -{"action", "java.lang.String"}, -{"type", "java.lang.String"}, -{"data", "java.lang.String"}, -{"URL", "java.lang.String"}, -{"file", "java.lang.String"}, -{"method", "java.lang.String"}, -{"lx", "java.lang.String"}, -{"ly", "java.lang.String"}, -{"lw", "java.lang.String"}, -{"lh", "java.lang.String"}, -{"normal", "java.lang.String"}, -{"ghost", "java.lang.String"}, -{"active", "java.lang.String"}, -{"toggle", "java.lang.String"}, -{"boolean","java.lang.Boolean"}, -{"number", "java.lang.Integer"}, -{"int", "java.lang.Integer"}, -{"x", "java.lang.Integer"}, -{"y", "java.lang.Integer"}, -{"w", "java.lang.Integer"}, -{"h", "java.lang.Integer"}, -{"r", "java.lang.Integer"}, -{"g", "java.lang.Integer"}, -{"b", "java.lang.Integer"}, -{"alpha", "java.lang.Integer"}, -{"acl", "net.matrix_rad.security.ACL"}, -]] - - --- Wrapping the entire module in do .. end helps if people just join a bunch of modules together, which apparently is popular. --- By virtue of the fact we are stuffing our result into package.loaded[], just plain running this works as "loading the module". -do -- Only I'm not gonna indent this. - -mainSkin = {} - --- TODO - This needs to be expanded a bit to cover things like 1.42 -local versions = { - '0%.0', 'unwritten', 'Just a stub, no code at all, or completely non-existant.', - '0%.1', 'prototype', 'Stuff that has only been prototyped, or partly written. There is some code, and it may even work, but it is not even close to the finished product.', - '%d%.3', 'written', 'Stuff that has already been written. It may not be perfect, but it is considered an aproximation of the finished product.', - '%d%.5', 'alpha', 'Version being tested by official alpha testers.', - '%d%.9', 'beta', 'Version passed alpha testing, but not ready for final release.', - '1%.0', 'final', 'Version ready for final release, fully tested.', - '3%.0', 'poetry', 'Near perfection has been acheived.', - '5%.0', 'nirvana', 'Perfection has been acheived.', - '9%.0', 'bible', 'This is the Whord of Ghod.', -} - --- Trying to capture best practices here for creating modules, especially since module() is broken and deprecated. --- TODO - Should parse in license type to. -moduleBegin = function (name, author, copyright, version, timestamp, skin, isLua) - local _M = {} -- This is what we return to require(). - local level = 2 - - if 'nil' == type(isLua) then isLua = true end - - package.loaded[name] = _M -- Stuff the result into where require() can find it, instead of returning it at the end. - -- Returning it at the end does the same thing. - -- This is so that we can have all the module stuff at the top, in this function. - -- Should do this before any further require(), so that circular references don't blow out. - - -- Save the callers environment. - local savedEnvironment - if isLua then - savedEnvironment = getfenv(level) - else - -- While the above works fine for test_c, it doesn't for GuiLua. Odd. - savedEnvironment = getfenv(1) - end - - -- Clone the environment into _M, so the module can access everything as usual after the setfenv() below. - --[[ TODO - Check if this also clones _G or _ENV. And see if it leaks stuff in either direction. - local _G = _G -- Only sets a local _G for this function. - _M._G = _G -- This clone loop might do this, but we don't want to be able to access the old _G from outside via this leak. - In Lua 5.1 at least, _G was special. In 5.2, _ENV sorta replaces setfenv(), but no idea if this clone loop stomps on that. - ]] - for k, v in pairs(savedEnvironment) do - _M[k] = v - end - - _M._M = _M -- So that references to _M below the setfenv() actually go to the real _M. - _M._NAME = name - _M._PACKAGE = string.gsub(_M._NAME, "[^.]*$", "") -- Strip the name down to the package name. - _M.isLua = isLua - - -- Parse in an entire copyright message, and strip that down into bits, to put back together. - local date, owner = string.match(copyright, '[Cc]opyright (%d%d%d%d) (.*)') - _M.AUTHOR = author or owner - _M.COPYRIGHT = 'Copyright ' .. date .. ' ' .. _M.AUTHOR - -- Translate the version number into a version string. - local versionName, versionDesc = ' ', '' - for i = 1, #versions / 3 do - if 1 == string.find(version, versions[i]) then - versionName = ' ' .. versions[i + 1] .. ' ' - versionDesc = versions[i + 2] - break - end - end - _M.VERSION = version .. versionName .. timestamp - _M.VERSION_DESC = versionDesc - -- If there is a .skang file, read that in and override the passed in skin. - local f = io.open(name .. '.skang') - if f then - skin = f:read('*l') - if '#' == string.sub(skin, 1, 1) then skin = '' end - skin = skin .. f:read('*a') - f:close() - end - if skin then - skin = "local skang = require 'skang'\nlocal " .. name .. " = require '" .. name .. "'\n" .. skin - if nil == mainSkin._NAME then mainSkin = _M end - end - _M.DEFAULT_SKANG = skin - - --_G[_M._NAME] = _M -- Stuff it into a global of the same name. - -- Not such a good idea to stomp on global name space. - -- It's also redundant coz we get stored in package.loaded[_M._NAME] anyway. - -- This is why module() is broken. - _M.savedEnvironment = savedEnvironment - -- NOTE - setfenv() wont work if the environment it refers to is a C function. Worse, getfenv() returns the global environment, so we can't tell. - if isLua then - -- setfenv() sets the environment for the FUNCTION, stack level deep. - -- The number is the stack level - - -- 0 running thread, 1 current function, 2 function that called this function, etc - setfenv(level, _M) -- Use the result for the modules internal global environment, so they don't need to qualify internal names. - -- Dunno if this causes problems with the do ... end style of joining modules. It does. So we need to restore in moduleEnd(). - -- Next question, does this screw with the environment of the skang module? No it doesn't, coz that's set up at require 'skang' time. - end - - print('Loaded module ' .. _M._NAME .. ' version ' .. _M.VERSION .. ', ' .. _M.COPYRIGHT .. '.\n ' .. _M.VERSION_DESC) - - return _M -end - - ---[[ Parse command line parameters. - -This is done in two parts. Skang will do an initial scan and tokenise, -then each module gets a chance to pull it's own Things from the result. - -Make the command line parameter getting MUCH more intelligent, try to support the common -command line interfaces - - -arg value -a value -/arg value -/a value ---arg value ---a value --a value --ab ('a' and 'b' are both shortcuts.) -arg=value -a=value -arg1=value1&arg2=value2 -arg1=value1|arg2=value2 -a=value1&a=value2 -+arg/-arg (Can't support this generically.) - -Ignore /,-,--,& except as arg introducers. Use = as value introducer. Expect -arg or a. If type is String, expect a value. If type is integer, and next token is -not an integer, increment current value, otherwise expect integer value. If type is -boolean, value beginning with T, t, F, f, etc is true, otherwise value is false, unless -next token starts with an introducer, then value is true. - -TODO - Finish supporting all of the above. - These all need deeper parsing, but we dunno if they might have been inside quoted strings from the shell. - arg=value Shell. - arg1=value1&arg2=value2 For URLs. - arg1=value1|arg2=value2 Can't remember why, probably the old skang multivalue syntax. - Test it all. - Skang command line should have standardish stuff, like --version, --help, --help module.thing. - Lua does these already, might be no need to do them ourselves - - -e 'some code'. - -i go interactive after running the script. - -v version. - - read from stdin non interactively. - LuaJIT also has this - - -- stop processing options. -]] - -ARGS = {} -lua = '' -command = '' - - --- Do an initial scan and tokenise of the command line arguments. -scanArguments = function (args) - if args then - lua = args[-1] - command = args[0] - for i, v in ipairs(args) do - local pre = '' - if '--' == string.sub(v, 1, 2) then pre = '--'; v = string.sub(v, 3, -1) end - if '-' == string.sub(v, 1, 1) then pre = '-'; v = string.sub(v, 2, -1) end - if '+' == string.sub(v, 1, 1) then pre = '+'; v = string.sub(v, 2, -1) end - -- TODO - Make this the opposite of the directory separator for what ever platform we are running on. - -- Which Lua can't figure out I think. - if '/' == string.sub(v, 1, 1) then pre = '/'; v = string.sub(v, 2, -1) end - if '=' == string.sub(v, 1, 1) then pre = '='; v = string.sub(v, 2, -1) end - if '&' == string.sub(v, 1, 1) then pre = '&'; v = string.sub(v, 2, -1) end - if '|' == string.sub(v, 1, 1) then pre = '|'; v = string.sub(v, 2, -1) end - if '' ~= v then ARGS[i] = {pre, v} end - end - end -end - -parseType = function (module, thingy, v, value) - if 'string' == thingy.types[1] then - if value then - module[v[2] ] = value[2] - value[2] = nil -- Mark it as used. - else - print('ERROR - Expected a string value for ' .. thingy.names[1]) - end - end - - if 'number' == thingy.types[1] then - if value then - -- If the introducer is '-', then this should be a negative number. - if '-' == value[1] then value[1] = ''; value[2] = '-' .. value[2] end - -- Only parse the next value as a number if it doesn't have an introducer. - if ('' == value[1]) or ('=' == value[1]) then - value[2] = tonumber(value[2]) - if value[2] then - module[v[2] ] = value[2] - value[2] = nil -- Mark it as used. - else - print('ERROR - Expected a number value for ' .. thingy.names[1]) - end - else - module[v[2] ] = module[v[2] ] + 1 - end - else - print('ERROR - Expected a number value for ' .. thingy.names[1]) - end - end - - if 'function' == thingy.types[1] then - local args = {} - -- TODO - Should allow more than one argument, but would need to pass in ARGS and i. - if 2 == #thingy.types then - if value then - -- TODO - Should check the type of the arguments. - args[#args + 1] = value[2] - module[v[2] ](args[1]) - value[2] = nil -- Mark it as used. - else - print('ERROR - Expected an argument for ' .. thingy.names[1]) - end - else - module[v[2] ]() - end - end - - if 'boolean' == thingy.types[1] then - if value then - -- Only parse the next value as a boolean if it doesn't have an introducer. - if ('' == value[1]) or ('=' == value[1]) then - module[v[2] ] = isBoolean(value[2]) - value[2] = nil -- Mark it as used. - else - module[v[2] ] = true - end - else - print('ERROR - Expected a boolean value for ' .. thingy.names[1]) - end - end -end - -pullArguments = function (module) - -- Look for our command line arguments. - local metaMum = getmetatable(module) - if metaMum and metaMum.__self then - for i, v in ipairs(ARGS) do - if v[2] then - local thingy = metaMum.__self.stuff[v[2] ] - -- Did we find one of ours? - if thingy then - parseType(module, thingy, v, ARGS[i + 1]) - v[2] = nil -- Mark it as used. - else - -- Didn't find one directly, check for single letter matches in '-abc'. - for k, w in pairs(metaMum.__self.stuff) do - if 1 == #w.names[1] then - for j = 1, #v[2] do - if string.sub(v[2], j, 1) == w.names[1] then - if 1 == j then - v[2] = string.sub(v[2], 2, -1) - if 'boolean' == w.types[1] then module[v[2] ] = true end - elseif #v[2] == j then - v[2] = string.sub(v[2], 1, j - 1) - -- The one at the end is the only one that could have a following value. - parseType(module, w, v, ARGS[i + 1]) - else - v[2] = string.sub(v[2], 1, j - 1) .. string.sub(v[2], j + 1, -1) - if 'boolean' == w.types[1] then module[v[2] ] = true end - end - if '' == v[2] then v[2] = nil end -- Mark it as used. - end - end - end - end - end - end - end - end -end - --- Restore the environment, and grab paramateres from standard places. -moduleEnd = function (module) - -- See if there is a properties file, and run it in the modules environment. - local properties, err = loadfile(module._NAME .. '.properties') - if properties then - setfenv(properties, getfenv(2)) - properties() - elseif 'cannot open ' ~= string.sub(err, 1, 12) then - print("ERROR - " .. err) - end - - pullArguments(module) - - -- Run the main skin, which is the first skin that is defined. In theory, the skin from the main module. - if mainSkin == module then - print("RUNNING SKIN FOR " .. module._NAME) - local skin, err = loadstring(module.DEFAULT_SKANG) - if skin then - setfenv(skin, getfenv(2)) - skin() - else - print("ERROR - " .. err) - end - end - - if module.isLua then setfenv(2, module.savedEnvironment) end -end - - --- Call this now so that from now on, this is like any other module. -local _M = moduleBegin('skang', 'David Seikel', 'Copyright 2014 David Seikel', '0.1', '2014-03-27 02:57:00') - --- This works coz LuaJIT automatically loads the jit module. -if type(jit) == 'table' then - print('Skang is being run by ' .. jit.version .. ' under ' .. jit.os .. ' on a ' .. jit.arch) -else - print('Skang is being run by Lua version ' .. _VERSION) -end - -scanArguments(arg) - - -function printTableStart(table, space, name) - print(space .. name .. ": ") - print(space .. "{") - printTable(table, space .. " ") - print(space .. "}") - if '' == space then print('') end -end - -function printTable(table, space) - if nil == table then return end - for k, v in pairs(table) do - if type(v) == "table" then - if v._NAME then - print(space .. "SKANG module " .. v._NAME .. ";") - else - printTableStart(v, space, k) - end - elseif type(v) == "string" then - print(space .. k .. ': "' .. v .. '";') - elseif type(v) == "function" then - print(space .. "function " .. k .. "();") - elseif type(v) == "userdata" then - print(space .. "userdata " .. k .. ";") - elseif type(v) == "boolean" then - if (v) then - print(space .. "boolean " .. k .. " TRUE ;") - else - print(space .. "boolean " .. k .. " FALSE ;") - end - else - print(space .. k .. ": " .. v .. ";") - end - end -end - - -csv2table = function (csv) - local result = {} - local i = 1 - - for v in string.gmatch(csv, ' *([^,]+)') do - result[i] = v - i = i + 1 - end - return result -end - - -shiftLeft = function (tab) - local result = tab[1] - table.remove(tab, 1) - return result -end - - --- My clever boolean check, this is the third language I've written this in. B-) --- true 1 yes ack ok one positive absolutely affirmative 'ah ha' 'shit yeah' 'why not' -local isTrue = 't1aopswy' --- false 0 no nack nope zero negative nah 'no way' 'get real' 'uh uh' 'fuck off' 'bugger off' -local isFalse = 'f0bgnuz' -isBoolean = function (aBoolean) - local result = false - - if type(aBoolean) ~= 'nil' then - -- The default case, presence of a value means it's true. - result = true - if type(aBoolean) == 'boolean' then result = aBoolean - elseif type(aBoolean) == 'function' then result = aBoolean() - elseif type(aBoolean) == 'number' then result = (aBoolean ~= 0) - elseif type(aBoolean) == 'string' then - if '' == aBoolean then - result = false - else - if 1 == string.find(string.lower(aBoolean), '^[' .. isTrue .. ']') then result = true end - if 1 == string.find(string.lower(aBoolean), '^[' .. isFalse .. ']') then result = false end - end - end - end - return result -end - - ---[[ Thing Java package - -matrix-RAD had Thing as the base class of everything. - -Each "users session" (matrix-RAD term that came from Java -applets/servlets) has a ThingSpace, which is a tree that holds -everything else. It holds the class cache, commands, loaded modules, -variables and their values, widgets and their states. In matrix-RAD I -built BonsiaTree and LeafLike, for the old FDO system I built dumbtrees. - -Other Thing things are - - get/set The getter and setter. - number No idea how this was useful. - skang The owning object, a Skang (actually got this, called module for now). - owner The owning object, a String (module._NAME). - clas Class of the Thing, a Class. (pointless) - type Class of the Thing, a String. (pointless) - realType Real Class of the Thing, a String. (pointless) - myRoot ThingSpace we are in, a ThingSpace. - - Also various functions to wrap checking the security, like canDo, canRead, etc. -]] - - ---[[ Stuff Java package - -In matrix-RAD Stuff took care of multi value Things, like database rows. - -Stuff is an abstract class that gets extended by other classes, like -SquealStuff, which was the only thing extending it. It dealt with the -basic "collection of things" stuff. Each individual thing was called a -stufflet. A final fooStuff would extend SquealStuff, and include an -array of strings called "stufflets" that at least named the stufflets, -but could also include metadata and links to other Stuffs. - -There was various infrastructure for reading and writing Stuff, throwing -rows of Stuff into grids, having choices of Stuff, linking stufflets to -individual widgets, having default Stuffs for windows, validating -Stuffs, etc. - -In Lua, setting up stuff has been folded into the general Thing stuff. - -]] - - ---[[ Thing structure - - -In the following, meta(table) is short for getmetatable(table). - -In Lua everything is supposed to be a first class value, and variables are just places to store values. -All variables are in fact stored in tables, even if it's just the local environment table. -Any variable that has a value of nil, doesn't actually exist. That's the definition. -While non table things can have metatables, Lua can only set metatables on tables, C has no such restriction. -meta(table).__index and __newindex only work on table entries that don't exist. - __index(table, key) is called if table.key is nil. - Though if __index is a table, then try __index[key]. - __newindex(table, key, value) is called if table.key is nil. - Though if __newindex is a table, then try __newindex[key] = value. -Using both __index and __newindex, and keeping the actual values elsewhere, is called a proxy table. -meta(table).__call(table, ...) is called when trying to access table as a function - table(...). - -It's worth repeating - -All variables in Lua are in some table somewhere, even if it's just the global environment table. -Metatables are only associated vith values, not variables. -Lua can only attach metatables to values that are tables, but C can attach metatables to any value. - - -A Thing is a managed variable stored in a parent proxy table, which is usually empty. -So the values stored in this Thing are actually stored in meta(parent)__values[thing]. - parent[thing] -> __index (parent, thing) -> meta(parent).__values[thing] - parent[thing] = value -> __newindex(parent, thing, value) -> meta(parent).__values[thing] = value - - -Each Thing has a description table that includes - - names - An array of names, the first one is the "official" name. - types - An array of types, the first one is the "official" type. - help - A descriptive text for humans to read. - default - The default value. - widget - A default widget definition. - required - If the Thing is required. - isValid - A function that tests if the Thing is valid. - errors - Any errors related to the Thing. - isKeyed - Is this a parent for Things that are stored under an arbitrary key. - stuff - An array of descriptions for sub Things, so Things that are tables can have their own Things. - and other things that aren't actually used yet. -All things that a description doesn't have should be inherited from the Thing table. - setmetatable(aStuff, {__index = Thing}) -Descriptions should be able to be easily shared by various Things. - - -A parent's metatable has __self, which is it's own description. -A parent is free to use it's own name space for anything it wants. -Only the variables it specifies as managed Things are dealt with here. - - -Things that are tables are treated differently, in two different ways even. -Ordinary table Things are basically treated recursively, the table is a parent, and it gets it's own Things. -There is also 'Keyed' type table Things, where the keys to this table are arbitrary, but we still want to store Things in it. -In this case, when a table is assigned to this Keyed Thing, via a new key, a new table Thing is created by copying the parent Thing description. - - -TODO - - test.foo -> test.__index(test, 'foo') -> test.__values[foo]; if that's nil, and test.stuff[foo], then return an empty table instead? - Do we still need a parent pointer? - Should be in __values I guess. - __values[key].value - __values[key].parent - Weak references might help in here somewhere. - Maybe try looking in the skang table for Things that are not found? - Maybe put Things in the skang table that are unique from modules? - I think this is what matrix-RAD Collisions was all about. -]] - --- There is no ThingSpace, or Stuff, now it's all just in this meta table. -local Thing = -{ --- Default Thing values. - names = {'unknown'}, - help = 'No description supplied.', -- help text describing this Thing. - default = '', -- The default value. This could be a funcion, making this a command. - types = {}, -- A list of types. The first is the type of the Thing itself, the rest are for multi value Things. Or argument types for commands. - required = false, -- Is this thing is required. TODO - Maybe fold this into types somehow, or acl? - widget = '', -- Default widget command arguments for creating this Thing as a widget. --- acl = '', -- Access Control List defining security restrains. --- boss = '', -- The Thing or person that owns this Thing, otherwise it is self owned. - - action = 'nada', -- An optional action to perform. - tell = '', -- The skang command that created this Thing. - pattern = '.*', -- A pattern to restrict values. - - isKeyed = false, -- Is this thing an arbitrarily Keyed table? - isReadOnly = false, -- Is this Thing read only? - isServer = false, -- Is this Thing server side? - isStub = false, -- Is this Thing a stub? - isStubbed = false, -- Is this Thing stubbed elsewhere? - - hasCrashed = 0, -- How many times this Thing has crashed. - - append = function (self,data) -- Append to the value of this Thing. - end, - - stuff = {}, -- The sub things this Thing has, for modules, tables, and Keyed tables. - errors = {}, -- A list of errors returned by isValid(). - - isValid = function (self, parent) -- Check if this Thing is valid, return resulting error messages in errors. - -- Anything that overrides this method, should call this super method first. - local name = self.names[1] - local metaMum = getmetatable(parent) - local value = metaMum.__values[name] - local mum = metaMum.__self.names[1] - - local t = type(value) or 'nil' - self.errors = {} - -- TODO - Naturally there should be formatting functions for stuffing Thing stuff into strings, and overridable output functions. - if 'nil' == t then - if self.required then table.insert(self.errors, mum .. '.' .. name .. ' is required!') end - else - if 'widget' == self.types[1] then - -- TODO - Should validate any attached Thing. - elseif self.types[1] ~= t then table.insert(self.errors, mum .. '.' .. name .. ' should be a ' .. self.types[1] .. ', but it is a ' .. t .. '!') - else - if 'number' == t then value = '' .. value end - if ('number' == t) or ('string' == t) then - if 1 ~= string.find(value, '^' .. self.pattern .. '$') then table.insert(self.errors, mum .. '.' .. name .. ' does not match pattern "' .. self.pattern .. '"!') end - end - end - end - - for k, v in pairs(self.stuff) do - if not v:isValid(value) then - for i, w in ipairs(v.errors) do - table.insert(self.errors, w) - end - end - end - - return #(self.errors) == 0 - end, - - remove = function (self) -- Delete this Thing. - end, -} - - -getStuffed = function (parent, key) - local metaMum = getmetatable(parent) - local thingy - - if metaMum and metaMum.__self then - thingy = metaMum.__self.stuff[key] - - if not thingy then - -- Deal with getting a table entry. - if metaMum.__values[key] then - thingy = getmetatable(metaMum.__values[key]).__self - end - end - end - return metaMum, thingy -end - -local Mum = -{ - -__index = function (parent, key) - -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. - - -- First see if this is a Thing. - local metaMum, thingy = getStuffed(parent, key) - - if thingy then - return metaMum.__values[thingy.names[1] ] or thingy.default - end - - -- Then see if we can inherit it from Thing. - return Thing[key] -end, - -__newindex = function (parent, key, value) - -- This only works for keys that don't exist. By definition a value of nil means it doesn't exist. - - -- First see if this is a Thing. - local metaMum, thingy = getStuffed(parent, key) - - if not thingy then - if metaMum.__self.isKeyed then - -- Deal with setting a new Keyed table entry. - local newThing = copy(parent, key) - local newSelf = getmetatable(newThing).__self - rawset(metaMum.__values, key, newThing) - thingy = {} - for k, v in pairs(newSelf) do - thingy[k] = v - end - thingy.names={key} - thingy.types={'table'} - setmetatable(thingy, {__index = Thing}) -- To pick up isValid, pattern, and the other stuff by default. - end - end - - if thingy then - local name = thingy.names[1] - local oldMum - - if 'table' == type(value) then - -- Coz setting it via metaMum screws with the __index stuff somehow. - local oldValue = metaMum.__values[name] - if 'table' == type(oldValue) then - oldMum = getmetatable(oldValue) - if oldMum then - -- TODO - This SHOULD work, but doesn't - - --setmetatable(value, oldMum) - -- Instead we do this - - -- Clear out any values in the old table. - for k, v in pairs(oldMum.__values) do - oldMum.__values[k] = nil - end - for k, v in pairs(value) do - local newK = oldMum.__self.stuff[k] - if newK then newK = newK.names[1] else newK = k end - oldMum.__values[newK] = v - end - end - end - end - if nil == oldMum then metaMum.__values[name] = value end - -- NOTE - invalid values are still stored, this is by design. - if not thingy:isValid(parent) then - for i, v in ipairs(thingy.errors) do - print('ERROR - ' .. v) - end - end - -- TODO - Go through it's linked things and set them to. - -- Done, don't fall through to the rawset() - return - end - - rawset(parent, key, value) -- Stuff it normally. -end, - -__call = function (func, ...) - return thingasm(func, ...) -end, - -} - -newMum = function () - local result = {} ---[[ From an email by Mike Pall - -"Important: create the metatable and its metamethods once and reuse -the _same_ metatable for _every_ instance." - -This is for LuaJIT, he's the author, and concerns performance. - -TODO - Which is the exact opposite of what we are doing. Perhaps we can fix that? -]] - for k, v in pairs(Mum) do - result[k] = v - end - result.__self = {stuff={}} - result.__values = {} - return result -end - - --- skang.thingasm() Creates a new Thing, or changes an existing one. ---[[ It can be called in many different ways - - -It can be called with positional arguments - (names, help, default, types, widget, required, acl, boss) -Or it can be called with a table - {names, help, pattern='.*', acl='rwx'} - -The first argument can be another Thing (the parent), or a string list of names (see below). - -It can be called by itself, with no parent specified - - thingasm('foo', 'help text) -In this case the surrounding Lua environment becomes the parent of foo. - If the first argument (or first in the table) is a string, then it's this form. -All others include the parent as the first argument, which would be a table. - -It can be called by calling the parent as a function - - foo('bar', 'some help', types='table') -- ___call(foo, 'bar', ...) And now foo is the parent. - foo.bar{'baz', types='Keyed'} -- thingasm({foo.bar, 'baz', ...}) - foo.bar.baz{'field0'} -- thingasm({foo.bar.baz, 'field0'}) - foo.bar.baz{'field1'} -]] - --- names - a comma seperated list of names, aliases, and shortcuts. The first one is the official name. --- If this is not a new thing, then only the first one is used to look it up. --- So to change names, use skang.thingasm{'oldName', names='newName,otherNewName'} -thingasm = function (names, ...) - local params = {...} - local new = false - local parent - local set = true - - -- Check how we were called, and re arrange stuff to match. - if 0 == #params then - if ('table' == type(names)) then -- thingasm{...} - params = names - names = shiftLeft(params) - if 'table' == type(names) then -- thingasm{parent, 'foo', ...} - parent = names - names = shiftLeft(params) - end - end -- thingasm("foo") otherwise - else - if 'table' == type(names) then - parent = names - if 'string' == type(...) then params = {...} -- C or __call(table, string, ..) - elseif 'table' == type(...) then params = ... -- __call(table, table) - end - names = shiftLeft(params) - end -- thingasm('foo', ...) otherwise - end - - -- Break out the names. - names = csv2table(names) - local name = names[1] - local oldNames = {} - - -- TODO - Double check this comment - No need to bitch and return if no names, this will crash for us. - - -- Grab the environment of the calling function if no parent was passed in. - parent = parent or getfenv(2) - local metaMum = getmetatable(parent) - -- Coz at module creation time, Thing is an empty table, or in case this is for a new parent. - if nil == metaMum then - metaMum = newMum() - metaMum.__self.names = {parent._NAME or 'NoName'} - if parent._NAME then metaMum.__self.types = {'Module'} end - setmetatable(parent, metaMum) - end - - local thingy = metaMum.__self.stuff[name] - if not thingy then -- This is a new Thing. - new = true - thingy = {} - thingy.names = names - thingy.stuff = {} - setmetatable(thingy, {__index = Thing}) -- To pick up isValid, pattern, and the other stuff by default. - end - - -- Pull out positional arguments. - thingy.help = params[1] or thingy.help - thingy.default = params[2] or thingy.default - local types = params[3] or table.concat(thingy.types or {}, ',') - - -- Pull out named arguments. - for k, v in pairs(params) do - if 'string' == type(k) then - if 'types' == k then types = v - elseif 'names' == k then - oldNames = thingy.names - thingy.names = cvs2table(v) - elseif 'required' == k then - if isBoolean(v) then thingy.required = true end - else thingy[k] = v - end - end - end - - -- Find type, default to string, then break out the other types. - local typ = type(thingy.default) - if 'nil' == typ then typ = 'string' end - if 'function' == typ then types = typ .. ',' .. types end - if '' == types then types = typ end - thingy.types = csv2table(types) - - if 'widget' == thingy.types[1] then - set = false - local args, err = loadstring('return ' .. thingy.widget) - if args then - setfenv(args, parent) - thingy.Cwidget = widget(args()) -print('\nNO IDEA WHY this does isValid() three times on the action, and the first one being a string.') - parent.W[name] = thingy - else - print("ERROR - " .. err) - end - end - - -- Deal with Keyed and tables. - if 'Keyed' == thingy.types[1] then - set = false - thingy.types[1] = 'table' - thingy.isKeyed = true - end - if 'table' == thingy.types[1] then - -- Default in this case becomes a parent. - if '' == thingy.default then thingy.default = {} end - local thisMum = newMum() - thisMum.__self = thingy - setmetatable(thingy.default, thisMum) - end - - if 'userdata' == thingy.types[1] then - set = false - end - - -- Remove old names, then stash the Thing under all of it's new names. - for i, v in ipairs(oldNames) do - metaMum.__self.stuff[v] = nil - end - for i, v in ipairs(thingy.names) do - metaMum.__self.stuff[v] = thingy - end - - -- This triggers the Mum.__newindex metamethod above. If nothing else, it triggers thingy.isValid() - if new and set then parent[name] = thingy.default end -end - - -fixNames = function (module, name) - local stuff = getmetatable(module) - if stuff then - stuff.__self.names[1] = name - for k, v in pairs(stuff.__self.stuff) do - if 'table' == v.types[1] then - local name = v.names[1] - print(name .. ' -> ' .. name) - fixNames(stuff.__values[name], name) - end - end - end -end - - -copy = function (parent, name) - local result = {} - local stuff = getmetatable(parent).__self.stuff - - for k, v in pairs(stuff) do - local temp = {} - for l, w in pairs(v) do - temp[l] = w - end - temp[1] = table.concat(temp.names, ',') - temp.names = nil - temp.types = table.concat(temp.types, ',') - temp.errors = nil - thingasm(result, temp) - end - getmetatable(result).__self.names = {name} - --- TODO - Should we copy values to? - - return result -end - -module = function (name) - _G[name] = require(name) - return _G[name] -end - -stuff = function (aThingy, aStuff) - return getmetatable(aThingy).__self.stuff[aStuff] -end - - -get = function (stuff, key, name) - local result - if name then - local thingy = getmetatable(stuff) - if thingy then - local this = thingy.__self.stuff[key] - if this then result = this[name] end - end - else - result = stuff[key] - end - return result -end - - -reset = function (stuff, key, name) - if name then - local thingy = getmetatable(stuff) - if thingy then - local this = thingy.__self.stuff[key] - if this then this[name] = nil end - end - else - stuff[key] = nil - end -end - - -set = function (stuff, key, name, value) - if 'nil' ~= type(value) then - local thingy = getmetatable(stuff) - if thingy then - local this = thingy.__self.stuff[key] - if this then this[name] = value end - end - else - -- In this case, value isn't there, so we are reusing the third argument as the value. - stuff[key] = name - end -end - - --- Get our C functions installed into skang. --- This has to be after thingasm is defined. -package.cpath = package.cpath .. ';../../libraries/lib?.so' -local GuiLua = require 'GuiLua' - - -thingasm('module,l', 'Load a module.', module, 'file') -thingasm('get', 'Get the current value of an existing Thing or metadata.', get, 'thing,key,name') -thingasm('reset', 'Reset the current value of an existing Thing or metadata.', reset, 'thing,key,name') -thingasm('set', 'Set the current value of an existing Thing or metadata.', set, 'thing,key,name,data') - -thingasm('nada', 'Do nothing.', function () --[[ This function intentionally left blank. ]] end) - - - --- Widget wrappers. --- TODO - Fix this up so we don't need .W -local widgets = {} ---thingasm{widgets, 'window', 'The window.', types='userdata'} -thingasm{widgets, 'W', 'Holds all the widgets', types='Keyed'} -widgets.W{'Cwidget', 'The widget.', types='userdata'} -widgets.W{'action,a', 'The action for the widget.', 'nada', types='string'} -local aIsValid = function (self, parent) - local result = Thing.isValid(self, parent) - - if result then - local value = parent[self.names[1] ] -print('NEW ACTION - ' .. self.names[1] .. ' = ' .. value .. ' ' .. type(parent.Cwidget)) - action(parent.Cwidget, value) - end - return result -end - -widgets.W{'look,l', 'The look of the widget.', types='string'} ---[[ -widgets.W{'colour,color,c', 'The colours of the widget.', types='table'} -widgets.W.c{'red,r', 'The red colour of the widget.', 255, types='number'} -widgets.W.c{'green,g', 'The green colour of the widget.', 255, types='number'} -widgets.W.c{'blue,b', 'The blue colour of the widget.', 255, types='number'} -widgets.W.c{'alpha,a', 'The alpha colour of the widget.', 255, types='number'} --- At this point we want to change widgets.W.c() to go to a different __call, coz right now it's going to the Mum.__call, which wraps thingasm. --- TODO - Keep an eye on this if we change to a single Mum, instead of the shallow copy we use now. -local wMum = getmetatable(widgets.W.c) -wMum.__call = function (func, ...) - return Colour(func, ...) -end -]] - -window = function(w, h, title, name) - name = name or 'myWindow' - local win = {} - win = copy(widgets, name) - local wMum, wThingy = getStuffed(win.W, 'a') - wThingy.isValid = aIsValid - win.window = Cwindow(w, h, title, name) - return win -end - -thingasm{'window', 'Specifies the size and title of the application Frame.', window, 'number,number,string', acl="GGG"} - - --- TODO - Some function stubs, for now. Fill them up later. -skang = function (name) -end - -thingasm('skang', 'Parse the contents of a skang file or URL.', skang, 'URL') - - -moduleEnd(_M) - -end - --- Boss is the person that owns a Thing. - ---[[ The original Skang parameters and commands. - public final static String MY_USAGE[][] = - { - {"skinURL", "skinURL", "Y", "s", null, "URL of skin file.", "", "RI-"}, - {"debug", "debug", "N", "", "0", "Set debugging level to :\n\t-1 - errors and warnings only (-q)\n\t0 - basic information\n\t1 - advanced information (-v)\n\t2 - trace functions\n\t3 - trace protocol\n\t4 - dump packets + stuff\n\t5 - detail", "", ""}, - {"browser", "browser", "N", "", "mozilla %f", "Browser to run.", "", ""}, - {"downloaddir", "downloadDir", "N", "", "download", "Download directory.", "", ""}, - {"sessionID", "sessionID", "N", "", null, "SessionID from servlet.", "", ""}, - {"JSESSIONID", "JSESSIONID", "N", "", null, "JSESSIONID from servlet engine.", "", ""}, - {"servletpath", "servletPath", "N", "", "matrix_rad", "Servlet path.", "", ""}, - {"servletport", "servletPort", "N", "", null, "Servlet port.", "", ""}, - {"servletsslport", "servletSSLPort", "N", "", null, "Servlet SSL port.", "", ""}, - {"HTML", "HTML", "N", "", "false", "Output to HTML?", "", ""}, - {"PHP", "PHP", "N", "", "false", "Output though the PHP wrapper", "", ""}, - {"inbrowser", "inBrowser", "N", "", "true", "Run in browser window?", "", ""}, - {"SSL", "SSL", "N", "", null, "Dummy to avoid a web server bug.", "", ""}, - {"NOSSL", "NOSSL", "N", "", null, "Dummy to avoid a web server bug.", "", ""}, - {"corporate", "corporate", "N", "", null, "Are we doing corporate shit?", "", ""}, - {"", "", "", "", "", "", "", ""} - }; - public final static String MY_SKANG[][] = - { --- {"module", "addModule", "file,data", "Load a module.", "", ""}, - {"append", "appendThing", "name,data", "Append to the current value of a Thing.", "", ""}, - {"#!java", "bash", "name,name,name,name,name,name,name", "A not so clever unix script compatability hack.", "", ""}, - {"pending", "pendingDoThing", "action", "Do an action when you are ready.", "", ""}, - {"applet", "doIfApplet", "action", "Only do this if we are an applet.", "", ""}, - {"application", "doIfApplication", "action", "Only do this if we are an application.", "", ""}, - {"corporateshit", "doIfCorporateShit", "action", "Only do this if we are doing corporate shit.", "", ""}, - {"realworld", "doIfRealWorld", "action", "Only do this if we are in the real world.", "", ""}, - {"servlet", "doIfServlet", "action", "Only do this if we are a servlet.", "", ""}, - {"do", "doThing", "action", "Do this action.", "", ""}, - {"grab", "getFile", "URL", "Grab a file from a URL.", "", ""}, --- {"get", "getThing", "name", "Get the current value of an existing thing.", "", ""}, - {"gimmeskin", "gimmeSkin", "", "Returns the modules default skin.", "", ""}, - {"help", "helpThing", "file", "Show help page.", "", ""}, --- {"nada", "nothing", "data", "Does nothing B-).", "", ""}, - {"postshow", "postShowThings", "URL,name", "POST the values of all Things to the URL, show the returned content.", "", ""}, - {"post", "postThings", "URL", "POST the values of all Things to the URL, return the content.", "", ""}, - {"postparse", "postParseThings", "URL", "POST the values of all Things to the URL, parse the returned content.", "", ""}, - {"quiet", "quiet", "", "Output errors and warnings only.", "", ""}, - {"remove", "removeThing", "name", "Remove an existing thing.", "", ""}, - {"sethelp", "setHelp", "name,data", "Change the help for something.", "", ""}, --- {"set", "setThing", "name,data", "Set the current value of an existing Thing.", "", ""}, --- {"skang", "skangRead", "URL", "Parse the contents of a skang file or URL.", "", ""}, --- {"quit", "startQuit", "", "Quit, exit, remove thyself.", "", ""}, - {"stopwhinging", "stopWhinging", "", "Clear all messages.", "", ""}, - {"tell", "tellThing", "name", "Returns details of an existing Thing.", "", ""}, - {"togglebug", "toggleIgnoreBrowserBug", "", "Toggle ignorance of a certain browser bug.", "", ""}, - {"verbose", "verbose", "", "Output advanced information.", "", ""}, - {"", "", "", "", "", ""} -]] - ---[[ The original SkangAWT parameters and commands. - public final static String MY_USAGE[][] = - { - {"", "", "", "", "", "", "", ""} - }; - public final static String MY_SKANG[][] = - { - {"taction", "tactionWidget", "name,action", "Set the alternative action for a widget.", "", ""}, - {"action", "actionWidget", "name,action", "Set the action for a widget.", "", ""}, - {"pane", "addPane", "name,x,y,w,h,data", "Add a pane to the current module.", "", ""}, - {"widget", "addWidget", "name,type,lx,ly,lw,lh,data,data", "Add a widget to the current skin.", "", ""}, - {"checkboxgroup", "checkBoxGroup", "number", "Make the next 'number' Checkboxes part of a check box group.", "", ""}, --- {"clear", "clearWidgets", "", "The current skin is cleared of all widgets.", "", ""}, - {"colour", "colourWidget", "name,r,g,b,alpha,r,g,b,alpha", "Set widget's background and foreground colour.", "", "GGG"}, - {"doaction", "doWidget", "name", "Do a widgets action.", "", "GGG"}, - {"disable", "disableWidget", "name", "Disable a widget.", "", "GGG"}, - {"enable", "enableWidget", "name", "Enable a widget.", "", "GGG"}, - {"hide", "hideWidget", "name", "Hide a widget.", "", "GGG"}, - {"hideall", "hideAllWidgets", "name,lx,ly,lw,lh", "Hide all widgets.", "", "GGG"}, - {"look", "lookWidget", "name,normal,ghost,active,toggle", "Set the current look of an existing widget.", "", "GGG"}, - {"mask", "maskWidget", "name,data", "Set the mask for a widget.", "", ""}, - {"onmouse", "onMouse", "name,data", "Do something on mouse hover.", "", ""}, - {"offmouse", "offMouse", "name,data", "Do something off mouse hover.", "", ""}, - {"popup", "popupWidget", "name,data,data,data,data", "Create a popup.", "", "GGG"}, - {"readonly", "readOnlyWidget", "name", "Make a widget read only.", "", "GGG"}, - {"writeonly", "writeOnlyWidget", "name", "Make a widget write only.", "", "GGG"}, - {"satori", "satori", "x,y", "Give me the developers menu.", "", "GGG"}, - {"showloginwindow", "showLoginWindow", "", "Show user login window.", "", "GGG"}, - {"show", "showWidget", "name", "Show a widget.", "", "GGG"}, --- {"window", "setSkangFrame", "x,y,name", "Specifies the size and title of the application Frame.", "", "GGG"}, - {"stuff", "stuffWidget", "name,data", "Set the stuff for a widget's pane.", "", ""}, - {"stufflet", "stuffWidget", "name,data,data", "Set the stufflet for a widget.", "", ""}, - {"stufflist", "stuffListWidget", "name,data", "List the stuff in this widget.", "", ""}, - {"stuffload", "stuffLoadWidget", "name,data,data", "Load the stuff for a widget.", "", ""}, - {"stuffsave", "stuffSaveWidget", "name,data,data", "Save the stuff for a widget.", "", ""}, - {"stuffdelete", "stuffDeleteWidget", "name,data,data", "Delete the stuff for a widget.", "", "SSS"}, - {"stuffclear", "stuffClearWidget", "name,data", "Clear the stuff for a widget.", "", "SSS"}, - {"rowtowidgets", "rowToWidgets", "name", "Copy Grid row to matching widgets.", "", ""}, - {"widgetstorow", "widgetsToRow", "name,data", "Copy matching widgets to Grid row.", "", ""}, - {"clearrow", "clearRow", "name", "Clear Grid row and matching widgets.", "", ""}, - {"clearrowwidgets", "clearRowWidgets", "name", "Clear only the Grid row matching widgets.", "", ""}, - {"", "", "", "", "", ""} - }; -]] - - ---[[ security package - -Java skang could run as a stand alone applicion, as an applet in a web -page, or as a servlet on a web server. This was pretty much all -transparent to the user. The security system reflected that. Lua skang -wont run in web pages, but can still have client / server behaviour. -The general idea was, and still is, that the GUI is the client side (in -web page, in extantz GUI) that sends values back to the server side -(servlet, actual Lua package running as a separate process, or the world -server for in world scripts). Client side can request that server side -runs commands. Serevr side can send values and commands back to the -client. Mostly it all happenes automatically through the ACLs. - -Bouncer is the Java skang security manager, it extended the Java -SecurityManager. Lua has no such thing, though C code running stuff in -a sandbox does a similar job. Fascist is the Java security supervisor, -again should go into the C sandbox. - -Human is used for authenticating a human, Puter for authenticating a -computer, Suits for corporate style authentication, and they all -extended Who, the base authentication module. - -For now, I have no idea how this all translates into Lua, but putting -this here for a reminder to think about security during the design -stage. - - -This is the old Java ACL definition - - acl - access control list. -Owner is usually the person running the Thingspace. -RWX~,---,Rwxgroup1,r--group2,r-xgroup3,rw-group4,--X~user1 -rwx~ is for the owner. The second one is the default. The rest are per group or per user. -Capital letters mean that they get access from the network to. ---- No access at all. -RWX Full access. -R-- Read only access. -r-x Read and execute, but only locally. -rw- Read and write a field, but don't execute a method. --w- A password. --a- An append only log file. --A- An append only log file on the server. -Ri- read, but only set from init (ei. skinURL not set from properties or skang files). -RI- As above, but applet.init() can set it too. ---x Thing is both method and field, only execution of the method is allowed. ---p Run as owner (Pretend). ---P Run across the network as owner (can run in applet triggered by server). -s-- Read only, but not even visible to applets. -sss Only visible to servlets and applications. ---S Send to servlet to execute if applet, otherwise execute normally. -S-- Read only, but ignore local version and get it from server. -ggg GUI Thing, only visible to Applets and applications. -GGG GUI Thing, but servlets can access them across the net. - -For servlet only modules from an applet, the applet only loads the skanglet class, using it for all -access to the module. - - -Lua Security best practices - - - From an email by Mike Pall - - -"The only reasonably safe way to run untrusted/malicious Lua scripts is -to sandbox it at the process level. Everything else has far too many -loopholes." - -http://lua-users.org/lists/lua-l/2011-02/msg01595.html -http://lua-users.org/lists/lua-l/2011-02/msg01609.html -http://lua-users.org/lists/lua-l/2011-02/msg01097.html -http://lua-users.org/lists/lua-l/2011-02/msg01106.html - -So that's processes, not threads like LuaProc does. B-( - -However, security in depth is good, so still worthwhile looking at it from other levels as well. - -General solution is to create a new environment, which we are doing -anyway, then whitelist the safe stuff into it, instead of blacklisting -unsafe stuff. Coz you never know if new unsafe stuff might exist. - -Different between 5.1 (setfenv) and 5.2 (_ENV) - -http://lua-users.org/wiki/SandBoxes - - ------------------------------------------------------- --- make environment -local env = -- add functions you know are safe here -{ - ipairs = ipairs, - next = next, - pairs = pairs, - pcall = pcall, - tonumber = tonumber, - tostring = tostring, - type = type, - unpack = unpack, - coroutine = { create = coroutine.create, resume = coroutine.resume, - running = coroutine.running, status = coroutine.status, - wrap = coroutine.wrap }, - string = { byte = string.byte, char = string.char, find = string.find, - format = string.format, gmatch = string.gmatch, gsub = string.gsub, - len = string.len, lower = string.lower, match = string.match, - rep = string.rep, reverse = string.reverse, sub = string.sub, - upper = string.upper }, - table = { insert = table.insert, maxn = table.maxn, remove = table.remove, - sort = table.sort }, - math = { abs = math.abs, acos = math.acos, asin = math.asin, - atan = math.atan, atan2 = math.atan2, ceil = math.ceil, cos = math.cos, - cosh = math.cosh, deg = math.deg, exp = math.exp, floor = math.floor, - fmod = math.fmod, frexp = math.frexp, huge = math.huge, - ldexp = math.ldexp, log = math.log, log10 = math.log10, max = math.max, - min = math.min, modf = math.modf, pi = math.pi, pow = math.pow, - rad = math.rad, random = math.random, sin = math.sin, sinh = math.sinh, - sqrt = math.sqrt, tan = math.tan, tanh = math.tanh }, - os = { clock = os.clock, difftime = os.difftime, time = os.time }, -} - --- run code under environment [Lua 5.1] -local function run(untrusted_code) - if untrusted_code:byte(1) == 27 then return nil, "binary bytecode prohibited" end - local untrusted_function, message = loadstring(untrusted_code) - if not untrusted_function then return nil, message end - setfenv(untrusted_function, env) - return pcall(untrusted_function) -end - --- run code under environment [Lua 5.2] -local function run(untrusted_code) - local untrusted_function, message = load(untrusted_code, nil, 't', env) - if not untrusted_function then return nil, message end - return pcall(untrusted_function) -end ------------------------------------------------------- - -Also includes a table of safe / unsafe stuff. - - -While whitelisting stuff, could also wrap unsafe stuff to make them more safe. - -print() -> should reroute to our output widgets. -rawget/set() -> don't bypass the metatables, but gets tricky and recursive. -require -> don't allow bypassing the sandbox to get access to restricted modules -package.loaded -> ditto - - -Other things to do - - -debug.sethook() can be used to call a hook every X lines, which can help with endless loops and such. -Have a custom memory allocater, like edje_lua2 does. - ------------------------------------------------------- ------------------------------------------------------- - -The plan - - - Process level - - Have a Lua script runner C program / library. - It does the LuaProc thing, and the edje_lua2 memory allocater thing. - Other code feeds scripts to it via a pipe. - Unless they are using this as a library. - It can be chrooted, ulimited, LXC containered, etc. - It has an internal watchdog thread. - The truly paranoid can have a watchdog timer process watch it. - Watches for a "new Lua state pulled off the queue" signal. - This could be done from the App that spawned it. - - It runs a bunch of worker threads, with a queue of ready Lua states. - Each Lua state being run has lua_sethook() set to run each X lines, AND a watchdog timer set. - If either is hit, then the Lua state is put back on the queue. - (Currently LuaProc states go back an the queue when waiting for a "channel message", which does a lua_yeild().) - NOTE - apparently "compiled code" bypasses hooks, though there's an undocumented LuaJIT compile switch for that. http://lua-users.org/lists/lua-l/2011-02/msg01106.html - EFL is event based. - LSL is event based. - LuaSL is event based. - Java skang is event based, with anything that has long running stuff overriding runBit(). - Coz Java AWT is event based, the "events" are over ridden methods in each widget class. - Should all work if we keep this as event based. - An "event" is a bit of Lua script in a string, at Input trust level usually. - Configurable for this script runner is - - IP address & port, or pipe name. - Security level to run at, defaults to Network. - Number of worker threads, defaults to number of CPUs. - Memory limit per Lua state. - Lines & time per tick for Lua states. - - Different levels of script trust - - System - the local skang and similar stuff. - -> No security at all. - App - Lua scripts and C from the running application. - -> Current module level security. - Each has it's own environment, with no cross environment leakage. - Runs in the Apps process, though that might be the script runner as a library. - Or could be skang's main loop. - Local - Lua scripts and skang files sent from the client apps running on the same system. - -> As per App. - Runs in a script runner, maybe? Or just the Apps script runner. - Limit OS and file stuff, the client app can do those itself. - Network - Lua scripts and skang files sent from the network. - -> Runs in a script runner. - Option to chroot it, ulimit it, etc. - Heavily Lua sandboxed via environment. - It can access nails, but via network derived credentials. - Can have very limited local storage, not direct file access though, but via some sort of security layer. - Can have network access. - Can have GUI access, but only to it's own window. - Config - Lua scripts run as configuration files. - -> Almost empty local environment, can really only do math and set Things. - Input - Lua scripts run as a result of hitting skang widgets on the other end of a socket. - -> As per Config, but can include function calls. - Also would need sanitizing, as this can come from the network. - Microsoft - Not to be trusted at all. - Apple - Don't expect them to trust us. - - NOTE - edje_lua2 would be roughly Local trust level. - - So we need to be able to pass Lua between processes - - Have to be able to do it from C, from Lua, and from Lua embedded in C. - edje_lua2 - uses Edje messages / signals. - LuaSL - uses Ecore_Con, in this case a TCP port, even though it's only local. - LuaSL mainloop for it's scripts is to basically wait for these messages from LuaProc. - Which yield's until we get one. - Eventually gets Lua code as a string -> loadstring() -> setfenv() -> pcall() - The pcall returns a string that we send back as a LuaProc message. - Extantz - we want to use stdin/stdout for the pipe, but otherwise LuaSL style semantics. - - Hmm, Extantz could run external skang modules in two ways - - Run the module as a separate app, with stdin/stdout. - Require the module, and run it internally. - Stuff like the in world editor and radar would be better as module, since they are useless outside Extantz? - Radar is useless outside Extantz, editor could be used to edit a local file. - Stuff like woMan would be better off as a separate application, so it can start and stop extantz. - -]] - - ---[[ -The main loop. - A Lua skang module is basically a table, with skang managed fields. - Once it calls moduleEnd(), it's expected to have finished. - test.lua is currently an exception, it runs test stuff afterwards. - So their code just registers Things and local variables. - Some of those Things might be functions for manipulating internal module state. - A C module has it's variables managed outside of it by Lua. - So would have to go via LUA_GLOBALSINDEX to get to them. - Unless they are userdata, which are C things anyway. - Though it's functions are obviously inside the C module. - Normal Lua module semantics expect them to return to the require call after setting themselves up. - So test.lua is really an aberation. - - Soooo, where does the main loop go? - The skang module itself could define the main loop. - Should not actually call it though, coz skang is itself a module. - - In Java we had different entry points depending on how it was called. - If it was called as an applet or application, it got it's own thread with a mainloop. - That main loop just slept and called runBit() on all registered modules. - If it was loaded as a module, it bypassed that stuff. - I don't think Lua provides any such mechanism. - In theory, the first call to moduleBegin would be the one that was started as an application. - So we could capture that, and test against it in moduleEnd to find when THAT module finally got to the end. - THEN we can start the main loop (test.lua being the exception that fucks this up). - Though test.lua could include a runBits() that quits the main loop, then starts the main loop at the very end once more? - The problem with this is applications that require skang type modules. - The first one they require() isn't going to return. - Eventually skang itself will get loaded. It looks at the "arg" global, which SHOULD be the command line. - Including the name of the application, which we could use to double check. - Extantz / script runner would set this arg global itself. - - Skang applications have one main loop per app. - Skang modules use the main loop of what ever app called them. - Non skang apps have the option of calling skangs main loop. - Extantz starts many external skang apps, which each get their own main loop. - Extantz has it's own Ecore main loop. - LuaSL still has one main loop per script. - LSL scripts get their own main loop, but LSL is stupid and doesn't have any real "module" type stuff. - -What does skang main loop actually do? - In Java it just slept for a bit, then called runBit() from each module, and the only module that had one was watch. - Actually better off using Ecore timers for that sort of thing. - Skang main loop has nothing to do? lol - Well, except for the "wait for LuaProc channel messages" thing. - Widget main loop would be Ecore's main loop. - - Extantz loads a skang module. - Module runs in extantz script runner. - Module runs luaproc message main loop from skang. - Evas / Elm widgets send signals, call C callbacks. - Extantz sends Lua input scripts via luaproc messages to module. - Extantz runs separate skang module. - Module runs in it's own process. - Module runs it's own message loop on the end of stdin. - Evas / Elm widgets send signals, call C callbacks. - Extantz sends Lua Input scripts to module via stdout. - Module runs stand alone. - Module runs in it's own process. - Module has to have widget start Ecore's main loop. - Module runs it's own message loop, waiting for widget to send it messages. - Evas / Elm widgets send signals, call C callbacks. - Widget sends Lua Input scripts to module. - -Alternate plan - - Skang has no main loop, modules are just tables. - OK, so sometimes skang has to start up an Ecore main loop. - With either Ecore_Con, or Evas and Elm. - skang.message(string) - Call it to pass a bit of Lua to skang, which is likely Input. - Widget twiddles happen in Ecore's main loop, via signals and call backs. - Eventually these call backs hit the widgets action string. - Send that action string to skang.message(). - - Extantz loads a skang module. - Extantz has a skang Lua state. - Module is just another table in skang. - Widget -> callback -> action string -> skang.message() - Extantz runs separate skang module. - Skang module C code runs an Ecore main loop. - Module is just another table in skang. - Skang C uses Ecore_Con to get messages from Extantz' Ecore_Con. - Widget -> callback -> action string -> Ecore_Con -> skang.message() - OOORRRR .... - Skang runs a main loop reading stdin. - Widget -> callback -> action string -> stdout -> skang.message() - Module runs stand alone. - Skang module C code runs an Ecore main loop. - Module is just another table in skang. - Widget -> callback -> action string -> skang.message() - Extantz loads a skang module from the network. - Skang module runs on the server with it's own Ecore main loop somehow. - Module is just another table in skang. - Extantz uses Ecore_Con to get messages from Extantz' Ecore_Con, via TCP. - Widget -> callback -> action string -> Ecore_Con -> skang.message() - OOORRRR .... - Remember, these are untrusted, so that's what the script runner is for. - Skang module runs in the script runner, with some sort of luaproc interface. - Widget -> callback -> action string -> Ecore_Con -> luaproc -> skang.message() - - Skang running as a web server. - Skang runs an Ecore main loop. - Skang has an Ecore_Con server attached to port 80. - Skang loads modules as usual. - Skang responds to specific URLs with HTML forms generated from Skang files. - Skang gets post data back, which kinda looks like Input. B-) - - Extantz runs a LuaSL / LSL script from the network. - Send this one to the LuaSL script runner. - Coz LSL scripts tend to have lots of copies with the same name in different objects. - Could get too huge to deal with via "just another table". - In this case, compiling the LSL might be needed to. - -]] - - ---[[ TODO - NOTE that skang.thingasm{} doesn't care what other names you pass in, they all get assigned to the Thing. - - - Widget - - Should include functions for actually dealing with widgets, plus a way - of creating widgets via introspection. Should also allow access to - widget internals via table access. Lua code could look like this - - - foo = widget('label', 0, "0.1", 0.5, 0, 'Text goes here :") - -- Method style. - foo:colour(255, 255, 255, 0, 0, 100, 255, 0) - foo:hide() - foo:action("skang.load(some/skang/file.skang)") - -- Table style. - foo.action = "skang.load('some/skang/file.skang')" - foo.colour.r = 123 - foo.look('some/edje/file/somewhere.edj') - foo.help = 'This is a widget for labelling some foo.' - - Widgets get a type as well, which would be label, button, edit, grid, etc. - A grid could even have sub types - grid,number,string,button,date. - A required widget might mean that the window HAS to have one. - Default for a widget could be the default creation arguments - '"Press me", 1, 1, 10, 50'. - - skang.thingasm{'myButton', types='Button', rectangle={1, 1, 10, 50}, title='Press me', ...} - - skang.thingasm('foo,s,fooAlias', 'Foo is a bar, not the drinking type.', function () print('foo') end, '', '"button", "The foo :"' 1, 1, 10, 50') - myButton = skang.widget('foo') -- Gets the default widget creation arguments. - myButton:colour(1, 2, 3, 4) - -- Use generic positional / named arguments for widget to, then we can do - - myEditor = skang.widget{'foo', "edit", "Edit foo :", 5, 15, 10, 100, look='edit.edj', colour={blue=20}, action='...'} - -- Using the Thing alias stuff, maybe we can do the "first stage tokenise" step after all - - myEditor = skang.widget{'foo', "edit", "Edit foo :", 5, 15, 10, 100, l='edit.edj', c={b=20}, a='...'} - myEditor:colour(1, 2, 3, 4, 5, 6, 7, 8) - myButton = 'Not default' -- myEditor and foo change to. Though now foo is a command, not a parameter, so maybe don't change that. - -- Though the 'quit' Thing could have a function that does quitting, this is just an example of NOT linking to a Thing. - -- If we had linked to this theoretical 'quit' Thing, then pushing that Quit button would invoke it's Thing function. - quitter = skang.widget(nil, 'button', 'Quit', 0.5, 0.5, 0.5, 0.5) - quitter:action('quit') - - For widgets with "rows", which was handled by Stuff in skang, we could - maybe use the Lua concat operator via metatable. I think that works by - having the widget (a table) on one side of the concat or the other, and - the metatable function gets passed left and right sides, then must - return the result. Needs some experimentation, but it might look like - this - - - this.bar = this.bar .. 'new choice' - this.bar = 'new first choice' .. this.bar - - - coordinates and sizes - - - Originally skang differentiated between pixels and character cells, - using plain integers to represent pixels, and _123 to represent - character cells. The skang TODO wanted to expand that to percentages - and relative numbers. We can't use _123 in Lua, so some other method - needs to be used. Should include those TODO items in this new design. - - Specifying character cells should be done as strings - "123" - - Percentages can be done as small floating point numbers between 0 and 1, - which is similar to Edje. Since Lua only has a floating point number - type, both 0 and 1 should still represent pixels / character cells - - - 0.1, 0.5, "0.2", "0.9" - - Relative numbers could be done as strings, with the widget to be - relative to, a + or -, then the number. This still leaves the problem - of telling if the number is pixels or character cells. Also, relative - to what part of the other widget? Some more thought needs to be put - into this. - - Another idea for relative numbers could be to have a coord object with - various methods, so we could have something like - - - button:bottom(-10):right(5) -- 10 pixels below the bottom of button, 5 pixels to the right of the right edge of button. - button:width("12") -- 12 characters longer than the width of button. - - But then how do we store that so that things move when the thing they are - relative to moves? - - - Squeal - - Squeal was the database driver interface for SquealStuff, the database - version of Stuff. Maybe we could wrap esskyuehl? Not really in need of - database stuff for now, but should keep it in mind. - For SquealStuff, the metadata would be read from the SQL database automatically. - - squeal.database('db', 'host', 'someDb', 'user', 'password') -> Should return a Squeal Thing. - local db = require 'someDbThing' -> Same as above, only the database details are encodode in the someDbThing source, OR come from someDbThing.properties. - db:getTable('stuff', 'someTable') -> Grabs the metadata, but not the rows. - db:read('stuff', 'select * from someTable'} -> Fills stuff up with several rows, including setting up the metadata for the columns. - stuff[1].field1 -> Is a Thing, with a proper metatable, that was created automatically from the database meta data. - stuff:read('someIndex') -> Grabs a single row that has the key 'someIndex', or perhaps multiple rows since this might have SQL under it. - stuff = db:read('stuff', 'select * from someTable where key='someIndex') - - stuff:write() -> Write all rows to the database table. - stuff:write(1) -> Write one row to the database table. - stuff:stuff('field1').isValid = someFunction -- Should work, all stuff[key] share the same Thing description. - stuff:isValid(db) -> Validate the entire Thing against it's metadata at least. - window.stuff = stuff -> Window gets stuff as it's default 'Keyed' table, any widgets with same names as the table fields get linked. - grid.stuff = stuff -> Replace contents of this grid widget with data from all the rows in stuff. - choice.stuff = stuff -> As in grid, but only using the keys. - widget.stuff = stuff:stuff('field1') -> This widget gets a particular stufflet. - widget would have to look up getmetatable(window.stuff).parent. Or maybe this should work some other way? - - In all these cases above, stuff is a 'Keyed' table that has a Thing metatable, so it has sub Things. - Should include some way of specifyings details like key name, where string, etc. - getmetatable(stuff).__keyName - getmetatable(stuff).__squeal.where - And a way to link this database table to others, via the key of the other, as a field in this Stuff. - stuff:stuff('field0').__link = {parent, key, index} - In Java we had this - - -public class PersonStuff extends SquealStuff -{ - -... - - public final static String FULLNAME = "fullname"; - - public static final String keyField = "ID"; // Name of key field/s. - public static final String where = keyField + "='%k'"; - public static final String listName = "last"; - public static final String tables = "PEOPLE"; - public static final String select = null; - public static final String stufflets[] = - { - keyField, - "PASSWD_ID|net.matrix_rad.squeal.PasswdStuff|,OTHER", - "QUALIFICATION_IDS|net.matrix_rad.people.QualificationStuff|,OTHER", - "INTERESTING_IDS|net.matrix_rad.people.InterestingStuff|,OTHER", - "title", - "first", - "middle", - "last", - "suffix", - -... - - FULLNAME + "||,VARCHAR,512" - }; -} - -]] - - --- Gotta check out this _ENV thing, 5.2 only. Seems to replace the need for setfenv(). Seems like setfenv should do what we want, and is more backward compatible. --- "_ENV is not supported directly in 5.1, so its use can prevent a module from remaining compatible with 5.1. --- Maybe you can simulate _ENV with setfenv and trapping gets/sets to it via __index/__newindex metamethods, or just avoid _ENV." --- LuaJIT doesn't support _ENV anyway. -- cgit v1.1