Skip to content

Instantly share code, notes, and snippets.

@kaeza
Created February 20, 2016 23:57
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 kaeza/1a970dec497ffd2e453a to your computer and use it in GitHub Desktop.
Save kaeza/1a970dec497ffd2e453a to your computer and use it in GitHub Desktop.
local strfind, strsub, strgsub = string.find, string.sub, string.gsub
local strlen, ipairs, tinsert = string.len, ipairs, table.insert
local function formspec_unescape(str)
return (strgsub(str, "\\(.)", "%1"))
end
---
-- Parse a string and return a list of formspec elements.
-- Has limited detection of malformed data and automatically unescapes
-- formspec item parameters.
-- Each returned element is a table with the following format:
-- {
-- type = "label",
-- params = {
-- "1,2",
-- "Hello;] world!",
-- },
-- }
local function parse_formspec(fs)
local items = { }
local pos, len = 1, strlen(fs)
while pos <= len do
-- Search for `type[`
local start, startend, type = strfind(fs, "([a-z_]+)%[", pos)
if not start then break end
pos = startend + 1
startend = startend + 1
start = startend
local params
local paramstart, paramend
while true do
-- Search for unescaped `]`
local fin, finend, slashes = strfind(fs, "(\\*)%]", startend)
if not fin then
return nil, "malformed data"
end
if #slashes%2 == 0 then
paramstart, paramend = start, finend-1
params = strsub(fs, paramstart, paramend)
break
end
startend = finend+1
end
-- At this point, `type` is the element type (`image`,
-- `button`, etc.), and `params` is everything between
-- `[` and `]`.
local paramlist = { }
-- Split parameters by `;`.
paramstart, paramend = 1, strlen(params)
local paramp = paramstart
while paramp <= paramend and paramstart <= paramend do
-- Search for next unescaped `;`
local sc, scend, slashes = strfind(params, "(\\*);", paramp)
if not sc then
-- No more `;`s; add remaining data and bail out.
tinsert(paramlist, strsub(params, paramstart, paramend))
break
end
if #slashes%2 == 0 then
-- Unescaped `;`: add data up to that point and continue.
tinsert(paramlist, strsub(params, paramstart, scend-1))
paramstart = scend+1
paramp = paramstart
else
-- Escaped `;`: keep searching.
paramp = scend+1
end
end
-- Unescape parameters.
for i, v in ipairs(paramlist) do
paramlist[i] = formspec_unescape(v)
end
tinsert(items, {
type = type,
params = paramlist,
})
end
return items
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment