MODULO
Memtesto disponeblas sur la dokumentaĵa subpaĝo.

--[===[

MODULE "MDEV32KAT" (deveno 3 2 kategorioj)

"eo.wiktionary.org/wiki/Modulo:mdev32kat" <!--2024-Jan-19-->

Purpose: brews 2 cat insertions from 2 language codes

Utilo: kreas 2 kategorienmetojn el 2 lingvokodoj

Manfaat: membutat 2 masukan kategori dari 2 kode bahasa

Syfte: skapar 2 kategoriinlaeggningar ...

Used by templates / Uzata far sxablonoj / Digunakan oleh templat:
- deveno3 (EO)

Required submodules / Bezonataj submoduloj / Submodul yang diperlukan:
- "loaddata-tbllingvoj" T76 in turn requiring template "tbllingvoj" (EO)

Incoming: - 2 anonymous obligatory parameters
              - lemma language code (kapvorta)
              - origin language code (devena)
          - 2 named optional parameters somewhat hidden
              - "noc=" only possible value is "true" (any other value
                ignored), "true" causes empty result, forward "nocat="
                to this one if desired
              - "detrc=" only possible value is "true"

Returned: - one string with 2 cat insertions or empty on error or
            if "noc=" is "true"

{{hr3}} <!-------------------------------->

* #T00 ("en", missing param)
* expected result: empty
* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|en}}|outctl=nw}}"

::* #T01 ("en|eo|vo", three params)
::* expected result: empty
::* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|en|eo|vo}}|outctl=nw}}"

* #T02 ("en|art", invalid code latter)
* expected result: empty
* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|en|art}}|outctl=nw}}"

::* #T03 ("deu|en", invalid code former)
::* expected result: empty
::* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|deu|en}}|outctl=nw}}"

* #T04 ("en|zzz", unknown code latter)
* expected result: empty
* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|en|zzz}}|outctl=nw}}"

::* #T05 ("zzz|en", unknown code former)
::* expected result: empty
::* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|zzz|en}}|outctl=nw}}"

* #T06 ("en|grc|noc=true", suppression)
* expected result: empty
* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|en|grc|noc=true}}|outctl=nw}}"

{{hr3}} <!-------------------------------->

* #T10 ("en|grc")
* expected result: 2 cats ("El la greka" ...)
* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|en|grc}}|outctl=nw}}"

::* #T11 ("grc|en", silly example)
::* expected result: 2 cats ("El la angla" ...)
::* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|grc|en}}|outctl=nw}}"

* #T12 ("en|vo", silly example)
* expected result: 2 cats ("El Volapuko" ...)
* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|en|vo}}|outctl=nw}}"

::* #T13 ("vo|en")
::* expected result: 2 cats (more sane example) ("El la angla" ...)
::* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|vo|en}}|outctl=nw}}"

* #T14 ("vo|eo")
* expected result: 2 cats (more sane example) ("El Esperanto" ...)
* actual result via debu: "{{debu|{{#invoke:mdev32kat|ek|vo|eo}}|outctl=nw}}"

{{hr3}} <!-------------------------------->

* note that all tests depend on "debu"
* note that all tests cannot be reasonably executed on the docs subpage without help of "pate" or "debu"

{{hr3}} <!-------------------------------->

]===]

local zzdev32kat = {}

  -- uncommentable EO vs ID constant strings

  local constringvoj = "Modulo:loaddata-tbllingvoj"
  local constrkatup  = "Kategorio:"

  -- constant table (ban list)

  local contabisbanned = {}
  contabisbanned = {'by','dc','ll','jp','art','deu','eng','epo','fra','gem','ger','ido','lat','por','rus','spa','swe','tup','zxx'} -- 1...19

  -- constant table

  local contabparam = {}
  contabparam[0] = 2   -- minimal number of anon parameters
  contabparam[1] = 2   -- maximal number of anon parameters
  contabparam[2] = 160 -- maximal length of single para

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

local qldingvoj = {}     -- type "table" and nested
local qbooguard = false  -- only for the guard test, pass to other var ASAP

qbooguard = (type(constringvoj)~='string') or (type(constrkatup)~='string')
if (not qbooguard) then
  qldingvoj = mw.loadData(constringvoj) -- can crash here
  qbooguard = (type(qldingvoj)~='table') -- seems to be always false
end--if

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

-- test whether char is an ASCII digit

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

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

-- test whether char is an ASCII lower

local function lftestlc (numcode)
  local boolowerc = false
  boolowerc = ((numcode>=97) and (numcode<=122))
  return boolowerc
