nested[o] = nil
if indent ~= "" then
local indent_str = "\n"..string.rep(indent, level)
- local end_indent_str = "\n"..string.rep("\t", level - 1)
+ local end_indent_str = "\n"..string.rep(indent, level - 1)
return string.format("{%s%s%s}",
indent_str,
table.concat(t, ","..indent_str),
end
--------------------------------------------------------------------------------
-function string.split(str, delim, include_empty, max_splits)
+-- Localize functions to avoid table lookups (better performance).
+local table_insert = table.insert
+local str_sub, str_find = string.sub, string.find
+function string.split(str, delim, include_empty, max_splits, sep_is_pattern)
delim = delim or ","
- max_splits = max_splits or 0
- local fields = {}
- local num_splits = 0
- local last_pos = 0
- for part, pos in str:gmatch("(.-)[" .. delim .. "]()") do
- last_pos = pos
- if include_empty or part ~= "" then
- num_splits = num_splits + 1
- fields[num_splits] = part
- if max_splits > 0 and num_splits + 1 >= max_splits then
- break
- end
+ max_splits = max_splits or -1
+ local items = {}
+ local pos, len, seplen = 1, #str, #delim
+ local plain = not sep_is_pattern
+ max_splits = max_splits + 1
+ repeat
+ local np, npe = str_find(str, delim, pos, plain)
+ np, npe = (np or (len+1)), (npe or (len+1))
+ if (not np) or (max_splits == 1) then
+ np = len + 1
+ npe = np
end
- end
- -- Handle the last field
- if max_splits <= 0 or num_splits <= max_splits then
- local last_part = str:sub(last_pos)
- if include_empty or last_part ~= "" then
- fields[num_splits + 1] = last_part
+ local s = str_sub(str, pos, np - 1)
+ if include_empty or (s ~= "") then
+ max_splits = max_splits - 1
+ table_insert(items, s)
end
- end
- return fields
+ pos = npe + 1
+ until (max_splits == 0) or (pos > (len + 1))
+ return items
end
-
--------------------------------------------------------------------------------
function file_exists(filename)
local f = io.open(filename, "r")
return x * math.sqrt(1 + t * t)
end
+--------------------------------------------------------------------------------
+function math.sign(x, tolerance)
+ tolerance = tolerance or 0
+ if x > tolerance then
+ return 1
+ elseif x < -tolerance then
+ return -1
+ end
+ return 0
+end
+
--------------------------------------------------------------------------------
function get_last_folder(text,count)
local parts = text:split(DIR_DELIM)
local t = parts[1]:trim()
local r = tonumber(parts[2]:trim())
local c = tonumber(parts[3]:trim())
- if type(r) == "number" and type(c) == "number" and t ~= "INV" then
+ if type(r) == "number" and type(c) == "number"
+ and t ~= "INV" then
return {type=t, row=r, column=c}
end
end
end
--------------------------------------------------------------------------------
-function core.pos_to_string(pos)
- return "(" .. pos.x .. "," .. pos.y .. "," .. pos.z .. ")"
+function core.pos_to_string(pos, decimal_places)
+ local x = pos.x
+ local y = pos.y
+ local z = pos.z
+ if decimal_places ~= nil then
+ x = string.format("%." .. decimal_places .. "f", x)
+ y = string.format("%." .. decimal_places .. "f", y)
+ z = string.format("%." .. decimal_places .. "f", z)
+ end
+ return "(" .. x .. "," .. y .. "," .. z .. ")"
end
+--------------------------------------------------------------------------------
+function core.string_to_pos(value)
+ if value == nil then
+ return nil
+ end
+
+ local p = {}
+ p.x, p.y, p.z = string.match(value, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$")
+ if p.x and p.y and p.z then
+ p.x = tonumber(p.x)
+ p.y = tonumber(p.y)
+ p.z = tonumber(p.z)
+ return p
+ end
+ local p = {}
+ p.x, p.y, p.z = string.match(value, "^%( *([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+) *%)$")
+ if p.x and p.y and p.z then
+ p.x = tonumber(p.x)
+ p.y = tonumber(p.y)
+ p.z = tonumber(p.z)
+ return p
+ end
+ return nil
+end
+
+assert(core.string_to_pos("10.0, 5, -2").x == 10)
+assert(core.string_to_pos("( 10.0, 5, -2)").z == -2)
+assert(core.string_to_pos("asd, 5, -2)") == nil)
+
+--------------------------------------------------------------------------------
+function table.copy(t, seen)
+ local n = {}
+ seen = seen or {}
+ seen[t] = n
+ for k, v in pairs(t) do
+ n[(type(k) == "table" and (seen[k] or table.copy(k, seen))) or k] =
+ (type(v) == "table" and (seen[v] or table.copy(v, seen))) or v
+ end
+ return n
+end
--------------------------------------------------------------------------------
-- mainmenu only functions
--------------------------------------------------------------------------------
return nil
end
- function fgettext(text, ...)
+ function fgettext_ne(text, ...)
text = core.gettext(text)
local arg = {n=select('#', ...), ...}
if arg.n >= 1 then
-- Insert positional parameters ($1, $2, ...)
- result = ''
- pos = 1
+ local result = ''
+ local pos = 1
while pos <= text:len() do
- newpos = text:find('[$]', pos)
+ local newpos = text:find('[$]', pos)
if newpos == nil then
result = result .. text:sub(pos)
pos = text:len() + 1
else
- paramindex = tonumber(text:sub(newpos+1, newpos+1))
- result = result .. text:sub(pos, newpos-1) .. tostring(arg[paramindex])
+ local paramindex =
+ tonumber(text:sub(newpos+1, newpos+1))
+ result = result .. text:sub(pos, newpos-1)
+ .. tostring(arg[paramindex])
pos = newpos + 2
end
end
text = result
end
- return core.formspec_escape(text)
+ return text
+ end
+
+ function fgettext(text, ...)
+ return core.formspec_escape(fgettext_ne(text, ...))
end
end