Module:Xconv

Lua

CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules

The main function in this module is "xconv", for Template:{{Xconv}}

LUA performs conversions very differently:

An example can be performed with the functions h2d and d2h

Code

local p = {}

local min = math.min
local max = math.max
local floor = math.floor
local format = string.format
local sub = mw.ustring.sub
local gsub = mw.ustring.gsub
local upper = mw.ustring.upper
local lower = mw.ustring.lower
local trim = mw.text.trim
local split = mw.text.split

--------------------------------------------------------------------------------

-- Main function: for numeric check
-- Hex-conversion and selection of conversion mode
function p.xconv(frame)
--	local lprm = frame --  local parms
	local gprm = frame.args -- global parms
--	local pprm = mw.getCurrentFrame():getParent().args

	local inpt = {}
	for i = 1, 3 do
		local v = gprm[i] or ''
		gprm[i] = v
		v = trim(v)
		inpt[i] = upper(v)
		inpt[i + 3] = v
	end

	local err = ''	-- detected errors
	local fna = '' -- assumed mode
	local fno = '' -- output mode
	local fnr = ''	-- 'r' for rgb() color, or '#' for hex color
	local sp0 = '('	-- or 'rgb('
	local sp1 = ','	-- or '%,'
	local sp3 = ')'	-- or '%)'
	if inpt[3] ~= '' then
		fna = '4' -- three parms: 4a (or 3c)
		inpt[1] = inpt[1] .. '/' .. inpt[2]  .. '/' .. inpt[3]
	else
		if inpt[2] ~= '' then -- only one param
			inpt[5] = sub(inpt[5], 'r', '')
			if #inpt[2] > #inpt[5] then
				sp0 = 'rgb('
			end
			if inpt[5] == 'n' then
				fna = 'n' -- 1: d2h
			elseif inpt[5] == 'h' then
				fna = 'h' -- 2: h2d
			elseif inpt[5] == 'o' then
				fno = 'o' -- 3: rgb(3ab or 4bcd)
			elseif inpt[5] == 'no' or inpt[5] == 'on' then
				fna = 'n' -- 1: d2h, or 4bcd
				fno = 'o' -- edit
			elseif inpt[5] == 's' or inpt[5] == 'ns' or inpt[5] == 'sn' then
				fna = 'n' -- 4bcd
				fno = 's' -- shorten
			elseif inpt[5] == 'ho' or inpt[5] == 'oh' then
				fna = 'h' -- 2: h2d, or 3ab
				fno = 'o' -- edit
			elseif inpt[5] == '%' then
				fna = 'h' -- rgb(3ab)
				sp1 = '%,'
				sp3 = '%)'
			else
				err = err .. '4' -- parm2 is wrong function code
			end
		end
		if inpt[1] ~= '' then
			if lower(sub(inpt[4], 1, 4)) == 'rgb(' then
				fna = 'n' -- 4cd
				fnr = 'r' -- rgb
				inpt[1] = sub(inpt[1], 4, #inpt[1])
			end
		end
	end

	local rgp = '' -- empty or 3 rgb % signs
	local num = '' -- number bytes
	local hex = '' -- number + hex bytes
	local nhs = '' -- number + hex bytes + separator slashes
	local pts = 0 -- numbers of decimal points
	for i = 1, #inpt[1] do
		local tmp = sub(inpt[1], i, i)
--		if tmp >= '0' and tmp <= "9" then
		if tmp == '0' or tmp == '1' or tmp == '2' or tmp == '3' or tmp == '4'
		or tmp == '5' or tmp == '6' or tmp == '7' or tmp == '8' or tmp == '9' then
			num = num .. tmp
			hex = hex .. tmp
			nhs = nhs .. tmp
		elseif tmp == '.' then -- fnc = 4d
			if pts == 0 then
				num = num .. '.'
				hex = hex .. '.'
				nhs = nhs .. '.'
				pts = 1
			else
				err = err .. '5' -- more than one point
			end
--		elseif tmp >= 'A' and tmp <= 'F' then
		elseif tmp == 'A' or tmp == 'B' or tmp == 'C' or tmp == 'D' or tmp == 'E' or tmp == 'F' then
			hex = hex .. tmp
			nhs = nhs .. tmp
		elseif tmp == ' ' or tmp == ',' or tmp == '-' or tmp == '/' then
			if sub(nhs, #nhs, #nhs) ~= '/' then
				nhs = nhs .. '/'
				pts = 0 --	reset for next item
			elseif sub(inpt[1], i-1, i) ~= ', ' then
				err = err .. '3' --	more than one delimiter in sequ.
			end
		elseif tmp == '%' then -- fnc = 4d
			if i < #inpt[1] then
				inpt[7] = sub(inpt[1], i + 1, i + 1)
			end
			if inpt[7] == ',' or inpt[7] == ')'	then
				inpt[7] = '/'
			end
			if  i < #inpt[1] and inpt[7] ~= '/' then
				nhs = nhs .. '/'
				pts = 0 --	reset for next item
			end
			rgp = rgp .. '%' --	3 times
			if #rgp > 3 then
				err = err .. '6' --	% sign error
			end
		elseif i == 1 then
			if tmp == '(' then
				fnr = 'r'
			elseif tmp == '#' then
				fnr = '#'
			else
				err = err .. '2' -- '(' or '#' occurs at non-first position
			end
		elseif i == #inpt[1] then
			if	tmp == ')' and fnr == 'r' then
				tmp = tmp
			end --	ignore end-')' when 'r'
		elseif tmp ~= '' then -- ignore spacing separator
			err = err .. '1' --	character not identifiable
		end -- if
	end -- for

	local dect = {0, 0, 0}
	local fnc = '' -- conversion mode
	if fnr == '#' and err == ''	then
		if #hex == 3 then -- 3a
			inpt[6] = sub(hex, 3, 3) .. sub(hex, 3, 3)
			inpt[5] = sub(hex, 2, 2) .. sub(hex, 2, 2)
			inpt[4] = sub(hex, 1, 1) .. sub(hex, 1, 1)
		elseif #hex == 6 then
			inpt[6] = sub(hex, 5, 6)
			inpt[5] = sub(hex, 3, 4)
			inpt[4] = sub(hex, 1, 2)
		else
			err = err .. '#'
		end -- neither 6 nor 3
		for i = 1, 3 do
			dect[i] = tonumber(inpt[i + 3], 16)
			if sp3 == '%)' then
				dect[i] = floor(dect[i] / 255 * 1000) / 1000
			end
		end	-- for
		fnc = '3' -- 3
	elseif #num < #hex or fna == 'h' then
		if #nhs == #hex + 2 then --	3bC
			local sndt = split(nhs, '/')
			for i = 1, 3 do
				dect[i] = tonumber(sndt[i], 16)
				if dect[i] > 255 then
					err = err .. '8'
				else
					if sp3 == '%)' then
						dect[i] = floor(dect[i] / 255 * 1000) / 1000
					end
				end
			end	-- for
			fnc = '3' -- 3
		else
			if fnr ~= '#' then
				dect[1] = tonumber(hex, 16)
				fnc = '2' -- 2
			end
		end
	else -- #num == #hex (a numeric value, and not 'h')
		if #nhs == #hex then
			fnc = '1' -- 1
			inpt[1]	= format('%X', num)
		else -- #nhs == #hex + 2 == #num + 2 (3 num values) -- 4A, 4b or 4c, 4d
			dect = split(nhs, '/')
			fnc = '4' -- 4
			for i = 1, 3 do
				if rgp == '' then
					if tonumber(dect[i]) > 255 then -- 4A, 4b, 4c
						err = err .. '8'
					end
					inpt[i]	= format('%02X', dect[i])
				else --	rgp = '%%%' -- 4d
					if rgp ~= '%%%' then
						err = err .. '7' -- (6) not three '%'
					end
					if tonumber(dect[i]) > 100 then -- 4d
						err = err .. '9'
					end
					dect[i + 3] = floor(dect[i] * 255 / 100 + .5)
					inpt[i] = format('%02X', dect[i + 3])
				end
			end	-- for
			if fno == 's' -- shortening required ?
			and sub(inpt[1], 1, 1) == sub(inpt[1], 2, 2)
			and sub(inpt[2], 1, 1) == sub(inpt[2], 2, 2)
			and sub(inpt[3], 1, 1) == sub(inpt[3], 2, 2) then
				inpt[1] = sub(inpt[1], 1, 1)
				inpt[2] = sub(inpt[2], 1, 1)
				inpt[3] = sub(inpt[3], 1, 1)
			end	-- shorten #rrggbb to #rgb
		end	-- if #nhs
	end	-- if #num

--[[
	err: string, indicates parsing errors that may have been encountered:
		'1': non-numeric or non-hexadecimal characters
		'2': '(' or '#' occurs at non-first position
		'3': separator (or separator combination}
		'4': parm2 input wrong function code
		'5': decimal point error
		'6': % sign error
		'7': not three '%'
		'8': not all decimal color codes are < 256
		'9': more than 100%
	inpt: table of 6 strings, contains 3 trimmed parameters after their uppercase versions
	dect: table of 3 decimal values
	num: string, contains all numeric bytes
	hex: string, contains all numeric plus hexadecimal bytes
	nhs: string, contains all numeric plus hexadecimal bytes plus inbetween slashes
	rgp: string, may contain three '%' from rgb() notation
--]]

--[[ Only for tests:
	if fnc == '4' then
		return 'err=' .. err .. ', fn=' .. fna .. fno .. fnr .. fnc
			.. ', '.. inpt[1]
			.. ', '.. num .. '~' .. hex .. '~' .. nhs
			 .. ', '.. tostring(dect[1]) .. "'" .. tostring(dect[2]) .. "'" .. tostring(dect[3])
			.. ', ' .. rgp
			.. ', ' .. inpt[1] .. '"' .. inpt[2] .. '"' .. inpt[3]
	else
		return 'err=' .. err .. ', fn=' .. fna .. fno .. fnr .. fnc
			.. ', '.. inpt[1]
			.. ', '.. num .. '~' .. hex .. '~' .. nhs
			.. ', '.. tostring(dect[1]) .. "'" .. tostring(dect[2]) .. "'" .. tostring(dect[3])
			.. ', '.. rgp
	end
--]]
	if err ~= '' then
		return 'Error = ' .. err
	elseif fnc == '1' then
		return inpt[1] .. '<sub>h</sub>'
	elseif fnc == '2' then
		return tostring(dect[1]) .. '<sub>d</sub>'
	elseif fnc == '3' then
		return sp0 .. dect[1] .. sp1 .. dect[2] .. sp1 .. dect[3] .. sp3
	elseif fnc == '4' then
		return '&#35;'-- leading '#' HTML-escaped against MediaWiki reinterpretation
			.. inpt[1] .. inpt[2] .. inpt[3]
	end

end	-- function xconv

--------------------------------------------------------------------------------

-- Convert hexadecimal value (from 0 to FFFFFFFFFFF) to decimal value(from 0 to 17592186044415)
function p.h2d(frame)
	local gprm = frame.args	-- global parms
	return tonumber(gprm[1], 16) or ''
end -- function h2d

--------------------------------------------------------------------------------

-- Convert decimal value (from 0 to 17592186044415) to hexadecimal value(from 0 to FFFFFFFFFFF)
function p.d2h(frame)
	local gprm = frame.args	-- global parms
	local value = tonumber(gprm[1]) or 0
	local width = min(max(tonumber(gprm[2]) or 1, 1), 16)
	return format('%0' .. tostring(width) .. 'X', value)
end -- function d2h

--------------------------------------------------------------------------------

return p
Category:Modules for general use