-- remove leading/trailing spaces from a string function trim (s) return string.gsub (s, "^( *)(.*)( *)$", "%2") end -- trim -- get a yes/no reponse from the client function yes_no (client, query) local reply while true do Send (client, query, true) reply = string.lower (trim (coroutine.yield ())) if reply == "yes" or reply == "y" then return true elseif reply == "no" or reply == "n" then return false end -- if good reply Send (client, "Please reply 'yes' or 'no'.") end -- while loop end -- yes_no function capitalize (s) return string.upper (string.sub (s, 1, 1)) .. string.lower (string.sub (s, 2)) end -- capitalize function validname (name) name = trim (name) if string.len (name) == 0 then return nil, "Name cannot be blank" end -- no name if not string.find (name, "^%a+$") then return nil, "Invalid name, must consist of letters only" end -- bad name return true -- good name end -- validname -- ---------------------------------------------------------- -- serializer -- See "Programming In Lua" chapter 12.1.2. -- Also see forum thread: -- http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=4960 -- ---------------------------------------------------------- function basicSerialize (o) if type(o) == "number" or type(o) == "boolean" then return tostring(o) else -- assume it is a string return string.format("%q", o) end end -- basicSerialize -- -- Lua keywords might look OK to not be quoted as keys but must be. -- So, we make a list of them. -- lua_reserved_words = {} for _, v in pairs ({ "and", "break", "do", "else", "elseif", "end", "false", "for", "function", "if", "in", "local", "nil", "not", "or", "repeat", "return", "then", "true", "until", "while" }) do lua_reserved_words [v] = true end -- ---------------------------------------------------------- -- save one variable (calls itself recursively) -- -- Modified on 23 October 2005 to better handle keys (like table keys) -- ---------------------------------------------------------- function save (name, value, out, indent, saved) saved = saved or {} -- initial value indent = indent or 0 -- start indenting at zero cols local iname = string.rep (" ", indent) .. name -- indented name -- numbers, strings, and booleans can be simply serialized if type(value) == "number" or type(value) == "string" or type(value) == "boolean" then table.insert (out, iname .. " = " .. basicSerialize(value)) -- tables need to be constructed, unless we have already done it elseif type(value) == "table" then if saved[value] then -- value already saved? table.insert (out, iname .. " = " .. saved[value]) -- use its previous name else -- remember we have created this table so we don't do it twice saved[value] = name -- save name for next time -- make the table constructor, and recurse to save its contents table.insert (out, iname .. " = {}") -- create a new table local k, v for k, v in pairs (value) do -- save its fields local fieldname -- if key is a Lua variable name which is not a reserved word -- we can express it as tablename.keyname if type (k) == "string" and string.find (k, "^[_%a][_%a%d]*$") and not lua_reserved_words [k] then fieldname = string.format("%s.%s", name, k) -- if key is a table itself, and we know its name then we can use that -- eg. tablename [ tablekeyname ] elseif type (k) == "table" and saved[k] then fieldname = string.format("%s[%s]", name, saved [k]) -- if key is an unknown table, we have to raise an error as we cannot -- deduce its name elseif type (k) == "table" then error ("Key table entry " .. tostring (k) .. " in table " .. name .. " is not known") -- if key is a number or a boolean it can simply go in brackets, -- like this: tablename [5] or tablename [true] elseif type (k) == "number" or type (k) == "boolean" then fieldname = string.format("%s[%s]", name, tostring (k)) -- now key should be a string, otherwise an error elseif type (k) ~= "string" then error ("Cannot serialize table keys of type '" .. type (k) .. "' in table " .. name) -- if key is a non-variable name (eg. "++") then we have to put it -- in brackets and quote it, like this: tablename ["keyname"] else fieldname = string.format("%s[%s]", name, basicSerialize(k)) end -- now we have finally worked out a suitable name for the key, -- recurse to save the value associated with it save(fieldname, v, out, indent + 2, saved) end end -- cannot serialize things like functions, threads else error("Cannot save a " .. type(value)) end end -- save -- ---------------------------------------------------------- -- Serialize a variable or nested set of tables: -- ---------------------------------------------------------- --[[ Example of use: SetVariable ("mobs", serialize ("mobs")) --> serialize mobs table loadstring (GetVariable ("mobs")) () --> restore mobs table If you need to serialize two tables where subsequent ones refer to earlier ones you can supply your own "saved tables" variable, like this: t = {} result = serialize ("mobs", nil, t) result = result .. "\n" .. serialize ("quests", nil, t) In this example the serializing of "quests" also knows about the "mobs" table and will use references to it where necessary. You can also supply the actual variable if the variable to be serialized does not exist in the global namespace (for instance, if the variable is a local variable to a function). eg. do local myvar = { 1, 2, 8, 9 } print (serialize ("myvar", myvar)) end In this example, without supplying the location of "myvar" the serialize would fail because it would not be found in the _G namespace. --]] function serialize (what, v, saved) v = v or _G [what] -- default to "what" in global namespace assert (type (what) == "string", "1st argument to serialize should be the *name* of a variable") assert (v, "Variable '" .. what .. "' does not exist") assert (type (saved) == "table" or type (saved) == "nil", "3rd argument to serialize should be a table or nil") local out = {} -- output to this table save (what, v, out, nil, saved) -- do serialization table.insert (out, "") -- final entry to force out newline return table.concat (out, "\r\n") -- turn into a string end -- serialize -- ---------------------------------------------------------- -- tprint - table printer -- -- For debugging what tables have in them, prints recursively -- eg. tprint (GetStyleInfo (20)) -- See forum thread: -- http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=4903 -- ---------------------------------------------------------- function tprint (t, indent, done) -- show strings differently to distinguish them from numbers local function show (val) if type (val) == "string" then return '"' .. val .. '"' else return tostring (val) end -- if end -- show -- entry point here done = done or {} indent = indent or 0 for key, value in pairs (t) do io.write (string.rep (" ", indent)) -- indent it if type (value) == "table" and not done [value] then done [value] = true io.write (show (key) .. ":\n"); tprint (value, indent + 2, done) else io.write (show (key) .. "=") io.write (show (value).. "\n") end end end