Modulo:mchklngcode

El Vikivortaro
Salti al navigilo Salti al serĉilo
StopsignIndonesia.png Ĉi tiu modulo estas multfoje bindita.
Se vi konas la eblajn sekvojn, tiam vi povas zorgeme ekredakti.
Se vi ne kuraĝas redakti tiam vi povas proponi la deziratan ŝanĝon en la diskutejo.
Memtesto disponeblas sur la dokumentaĵa subpaĝo

--[===[

MODULE "MCHKLNGCODE" (check language code)

"eo.wiktionary.org/wiki/Modulo:mchklngcode" <!--2019-Dec-31-->
"id.wiktionary.org/wiki/Modul:mchklngcode"

Purpose: checks validity of 1 or 2 parameters that are supposed to
         contain language code in 2 stages: by testing whether they
         are obviously invalid, and if this does not apply whether
         they are known

Utilo: kontrolas validecon de 1 aux 2 parametroj kiuj enhavu
       lingvokodon en 2 pasxoj: testante cxu ili estas evidente
       nevalidaj, kaj se tio ne veras cxu ili estas konataj

Manfaat: mengontrol validitas 1 atau 2 parameter yang ...

Syfte: kontrollerar giltighet av 1 eller 2 parametrar ...

Used by templates / Uzata far sxablonoj:
- deveno3 elpropra Lingvo t

Required submodules / Bezonataj submoduloj / Submodul yang diperlukan:
- "mpiktbllki" in turn requiring "mtmplloaddata" in turn requiring
  template "tbllingvoj" (EO) or "tblbahasa" (ID)

This module is special in that it takes parameters both those sent
to itself (own frame) and those sent to the caller (caller's frame).

Incoming: - 1 or 2 anonymous parameters
            - 1 or 2 parameters forwarded from the caller using "{{{1}}}"
              or "{{{ling}}}" or similarly, wall "|" is not needed,
              maybe "{{{ling|eo}}}" for an optional parameter,
              conversely "{{{ling|}}}" is bad
          - 1 optional named parameter
            - "xx=" tuning string with 5 char:s (one tristate letter
              and 4 bool digits "0" or "1")
              - letter : desired type of result (default is "b"):
                - "b" -- bool (0 invalid -- 1 good) for conditional logic
                         in classic templates
                - "t" -- tristate (0 invalid -- 1 unknown -- 2 known)
                - "k" -- category (2 categories without EOL between them
                         if applicable, or empty string if known, see below)
              - bool: do check 2 codes (by default only 1 code is checked)
              - bool: allow "??" (default false ie NOT allowed)
              - bool: allow digit in middle position of 3-letter codes
                      ("t8i") (default false ie NOT allowed)
              - bool: do NOT disallow some common bad codes ("epo",
                      "por", ...) by ban table (default false ie NOT allowed)

Returned: - "b" : string "1" if the parameters are accepted (known or
                  unknown code), string "0" if the parameters are bad
                  (obviously invalid), or this module itself becomes
                  victim of misuse
          - "t" : string "2" if the parameters are accepted (known code or
                  codes), string "1" if the parameters are unknown but not
                  obviously invalid, string "0" if the parameters are bad
                  (at least one is obviously invalid), or this module itself
                  becomes victim of misuse
          - "k" : 2 categories (of 2 possible types) without EOL between
                  them, or empty string if the parameters are accepted,
                  no junk categories if this module itself becomes
                  victim of misuse

For "b" and "t" the principle is "the worst result counts", but for "k"
the 2 categories are based on separate evaluations of the 2 codes.

Parameters seized from the caller's frame:
          - 1 named optional parameter
            - "nocat" (value "true" to suppress categorization in "k" mode,
              anything else is ignored)

The validity check for obviously invalid code
requires in order to return result "good":
- must be 2 or 3 ASCII char:s long
- must consist of lowercase letters only (optionally,
  digit in the middle position can be allowed)
- must not be on the ban list (this check can optionally be deactivated)
- optionally string "??" (but not "???") can be allowed as
  valid (but not as known)

La kontrolo pri evidente nevalida kode postulas
por redoni rezulton "bona":
- longo estu 2 aux 3 ASCII signoj
- enhavu nur minusklajn literojn (opcie, cifero povas
  esti permesita en la meza pozicio)
- ne trovigxu sur la forbara listo (cxi tiu kontrolo povas opcie
  esti senaktivigita)
- opcie signocxeno "??" (sed ne "???") povas esti permesita kiel
  valida (sed ne kiel konata)

Note that the operation modes "b" or "t" and on the other side "k" are
separated and it is NOT possible to merge them. Result from "b" is fed into
"#ifeq" and possible categories would be ignored. Thus this module will be
usually called several times from one template, even with same language code.

Note that the result in bool mode "b" is either "1" "accepted" or "0" "bad"
after this module has succeeded to run. But there is a third option "module
failed to run" due to not found or timeout for example. The conditional logic
in the calling template must be aware of this.

In the category mode "k" the format of the categories is:
- obviously invalid
  - "[[Kategorio:Evidente nevalida lingvokodo (Deutsch)]]"
  - "[[Kategorio:Evidente nevalida lingvokodo]]"
  the reported string is sanitized:
  - replaced with "e-m-p-t-y" if empty
  - otherwise truncated to max 14 octet:s and unsafe char:s are
    replaced with dot:s (safe are "0"..."9" "A"..."Z" "a"..."z"
    "(" ")" "," "-")
or
- uknown
  - "[[Kategorio:Nekonata lingvokodo (haw)]]"
  - "[[Kategorio:Nekonata lingvokodo]]"
  there is no need to filter any unsafe char:s here

If two codes are tested then two separate pairs of categories can be created
of same type or of different types (one invalid and one unknown).

This module allows to mostly separate cases of "obviously invalid language
code" (for example "" (empty), "...", "Deutsch", "De", "FR", "taja", ...)
from "unknown language code" (for example "haw" that is valid according to
"ISO 639-3:2007" but might lack in the list of languages)

: ---------------------------------------

* #00 (no params, bad)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek}}"

* #01 ("eo")
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|eo}}"

* #02 ("eo|crap", only 1 code is tested)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|eo|crap}}"

* #03 ("eo|sv|id", 3 anon params, bad)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|eo|sv|id}}"

* #04 ("eo|xx=b0000", all 5 defaults explicitely confirmed)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|eo|xx=b0000}}"

* #05 ("eo|xx=b00000", parameter too long)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|eo|xx=b00000}}"

* #06 ("eo|xx=b0020", invalid digit "2")
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|eo|xx=b0020}}"

