Skip to content

Instantly share code, notes, and snippets.

@sfan5
Created April 9, 2016 18:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfan5/9b366299a7e3a2103ffc70cdc36806b6 to your computer and use it in GitHub Desktop.
Save sfan5/9b366299a7e3a2103ffc70cdc36806b6 to your computer and use it in GitHub Desktop.
local function formspec_escape(text)
text = string.gsub(text,"\\","\\\\")
text = string.gsub(text,"%]","\\]")
text = string.gsub(text,"%[","\\[")
text = string.gsub(text,";","\\;")
text = string.gsub(text,",","\\,")
return text
end
local function assert_fields(tbl, names, i)
for _, name in ipairs(names) do
local found = false
for fieldname, _ in ipairs(tbl) do
if fieldname == name then
found = true
end
end
if not found then
error("Element " .. i .. " has no '" .. name .. "' field")
end
end
end
local function assert_type(tbl, eln, ex, i)
if type(tbl[eln]) ~= ex then
error("The '" .. eln .. "' field of Element " .. i .. " is of type '" .. type(tbl[eln])
.. "', expected was '" .. ex .. "'")
end
end
local function boolstr(b)
if b == true then
return "true"
else
return "false"
end
end
local conv_tbl = {
-- Type additional Check Func args arg types template
{"invsize", true, {"w", "h"}, {"number", "number"}, "size[{w},{h}]"},
{"size", true, {"w", "h"}, {"number", "number"}, "size[{w},{h}]"},
{"list", function(t) return t.startingitemindex == nil end,
{"inventorylocation", "listname", "x", "y", "w", "h"},
{"string", "string", "number", "number", "number", "number"},
"list[{inventorylocation};{listname};{x},{y};{w},{h}]"},
{"list", function(t) return t.startingitemindex ~= nil end,
{"inventorylocation", "listname", "x", "y", "w", "h", "startingitemindex"},
{"string", "string", "number", "number", "number", "number", "number"},
"list[{inventorylocation};{listname};{x},{y};{w},{h};{startingitemindex}]"},
{"image", true, {"x", "y", "w", "h", "texturename"},
{"number", "number", "number", "number", "string"},
"image[{x},{y};{w},{h};{texturename}]"},
{"item_image", true, {"x", "y", "w", "h", "itemname"},
{"number", "number", "number", "number", "string"},
"item_image[{x},{y};{w},{h};{itemname}]"},
{"background", true, {"x", "y", "w", "h", "texturename"},
{"number", "number", "number", "number", "string"},
"background[{x},{y};{w},{h};{texturename}]"},
{"pwdfield", true, {"x", "y", "w", "h", "name", "label"},
{"number", "number", "number", "number", "string", "string"},
"pwdfield[{x},{y};{w},{h};{name};{label}]"},
{"field", function(t) return t.x ~= nil end,
{"x", "y", "w", "h", "name", "label", "default"},
{"number", "number", "number", "number", "string", "string", "string"},
"field[{x},{y};{w},{h};{name};{label};{default}]"},
{"field", function(t) return t.x == nil end,
{"name", "label", "default"},
{"string", "string", "string"},
"field[{name};{label};{default}]"},
{"textarea", true, {"x", "y", "w", "h", "name", "label", "default"},
{"number", "number", "number", "number", "string", "string", "string"},
"textarea[{x},{y};{w},{h};{name};{label};{default}]"},
{"label", true, {"x", "y", "label"}, {"number", "number", "string"},
"label[{x},{y};{label}]"},
{"vertlabel", true, {"x", "y", "label"}, {"number", "number", "string"},
"vertlabel[{x},{y};{label}]"},
{"button", true, {"x", "y", "w", "h", "name", "label"},
{"number", "number", "number", "number", "string", "string"},
"button[{x},{y};{w},{h};{name};{label}]"},
{"image_button", function(t, i)
if t.noclip == nil and (t.drawborder ~= nil or t.pressed ~= nil) then
error("Element " .. i .. " does have 'drawborder' or 'pressed' field but not 'noclip'")
end
if t.drawborder == nil and t.pressed ~= nil then
error("Element " .. i .. " does have 'pressed' field but not 'drawborder'")
end
return t.noclip == nil and t.drawborder == nil and t.pressed == nil
end,
{"x", "y", "w", "h", "texturename", "name", "label"},
{"number", "number", "number", "number", "string", "string", "string"},
"image_button[{x},{y};{w},{h};{texturename};{name};{label}]"},
{"image_button", function(t)
return t.noclip ~= nil and t.drawborder == nil and t.pressed == nil
end,
{"x", "y", "w", "h", "texturename", "name", "label", "noclip"},
{"number", "number", "number", "number", "string",
"string", "string", "boolean"},
"image_button[{x},{y};{w},{h};{texturename};{name};{label};{noclip};true]"},
{"image_button", function(t)
return t.noclip ~= nil and t.drawborder ~= nil and t.pressed == nil
end,
{"x", "y", "w", "h", "texturename", "name", "label", "noclip", "drawborder"},
{"number", "number", "number", "number", "string",
"string", "string", "boolean", "boolean"},
"image_button[{x},{y};{w},{h};{texturename};{name};{label};{noclip};{drawborder}]"},
{"image_button", function(t)
return t.noclip ~= nil and t.drawborder ~= nil and t.pressed ~= nil
end,
{"x", "y", "w", "h", "texturename", "name", "label", "noclip", "drawborder", "pressed"},
{"number", "number", "number", "number", "string",
"string", "string", "boolean", "boolean", "string"},
"image_button[{x},{y};{w},{h};{texturename};{name};{label};{noclip};{drawborder};{pressed}]"},
{"item_image_button", true,
{"x", "y", "w", "h", "itemname", "name", "label"},
{"number", "number", "number", "number", "string", "string", "string"},
"item_image_button[{x},{y};{w},{h};{itemname};{name};{label}]"},
{"button_exit", true, {"x", "y", "w", "h", "name", "label"},
{"number", "number", "number", "number", "string", "string"},
"button_exit[{x},{y};{w},{h};{name};{label}]"},
{"image_button_exit", true,
{"x", "y", "w", "h", "texturename", "name", "label"},
{"number", "number", "number", "number", "string", "string", "string"},
"image_button_exit[{x},{y};{w},{h};{texturename};{name};{label}]"},
{"textlist", function(t) return t.tranparent == nil end,
{"x", "y", "w", "h", "name", "list"},
{"number", "number", "number", "number", "string", {"table", colors=true}},
"textlist[{x},{y};{w},{h};{name};{list}]"},
{"textlist", function(t) return t.tranparent ~= nil end,
{"x", "y", "w", "h", "name", "list", "transparent"},
{"number", "number", "number", "number", "string", {"table", colors=true}, "boolean"},
"textlist[{x},{y};{w},{h};{name};{list};{transparent}]"},
{"tabheader", true, {"x", "y", "name", "captions",
"current_tab", "transparent", "drawborder"},
{"number", "number", "string", "table", "number",
"boolean", "boolean"},
"tabheader[{x},{y};{name};{captions};{current_tab};{transparent};{drawborder}]"},
{"box", true, {"x", "y", "w", "h", "color"},
{"number", "number", "number", "number", {"string", color=true}},
"box[{x},{y};{w},{h};{color}]"},
{"dropdown", true, {"x", "y", "w", "name", "items", "index"},
{"number", "number", "number", "string", "table", "number"},
"dropdown[{x},{y};{w};{name};{items};{index}]"},
{"checkbox", function(t) return t.selected == nil end,
{"x", "y", "name", "label"},
{"number", "number", "string", "string"},
"checkbox[{x},{y};{name};{label}]"},
{"checkbox", function(t) return t.selected ~= nil end,
{"x", "y", "name", "label", "selected"},
{"number", "number", "string", "string", "boolean"},
"checkbox[{x},{y};{name};{label};{selected}]"},
}
function formspectable2formspecstring(tbl)
local outstring = ""
if type(tbl) ~= "table" then
error("Expected 'table' for first argument, got '" .. type(tbl) .. "'")
end
for i, el in ipairs(tbl) do
if type(el) ~= "table" then
error("Element " .. i .. " is not of type 'table', but '" .. type(el) .. "'")
end
local t = tbl[1]
if t == nil then
error("Element " .. i .. " has no type field")
end
local processed = false
for _, conv in conv_tbl do
if t == conv[1] then
if type(conv[2]) == "boolean" and conv[2] == true then
conv[2] = function(t) return true end
end
if conv[2](tbl, i) then
processed = true
assert_fields(tbl, conv[3], i)
for j, ftype in conv[4] do
if type(ftype) == "table" then
ftype = ftype[1]
end
assert_type(tbl, conv[3][j], ftype, i)
end
local out = conv[5]
for j, fname in conv[3] do
if type(tbl[fname]) == "string" then
if type(conv[4][j]) == "table" and conv[4][j].color then
_col = tbl[fname]
if #_col ~= 6 then
error("Argument " .. j .. " of Element " .. i .. " is " .. #_col .." characters long, expected was 6")
end
for l in 1, #_col do
_cc = string.byte(_col, l)
if (_cc >= 48 and _cc <= 57) or (_cc >= 65 and _cc <= 70) or (_cc >= 97 and _cc <= 102) then
--Character valid
else
error("Character " .. l .. " of Argument " .. j .. " of Element " .. i .. " is " .. string.char(_cc) .. ", expected was one of 0123456789ABCDEFabcdef")
end
end
end
out = out:gsub("{" .. fname .. "}", formspec_escape(tbl[fname]))
elseif type(tbl[fname]) == "number" then
out = out:gsub("{" .. fname .. "}", tbl[fname])
elseif type(tbl[fname]) == "boolean" then
out = out:gsub("{" .. fname .. "}", boolstr(tbl[fname]))
elseif type(tbl[fname]) == "table" then
local out2 = ""
for k, tv in ipairs(tbl[fname]) do
if type(tv) == "string" then
if type(conv[4][j]) == "table" and conv[4][j].colors and tv:sub(1,1) == "#" then
tv = "#" .. tv
end
out2 = out2 .. formspec_escape(tv)
elseif type(tv) == "number" then
out2 = out2 .. tv
elseif type(tv) == "boolean" then
out2 = out2 .. boolstr(tv)
elseif type(tv) == "table" and type(conv[4][j]) == "table" and conv[4][j].colors then
_col = tv.color
_txt = tv.text
if _col == nil then
error("Element " .. i .. ", Argument " .. j .. " has no 'color' field")
elseif _txt == nil then
error("Element " .. i .. ", Argument " .. j .. " has no 'text' field")
end
if type(_col) ~= "string" then
error("The 'color' field of Element " .. i .. ", Argument " .. j .. " is of type '" .. type(_col) .. "', expected was 'string'")
elseif type(_txt) ~= "string" then
error("The 'text' field of Element " .. i .. ", Argument " .. j .. " is of type '" .. type(_col) .. "', expected was 'string'")
end
if #_col ~= 6 then
error("The 'color' field of Element " .. i .. ", Argument " .. j .. " is " .. #_col .." characters long, expected was 6")
end
for l in 1, #_col do
_cc = string.byte(_col, l)
if (_cc >= 48 and _cc <= 57) or (_cc >= 65 and _cc <= 70) or (_cc >= 97 and _cc <= 102) then
--Character valid
else
error("Character " .. l .. " of the 'color' field of Element " .. i .. ", Argument " .. j .. " is " .. string.char(_cc) .. ", expected was one of 0123456789ABCDEFabcdef")
end
end
out2 = out2 .. "#" .. _col .. formspec_escape(tv)
else
error("Cannot serialize " .. type(tv) .. " in table Element " .. i .. ", Argument " .. j)
end
if not k == #tbl[fname] then
out2 = out2 .. ","
end
end
out = out:gsub("{" .. fname .. "}", out2)
end
end
outstring = outstring .. out
end
end
end
if not processed then
error("Element " .. i .. " has unknown type '" .. t .. "'")
end
end
return outstring
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment