aboutsummaryrefslogtreecommitdiff
path: root/src/particles.cpp
diff options
context:
space:
mode:
authorShadowNinja <shadowninja@minetest.net>2013-11-30 12:11:07 -0500
committerShadowNinja <shadowninja@minetest.net>2013-11-30 13:05:13 -0500
commit4594ba652293e776ccba2184c16502a346f4147a (patch)
tree19713fac8de559ba86cd9d08d9c07cb1c7241e37 /src/particles.cpp
parent06baf05c641355ead97e9428c4455af9e8b11cef (diff)
downloadminetest-4594ba652293e776ccba2184c16502a346f4147a.tar.gz
minetest-4594ba652293e776ccba2184c16502a346f4147a.tar.bz2
minetest-4594ba652293e776ccba2184c16502a346f4147a.zip
Optimize table creation
Diffstat (limited to 'src/particles.cpp')
0 files changed, 0 insertions, 0 deletions
4' href='#n124'>124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
local unescape_string
do
	local schartbl = { -- https://en.wikipedia.org/wiki/Escape_sequences_in_C
		a = "\a",
		b = "\b",
		e = string.char(0x1b),
		f = "\f",
		n = "\n",
		r = "\r",
		t = "\t",
		v = "\v",
	}
	local function replace_single(pfx, c)
		local pl = #pfx
		if pl % 2 == 0 then
			return string.sub(pfx, 1, pl/2) .. c
		end
		return string.sub(pfx, 1, math.floor(pl/2)) .. (schartbl[c] or c)
	end
	unescape_string = function(str)
		return string.gsub(str, [[(\+)([abefnrtv'"?])]], replace_single)
	end
end

local function readstring_aux(str, pos)
	local _, spos = string.find(str, [[^%s*"]], pos)
	if not spos then
		return nil
	end
	local ipos = spos
	while true do
		local _, epos, m = string.find(str, [[(\*)"]], ipos+1)
		if not epos then
			return error("String extends beyond the end of input")
		end
		ipos = epos
		if #m % 2 == 0 then
			return unescape_string(string.sub(str, spos+1, epos-1)), epos+1
		end
	end
end

local function readstring(str, pos)
	local st = {}
	local nxt = pos
	while true do
		local s, npos = readstring_aux(str, nxt)
		if not s then
			if not st[1] then
				return nil, nxt
			else
				return table.concat(st), nxt
			end
		end
		nxt = npos
		table.insert(st, s)
	end
end

local function readtoken(str, pos)
	local _, epos, tok = string.find(str, [[^%s*(%S+)]], pos)
	if epos == nil then
		return nil, pos
	end
	return tok, epos+1
end

local function readcomment_add_flags(flags, s)
	for flag in string.gmatch(s, ",%s*([^,]+)") do
		flags[flag] = true
	end
end

local function readcomment_aux(str, pos)
	local _, epos, sval = string.find(str, "^\n*#([^\n]*)", pos)
	if not epos then
		return nil
	end
	return sval, epos+1
end

local function readcomment(str, pos)
	local st = {}
	local nxt = pos
	local flags = {}
	while true do
		local s, npos = readcomment_aux(str, nxt)
		if not npos then
			local t = {
				comment = table.concat(st, "\n"),
				flags = flags,
			}
			return t, nxt
		end
		if string.sub(s, 1, 1) == "," then
			readcomment_add_flags(flags, s)
		end
		table.insert(st, s)
		nxt = npos
	end
end

local function readpo(str)
	local st = {}
	local pos = 1
	while true do
		local entry, nxt = readcomment(str, pos)
		local msglines = 0
		while true do
			local tok, npos = readtoken(str, nxt)
			if tok == nil or string.sub(tok, 1, 1) == "#" then
				break
			elseif string.sub(tok, 1, 3) ~= "msg" then
				return error("Invalid token: " .. tok)
			elseif entry[tok] ~= nil then
				break
			else
				local value, npos = readstring(str, npos)
				assert(value ~= nil, "No string provided for " .. tok)
				entry[tok] = value
				nxt = npos
				msglines = msglines+1
			end
		end
		if msglines == 0 then
			return st
		elseif entry.msgid ~= "" then
			assert(entry.msgid ~= nil, "Missing untranslated string")
			assert(entry.msgstr ~= nil, "Missing translated string")
			table.insert(st, entry)
		end
		pos = nxt
	end
end

local escape_lookup = {
	["="] = "@=",
	["\n"] = "@n"
}
local function escape_string(st)
	return (string.gsub(st, "[=\n]", escape_lookup))
end

local function convert_po_string(textdomain, str)
	local st = {string.format("# textdomain: %s", textdomain)}
	for _, entry in ipairs(readpo(str)) do
		local line = ("%s=%s"):format(escape_string(entry.msgid), escape_string(entry.msgstr))
		if entry.flags.fuzzy then
			line = "#" .. line
		end
		table.insert(st, line)
	end
	return table.concat(st, "\n")
end

local function convert_po_file(textdomain, inpath, outpath)
	local f, err = io.open(inpath, "rb")
	assert(f, err)
	local str = convert_po_string(textdomain, f:read("*a"))
	f:close()
	minetest.safe_file_write(outpath, str)
	return str
end

local function convert_flat_po_directory(textdomain, modpath)
	assert(textdomain, "No textdomain specified for po file conversion")
	local mp = modpath or minetest.get_modpath(textdomain)
	assert(mp ~= nil, "No path to write for " .. textdomain)
	local popath = mp .. "/po"
	local trpath = mp .. "/locale"
	for _, infile in pairs(minetest.get_dir_list(popath, false)) do
		local lang = string.match(infile, [[^([^%.]+)%.po$]])
		if lang then
			local inpath = popath .. "/" .. infile
			local outpath = ("%s/%s.%s.tr"):format(trpath, textdomain, lang)
			convert_po_file(textdomain, inpath, outpath)
		end
	end
end

return {
	from_string = convert_po_string,
	from_file = convert_po_file,
	from_flat = convert_flat_po_directory,
}