* #07 ("eo|crap|xx=b1000", both codes are tested)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|eo|crap|xx=b1000}}"

: ---------------------------------------

* #10 ("eo|haw|xx=b1000", both codes are tested)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|eo|haw|xx=b1000}}"

* #11 ("eo|??|xx=b1000", both codes are tested, "??" prohibited)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|eo|??|xx=b1000}}"

* #12 ("eo|??|xx=b1100", both codes are tested, "??" allowed)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|eo|??|xx=b1100}}"

* #13 ("por|xx=b0000", "por" prohibited)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|por|xx=b0000}}"

* #14 ("por|xx=b0001", "por" allowed)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|por|xx=b0001}}"

* #15 ("eo|z|xx=b1101", both codes are tested, right "z" is bad)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|eo|z|xx=b1101}}"

* #16 ("z|eo|xx=b1101", both codes are tested, left "z" is bad)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|z|eo|xx=b1101}}"

* #17 ("epo|eo|xx=b1101", both codes are tested, "epo" allowed)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|epo|eo|xx=b1101}}"

: ---------------------------------------

* #20 ("|ek|id||xx=b1101", both codes are tested, empty is bad)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|id||xx=b1101}}"

* #21 ("|ek|id||xx=b0101", only one code is tested, empty is bad but ignored)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|id||xx=b0101}}"

* #22 ("|ek||id|xx=b0101", only one code is tested, empty is bad)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek||id|xx=b0101}}"

