Module:Xconv

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Lua

CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules

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

LUA performs conversions very differently:

  • h→d 0 tonumber ( HEXNUM, 16 )
  • d→h 0 string.format ( "%X", DECNUM )

An example can be performed with the functions h2d and d2h

  • {{#invoke:Xconv|h2d|50FFFF2FFFF0}}<sub>d</sub> gives 89060428218352d
  • {{#invoke:Xconv|d2h|4096}}<sub>h</sub> will give 1000h

Code

local p = {}

-- main function:	for numeric check  
--	"hex conv"		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 = {};
	local sndt = {};
	local dect = {0, 0, 0};
	local tmp = "";	-- temp. work string
	local err = "";	-- detected error 
	local fna = "";	-- assumed mode
	local fnc = "";	-- conversion mode
	local fno = "";	-- output mode
	local fnr = "";	-- "r" rgb(, "#" 
	local num = "";	-- number bytes
	local hex = "";	-- number + hex bytes
	local nhs = "";	-- number + hex bytes + separator slashes
	local rgp = "";	-- empty or 3 rgb % signs
	local pts = 0;	-- numbers of decimal points
	local sp0 = '('	-- or 'rgb('
	local sp1 = ","	-- or "%,"
	local sp3 = ")"	-- or "%)"
	for i = 1, 3 do
		if gprm[i] == nil then gprm[i] = "" end
		inpt[i+3] = mw.text.trim( gprm[i] )
		inpt[i] = mw.ustring.upper( inpt[i+3] )
	end

	if inpt[3] ~= "" then fna = "4" -- three parms: 4a (or 3c)
	else
		if inpt[2] ~= "" then	-- 		only one param
			inpt[5] = mw.ustring.gsub( 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	mw.ustring.lower( mw.ustring.sub( inpt[4], 1, 4)) == "rgb(" then
				fna = "n"	-- 4cd
				fnr = "r"	-- rgb
				inpt[1] = mw.ustring.sub( inpt[1], 4, #inpt[1] )
			end
		end
	end

	if inpt[3] ~= "" then	-- 4a, 3c
		inpt[1] = inpt[1]  .."/".. inpt[2]  .."/".. inpt[3]
	end


	for i = 1, #inpt[1] do
		tmp = mw.ustring.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  mw.ustring.sub( nhs, #nhs, #nhs ) ~= "/" then
				nhs = nhs .. "/"
				pts = 0				--	reset for next item
			elseif	mw.ustring.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] = mw.ustring.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 '#' not first char
			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 identifyable
		end -- if
	end -- for



	if fnr == '#' and err == ""	then 
		if #hex == 3 then		--	3a
			inpt[6] = mw.ustring.sub( hex, 3, 3)..mw.ustring.sub( hex, 3, 3)
			inpt[5] = mw.ustring.sub( hex, 2, 2)..mw.ustring.sub( hex, 2, 2)
			inpt[4] = mw.ustring.sub( hex, 1, 1)..mw.ustring.sub( hex, 1, 1)
		elseif #hex == 6 then
			inpt[6] = mw.ustring.sub( hex, 5, 6)		
			inpt[5] = mw.ustring.sub( hex, 3, 4)		
			inpt[4] = mw.ustring.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] = math.floor( dect[i] / .00255 ) / 1000
			end
		end	-- for
		fnc = "3"			--	3 

	elseif #num < #hex or fna == "h" then
		if #nhs == #hex+2 then	--	3bC
			sndt = mw.text.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] = math.floor( dect[i] / .00255 ) / 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]	= mw.ustring.format ( "%X", num )
			
		else	-- #nhs == #hex+2 == #num+2 (3 num values) -- 4A,4b or 4c,4d 
			dect = mw.text.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]	= mw.ustring.format ( "%X", 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] = math.floor( 2.55 * dect[i] + .5 )
					inpt[i] = mw.ustring.format ( "%X", dect[i+3] )
				end	-- if
				if #inpt[i] == 1 then inpt[i] = "0"..inpt[i] end 
			end	-- for
			if fno == "s"		-- shortening required ?
			and  mw.ustring.sub ( inpt[1], 1, 1 ) ==  mw.ustring.sub ( inpt[1], 2, 2 )
			and  mw.ustring.sub ( inpt[2], 1, 1 ) ==  mw.ustring.sub ( inpt[2], 2, 2 )
			and  mw.ustring.sub ( inpt[3], 1, 1 ) ==  mw.ustring.sub ( inpt[3], 2, 2 ) then
				inpt[1] = mw.ustring.sub ( inpt[1], 1, 1 )
				inpt[2] = mw.ustring.sub ( inpt[2], 1, 1 )
				inpt[3] = mw.ustring.sub ( inpt[3], 1, 1 )
			end	-- shorten #rrggbb to #rgb
		end	-- if #nhs
	end	-- if #num


--		now errors may be encountered: 
--			1:	character not numeric/hexa
--			2:	'(' or '#' occurs at not 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%
--		'num' contains all numeric bytes
--		'hex' contains all numeric plus hexadecimal bytes
--		'nhs' contains all numeric plus hexadecimal bytes plus inbetween slashes
--		'rgp' may contain three '%' from rgb notation
--		dect contains three dec values 
--		
--	if fnc == "4" then 	
--	return "err="..err..", fn="..fna..fnc..fno..fnr..", "..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..fnc..fno..fnr..", "..inpt[1].."; "..num.."~"..hex.."~"..nhs.." "..tostring(dect[1]).."'"..tostring(dect[2]).."'"..tostring(dect[3]).." "..rgp;	-- test		
--	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;"..inpt[1]..inpt[2]..inpt[3]
	end 

end	-- function xconv		

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

-- hex to decimal value (0 ... FFFFFFFFFFF)
function p.h2d ( frame )
	local gprm = frame.args	-- global parms
	return tonumber ( gprm[1], 16 )
end --  function h2d
-- hex to decimal value (0 ...  17592186044415)
function p.d2h ( frame )
	local gprm = frame.args	-- global parms
	return mw.ustring.format ( "%X", gprm[1] )
end --  function d2h

return p;