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

--[===[

MODULE "MKONTEK" (kondicxa teksto)

"eo.wiktionary.org/wiki/Modulo:mkontek" <!--2019-Nov-20-->
"id.wiktionary.org/wiki/Modul:mkontek"

Purpose: copies or omits fragments of text depending of a boolean condition

Utilo: kopias aux preterlasas fragmentojn de teksto depende de bolea kondicxo

Manfaat: menyunting atau menghilangkan fragmen teks tergantung pada kondisi

Syfte: kopierar eller utelaemnar fragment av text beroende paa ett villkor

Used by templates / Uzata far sxablonoj:
- EO: "protektomosxa" / "ID": "lindungmote"

Required submodules / Bezonataj submoduloj:
- none / neniuj

Incoming: - 2 anonymous obligatory parameters
            - condition ("1" is true, anything else (preferably use "0")
              evaluates to false, empty string permitted)
            - text with conditional fragments (5...4000 octet:s,
              can cause an error)

Returned: - censored text (can even happen to be empty, or "=" on error,
            latter occurs usually due to unencoded equal signs "="
            in the input text)

Note that there are some restrictions resulting from wiki parsing:
- wall "|" is tolerable only if enclosed by "{{}}" or "[[]]"
  (this is usually NOT a real problem)
- equal sign "=" is absolutely prohibited (this IS a real
  problem, use the percent-trick: "<span title="protective earth">PE</span>"
  -> "<span title%3D"protective earth">PE</span>")

Text processing:
- use double angle brackets "<<...>>" for fragments relevant if "false" AKA 0
- use double arc brackets "((...))" for fragments relevant if "true" AKA 1
- use percent sign "%" to encode problematic char:s (most notably equal sign
  "=", maybe even wall "|", some brackets, and the percent sign "%" itself)

No checking for broken structures (empty, unclosed, nested, crossed, ...).

This module is unbreakable (when called with correct module name
and function name).

Cxi tiu modulo estas nerompebla (kiam vokita kun gxustaj nomo de modulo
kaj nomo de funkcio).

Usage examples with results / Ekzemploj de uzo
kun rezultoj / Contoh penggunaan dengan hasil:

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

* "{{#invoke:mkontek|ek}}" (no params)
* (expected result) -> "="

* "{{#invoke:mkontek|ek|fek}}" (one param, bad)
* (expected result) -> "="

* "{{#invoke:mkontek|ek|1|feek}}" (2 params, too short)
* (expected result) -> "="

* "{{#invoke:mkontek|ek|1|defek}}" (2 params, no conditional text)
* (expected result) -> "defek"

* "{{#invoke:mkontek|ek|abcde|fghij|klmno}}" (3 params,bad)
* (expected result) -> "="

* "{{#invoke:mkontek|ek|1|Z %25%3D%7C%22%3E FYI: zero%3E%3Eseven}}" (2 params)
* (expected result) -> "Z %=|"> FYI: zero>>seven"

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

* "{{#invoke:mkontek|ek|1|Mi estas ((mal))ricxa.}}" (true 1 "(())")
* (expected result) -> "Mi estas malricxa."

* "{{#invoke:mkontek|ek|0|Mi estas ((mal))ricxa.}}" (false 0)
* (expected result) -> "Mi estas ricxa."

* "{{#invoke:mkontek|ek|%%%|Mi estas ((mal))ricxa.}}" (false from garbage)
* (expected result) -> "Mi estas ricxa."

* "{{#invoke:mkontek|ek|1|Mi estas ((mal))ricxa. <<Mono estas mojosa.>>}}"
* (expected result) -> "Mi estas malricxa."

* "{{#invoke:mkontek|ek|0|Mi estas ((mal))ricxa. <<Mono estas mojosa.>>}}"
* (expected result) -> "Mi estas ricxa. Mono estas mojosa."

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

* "{{#invoke:mkontek|ek|1|((X))}}" (true 1 and available "(())")
* (expected result) -> "X"

* "{{#invoke:mkontek|ek|0|((X))}}" (false 0 and inexistent "<<>>")
* (expected result) -> "" (empty)

* "{{#invoke:mkontek|ek|0|((zero%3E%3Etwo))<<zero%3C%3Ctwo>>}}"
* (expected result) -> "zero<<two"

* "{{#invoke:mkontek|ek|1|((zero%3E%3Etwo))<<zero%3C%3Ctwo>>}}"
* (expected result) -> "zero>>two"

* "{{#invoke:mkontek|ek|0|((zero%3C%3Etwo))<<zero%3Dtwo>>}}" (false 0 "<<>>")
* (expected result) -> "zero=two"

* "{{#invoke:mkontek|ek|1|((zero%3C%3Etwo))<<zero%3Dtwo>>}}" (true 1 "(())")
* (expected result) -> "zero<>two"

* "{{#invoke:mkontek|ek|1|-((true))-<<false>>-((true))-<<false>>-((true))-}}"
* (expected result) -> "-true--true--true-"

* "{{#invoke:mkontek|ek|0|-((true))-<<false>>-((true))-<<false>>-((true))-}}"
* (expected result) -> "--false--false--"

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

]===]