* #23 ("|ek|t8i|xx=b0000", digits prohibited as default)
* expected result: "0" (bad)
* actual result: "{{#invoke:mchklngcode|ek|t8i|xx=b0000}}"

* #24 ("|ek|t8i|xx=b0010", digits permitted)
* expected result: "1" (good)
* actual result: "{{#invoke:mchklngcode|ek|t8i|xx=b0010}}"

: ---------------------------------------

* #30 ("grc|xx=t0000", tristate)
* expected result: "2" (good and known)
* actual result: "{{#invoke:mchklngcode|ek|grc|xx=t0000}}"

* #31 ("t8i|xx=t0010", tristate, digits permitted)
* expected result: "2" (good and known) or "1" (valid but unknown)
* actual result: "{{#invoke:mchklngcode|ek|t8i|xx=t0010}}"

* #32 ("??|xx=t0100", tristate, "??" is allowed)
* expected result: "1" (valid but unknown)
* actual result: "{{#invoke:mchklngcode|ek|??|xx=t0100}}"

* #33 ("???|xx=t0100", tristate, "??" is allowed but "???" is NOT)
* expected result: "0" (obviously invalid)
* actual result: "{{#invoke:mchklngcode|ek|???|xx=t0100}}"

* #34 ("fri|xx=t0000", tristate, this code is officially banned)
* expected result: "1" (valid but unknown)
* actual result: "{{#invoke:mchklngcode|ek|fri|xx=t0000}}"

: ---------------------------------------

* #40 ("f3i|xx=t0000", tristate, digits prohibited by default)
* expected result: "0" (obviously invalid)
* actual result: "{{#invoke:mchklngcode|ek|f3i|xx=t0000}}"

* #41 ("f3i|xx=t0010", tristate, digits permitted)
* expected result: "1" (valid but unknown)
* actual result: "{{#invoke:mchklngcode|ek|f3i|xx=t0010}}"

* #42 ("fi3|xx=t0010", tristate, digits permitted but only in middle position)
* expected result: "0" (obviously invalid)
* actual result: "{{#invoke:mchklngcode|ek|fi3|xx=t0010}}"

* #43 ("3fi|xx=t0010", tristate, digits permitted but only in middle position)
* expected result: "0" (obviously invalid)
* actual result: "{{#invoke:mchklngcode|ek|3fi|xx=t0010}}"

: ---------------------------------------

* #50 ("grc|xx=k0000", 4 defaults explicitely confirmed, category mode)
* expected result: "" (empty string, good)
* actual result: "{{#invoke:mchklngcode|ek|grc|xx=k0000}}"

<pre>
* #51 ("fri|xx=k0000", 4 defaults explicitely confirmed, category mode)
* expected result: N/A (valid but unknown, categories)
* actual result: "{{#invoke:mchklngcode|ek|fri|xx=k0000}}"

* #52 ("fori|xx=k0000", 4 defaults explicitely confirmed, category mode)
* expected result: N/A (obviously invalid, categories)
* actual result: "{{#invoke:mchklngcode|ek|fori|xx=k0000}}"
</pre>

* note that tests #51 and #52 cannot be executed on the docs subpage

: ---------------------------------------

]===]

local chklngcode = {}

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

---- CONSTANTS ----

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

  -- ban list (only 3-letter codes, maybe also bad 2-letter codes)

  -- length of the list is NOT stored anywhere, the processing stops when "nil" comes

  local contabisbanned = {}
  contabisbanned = {'deu','eng','epo','fra','lat','por','rus','spa','swe'} -- 1...9

  -- constant strings EO vs ID

  local constrplki = "Modulo:mpiktbllki"  -- EO
  -- local constrplki = "Modul:mpiktbllki"   -- ID

  local constrneva = "Kategorio:Evidente nevalida lingvokodo"        -- EO -- no brackets ("[[","]]") here
  -- local constrneva = "Kategori:Kode bahasa jelas-jelas tidak valid"  -- ID -- no brackets ("[[","]]") here

  local constrneko = "Kategorio:Nekonata lingvokodo"                 -- EO -- no brackets ("[[","]]") here
  -- local constrneko = "Kategori:Kode bahasa tidak diketahui"          -- ID -- no brackets ("[[","]]") here

  -- emergency brake (4 binary digits: nevaspec,nevagene,nekospec,nekogene)

  local constrfilter = "0101"  -- change one or several digits to ZERO to prevent categorization

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