end--function lftestlc

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

-- Local function LFCHKKODINV

-- Check whether a string (intended to be a language code) contains only 2
-- or 3 lowercase letters or maybe a digit in middle position or maybe
-- instead equals to "-" or "??" and maybe additionally is not
-- included on the ban list.

-- Input  : * strqooq -- string (empty is useless and returns
--                       "true" ie "bad" but can't cause any harm)
--          * numnokod -- "0" ... "3" how special codes "-" "??" should pass
--          * boodigit -- "true" to allow digit in middle position
--          * boonoban -- "true" to skip test against ban table

-- Output : * booisbadlk -- bool "true" if the string is evil

-- const table "contabisbanned"

local function lfchkkodinv (strqooq, numnokod, boodigit, boonoban)
  local varomongkosong = "" -- for check against the ban list
  local booisbadlk = false -- pre-assume good
  local numchiiar = 0
  local numukurran = 0
  local numindeex = 0 -- ZERO-based
  while (true) do -- fake (outer) loop
    if ((strqooq=="-") and ((numnokod==1) or (numnokod==3))) then
      break -- to join mark -- good
    end--if
    if ((strqooq=="??") and ((numnokod==2) or (numnokod==3))) then
      break -- to join mark -- good
    end--if
    numukurran = string.len (strqooq)
    if ((numukurran<2) or (numukurran>3)) then
      booisbadlk = true
      break -- to join mark -- evil
    end--if
    numchiiar = string.byte (strqooq,1,1)
    if (lftestlc(numchiiar)==false) then
      booisbadlk = true
      break -- to join mark -- evil
    end--if
    numchiiar = string.byte (strqooq,numukurran,numukurran)
    if (lftestlc(numchiiar)==false) then
      booisbadlk = true
      break -- to join mark -- evil
    end--if
    if (numukurran==3) then
      numchiiar = string.byte (strqooq,2,2)
      if ((boodigit==false) or (lftestnum(numchiiar)==false)) then
        if (lftestlc(numchiiar)==false) then
          booisbadlk = true
          break -- to join mark -- evil
        end--if
      end--if ((boodigit==false) or (lftestnum(numchiiar)==false))
    end--if
    if (boonoban==false) then
      while (true) do -- ordinary inner loop
        varomongkosong = contabisbanned[numindeex+1] -- number of elem unknown
        if (type(varomongkosong)~="string") then
          break -- abort inner loop (then fake outer loop) due to end of table
        end--if
        numukurran = string.len (varomongkosong)
        if ((numukurran<2) or (numukurran>3)) then
          break -- abort inner loop (then fake outer loop) due to faulty table
        end--if
        if (strqooq==varomongkosong) then
          booisbadlk = true
          break -- abort inner loop (then fake outer loop) due to violation
        end--if
        numindeex = numindeex + 1 -- ZERO-based
      end--while -- ordinary inner loop
    end--if (boonoban==false) then
    break -- finally to join mark
  end--while -- fake loop -- join mark
  return booisbadlk
end--function lfchkkodinv

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

function zzdev32kat.ek (arxframent)

  -- general unknown type

  local vartmp = 0     -- variable without type multipurpose

  -- special type "args" AKA "arx"

  local arxourown = 0  -- metaized "args" from our own "frame"

  -- general "tab"

  local tablg76yleft = {}

  -- general str

  local strtmp      = ""  -- temp

  local strvistrc   = ""  -- debug report requested by "detrc="
  local strinvkat   = ""  -- invisible category part
  local strret      = ""  -- final result string

  local strkodbah3  = ""  -- language code from arxourown[1] kapvorta
  local strkodbah4  = ""  -- language code from arxourown[2] devena
  local strnambah3  = ""  -- language name kapvorta
  local strnambah4  = ""  -- language name devena

  -- general num

  local num2statcode = 0
  local numpindex = 0 -- number of anon params
  local numlong   = 0 -- for parameter processing
  local numtamp   = 0 -- for parameter processing
  local numoct    = 0

  -- general boo

  local booerr    = false
  local boonocat  = false  -- from "noc=true" forwarded
  local bootrace  = false  -- from "detrc=true"

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

  boerr = qbooguard

  ---- PICK ONE SUBTABLE ----

  while true do -- fake loop
    if (boerr) then
      break -- to join mark
    end--if
    num2statcode = qldingvoj[2] -- from "loaddata-tbllingvoj"
    if (type(num2statcode)~='number') then -- important check
      boerr = true
      break -- to join mark
    end--if
    if (num2statcode~=0) then
      boerr = true
      break -- to join mark
    end--if
    tablg76yleft = qldingvoj['T76']
    if (type(tablg76yleft)~='table') then -- important check
      boerr = true
      break -- to join mark
    end--if
    break -- finally to join mark
  end--while -- fake loop -- join mark

  ---- ARX ----

  arxourown = arxframent.args -- "args" from our own "frame"

  ---- PRELIMINARILY ANALYZE ANONYMOUS PARAMETERS ----

  -- below on exit var "numpindex" will contain number of
  -- prevalidated anonymous params

  -- this depends on 3 constants:
  -- * contabparam[0] minimal number
  -- * contabparam[1] maximal number
  -- * contabparam[2] maximal length (default 160)

  if (not booerr) then
    numpindex = 0 -- ZERO-based
    numtamp = contabparam[1] -- maximal number of params
    while (true) do
      vartmp = arxourown [numpindex+1] -- can be "nil"
      if ((type(vartmp)~="string") or (numpindex>numtamp)) then
        break -- good or bad
      end--if
      numlong = string.len (vartmp)
      if ((numlong==0) or (numlong>contabparam[2])) then
        booerr = true
        break -- only bad here
      end--if
      numpindex = numpindex + 1 -- on exit has number of valid parameters
    end--while
    if ((numpindex<contabparam[0]) or (numpindex>numtamp)) then
      booerr = true
    end--if
  end--if

  ---- PROCESS 2 OBLIGATORY ANONYMOUS PARAMS INTO 2 STRINGS ----

  -- now var "numpindex" sudah contains number of prevalidated params
  -- always 2 and is useless

  -- here we validate and assign "strkodbah3" and "strkodbah4"

  -- "lfchkkodinv" returns "true" on failure (control
  -- code 0: neither "-" nor "??" is permitted)

  -- this depends indirectly on const table "contabisbanned" via "lfchkkodinv"

  if (not booerr) then
    strkodbah3 = arxourown[1] -- language code kapvorta
    booerr = booerr or (lfchkkodinv(strkodbah3,0,false,false))
    strkodbah4 = arxourown[2] -- language code devena
    booerr = booerr or (lfchkkodinv(strkodbah4,0,false,false))
  end--if

  strtmp = 'Done with anon parameters, got kav = "' .. strkodbah3 .. '" and dev = "' .. strkodbah4 .. '".'
  strvistrc = strvistrc .. "<br>" .. strtmp
  strtmp = 'Critical "booerr" flag is ' .. tostring (booerr)
  strvistrc = strvistrc .. "<br>" .. strtmp

  ---- PROCESS 2 HIDDEN NAMED PARAMS ----

  -- "detrc=" must be seized unconditionally even if we already suck

  boonocat = (arxourown['noc']=='true')
  bootrace = (arxourown['detrc']=='true')

  ---- PEEK THE LANGUAGE NAMES VIA SUBMODULE ----

  -- get name in site language (/c0/) 2 times

  if (not booerr) then
    strnambah3 = tablg76yleft[strkodbah3]
    if ((type(strnambah3)~="string") or (strnambah3=="-")) then
      strnambah3 = ''
      booerr = true
    else
      strnambah4 =  tablg76yleft[strkodbah4]
      if ((type(strnambah4)~="string") or (strnambah4=="-")) then
        strnambah4 = ''
        booerr = true
      end--if
    end--if
  end--if

  if (bootrace) then
    strtmp = 'Peeking done, critical "booerr" flag is ' .. tostring (booerr)
    strvistrc = strvistrc .. "<br>" .. strtmp
  end--if

  ---- AUGMENT ONE LANGUAGE NAME IF NEEDED ----

  -- only "strnambah4" ie "devena" has to be augmented !!!

  if (not booerr) then
    numlong = string.len (strnambah4)
    numoct = string.byte (strnambah4,numlong,numlong)
    if (numoct~=111) then -- "o"
      strnambah4 = "la " .. strnambah4
    end--if
  end--if

  ---- BREW THE INVISIBLE CATEGORY PART ----

  -- string "constrkatup" is cat prefix and includes the colon ":"

  if ((not booerr) and (boonocat==false)) then
    strinvkat = '[[' .. constrkatup .. 'El ' .. strnambah4 .. ']]'
    strinvkat = strinvkat ..'[[' .. constrkatup .. 'El ' .. strnambah4 .. ' (' .. strnambah3 .. ')]]'
  end--if

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

  strret = strinvkat
  if (bootrace) then
    strret = "<br>" .. strvistrc .. "<br><br>" .. strret
  end--if
  return strret

end--function

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

return zzdev32kat