local kontek = {}

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

---- ORDINARY LOCAL LOW LEVEL FUNCTIONS ----

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

-- Local function LFONEHEXTOINT

-- Convert 1 ASCII code of a hex digit to an UINT4 ie 0...15 (255 invalid)

-- Only uppercase accepted

local function lfonehextoint (numdigit)
  local numresult = 255
  if ((numdigit>47) and (numdigit<58)) then
    numresult = numdigit-48
  end--if
  if ((numdigit>64) and (numdigit<71)) then
    numresult = numdigit-55
  end--if
  return numresult
end--function lfonehextoint

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

-- Local function LFTWOHEXTOINT

-- Convert 2 ASCII codes of hex digits to an UINT8 ie 0...255 (255 invalid)

-- Only uppercase accepted

local function lftwohextoint (numza, numzb)
  local numrezalt = 255
  numza = lfonehextoint (numza)
  numzb = lfonehextoint (numzb)
  if ((numza<=15) and (numzb<=15)) then
    numrezalt = numza * 16 + numzb
  end--if
  return numrezalt
end--function lftwohextoint

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

---- MAIN EXPORTED FUNCTION ----

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

function kontek.ek (arxframent)

  -- special type "args" AKA "arx"

  local arxourown = 0  -- metaized "args" from our own "frame" (NOT caller's)

  -- general "str"

  local strinn    = ""  -- incoming text
  local strtmp    = ""
  local strret    = ""  -- output string

  -- general "num"

  local numlong   = 0  -- length of parameter
  local numind    = 0
  local numoct    = 0  -- temp some char
  local numocx    = 0  -- temp following char

  -- general "boo"

  local booerr    = false  -- fatal error flag
  local boosvic   = false  -- from arxourown[1] -- the switching condition
  local boocopy   = true   -- assign to "false" to suspend copying
  local booperc   = false  -- assign to "true" after a percent conversion
  local boomark   = false  -- assign to "true" if a valid marker is found

  ---- SEIZE 2 OBLIGATORY PARAMETERS FROM CALLER ----

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

  if ((arxourown[1]==nil) or (arxourown[2]==nil) or (arxourown[3])) then
    booerr = true -- need 2 obligatory params, 3 are not appreciated
  else
    strtmp = arxourown[1] -- becomes a bool -- empty string permitted
    numlong = string.len(strtmp)
    if (numlong==1) then
      numoct = string.byte(strtmp,1,1)
      if (numoct==49) then
        boosvic = true -- was preset to "false"
      end--if
    end--if (numlong==1) then
    strinn = arxourown[2] -- string 5...4000
    numlong = string.len(strinn)
    if ((numlong<5) or (numlong>4000)) then
      booerr = true -- must be 5...4000 octet:s
    end--if
  end--if

  ---- CARRY OUT THE HARD WORK ----

  -- "%" 37 | "(" 40 | ")" 41 | "<" 60 | ">" 62

  -- we refuse to care about "%" if there are not at least 2 char:s left
  -- after having translated "%" we refuse to care about markers
  -- we also refuse to care about markers if there is not at least 1 char left

  if (booerr) then
    strret = "=" -- damn (hardcoded error string)
  else
    numlong = string.len (strinn)
    while (true) do
      if (numind==numlong) then
        break -- done -- "numind" is ZERO-based
      end--if
      numoct = string.byte (strinn,(numind+1),(numind+1)) -- + 0
      booperc = false
      boomark = false
      if ((numoct==37) and ((numind+2)<numlong)) then -- "%"
        booperc = true
        numind = numind + 1 -- ZERO-based index
        numoct = string.byte (strinn,(numind+1),(numind+1))
        numind = numind + 1 -- ZERO-based index
        numocx = string.byte (strinn,(numind+1),(numind+1))
        numoct = lftwohextoint (numoct,numocx)
      end--if
      if ((booperc==false) and ((numind+1)<numlong)) then
        numocx = string.byte (strinn,(numind+2),(numind+2)) -- + 1
        if (numoct==numocx) then -- maybe a marker
          if ((numoct==41) or (numoct==62)) then -- ")" or ">"
            boomark = true
            boocopy = true -- end of conditional fragment
          end--if
          if (numoct==40) then -- fragment relevant if "true"
            boomark = true
            if (boosvic==false) then
              boocopy = false -- but condition is "false" :-(
            end--if
          end--if
          if (numoct==60) then -- fragment relevant if "false"
            boomark = true
            if (boosvic) then
              boocopy = false -- but condition is "true" :-(
            end--if
          end--if
        end--if (numoct==numocx) then
      end--if ((booperc==false) and ((numind+1)<numlong)) then
      if (boomark) then
        numind = numind + 2 -- skip the marker
      else
        if (boocopy) then
          strret = strret .. string.char (numoct) -- conditionally copy char
        end--if
        numind = numind + 1 -- ZERO-based index -- increment in any case
      end--if
    end--while
  end--if

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

  return strret

end--function

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

return kontek