---- IMPORTS ----

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

local piktbllki = require(constrplki) -- can crash here

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

---- ORDINARY LOCAL HIGH LEVEL FUNCTIONS ----

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

-- Local function LFFIXUNSAFE

-- Fix obviously invalid language code so that it can at least be used
-- inside name of a tracking category

-- # empty string replaced with "e-m-p-t-y"
-- # truncated to 14 octet:s if longer
-- # unsafe char:s are replaced with dot:s (safe are only "0"..."9" and
--   "A"..."Z" and "a"..."z" and "(" and ")" and "," and "-" and maybe ".")

-- Input  : - strbahaya

-- Output : - strfixed

local function lffixunsafe (strbahaya)
  local strfixed = ""
  local numlencx = 0
  local numcxaar = 0
  local numuindex = 1 -- ONE-based
  local boogood = false
  if (strbahaya=="") then
    strfixed = "e-m-p-t-y"
  else
    numlencx = string.len (strbahaya)
    if (numlencx>14) then
      strbahaya = string.sub (strbahaya,1,14)
      numlencx = 14
    end--if
    while (true) do
      if (numuindex>numlencx) then
        break
      end--if
      numcxaar = string.byte (strbahaya,numuindex,numuindex)
      boogood = false
      if ((numcxaar>=48) and (numcxaar<=57)) then
        boogood = true
      end--if
      if ((numcxaar>=65) and (numcxaar<=90)) then
        boogood = true
      end--if
      if ((numcxaar>=97) and (numcxaar<=122)) then
        boogood = true
      end--if
      if ((numcxaar==40) or (numcxaar==41)) then
        boogood = true -- "()"
      end--if
      if ((numcxaar>=44) and (numcxaar<=46)) then
        boogood = true -- ",-" maybe ."
      end--if
      if (boogood==false) then
        numcxaar = 46 -- replace by dot "."
      end--if
      strfixed = strfixed .. string.char (numcxaar)
      numuindex = numuindex + 1
    end--while
  end--if
  return strfixed
end--function lffixunsafe

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

-- Local function LFCHKKODIV

-- Check whether a string contains only 2 or 3 lowercase letters
-- or maybe digit in middle position or maybe equals "??" or 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)
--          - booquest -- "true" if special code "??" 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 bad

-- needs const table "contabisbanned"

local function lfchkkodiv (strqooq, booquest, boodigit, boonoban)
  local varomongkosong = "" -- for check against the ban list
  local booisbadlk = false
  local numchiiar = 0
  local numukurran = 0
  local numindeex = 0 -- ZERO-based
  while (true) do -- fake (outer) loop
    numukurran = string.len (strqooq)
    if ((numukurran<2) or (numukurran>3)) then
      booisbadlk = true
      break -- to join mark
    end--if
    if ((booquest==false) or (strqooq~="??")) then
      numchiiar = string.byte (strqooq,1,1)
      if ((numchiiar<97) or (numchiiar>122)) then
        booisbadlk = true
        break -- to join mark
      end--if
      numchiiar = string.byte (strqooq,numukurran,numukurran)
      if ((numchiiar<97) or (numchiiar>122)) then
        booisbadlk = true
        break -- to join mark
      end--if
      if (numukurran==3) then
        numchiiar = string.byte (strqooq,2,2)
        if ((boodigit==false) or ((numchiiar<48) or (numchiiar>57))) then
          if ((numchiiar<97) or (numchiiar>122)) then
            booisbadlk = true
            break -- to join mark
          end--if
        end--if ((boodigit==false) or ((numchiiar<48) or (numchiiar>57))) then
      end--if
    end--if ((booquest==false) or (strqooq~="??")) then
    if (boonoban==false) then
      while (true) do -- ordinary inner loop
        varomongkosong = contabisbanned[numindeex+1] -- amount 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
      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 lfchkkodiv

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

