Modulo:mchar

El Vikivortaro
Salti al navigilo Salti al serĉilo





--[===[

MODULE "MCHAR" (unicode character)

"eo.wiktionary.org/wiki/Modulo:mchar" <!--2022-Jul-07-->
"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 caller (caller's frame). If there is a parameter "caller=true"
on the own frame then that own frame is discarded in favor of the
caller'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 a HTML table or inline ERROR

]===]

local ch = {}

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

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

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

  -- uncommentable EO vs ID constant strings (core site-related features)

  local constrpriv = "eo"                 -- EO (privileged site language)
  -- local constrpriv = "id"                 -- ID (privileged site language)

  -- constant table (surrogate transcoding table, only needed for EO)

  local contabtransiltable = {}
  contabtransiltable[ 67] = 0xC488 -- CX
  contabtransiltable[ 99] = 0xC489 -- cx
  contabtransiltable[ 71] = 0xC49C -- GX
  contabtransiltable[103] = 0xC49D -- gx
  contabtransiltable[ 74] = 0xC4B4 -- JX
  contabtransiltable[106] = 0xC4B5 -- jx
  contabtransiltable[ 83] = 0xC59C -- SX
  contabtransiltable[115] = 0xC59D -- sx
  contabtransiltable[ 85] = 0xC5AC -- UX breve
  contabtransiltable[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 string (caller name for error messages)

  local constrkoll = 'sxablono "signo"'    -- EO augmented name of the caller (semi-hardcoded, we do NOT peek it)
  -- local constrkoll = 'templat "karakter"'  -- ID augmented name of the caller (semi-hardcoded, we do NOT peek it)

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

  -- #E02...#E99, holes permitted (max 3 consecutive)
  -- note that #E00 and #E01 are NOT supposed to be included here
  -- separate "constrkoll" needed for "\\@"

  local contaberaroj = {}
  contaberaroj[2] = 'Erara uzo de \\@, legu gxian dokumentajxon'                                       -- EO #E02
  -- contaberaroj[2] = 'Penggunaan salah \\@, bacalah dokumentasinya'                                     -- ID #E02
  contaberaroj[3] = 'Erara uzo de \\@ pro pagxonomo, estu unu signo'                                   -- EO #E03
  -- contaberaroj[3] = 'Penggunaan salah \\@ oleh karena nama halaman, sebaiknya satu karakter"'          -- ID #E03
  contaberaroj[4] = 'Erara uzo de \\@ pro "des=" priskriba parametro, estu majuskla'                   -- EO #E04
  -- contaberaroj[4] = 'Penggunaan salah \\@ oleh karena "des=" parameter deskripsi, sebaiknya kapital'   -- ID #E04

  -- constant table (HTML)

  -- beware of U+$2BD3 and failure rectangle in FireFox

  local contabhtml = {}
  contabhtml[0] = '<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[4] = '<tr><td>&nbsp;</td></tr>' -- empty table row
  contabhtml[5] = '</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] = "greka aux kopta"
  -- contabboasting [20] = "Yunani atau Koptik"
  contabboasting [21] = 880
  contabboasting [22] = 1023

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

---- SPECIAL STUFF OUTSIDE MAIN [B] ----

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

---- VAR:S ----

local qbooguard = false  -- only for the guard test, pass to other var ASAP

---- GUARD AGAINST INTERNAL ERROR ----

if ((type(constrpriv)~="string") or (type(constrkoll)~="string")) then
  qbooguard = true
end--if

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

---- MATH FUNCTIONS [E] ----

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

local function mathmin (xmindd, xminee)
  local resultmin = 0 -- min operator lacks in LUA :-(
  resultmin = xmindd
  if (resultmin>xminee) then
    resultmin = xminee
  end--if
  return resultmin
end--function mathmin

local function mathdiv (xdividend, xdivisor)
  local resultdiv = 0 -- DIV operator lacks in LUA :-(
  resultdiv = math.floor (xdividend / xdivisor)
  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

-- This sub depends on "MATH FUNCTIONS"\"mathdiv"
-- and "MATH FUNCTIONS"\"mathmod".

local function mathxor (xa, xb)
  local resultxor = 0
  local crap6 = 0
  local crap7 = 0
  local crap8 = 1 -- single bit value 1 -> 2 -> 4 -> 8 ...
  while (true) do
    if ((xa==0) and (xb==0)) then
      break
    end--if
    crap6 = mathmod (xa,2) -- seize remainder before dividing
    crap7 = mathmod (xb,2) -- seize remainder before dividing
    xa    = mathdiv (xa,2)
    xb    = mathdiv (xb,2)
    if (crap6~=crap7) then
      resultxor = resultxor + crap8
    end--if
    crap8 = crap8 * 2
  end--while
  return resultxor
end--function mathxor

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

---- NUMBER CONVERSION FUNCTIONS [N] ----

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

-- Local function LFUINT8TOHEX

-- Convert UINT8 (0...255) to a 2-digit hex string.

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

local function lfuint8tohex (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 lfuint8tohex

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

-- Local function LFUINT32TOHEX

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

-- This sub depends on "MATH FUNCTIONS"\"mathdiv" and
-- "MATH FUNCTIONS"\"mathmod" and "CONVERSION FUNCTIONS"\"lfuint8tohex".

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

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

-- Local function LFNUMTODECBUN

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

-- This sub depends on "MATH FUNCTIONS"\"mathdiv"
-- and "MATH FUNCTIONS"\"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

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

-- Local function LFNUMTO2DIGIT

-- Convert integer 0...99 to 2-digit decimal string "00"..."99".

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

local function lfnumto2digit (numzerotoninetynine)
  local strtwodig = '' -- always 2 digits
  numzerotoninetynine = math.floor (numzerotoninetynine) -- no transcendental
  numzerotoninetynine = mathmin (numzerotoninetynine,99) -- no trillions
  strtwodig = tostring(mathdiv(numzerotoninetynine,10)) .. tostring(mathmod(numzerotoninetynine,10))
  return strtwodig
end--function lfnumto2digit

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

---- LOW LEVEL STRING FUNCTIONS [G] ----

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

-- 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 FUNCTIONS [U] ----

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

-- Local function LFUTF8DEKO

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

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

-- This sub depends on "MATH FUNCTIONS"\"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 FUNCTIONS [H] ----

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

-- Local function LFBREWERROR

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

-- We need 3 const strings "constrelabg", "constrelaen",
-- "constrlaxhu" and const table "contaberaroj".

-- This sub depends on "CONVERSION FUNCTIONS"\"lfnumto2digit".

local function lfbrewerror (numerrorcode)
  local vardeskrip = 0
  local strytsux = '#E'
  vardeskrip = contaberaroj[numerrorcode] -- risk of type "nil"
  if (type(vardeskrip)=="string") then
    strytsux = strytsux .. lfnumto2digit(numerrorcode) .. ' ' .. vardeskrip
  else
    strytsux = strytsux .. '??'
  end--if
  strytsux = constrlaxhu .. constrelabg .. strytsux .. constrelaen .. constrlaxhu
  return strytsux
end--function lfbrewerror

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

-- Local function LFIFILLNAME

-- Replace placeholder "\@" "\\@" by augmented name of the caller.

-- The caller name is submitted to us as a parameter thus we
-- do NOT access any constants and do NOT have to peek it either.

local function lfifillname (strmessage,strcaller)

  local strhasill = ''
  local numstrloen = 0
  local numindfx = 1 -- ONE-based
  local numcjar = 0
  local numcjnext = 0

  numstrloen = string.len (strmessage)

  while (true) do
    if (numindfx>numstrloen) then
      break -- empty input is useless but cannot cause major harm
    end--if
    numcjar = string.byte (strmessage,numindfx,numindfx)
    numindfx = numindfx + 1
    numcjnext = 0
    if (numindfx<=numstrloen) then
      numcjnext = string.byte (strmessage,numindfx,numindfx)
    end--if
    if ((numcjar==92) and (numcjnext==64)) then
      strhasill = strhasill .. strcaller -- invalid input is caller's risk
      numindfx = numindfx + 1 -- skip 2 octet:s of the placeholder
    else
      strhasill = strhasill .. string.char (numcjar)
    end--if
  end--while

  return strhasill

end--function lfifillname

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

-- Local function LFIKODEOSG

-- 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

-- * 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"

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

-- Depends on constants :
-- * table "contabtransiltable" holy

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 = contabtransiltable[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 LFHKODEOTBA

-- Process (fill in, transcode, ...) all string items in a table
-- using any type of keys/indexes (such as a holy 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 -- type "nil" if no filling-in desired
--          * booeoxx -- true to convert X-surrogates

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

-- Depends on constants :
-- * table "contabtransiltable" inherently holy (via "lfikodeosg")

local function lfhkodeotba (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 (type(varfyllo)=="string") then
        varele = lfifillname (varele,varfyllo) -- fill-in
      end--if
      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 lfhkodeotba

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

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

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

function ch.ek (arxframent)

  -- general unknown type

  local vartmp = 0     -- variable without type multipurpose

  -- special type "args" AKA "arx"

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

  -- general tab

  local tabutf8dec = {}

  -- general str

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

  local strtmp      = '' -- 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 3 pagename 4 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
  local numtump   = 0

  -- general boo

  local boohavdes  = false
  local boohaven   = false
  local boohavsl   = false

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

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

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

  ---- GUARD AGAINST INTERNAL ERROR AGAIN ----

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

  if (qbooguard) then
    numerr = 1 -- #E01 internal
  end--if

  ---- PROCESS ERROR MESSAGES, FILL IN ALWAYS, CONVERT EO ONLY IF NEEDED ----

  -- placeholder "\@" "\\@" is replaced by augmented name of the caller
  -- from "constrkoll" in any case, for example 'sxablono "test"' or
  -- 'templat "test"', only for EO the X-substitution is subsequently done

  if (numerr==0) then
    contaberaroj = lfhkodeotba (contaberaroj, constrkoll, (constrpriv=="eo"))
  end--if

  ---- TRANSCODE EO IF NEEDED ----

  if ((numerr==0) and (constrpriv=="eo")) then
    contabboasting[20] = lfikodeosg (contabboasting[20])
  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 (would cause #E02)

  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['caller']=="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 1 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 (would cause #E02)

  strpagenam = ""
  if (numerr==0) then
    vartmp = arxsomons['pagenameoverridetestonly']
    if (type(vartmp)=="string") then
      numtamp = string.len(vartmp)
      if ((numtamp>=1) and (numtamp<=120)) then
        strpagenam = vartmp -- empty is not legal
      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
    vartmp = mw.title.getCurrentTitle().text -- without namespace prefix
    if (type(vartmp)=="string") then -- this can leave bhnd "strpagenam" empty
      numtamp = string.len(vartmp)
      if ((numtamp>=1) and (numtamp<=120)) then
        strpagenam = vartmp -- pagename here (empty is NOT legal)
      else
        numerr = 1 -- #E01 internal
      end--if
    end--if
  end--if

  if (strpagenam=='') then
    numerr = 1 -- #E01 internal -- no other error is possible so far
  end--if

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

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

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

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

  ---- PROHIBIT ANON ----

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

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

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

  if (numerr==0) then
    while (true) do -- fake loop -- abort on both success or failure -- "des="
      vartmp = arxsomons['des'] -- "des="
      if (type(vartmp)~="string") then
        break -- parameter not supplied
      end--if
      numtamp = string.len(vartmp)
      if ((numtamp<3) or (numtamp>80)) then
        numerr = 4 -- #E04
        break
      end--if
      boohavdes = true
      strdesdes = vartmp
      numlong = string.len (strdesdes)
      numtamp = 1 -- ONE-based
      while (true) do -- inner genuine loop
        if (numtamp>numlong) then
          break -- inner -- OK
        end--if
        numoct = string.byte (strdesdes,numtamp,numtamp)
        if ((lftestnum(numoct)==false) and (lftestuc(numoct)==false) and (numoct~=32) and (numoct~=45)) then
          numerr = 4 -- #E04 "des=" bad (must be number or uc or "-")
          break -- inner
        end--if
        numtamp = numtamp + 1
      end--while
      break -- finally
    end--while
  end--if

  if (numerr==0) then
    while (true) do -- fake loop -- abort on both success or failure -- "en="
      vartmp = arxsomons['en']
      if (type(vartmp)~="string") then
        break -- parameter not supplied
      end--if
      numtamp = string.len(vartmp)
      if ((numtamp<3) or (numtamp>80)) then
        numerr = 2 -- #E02
        break
      end--if
      boohaven = true
      strenen = vartmp
      break -- finally
    end--while
  end--if

  if (numerr==0) then
    while (true) do -- fake loop -- abort on both success or failure -- "sl="
      vartmp = arxsomons['sl']
      if (type(vartmp)~="string") then
        break -- parameter not supplied
      end--if
      numtamp = string.len(vartmp)
      if ((numtamp<3) or (numtamp>80)) then
        numerr = 2 -- #E02
        break
      end--if
      boohavsl = true
      strslsl = vartmp
      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
    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 = 3 -- #E03 -- length must be one character only
    end--if
  end--if

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

  -- reporting of errors #E02...#E99 depends on uncommentable strings
  -- and name of the caller filled in from "constrkoll"

  if (numerr>1) then
    strviserr = lfbrewerror(numerr)
  end--if

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

  -- incoming "numdecode"

  -- this depends on "constrpriv"

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

  if (numerr==0) then
    if (constrpriv=="eo") then
      strtmp = contabboasting[1] .. ' ' .. contabboasting[0] -- "nigra lumo"
    else
      strtmp = contabboasting[0] .. ' ' .. contabboasting[1] -- "cahaya hitam"
    end--if
    strextra = contabhtml[2] .. strtmp .. contabhtml[3] -- unconditional line
    numtamp = 10 -- index step 10
    strtmp = '' -- preassume bugger all
    while (true) do
      vartmp = contabboasting[numtamp] -- risk of type "nil"
      if (type(vartmp)~="string") then -- number of ranges is NOT hardcoded
        break -- NOT found
      end--if
      if ((contabboasting[numtamp+1]<=numdecode) and (numdecode<=contabboasting[numtamp+2])) then
        strtmp = vartmp -- name of the range
        break -- found the range
      end--if
      numtamp = numtamp + 10 -- step 10 !!!
    end--while
    if (strtmp~='') then
      if (constrpriv=="eo") then
        strtmp = strtmp .. ' ' .. contabboasting[0] -- "griza lumo"
      else
        strtmp = contabboasting[0] .. ' ' .. strtmp -- "cahaya abu-abu"
      end--if
      strextra = strextra .. contabhtml[2] .. strtmp .. contabhtml[3]
    end--if
  end--if

  ---- 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[0] .. strextra -- begin table and 1 or 2 lines
    strvisgud = strvisgud .. contabhtml[1] .. strpagenam .. contabhtml[3] .. contabhtml[4]
    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[5] -- close table
  end--if

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

  strret = strviserr .. strvisgud
  return strret

end--function

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

return ch