Saltu al enhavo

Modulo:mchar

El Vikivortaro
 MODULO
Memtesto disponeblas sur la paĝo Ŝablono:signo.

--[===[

MODULE "MCHAR" (unicode character)

"eo.wiktionary.org/wiki/Modulo:mchar" <!--2025-May-01-->
"id.wiktionary.org/wiki/Modul:mchar"

Purpose: brews a box located on the right about
         a unicode char read from pagename

Utilo: kreas skatolon lokigitan dekstre pri
       unikoda signo legata el pagxonomo

Manfaat: membutat kotak terletak di sebelah kanan halaman tentang
         karakter unikode dibaca dari nama halaman

Syfte: skapar en ruta belaegen till hoeger ...

Used by templates / Uzata far sxablonoj / Digunakan oleh templat:
* signo (EO)

Required submodules / Bezonataj submoduloj / Submodul yang diperlukan:
* none

This module can accept parameters whether sent to itself (own frame) or
to the parent (parent's frame). If there is a parameter "parentframe=true"
on the own frame then that own frame is discarded in favor of the
parent's one.

Incoming: * no anonymous parameters
          * 3 optional named parameters
            * "des=" -- official name written with uppercase letters (3...80)
            * "en=" -- (3...80)
            * "sl=" -- description in site language (3...80)
          * 1 hidden named parameter
            * "pagenameoverridetestonly="

Returned: * one string with either a HTML table or inline ERROR

]===]

local exporttable = {}

require('strict')

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

---- CONSTANTS [O] ----

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

-- surrogate transcoding table

local contabtransluteo = {}
contabtransluteo[ 67] = 0xC488 -- CX
contabtransluteo[ 99] = 0xC489 -- cx
contabtransluteo[ 71] = 0xC49C -- GX
contabtransluteo[103] = 0xC49D -- gx
contabtransluteo[ 74] = 0xC4B4 -- JX
contabtransluteo[106] = 0xC4B5 -- jx
contabtransluteo[ 83] = 0xC59C -- SX
contabtransluteo[115] = 0xC59D -- sx
contabtransluteo[ 85] = 0xC5AC -- UX breve
contabtransluteo[117] = 0xC5AD -- ux breve

-- constant strings (error circumfixes)

  local constrelabg = '<span class="error"><b>'  -- lagom whining begin
  local constrelaen = '</b></span>'              -- lagom whining end
  local constrlaxhu = '&nbsp;&#91;&#93;&nbsp;'   -- lagom -> huge circumfix " [] "

-- uncommentable EO vs ID constant table (error messages)

  -- #E02...#E98, holes permitted
  -- note that #E00 #E01 #E99 are NOT supposed to be included here

local contaberaroj = {}
      contaberaroj[06] = 'Erara uzo de %@, nekonata parametro'                                              -- EO #E06
        -- contaberaroj[06] = 'Penggunaan salah %@, parameter tidak dikenal'                                   -- ID #E06
      contaberaroj[8] = 'Erara uzo de %@, legu gxian dokumentajxon'                                         -- EO #E08
        -- contaberaroj[8] = 'Penggunaan salah %@, bacalah dokumentasinya'                                     -- ID #E08
      contaberaroj[14] = 'Erara uzo de %@ pro pagxonomo, estu unu signo'                                    -- EO #E14
        -- contaberaroj[14] = 'Penggunaan salah %@ oleh karena nama halaman, sebaiknya satu karakter"'         -- ID #E14
      contaberaroj[15] = 'Erara uzo de %@ pro "des=" priskriba parametro, estu majuskla'                    -- EO #E15
        -- contaberaroj[15] = 'Penggunaan salah %@ oleh karena "des=" parameter deskripsi, sebaiknya kapital'  -- ID #E15

  -- constant table (HTML)

-- beware of U+$2BD3 "Pluto's orb" and failure rectangle in FireFox  -- !!!FIXME!!! ??

local contabhtml = {}
  contabhtml.matabg = '<table style="float:right; margin:0 0 0.3em 0.3em; background-color:#DDEEFF; border:2px solid #AAAAFF; padding:0.1em;">'
  contabhtml[1] = '<tr><td style="padding:0.3em; text-align:center; font-size:600%; line-height:65%;">'
  contabhtml[2] = '<tr><td style="padding:0.1em; text-align:center; line-height:1em;">'
  contabhtml[3] = '</td></tr>'
  contabhtml.emprow = '<tr><td>&nbsp;</td></tr>' -- empty table row
  contabhtml.mataen = '</table>'

-- uncommentable EO vs ID constant table (unconditional boasting and ranges)

  -- ranges start at index 10 step 10
  -- +0 is name of the range
  -- +1 is starting codepoint
  -- +2 is last codepoint

local contabboasting = {}

      contabboasting [ 0] = "signo"       -- EO
        -- contabboasting [ 0] = "karakter"  -- ID
      contabboasting [ 1] = "unikoda"     -- EO
        -- contabboasting [ 1] = "unikode"   -- ID

      contabboasting [10] = "videbla askia"       -- EO
        -- contabboasting [10] = "ASCII terlihat"    -- ID
  contabboasting [11] = 33
  contabboasting [12] = 126

      contabboasting [20] = "minuskla askia"      -- EO
        -- contabboasting [20] = "ASCII kecil"       -- ID
  contabboasting [21] = 97
  contabboasting [22] = 122

  contabboasting [30] = "greka aux kopta"     -- EO
  -- contabboasting [30] = "Yunani atau Koptik"  -- ID
  contabboasting [31] = 880
  contabboasting [32] = 1023

  contabboasting [40] = "cirila"              -- EO
  -- contabboasting [40] = "sirilik"             -- ID
  contabboasting [41] = 1024
  contabboasting [42] = 1279

-- uncommentable (override)

-- * name of table MUST always be declared, OTOH elements are usually NOT
-- * for testing only, values automatically peeked otherwise

local contabovrd = {}
  -- contabovrd.sitelang = 'eo'                                     -- "en"
  -- contabovrd.parentfn = string.char(0xC5,0x9C) .. 'ablono:nope'  -- "Template:nope" (!!! no surr translation !!!)

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

---- MATH PROCEDURES [E] ----

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

local function mathisintrange (numzjinput, numzjmin, numzjmax)
  local booisclean = false -- preASSume guilt
  if (type(numzjinput)=='number') then -- no non-numbers, thanks
    if (numzjinput==math.floor(numzjinput)) then -- no transcendental
      booisclean = ((numzjinput>=numzjmin) and (numzjinput<=numzjmax)) -- rang
    end--if
  end--if
  return booisclean
end--function mathisintrange

local function mathdiv (xdividens, xdivisero)
  local resultdiv = 0 -- DIV operator lacks in LUA :-(
  resultdiv = math.floor (xdividens / xdivisero)
  return resultdiv
end--function mathdiv

local function mathmod (xdividendo, xdivisoro)
  local resultmod = 0 -- MOD operator is "%" and bitwise AND operator lack too
  resultmod = xdividendo % xdivisoro
  return resultmod
end--function mathmod

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

-- Local function MATHXOR

-- Depends on functions :
-- [E] mathdiv mathmod

local function mathxor (xa, xb)
  local numresultxor = 0
  local numpikaa = 0
  local numpikbb = 0
  local numbitshl = 1 -- single bit value 1 -> 2 -> 4 -> 8 ...
  while true do
    if ((xa==0) and (xb==0)) then
      break -- we have run out of bits on both
    end--if
    numpikaa = mathmod (xa,2) -- pick bit before dividing
    numpikbb = mathmod (xb,2) -- pick bit before dividing
    xa       = mathdiv (xa,2) -- shift right
    xb       = mathdiv (xb,2) -- shift right
    if (numpikaa~=numpikbb) then
      numresultxor = numresultxor + numbitshl -- add one bit rtl only if true
    end--if
    numbitshl = numbitshl * 2
  end--while
  return numresultxor
end--function mathxor

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

---- NUMBER CONVERSION PROCEDURES [N] ----

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

-- Local function LFNUINT8TOHEX

-- Convert UINT8 to string HEX fixed size 2 digits.

-- Depends on functions :
-- [E] mathdiv mathmod

local function lfnuint8tohex (numinclow)
  local strheksulo = ''
  local numhajhaj = 0
  numhajhaj = mathdiv (numinclow,16)
  numinclow = mathmod (numinclow,16)
  if (numhajhaj>9) then
    numhajhaj = numhajhaj + 7 -- now 0...9 or 17...22
  end--if
  if (numinclow>9) then
    numinclow = numinclow + 7 -- now 0...9 or 17...22
  end--if
  strheksulo = string.char (numhajhaj+48) .. string.char (numinclow+48)
  return strheksulo
end--function lfnuint8tohex

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

-- Local function LFUINT32TOHEX

-- Convert UINT32 (0 ... $FFFF'FFFF = #4'294'967'295) to
-- a (2 or 4 or 6 or 8)-digit hex string.

-- Depends on functions :
-- [N] lfnuint8tohex
-- [E] mathdiv mathmod

local function lfuint32tohex (numincom)
  local strheksulego = ''
  while true do
    strheksulego = lfnuint8tohex ( mathmod (numincom,256) ) .. strheksulego
    numincom = mathdiv (numincom,256)
    if (numincom==0) then
      break
    end--if
  end--while
  return strheksulego
end--function lfuint32tohex

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

-- Convert integer 0...99 to decimal ASCII string always 2 digits "00"..."99".

-- Depends on functions :
-- [E] mathisintrange mathdiv mathmod

local function lfnnumto2digit (numzerotoninetynine)
  local strtwodig = '??' -- always 2 digits
  if (mathisintrange(numzerotoninetynine,0,99)) then
    strtwodig = tostring(mathdiv(numzerotoninetynine,10)) .. tostring(mathmod(numzerotoninetynine,10))
  end--if
  return strtwodig
end--function lfnnumto2digit

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

-- Local function LFNUMTODECBUN

-- Convert non-negative integer to decimal string with bunching.

-- Depends on functions :
-- [E] mathdiv mathmod

local function lfnumtodecbun (numnomoriin)
  local strnomorut = ''
  local numindeex = 0
  local numcaar = 0
  numnomoriin = math.floor (numnomoriin) -- transcendental numbers suck
  if (numnomoriin<0) then
    numnomoriin = 0 -- negative numbers suck
  end--if
  while true do
    numcaar = mathmod(numnomoriin,10) + 48 -- get digit moving right to left
    numnomoriin = mathdiv(numnomoriin,10)
    if (numindeex==3) then
      strnomorut = "'" .. strnomorut -- ueglstr apo
      numindeex = 0
    end--if
    strnomorut = string.char(numcaar) .. strnomorut -- ueglstr digit
    numindeex = numindeex + 1
    if (numnomoriin==0) then
      break
    end--if
  end--while
  return strnomorut
end--function lfnumtodecbun

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

---- LOW LEVEL STRING PROCEDURES [G] ----

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

-- Local function LFGSTRINGRANGE

local function lfgstringrange (varvictim, nummini, nummaxi)
  local nummylengthofstr = 0
  local booveryvalid = false -- preASSume guilt
  if (type(varvictim)=='string') then
    nummylengthofstr = string.len(varvictim)
    booveryvalid = ((nummylengthofstr>=nummini) and (nummylengthofstr<=nummaxi))
  end--if
  return booveryvalid
end--function lfgstringrange

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

-- test whether char is an ASCII digit "0"..."9", return boolean

local function lftestnum (numkaad)
  local boodigit = false
  boodigit = ((numkaad>=48) and (numkaad<=57))
  return boodigit
end--function lftestnum

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

-- test whether char is an ASCII uppercase letter, return boolean

local function lftestuc (numkode)
  local booupperc = false
  booupperc = ((numkode>=65) and (numkode<=90))
  return booupperc
end--function lftestuc

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

---- UTF8 PROCEDURES [U] ----

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

-- Local function LFUTF8DEKO

-- Decode a UTF8 char, return ZERO length if invalid.

-- Result is a table: [0] length and [1] codepoint

-- Depends on functions :
-- [E] mathdiv mathmod mathxor

local function lfutf8deko (num0, num1, num2, num3)

  local tabresult = {}
  local numlength = 0 -- preASSume invalid
  local numkodepoin = 0 -- preASSume invalid

  num1 = mathxor (num1,128) -- XOR 3 of 4
  num2 = mathxor (num2,128) -- XOR 3 of 4
  num3 = mathxor (num3,128) -- XOR 3 of 4

  while true do -- fake loop

    if ((num0>193) and (num1>63)) then
      break -- to join mark
    end--if
    if ((num0>223) and (num2>63)) then
      break -- to join mark
    end--if
    if ((num0>239) and (num3>63)) then
      break -- to join mark
    end--if

    if (num0<128) then -- ZERO to $7F
      numkodepoin = num0
      numlength = 1
      break -- to join mark
    end--if

    if ((num0>193) and (num0<224)) then -- $C0 # $C2 to $DF
      numkodepoin = (mathxor(num0,192)) * 64 + num1
      if ((numkodepoin>127) and (numkodepoin<2048)) then
        numlength = 2
      end--if
      break -- to join mark
    end--if

    if ((num0>223) and (num0<240)) then -- $E0 to $EF
      numkodepoin = (mathxor(num0,224)) * 4096 + num1 * 64 + num2
      if (((numkodepoin>2047) and (numkodepoin<55296)) or ((numkodepoin>57343) and (numkodepoin<65536))) then
        numlength = 3
      end--if
      break -- to join mark
    end--if

    if ((num0>239) and (num0<245)) then -- $F0 to $F7 # $F4
      numkodepoin = (mathxor(num0,240)) * 262144 + num1 * 4096 + num2 * 64 + num3
      if ((numkodepoin>65535) and (numkodepoin<1114112)) then
        numlength = 4
      end--if
      break -- to join mark
    end--if

    break -- finally to join mark
  end--while -- fake loop -- join mark

  tabresult [0] = numlength
  tabresult [1] = numkodepoin
  return tabresult

end--function lfutf8deko

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

---- HIGH LEVEL STRING PROCEDURES [I] ----

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

local function lficheckuppernumdash (strmajstring)

local numloonng = 0
local numaprindex = 1 -- ONE-based
local numbagoct = 0
local booaprgood = true -- return true if valid

  numloonng = string.len (strmajstring)
  while true do
    if (numaprindex>numloonng) then
      break -- OK
    end--if
    numbagoct = string.byte (strmajstring,numaprindex,numaprindex)
    if ((numbagoct~=32) and (numbagoct~=45) and (not lftestnum(numbagoct)) and (not lftestuc(numbagoct))) then
      booaprgood = false
      break
    end--if
    numaprindex = numaprindex + 1
  end--while

  return booaprgood

end--function lficheckuppernumdash

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

local function lfiwordorder (boofalsidtrueen, strsbsb, strajaj)
  local strrezu4lt = ''
  if (boofalsidtrueen) then
    strrezu4lt = strajaj .. ' ' .. strsbsb -- "nigra lumo" EN EO SV
  else
    strrezu4lt = strsbsb .. ' ' .. strajaj -- "cahaya hitam" ID
  end--if
  return strrezu4lt
end--function lfiwordorder

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

---- HIGH LEVEL PROCEDURES [H] ----

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

-- Local function LFHCONSTRUCTERAR

-- Construct error message maybe peeking description.

-- Input  : * numerar3code -- 1 ... 98 or 2 ... 98 (resistant against invalid
--                            data type, giving "??" on such)
--          * boopeek3it   -- do peek description #E02...#E98 from table

-- Depends on procedures :
-- [N] lfnnumto2digit
-- [E] mathisintrange mathdiv mathmod

-- Depends on constants :
-- * maybe table contaberaroj TWO-based (holes permitted)

-- To be called ONLY from lfhbrewerror, lfhbrewerrsm,
-- lfhbrewerrsvr, lfhbrewerrinsi.

local function lfhconstructerar (numerar3code, boopeek3it)
  local vardes3krip = 0
  local numbottom3limit = 1
  local stryt3sux = '#E'
  if (boopeek3it) then
    numbottom3limit = 2 -- #E01 is a valid code for submodule only
  end--if
  if (mathisintrange(numerar3code,numbottom3limit,98)) then
    stryt3sux = stryt3sux .. lfnnumto2digit(numerar3code)
    if (boopeek3it) then
      vardes3krip = contaberaroj[numerar3code] -- risk of type "nil"
      if (type(vardes3krip)=='string') then
        stryt3sux = stryt3sux .. ' ' .. vardes3krip
      else
        stryt3sux = stryt3sux .. ' ??' -- no text found
      end--if
    end--if (boopeek3it) then
  else
    stryt3sux = stryt3sux .. '??' -- no valid error code
  end--if
  return stryt3sux

end--function lfhconstructerar

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

local function lfipl2altwre (strbeforfill, numaskikodo, varsupstitu)  -- !!!FIXME!!! move

-- Process all anon and fixed placeholders "%@" or "%~".

-- Input  : * strbeforfill -- request string with placeholders to be filled
--                            in, no placeholders or empty input is useless
--                            but cannot cause major harm
--          * numaskikodo  -- ASCII code of placeholder type, 64 for "%@" or
--                            126 for "%~"
--          * varsupstitu  -- substitute, either string (same content reused
--                            if multiple placeholders), or ZERO-based table
--                            (with one element per placeholder such as
--                            {[0]="none","neniu"}), length 1...80, further
--                            sanitization must be done elsewhere

-- Output : * strafterfill

-- Depends on procedures :
-- [G] lfgstringrange

local varpfiller    = 0  -- risky picking
local strufiller    = '' -- final validated filler
local strafterfill  = ''
local numlenbigtext = 0  -- len of strbeforfill
local numsfrcindex  = 0  -- char index ZERO-based
local numinsrtinde  = 0  -- index in table ZERO-based
local numtecken0d   = 0
local numtecken1d   = 0

  numlenbigtext = string.len (strbeforfill)

  while true do
    if (numsfrcindex>=numlenbigtext) then
      break -- empty input is useless but cannot cause major harm
    end--if
    numtecken0d = string.byte(strbeforfill,(numsfrcindex+1),(numsfrcindex+1))
    numsfrcindex = numsfrcindex + 1 -- INC here
    numtecken1d = 0 -- preASSume none
    if (numsfrcindex<numlenbigtext) then -- pick but do NOT INC
      numtecken1d = string.byte(strbeforfill,(numsfrcindex+1),(numsfrcindex+1))
    end--if
    if ((numtecken0d==37) and (numtecken1d==numaskikodo)) then -- "%@" "%~"
      numsfrcindex = numsfrcindex + 1 -- INC more, now totally + 2
      varpfiller = 0 -- preASSume nothing available
      strufiller = '??' -- preASSume nothing available
      if (type(varsupstitu)=='string') then
        varpfiller = varsupstitu -- take it as-is (length check below)
      end--if
      if (type(varsupstitu)=='table') then
        varpfiller = varsupstitu [numinsrtinde] -- risk of type "nil"
        numinsrtinde = numinsrtinde + 1 -- INC tab index on every placeholder
      end--if
      if (lfgstringrange(varpfiller,1,80)) then -- restrict
        strufiller = varpfiller -- now the substitute is finally accepted
      end--if
    else
      strufiller = string.char (numtecken0d) -- no placeholder -> copy octet
    end--if
    strafterfill = strafterfill .. strufiller -- add one of 4 possible cases
  end--while

return strafterfill

end--function lfipl2altwre

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

-- Local function LFHBREWERROR

-- Input  : * numerar6code -- TWO-based error code 2 ... 98 (resistant
--                            against invalid data type, giving "??" on such)
--          * strcaller6nm -- name of parent (not used and should be type
--                            "nil" if message does NOT contain "%@")

-- Output : * stryt6sux -- message with HTML

-- Depends on procedures :
-- [H] lfhconstructerar
-- [I] lfipl2altwre
-- [G] lfgstringrange
-- [N] lfnnumto2digit
-- [E] mathisintrange mathdiv mathmod

-- Depends on constants :
-- * 3 strings constrelabg constrelaen constrlaxhu
-- * table contaberaroj TWO-based (holes permitted)

-- #E02...#E98, note that #E00 #E01 #E99 are NOT supposed to be included here.

local function lfhbrewerror (numerar6code, strcaller6nm)
  local stryt6sux = ''
  stryt6sux = constrlaxhu .. constrelabg .. lfipl2altwre(lfhconstructerar(numerar6code,true),64,strcaller6nm) .. constrelaen .. constrlaxhu
  return stryt6sux
end--function lfhbrewerror

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

-- Local function LFIKODEOSG  !!!FIXME!!! move and update

-- Transcode eo X-surrogates to cxapeloj in a single string (EO only).

-- Input  : * strsurr -- ANSI string (empty is useless but cannot
--                                    cause major harm)

-- Output : * strcxapeloj -- UTF8 string

-- Depends on functions :
-- [E] mathdiv mathmod

-- Depends on constants :
-- * table "contabtransluteo"

-- * the "x" is case insensitive, both "kacxo" and "kacXo" give same result
-- * avoid "\", thus for example "ka\cxo" would get converted but the "\" kept
-- * double "x" prevents conversion and becomes reduced to single
--   "x", for example "kacxxo" becomes "kacxo"

local function lfikodeosg (strsurr)

  local varpeekz = 0
  local strcxapeloj = ''
  local numinputl = 0
  local numinpinx = 0 -- ZERO-based source index
  local numknar0k = 0 -- current char
  local numknaf1x = 0 -- next char (ZERO is NOT valid)
  local numknaf2x = 0 -- post next char (ZERO is NOT valid)
  local boonext1x = false
  local boonext2x = false
  local boosudahdone = false

  numinputl = string.len(strsurr)

  while true do

    if (numinpinx>=numinputl) then
      break
    end--if

    numknar0k = string.byte(strsurr,(numinpinx+1),(numinpinx+1))
    numknaf1x = 0
    numknaf2x = 0
    if ((numinpinx+1)<numinputl) then
      numknaf1x = string.byte(strsurr,(numinpinx+2),(numinpinx+2))
    end--if
    if ((numinpinx+2)<numinputl) then
      numknaf2x = string.byte(strsurr,(numinpinx+3),(numinpinx+3))
    end--if

    boonext1x = ((numknaf1x==88) or (numknaf1x==120))
    boonext2x = ((numknaf2x==88) or (numknaf2x==120))
    boosudahdone = false
    if (boonext1x and boonext2x) then -- got "xx"
      strcxapeloj = strcxapeloj .. string.char(numknar0k,numknaf1x) -- keep one "x" only
      numinpinx = numinpinx + 3 -- eaten 3 written 2
      boosudahdone = true
    end--if
    if (boonext1x and (not boonext2x)) then -- got yes-"x" and no-"x"
      varpeekz = contabtransluteo[numknar0k] -- UINT16 or type "nil"
      if (type(varpeekz)=="number") then
        strcxapeloj = strcxapeloj .. string.char(mathdiv(varpeekz,256),mathmod(varpeekz,256)) -- add UTF8 char
        numinpinx = numinpinx + 2 -- eaten 2 written 2
        boosudahdone = true
      end--if
    end--if
    if (not boosudahdone) then
      strcxapeloj = strcxapeloj .. string.char(numknar0k) -- copy char
      numinpinx = numinpinx + 1 -- eaten 1 written 1
    end--if

  end--while

  return strcxapeloj

end--function lfikodeosg

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

-- Local function LFHRECUSURRSTRTAB  !!!FIXME!!! update beware wrong set of 3 param

-- Process (fill in, transcode, ...) all string items in a table
-- using any type of keys/indexes (such as a number sequence
-- and non-numeric ones). Items with a non-string value are kept
-- as-is. Usable for filling in own name, and converting of eo
-- X-surrogates to cxapeloj (both via separate sub:s).

-- Input  : * varfyllo -- string, or type "nil" if no filling-in desired
--          * booeoxx -- boolean, true to convert X-surrogates

-- Depends on functions :
-- [I] lfikodeosg (only if converting of eo X-surrogates desired)
-- [E] mathdiv mathmod (via "lfikodeosg")

-- Depends on constants :
-- * table "contabtransluteo" inherently holey (via "lfikodeosg")

local function lfhrecusurrstrtab (tabinkommen, varfyllo, booeoxx)
  local varkey = 0 -- variable without type
  local varele = 0 -- variable without type
  local tabutmatning = {}
  varkey = next (tabinkommen) -- try to pick 0:th (in no order) key/index
  while true do
    if (varkey==nil) then
      break -- empty table or end reached
    end--if
    varele = tabinkommen[varkey] -- pick element of unknown type
    if (type(varele)=="string") then
      if (booeoxx) then
        varele = lfikodeosg (varele) -- convert
      end--if
    end--if
    tabutmatning[varkey] = varele -- put it back at same place in other table
    varkey = next (tabinkommen, varkey) -- try to pick next key/index
  end--while
  return tabutmatning
end--function lfhrecusurrstrtab

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

---- VARIABLES [R] ----

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

function exporttable.ek (arxframent)

  -- misc unknown type

  local vartymp = 0

  -- special type "args" AKA "arx"

  local arxsomons = 0 -- metaized "args" from our own or parent's "frame"

  -- general tab

  local tabutf8dec = {}

  -- general str

  local strpiklangcode = '' -- "en" privileged site language
  local strpikparent   = '' -- "Template:nope" FULLPAGENAME

  local strpagenam  = '' -- from "{{PAGENAME}}" or "pagenameoverridetestonly"
  local strdesdes   = '' -- "des="
  local strenen     = '' -- "en="
  local strslsl     = '' -- "sl="

  local strtomp     = '' -- temp
  local strextra    = '' -- 1 or 2 extra lines with TR&TD-stuff
  local strviserr   = '' -- visible error
  local strvisgud   = '' -- visible good output
  local strret      = '' -- final result string

  -- general num

  local numerr    = 0  -- 1 inter 2 param 14 pagename 15 des
  local numutflen = 0  -- decoded length (ZERO invalid)
  local numdecode = 0  -- decoded "codepoint" value
  local numlong   = 0  -- length of pagename
  local numoct    = 0  -- temp some char
  local numodt    = 0  -- temp some char
  local numoet    = 0  -- temp some char
  local numoft    = 0  -- temp some char
  local numtamp   = 0

  -- general boo

  local boohavdes   = false
  local boohaven    = false
  local boohavsl    = false
  local boowordenor = false -- false ID word order | true EN word order

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

---- MAIN [Z] ----

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

  ---- PEEK STUFF THAT IS NOT OVERRIDDEN ----

  -- this depends on "arxframent" (only if parent requested) but NOT on "arx"

  if (numerr==0) then
    strpiklangcode = contabovrd.sitelang or mw.getContentLanguage():getCode() or 'en'              -- privileged site language
    strpikparent   = contabovrd.parentfn or arxframent:getParent():getTitle() or 'Template:signo'  -- fullpagename
    if ((type(strpiklangcode)~='string') or (type(strpikparent)~='string')) then
      numerr = 1 -- #E01 internal (unlikely)
    end--if
  end--if (numerr==0) then

  ---- PROCESS ERROR MESSAGES ----

  if (numerr==0) then
    contaberaroj = lfhrecusurrstrtab (contaberaroj, '', (strpiklangcode=='eo'))  -- !!!FIXME!!! wrong set of 3
  end--if
  if ((numerr==0) and (strpiklangcode=='eo')) then
    contabboasting[30] = lfikodeosg (contabboasting[30])  -- !!!FIXME!!! merge with above
  end--if

  ---- GET THE ARX (ONE OF TWO) ----

  -- must be seized independently on "numerr" even if we already suck

  -- give a f**k in possible anon params for now

  arxsomons = arxframent.args -- "args" from our own "frame"
  if (type(arxsomons)~='table') then
    arxsomons = {} -- guard against indexing error
    numerr = 1 -- #E01 internal
  end--if
  if (arxsomons['parentframe']=='true') then
    arxsomons = arxframent:getParent().args -- "args" from caller's "frame"
  end--if
  if (type(arxsomons)~='table') then
    arxsomons = {} -- guard against indexing error again
    numerr = 1 -- #E01 internal
  end--if

  ---- PROCESS ONE HIDDEN NAMED PARAM PAGENAME ----

  -- this may override "mw.title.getCurrentTitle().text" and
  -- stipulate content in "strpagenam", missing OK, empty is NOT valid

  -- bad "pagenameoverridetestonly=" can give #E01

  -- give a f**k in possible anon params for now

  strpagenam = '' -- using vartymp here
  if (numerr==0) then -- get pagename (error if bad, silent if absent)
    vartymp = arxsomons['pagenameoverridetestonly']
    if (type(vartymp)=='string') then -- do NOT merge if:s
      if (lfgstringrange(vartymp,1,120)) then -- empty or too long NOT legal
        strpagenam = vartymp
      else
        numerr = 1 -- #E01 internal
      end--if
    end--if
  end--if

  ---- SEIZE THE PAGENAME FROM MW AFTER OVERRIDE AND PROHIBIT EMPTY ----

  -- later reporting of #E01 may NOT depend on uncommentable strings

  -- must be 1...120 octet:s keep consistent with "pagenameoverridetestonly="

  if ((numerr==0) and (strpagenam=='')) then -- get pagename (error if bad)
    vartymp = mw.title.getCurrentTitle().text -- without namespace prefix
    if (lfgstringrange(vartymp,1,120)) then -- empty or too long NOT legal
      strpagenam = vartymp -- cannot be left empty
    else
      numerr = 1 -- #E01 internal
    end--if
  end--if

  ---- WHINE IF YOU MUST #E01 ----

  -- reporting of this error #E01 may NOT depend on
  -- uncommentable strings such as "strpikparent" and "contaberaroj"

  -- do NOT use "lfhbrewerror", report our name (NOT of template) and in EN

  if (numerr==1) then
    strtomp = '#E01 Internal error in "Module:mchar".'
    strviserr = constrlaxhu .. constrelabg .. strtomp .. constrelaen .. constrlaxhu
  end--if

  ---- PROHIBIT ANON PARAM ----

  if ((numerr==0) and (arxsomons[1])) then
    numerr = 6 -- #E06 param
  end--if

  ---- PROCESS 3 NAMED AND OPTIONAL PARAMS ----

  -- "des=" (restrictive: only uppercase !!! bad -> #E15)
  -- "en=" "sl=" (bad -> #E08)
  -- minimum is 3 pga "SUN" U+$2609

  if (numerr==0) then
    while true do -- fake loop -- abort on both success or failure -- "des="
      vartymp = arxsomons['des'] -- "des="
      if (type(vartymp)~='string') then
        break -- parameter not supplied, OK
      end--if
      if (not lfgstringrange(vartymp,3,80)) then
        numerr = 15 -- #E15
        break
      end--if
      if (not lficheckuppernumdash(vartymp)) then
        numerr = 15 -- #E15 "des=" bad (all chars must be number or uc or "-")
        break
      end--if
      boohavdes = true
      strdesdes = vartymp
      break -- finally
    end--while
  end--if

  if (numerr==0) then
    while true do -- fake loop -- abort on both success or failure -- "en="
      vartymp = arxsomons['en']
      if (type(vartymp)~='string') then
        break -- parameter not supplied, OK
      end--if
      if (not lfgstringrange(vartymp,3,80)) then
        numerr = 8 -- #E08
        break
      end--if
      boohaven = true
      strenen = vartymp
      break -- finally
    end--while
  end--if

  if (numerr==0) then
    while true do -- fake loop -- abort on both success or failure -- "sl="
      vartymp = arxsomons['sl']
      if (type(vartymp)~="string") then
        break -- parameter not supplied
      end--if
      numtamp = string.len(vartymp)
      if ((numtamp<3) or (numtamp>80)) then
        numerr = 8 -- #E08
        break
      end--if
      boohavsl = true
      strslsl = vartymp
      break -- finally
    end--while
  end--if

  ---- DECODE THE PAGENAME AND CHECK VALIDITY ----

  -- it is in "strpagenam" and nonempty

  -- decoding if longer than 4 octet:s is actually unneeded

  if (numerr==0) then
    numlong = string.len (strpagenam) -- 1...120 legal so far but see below
    numoct = string.byte (strpagenam,1,1)
    numodt = 0
    numoet = 0 -- preASSume 3 x
    numoft = 0
    if (numlong>=2) then
      numodt = string.byte (strpagenam,2,2)
    end--if
    if (numlong>=3) then
      numoet = string.byte (strpagenam,3,3)
    end--if
    if (numlong>=4) then
      numoft = string.byte (strpagenam,4,4)
    end--if
    tabutf8dec = lfutf8deko (numoct,numodt,numoet,numoft)
    numutflen = tabutf8dec [0]
    numdecode = tabutf8dec [1]
    if (numutflen~=numlong) then
      numerr = 14 -- #E14 -- length must be one character only
    end--if
  end--if

  ---- WHINE IF YOU MUST #E02...#E98 ----

  -- reporting of errors #E02...#E98 depends on uncommentable strings

  if (numerr>=2) then
    strviserr = lfhbrewerror(numerr,('"'..strpikparent..'"'))
  end--if

  ---- PREBREW 1 OR 2 OR MORE EXTRA LINES ----

  -- incoming "numdecode"

  -- this depends on "strpiklangcode"

  -- this depends on "contabhtml" and "contabboasting"

  -- we can get multiple ranges and one more table row for every of them

  boowordenor = (strpiklangcode=="eo") -- true for EN EO SV ...

  if (numerr==0) then
    do -- scope
      local varte3mp = 0
      local strte3mp = ''
      local numtmp10z = 0
      strte3mp = lfiwordorder (boowordenor, contabboasting[0], contabboasting[1])
      strextra = contabhtml[2] .. strte3mp .. contabhtml[3] -- unconditional line
      numtmp10z = 10 -- index step 10
      while true do -- search range 10 11 12 -> 20 21 22 ...
        varte3mp = contabboasting[numtmp10z] -- risk of type "nil"
        if (type(varte3mp)~="string") then -- number of ranges is NOT hardcoded
          break -- end of table, found ZERO or ONE or more
        end--if
        if ((contabboasting[numtmp10z+1]<=numdecode) and (numdecode<=contabboasting[numtmp10z+2])) then
          strte3mp = lfiwordorder (boowordenor, contabboasting[0], varte3mp)
          strextra = strextra .. contabhtml[2] .. strte3mp .. contabhtml[3]
        end--if
        numtmp10z = numtmp10z + 10 -- step 10 !!!
      end--while
    end--do scope
  end--if (numerr==0) then

  ---- BREW THE BOX ----

  -- incoming "strpagenam" and "numdecode" and "strextra"

  -- do NOT link "des" but do link "en" and "sl" (EO or ID)

  -- this depends on "contabhtml"

  if (numerr==0) then
    strvisgud = contabhtml.matabg .. strextra -- begin table and 1 or 2 lines
    strvisgud = strvisgud .. contabhtml[1] .. strpagenam .. contabhtml[3] .. contabhtml.emprow
    strvisgud = strvisgud .. contabhtml[2] .. "<small>kodopunkto</small> U+$" .. lfuint32tohex (numdecode) .. contabhtml[3]
    strvisgud = strvisgud .. contabhtml[2] .. "<small>dec</small> #" .. lfnumtodecbun (numdecode) .. contabhtml[3]
    if (boohavdes) then
      strvisgud = strvisgud .. contabhtml[2] .. strdesdes .. contabhtml[3]
    end--if
    if (boohaven) then
      strvisgud = strvisgud .. contabhtml[2] .. '[[' .. strenen .. ']]' .. contabhtml[3]
    end--if
    if (boohavsl) then
      strvisgud = strvisgud .. contabhtml[2] .. '[[' .. strslsl .. ']]' .. contabhtml[3]
    end--if
    strvisgud = strvisgud .. contabhtml.mataen -- close table
  end--if

  ---- RETURN THE JUNK STRING ----

  strret = strviserr .. strvisgud
  return strret

end--function

  ---- RETURN THE JUNK LUA TABLE ----

return exporttable