-- Local function LFCHKKODKN

-- Check whether the code is known

-- invoked module "mpiktbllki" with parameter "-" returns
-- bool string "0" or "1" (known)

-- Input  : - strqoqoq

-- Output : - booisunknown

-- needs imported module "piktbllki"

local function lfchkkodkn (strqoqoq)
  local varfrominvo = ""
  local booisunknown = false
  varfrominvo = piktbllki.ek { args = { strqoqoq , "-" } }
  if (varfrominvo~="1") then
    booisunknown = true
  end--if
  return booisunknown
end--function lfchkkodkn

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

-- Local function LFBREW2KAT

-- Brew 2 categories from the bad code (specific and generic)

-- Input  : - strkatbase (kategory name with namespace prefix)
--          - strhintname (the bad code already sanitized)
--          - booxspec, booxgene

-- Output : - strduakucing (can be empty)

local function lfbrew2kat (strkatbase, strhintname, booxspec, booxgene)
  local strduakucing = ""
  if (booxspec) then
    strduakucing = "[[" .. strkatbase .. " (" .. strhintname .. ")|" .. strhintname .. "]]"
  end--if
  if (booxgene) then
    strduakucing = strduakucing .. "[[" .. strkatbase .. "]]"
  end--if
  return strduakucing
end--function lfbrew2kat

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

---- MAIN EXPORTED FUNCTION ----

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

function chklngcode.ek (arxframent)

  -- general unknown type

  local vartmp = 0     -- variable without type

  -- special type "args" AKA "arx"

  local arxourown = 0  -- metaized "args" from our own "frame"
  local arxcaller = 0  -- metaized "args" from caller's "frame"

  -- general "str"

  local strkodo3 = ""  -- code (obligatory)
  local strkodo4 = ""  -- code (optional)
  local strret   = ""  -- output string

  -- general "num"

  local numbtkmo = 98   -- operation mode / type of result: "b" or "t" or "k"

  local num012st3k = 2  -- tri-state sta "strkodo3"
  local num012st4k = 2  -- tri-state sta "strkodo4" (remains 2 if only 1 code)
  local num012stzz = 2  -- tri-state combo = min (num012st3k,num012st4k)

  local numlong  = 0    -- temp
  local numchar  = 0    -- temp

  -- general "boo"

  local boochktwo = false
  local booalloqu = false  -- "true" if "??" should pass
  local booallodg = false  -- "true" to allow digit in middle position
  local booskipbt = false  -- "true" to skip test against ban table

  local boonocat  = false  -- from "nocat=true" from "arxcaller"

  local boointer  = false  -- "true" on internal error (blocks categorization)

  local boodoccek = false  -- temp: do the check at all (maybe can be skipped)

  local boonevaspec = true  -- @
  local boonevagene = true  -- @ for "constrfilter", default is "true"
  local boonekospec = true  -- @
  local boonekogene = true  -- @

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

  -- "constrneva" and "constrneko" must be assigned and non-empty

  if ((type(constrneva)~="string") or (type(constrneko)~="string")) then
    boointer = true -- internal error -- was preassigned to "false"
  else
    if ((constrneva=="") or (constrneko=="")) then
      boointer = true -- internal error -- was preassigned to "false"
    end--if
  end--if

  ---- GET THE ARX:ES ----

  if (boointer==false) then
    arxourown = arxframent.args -- "args" from our own "frame"
    arxcaller = arxframent:getParent().args -- "args" from caller's "frame"
  end--if

  ---- SEIZE 1 OR 2 ANONYMOUS PARAMETERS AND "XX=" SENT BY CALLER TO US ----

  while (true) do -- fake loop

    if (boointer) then
      break -- to join mark
    end--if

    if (arxourown[3]) then
      boointer = true -- internal error -- was preassigned to "false"
      break -- to join mark -- 3 anon params are not appreciated
    end--if

    vartmp = arxourown[1] -- can be "nil"
    if (type(vartmp)=="string") then
      strkodo3 = vartmp -- give a f**k about risk of empty string
    end--if

    vartmp = arxourown[2] -- can be "nil"
    if (type(vartmp)=="string") then
      strkodo4 = vartmp -- give a f**k about risk of empty string
    end--if

    vartmp = arxourown["xx"] -- can be "nil" -- optional named
    if (type(vartmp)=="string") then
      numlong = string.len (vartmp)
      if (numlong~=5) then
        boointer = true -- internal error -- was preassigned to "false"
        break -- to join mark -- need 5 digits
      end--if
      numchar = string.byte (vartmp,1,1) -- need "b" (default) or "t" "k"
      if (numchar==116) then
        numbtkmo = 116 -- requested "t" -- was preassigned to 98 ie "b"
      else
        if (numchar==107) then
          numbtkmo = 107 -- requested "k" -- was preassigned to 98 ie "b"
        else
          if (numchar~=98) then
            boointer = true -- internal error -- was preassigned to "false"
            break -- to join mark
          end--if
        end--if
      end--if (numchar==116) else
      numchar = string.byte (vartmp,2,2)
      if (numchar==49) then
        boochktwo = true -- was preassigned to "false" -- check 2 codes
      else
        if (numchar~=48) then
          boointer = true -- internal error -- was preassigned to "false"
          break -- to join mark
        end--if
      end--if (numchar==49) else
      numchar = string.byte (vartmp,3,3)
      if (numchar==49) then
        booalloqu = true -- was preassigned to "false" -- allow "??"
      else
        if (numchar~=48) then
          boointer = true -- internal error -- was preassigned to "false"
          break -- to join mark
        end--if
      end--if (numchar==49) else
      numchar = string.byte (vartmp,4,4)
      if (numchar==49) then
        booallodg = true -- was preassigned to "false" -- allow digit
      else
        if (numchar~=48) then
          boointer = true -- internal error -- was preassigned to "false"
          break -- to join mark
        end--if
      end--if (numchar==49) else
      numchar = string.byte (vartmp,5,5)
      if (numchar==49) then
        booskipbt = true -- was preassigned to "false" -- skip the extra ban test
      else
        if (numchar~=48) then
          boointer = true -- internal error -- was preassigned to "false"
          break -- to join mark
        end--if
      end--if (numchar==49) else
    end--if (type(vartmp)=="string") then

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

  ---- SEIZE 1 OPTIONAL NAMED PARAMETER SENT BY SOMEONE TO CALLER ----

  if (boointer==false) then
    vartmp = arxcaller["nocat"] -- can be "nil"
    if (type(vartmp)=="string") then
      if (vartmp=="true") then
        boonocat = true
      end--if
    end--if
  end--if

  ---- CARRY OUT THE HARD WORK -- TEST FOR OBVIOUS INVALIDITY ----

  -- this is NOT needed if:
  -- # we already have an internal error
  -- or
  -- # result mode is "k" category and we have "nocat=true"

  boodoccek = true
  if (boointer) then
    boodoccek = false
  end--if
  if ((numbtkmo==107) and boonocat) then -- "k" and "nocat=true"
    boodoccek = false
  end--if

  if (boodoccek) then
    if (lfchkkodiv(strkodo3,booalloqu,booallodg,booskipbt)) then
      num012st3k = 0
    end--if
  end--if

  if (boodoccek and boochktwo) then
    if (lfchkkodiv(strkodo4,booalloqu,booallodg,booskipbt)) then
      num012st4k = 0
    end--if
  end--if

  ---- CHECK WHETHER THE CODES ARE KNOWN ----

  -- this is NOT needed if:
  -- # we already have an internal error
  -- or
  -- # result mode is "b" binary (then we do not distinguish "1" from "2")
  -- or
  -- # result mode is "k" category and we have "nocat=true"

  boodoccek = true
  if (boointer) then
    boodoccek = false
  end--if
  if (numbtkmo==98) then -- "b" bool / binary mode
    boodoccek = false
  end--if
  if ((numbtkmo==107) and boonocat) then -- "k" and "nocat=true"
    boodoccek = false
  end--if

  if ((num012st3k==2) and boodoccek) then
    if (lfchkkodkn(strkodo3)) then
      num012st3k = 1
    end--if
  end--if

  if ((num012st4k==2) and boodoccek and boochktwo) then
    if (lfchkkodkn(strkodo4)) then
      num012st4k = 1
    end--if
  end--if

  ---- BREW MIN ----

  -- we have 2 separate tristate results "num012st3k" and "num012st4k"

  -- "num012st4k" preassigned to 2 and remains 2 all the time if
  -- only one code is tested

  -- an internal error ie "boointer" = "true" results in "num012stzz"
  -- assigned to ZERO

  if (boointer) then
    num012stzz = 0 -- jaevlar
  else
    num012stzz = num012st3k
    if (num012st4k<num012stzz) then
      num012stzz = num012st4k -- combo num012stzz = min (num012st3k,num012st4k)
    end--if
  end--if

  ---- ASSIGN "STRRET" TO BOOL OR TRISTATE ----

  -- possible modes in "numbtkmo" are 98 "b" (default) or 116 "t" or 107 "k"

  if (numbtkmo==116) then -- "t" tristate
    strret = string.char(num012stzz+48) -- this was rocket science
  end--if
  if (numbtkmo==98) then -- "b" bool
    strret = "1" -- preassigned output string to report "accepted"
    if (num012stzz==0) then
      strret = "0" -- set output string to report "bad"
    end--if
  end--if

  ---- BREW CATEGORIES ----

  -- here we process the "k" mode

  -- we use the 2 separate tristate results "num012st3k" and "num012st4k"
  -- 0 invalid -- 1 unknown -- 2 known

  -- the strings are "constrneva" and "constrneko" and include the category
  -- prefix and the name, but not "[[","]]" nor space before "(",")"

  -- for obviously invalid codes we use "constrneva" and
  -- include the bad string (sanitized)

  -- for unknown codes we use "constrneko" and include the bad string

  -- categorization can be blocked by several conditions:
  -- # totally by "num012stzz" = 2 (code is or both codes are
  --   known, no need to whine)
  -- # totally by "nocat=true"
  -- # totally by "boointer=true" (junk categories on
  --   internal error NOT appreciated)
  -- # selectively by "num012st.." = 2 (code is known, no need to whine)
  -- # selectively by ZERO:s in "constrfilter", length must be
  --   4 char:s, default for 4 bool values is true

  -- "strret" was preassigned to empty "" and is so
  -- far untouched in the "k" mode

  if ((num012stzz~=2) and (numbtkmo==107) and (boointer==false) and (boonocat==false)) then

    if (string.len(constrfilter)==4) then
      if (string.byte(constrfilter,1,1)==48) then
        boonevaspec = false
      end--if
      if (string.byte(constrfilter,2,2)==48) then
        boonevagene = false
      end--if
      if (string.byte(constrfilter,3,3)==48) then
        boonekospec = false
      end--if
      if (string.byte(constrfilter,4,4)==48) then
        boonekogene = false
      end--if
    end--if

    strkodo3 = lffixunsafe (strkodo3) -- sanitize
    if (num012st3k==0) then -- 2 possib in 1 of "num012st3k" & "num012st4k"
      strret = strret .. lfbrew2kat (constrneva, strkodo3, boonevaspec, boonevagene)
    end--if
    if (num012st3k==1) then
      strret = strret .. lfbrew2kat (constrneko, strkodo3, boonekospec, boonekogene)
    end--if

    if (boochktwo) then
      strkodo4 = lffixunsafe (strkodo4) -- sanitize
      if (num012st4k==0) then -- 2 possib in 1 of "num012st3k" & "num012st4k"
        strret = strret .. lfbrew2kat (constrneva, strkodo4, boonevaspec, boonevagene)
      end--if
      if (num012st4k==1) then
        strret = strret .. lfbrew2kat (constrneko, strkodo4, boonekospec, boonekogene)
      end--if
    end--if

  end--if ((num012stzz~=2) ... (boonocat==false)) then

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

  return strret -- can vary depending on result type, even be empty

end--function

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

return chklngcode