Modulo:mpiktbllki

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 zorge 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 "MPIKTBLLKI" (pick from table lingvokodo al info)

"eo.wiktionary.org/wiki/Modulo:mpiktbllki" <!--2019-Jun-06-->
"id.wiktionary.org/wiki/Modul:mpiktbllki"

Purpose: picks an element from a raw two-dimensional table, or more
         precisely from "tbllingvoj" (EO) or "tblbahasa" (ID)

Utilo: ellegas elementon el kruda dudimensia tabelo, aux pli
       precize el "tbllingvoj" (EO) aux "tblbahasa" (ID)

Manfaat: membaca elemem dari tabel berdimensi dua

Syfte: laeser ut ett element fraan en tvaadimensionell tabell

Used by templates / Uzata far sxablonoj /
Digunakan oleh templat / Anvaent av mallar:
- "Lingvo" ... ??
- "Modulo:mlawc" siavice uzata far sxablono "livs" (EO) /
  "Modul:mlawc" digunakan oleh templat "bakk" (ID)

Required submodules / Bezonataj submoduloj / Submodul yang diperlukan:
- "mtmplloaddata" in turn requiring template
  "tbllingvoj" (EO) or "tblbahasa" (ID)
We do NOT need "mpiksubstrind" since we contain a copy of a part of its code.

Incoming: - 2 obligatory anonymous parameters
            - y-index word (access code of the
              language, 2 or 3 lowercase chars)
            - x-index number (0...9) or special value "+" or "-"
          - 2 optional anonymous parameters (1 or 2 can be given,
              but none can be skipped, specify default value if needed)
            - "1" if removal of rl-enclosement (for non-latin scripts) is
              desired, or "0" to keep it (default is "1")
            - alternative output string to replace "-" coming literally
              from the source table (1...64 char:s, default is "-")
          - 1 optional named parameter "err="
            - alternative output string to replace the "=" error
              message (1...64 char:s, default is "=") (this works even
              for errors coming from anonymous parameters)

Returned: - one string
            - for index number 0...9 the found element or "=" if the
              element was not found (due to y or x) or an error occurred
            - for special input value "+" the complete table line including
              the y-index word (but excessive whitespace reduced), or "="
              if the y-index word was not found or an error occurred
            - for special input value "-" binary output either "1" if the
              y-index word was found (not checking the table line), or
              "0" if the y-index word was not found or an error occurred

This module is unbreakable (when called with correct module name
and function name). Every imaginable input will output either a useful
result or the string "=" (not found or error).

Cxi tiu modulo estas nerompebla (kiam vokita kun gxustaj nomo de modulo
kaj nomo de funkcio). Cxiu imagebla enigo eldonas aux utilan
rezulton aux signocxenon "=" (ne trovita aux eraro).

General rules and specific limits:

- table lines are separated with EOL:s
- table elements within lines are separated with commas ","
- double square brackets "[[" and "]]" are reserved for y-index words
  and such may occur only at the beginning of line (here we assume this)
- usage of single square brackets "[" and "]" is not limited
- double round brackets "((" and "))" are reserved for x-index words
  (here we don't support x-index words at all)
- usage of single round brackets "(" and ")" is not limited
- more than two subsequent brackets ie for
  example "[[[" or ")))" are prohibited
- no comma "," following [[...]] and ((...)), inline whitespace
  is recommended but not required
- index words are optional, it's possible (and potentially useful) to mix
  elements with index words and elements without index words, and it's
  possible (but probaly less useful) to mix lines with index words and
  lines without index words (here we require index words for lines
  and disallow them for elements)
- index words must be 2 or 3 or 4 chars long and consist of either
  only lowercase letters (lowercase index word) or only digits
  (digit index word), it's possible (but maybe barely useful) to
  mix the 2 types (here we don't support digit index words at all,
  and limit lowercase index words to 2 or 3 chars)
- if digit index words are used then they must match the index numbers for
  both lines and columns, ie a digit index word inside [[...]] and ((...))
  is optional but cannot hold a value different from what it would be
  anyway based on ZERO-based counting (here we don't support digit
  index words at all)
- if y-index words are used then they must be sorted, with a privileged role
  for 1 entry at the beginning and 1 entry at the end of the table that
  are guaranteed to be found even if they are misplaced (here we
  require y-index words, sorting rule holds)
- redundant whitespace is not a problem as long as "maxwidth" is not exceeded
  (this applies also to the beginning of the table) and no inline whitespace
  (TAB or SPACE) follows EOL whitespace (ASCII 0...8 and 10...31),
  this applies both to table lines and empty lines, ie an EOL
  must be followed by either EOL or a table line (ie [[...]] or ((...))
  or raw table element data)
- an empty table not containing any lines is valid as long as whitespace
  rules are observed, this means EOL's are tolerable while inline whitespace
  is not (here we require at least 1 line)
- a table line may not be empty, there must be at least 1 element
  (note that allowing empty lines would cause inconsistencies between
  lines with [[...]] and those without it)
- truncated table lines, ie lines shorter than other lines are tolerable, they
  can end with element data or inline whitespace following element data, but
  not with a comma ","
- a table element may not empty, dash "-" is the recommended filler for
  dummy elements, or ((...)) can be used to "jump" over columns, even an
  x-index word ((...)) must be followed by at least one char of table
  data (here we don't support x-index words at all)
- a table element may not contain the string "=", if this string is found it
  is translated to "-", the string "=" is reserved to indicate "not found or
  error" (this rule holds even if alternative output string is requested)

Strategy:

- we assume table width minimal "minwidth" 11 and
  maximal "maxwidth" 160 octets (not checked)
- table size in octets must be (2 * "maxwidth") 320 ... 1'000'000 (checked)
- we support only lowercase index words, not digit index
  words, the supplied index y-word must have 2 or 3 chars (checked)
- the supplied x-index number must be 0...9 (checked)
- we support only index word for "y" and expect [[...]] in every line
- we support only index number for "x" and expect ((...)) not to occur
- we give a f**k in UTF8 and consider the table to be an array of octets
- for "y" indexing we apply a mixed strategy of linear forward and backward
  search with step 2 and binary search
- for "y" indexing we begin with checking 0th entry, then last entry, then
  continue with binary search, and switch back to linear search as soon as
  the remaining size becomes dangerously low
- for "x" indexing we perform a linear forward search with step 1
- we give a f**k in closing "]]" and compare only opening "[["
  and 2 or 3 chars

This is how "minwidth" and "maxwidth" constants work:

- they restrict the legth of a complete table line
  including the obligatory EOL in octets
- "maxwidth" is the maximal distande between two line beginnings, and
  includes possible trailing spaces and blank lines (no other
  redundant whitespace is permitted)
- there is a special rule for the earliest line allowing up to "maxwidth"
  of garbage preceding the table if "[[" is used in all lines, otherwise
  up to "maxwidth" of blank lines
- there is a special rule for the last line allowing up to "maxwidth"
  of garbage following the table if "[[" is used in all lines, otherwise
  up to "maxwidth" of blank lines
- the minimal teoretically possible "minwidth" value is 2 (one char + EOL)
- here the "minwidth" value is 11 ("[[..]]" (6) + space + "Ido" (3) + EOL

Special rule about enclosing of elements written with
non-latin scripts (rl-enclosement):

- non-ASCII, non-latin and even RTL (right-to-left) scripts are permitted
  in the table
- a table element longer than 2 Octet:s may be enclosed in "rl " and " lr"
  strings on both sides, this is useful since many editors would otherwise
  break the element order if an RTL script is used
- by default the enclosing strings are not stripped off, but an extra
  parameter "1" can enable this for ordinary x-index numbers (0...9),
  for special values "+" or "-" this extra parameter is ignored

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

(assuming that the huge table seized via "mw.loadData" contains the silly
line "[[id]]  indonezia        , rl bahasa Indonesia lr , 1 , id , i
nd , id  , - , Indonezia lingvo , Kategori:Bahasa Esperanto ,   100"
but no line with y-index word "zzz", note that it is pointless to
rl-enclose the string "bahasa Indonesia")

* "{{#invoke:mpiktbllki|ek|err=error}}" (obligatory params miss, "err=" param)
* (expected result) -> "error"

* "{{#invoke:mpiktbllki|ek|id|1}}"
* (expected result) -> "bahasa Indonesia"

* "{{#invoke:mpiktbllki|ek|id|1|0}}" (keep rl lr)
* (expected result) -> "rl bahasa Indonesia lr"

* "{{#invoke:mpiktbllki|ek|id|1|1}}"
* (expected result) -> "bahasa Indonesia"

* "{{#invoke:mpiktbllki|ek|id|2}}"
* (expected result) -> "1"

* "{{#invoke:mpiktbllki|ek|id|4}}"
* (expected result) -> "ind"

* "{{#invoke:mpiktbllki|ek|id|6}}" (keep "-")
* (expected result) -> "-"

* "{{#invoke:mpiktbllki|ek|id|6|1|N/A}}" (replace "-")
* (expected result) -> "N/A"

* "{{#invoke:mpiktbllki|ek|zzz|2}}" (unknown y-index)
* (expected result) -> "="

* "{{#invoke:mpiktbllki|ek|zzz|2|err=bugger}}" (unknown y-index, "err=" param)
* (expected result) -> "bugger"

* "{{#invoke:mpiktbllki|ek|id|10}}"
* (expected result) -> "="

* "{{#invoke:mpiktbllki|ek|id|A}}" (invalid x-index)
* (expected result) -> "="

* "{{#invoke:mpiktbllki|ek|id|A|1}}" (invalid x-index)
* (expected result) -> "="

* "{{#invoke:mpiktbllki|ek|id|A|err=bugger}}" (invalid x-index, "err=" param)
* (expected result) -> "bugger"

* "{{#invoke:mpiktbllki|ek|id|-}}"
* (expected result) -> "1"

* "{{#invoke:mpiktbllki|ek|id|+}}"
* (expected result) -> "[[id]] indonezia , rl bahasa Indo
    nesia lr , 1 , id , ind , id , - , Ind
    onezia lingvo , Kategori:Bahasa Esperanto , 100"

* "{{#invoke:mpiktbllki|ek|zzz|-}}"
* (expected result) -> "0"

Note that output from this module when called from a template will be
subject to partial wiki parsing and full HTML parsing. This will result
in "[[id]" turned into a wikilink and in whitespace reduction. It is
not possible to call a module between "<pre>". In order to test this
module more thoroughly the output can be fed into another module
that analyzes the string and diplays ASCII codes or similar.

]===]

local piktbllki = {}

---- CONSTANTS ----

  -- constant strings EO vs ID

  local construsmo = "Modulo:mtmplloaddata"  -- EO
  -- local construsmo = "Modul:mtmplloaddata"   -- ID

  -- integers "num"

  -- two limits for width of table row in the source table
  -- !!! these values are CRUCIAL !!!
  -- !!! these values must be SAME here in "Module:mpiktbllki"
  --     and in other "Module:mkomtbllin" !!!
  -- !!! DO NOT CHANGE these values unless you understand how they work !!!

  local conminwidth = 11   -- safe values 8 ... 1/2 * "maxwidth"
  local conmaxwidth = 216  -- safe values 40 ... 40'000 and lower is better

---- SEIZE THE HUGE TABLE (OUTSIDE OF MAIN FUNCTION) ----

local tbllingvoj = mw.loadData(construsmo) -- can crash here
local constrtbl = "" -- huge table (320 (2 * "maxwidth") ... 1'000'000 chars)
if (tbllingvoj~=nil) then -- seems to be always true
  constrtbl = tbllingvoj [1] -- table -> string (with a small risk)
end--if

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

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

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

local function lfdec1digit (num1digit) -- converts 1 digit to decimal
  num1digit = num1digit - 48 -- may become invalid
  if ((num1digit<0) or (num1digit>9)) then
    num1digit = 255
  end--if
  return num1digit
end--function lfdec1digit

local function lftestlc (numcode) -- tests whether char is lowercase
  local boolowerc = true
  if ((numcode<97) or (numcode>122)) then
    boolowerc = false
  end--if
  return boolowerc
end--function lftestlc

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

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

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

-- Local function LFRLSTRIP

-- Strip "rl .. lr" if present and string length is at least 8 octet:s

local function lfrlstrip (strrlinut)
  local numsoct = 0
  local numsodt = 0
  local numsoet = 0
  local numsoft = 0
  local numsogt = 0
  local numsoht = 0
  local numlaengd = 0
  numlaengd = string.len(strrlinut)
  if (numlaengd>=8) then -- at least 2 Octet:s length "rl .. lr" after strip
    numsoct = string.byte(strrlinut,1,1)
    numsodt = string.byte(strrlinut,2,2)
    numsoet = string.byte(strrlinut,3,3)
    numsoft = string.byte(strrlinut,(numlaengd-2),(numlaengd-2))
    numsogt = string.byte(strrlinut,(numlaengd-1),(numlaengd-1))
    numsoht = string.byte(strrlinut,(numlaengd  ),(numlaengd  ))
    if ((numsoct==114) and (numsodt==108) and (numsoet==32) and (numsoft==32) and (numsogt==108) and (numsoht==114)) then
      strrlinut = string.sub(strrlinut,4,(numlaengd-3)) -- stri off 3+3 char:s
    end--if
  end--if
  return strrlinut
end--function lfrlstrip

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

---- MAIN EXPORTED FUNCTION ----

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

function piktbllki.ek (arxframent)

  -- special type "args"

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

  -- general str

  local strtmp    = ""   -- temp for decimal conversion
  local striywo   = ""   -- searched y-index word from arxframent.args[1]
  local stroutdsh = "-"  -- alternative string to replace "-" literal fr table
  local strerrequ = "="  -- default or alterna string to replace "=" on error
  local strret    = ""   -- output string

  -- general num

  local numoct = 0     -- temp
  local numlong = 0    -- temp for parameter evaluation, length of parameter
  local numinxlen = 0  -- length of y-index word f arxframent.args[1] (2 or 3)
  local numfoulen = 0  -- length of found y-index word (2 or 3)
  local numiwo0 = 0    -- searched y-index word
  local numiwo1 = 0    -- searched y-index word
  local numiwo2 = 0    -- searched y-index word, ZERO if only 2 chars are used
  local numxin = 255   -- x-index number f arxframent.args[2] (0...9, 11, 22)
  local numtbllen = 0  -- length of the huge table seized via "mw.loadData"
  local numipos = 0    -- octet position in "constrtbl", ZERO-based
  local numfndpos = 0  -- position of found line with [[...]], ZERO-based
  local numbinlow = 0  -- lower limit for binary search, ZERO-based position
  local numbinhaj = 0  -- higher limit for binary search, ZERO-based position

  -- general boo

  local booerr   = true   -- overall error flag
  local boostrip = true   -- flag for stripping rl-enclosement
  local booyxfnd = false  -- multipurpose found flag
  local boospc   = false  -- flag for whitespace reduction feature
  local boouch   = false  -- flag for found useful char when skipping element

  -- only for built-in function "searchdblchr"

  local isubnumlim = 0     -- octets to check (2 * "amount of iterations")
  local isubnumchr = 0     -- char to search (91 for "[[" or 40 for "((")
  local isubboodwn = false -- "true" for downward search
  local osubboofnd = false -- "true" if the dblchar was found

  -- only for built-in function "cmp2or3wordeq"

  local osubbooequal = false -- "true" if found idx word equal to "numiwo"

  -- only for built-in function "cmp2or3wordbi"

  local osubboobiger = false -- "true" if found idx word bigger than "numiwo"

  ---- BUILT-IN GOSUB-STYLE FUNCTION "SEARCHDBLCHR" ----

  -- PURPOSE: searches for a dblchar (91 for "[[" or 40 for "((")
  --          upwards or downwards

  -- IN  : isubnumlim, isubnumchr, isubboodwn (unchanged)
  -- OUT : osubboofnd (not in)
  -- USE : constrtbl (acts as a constant in the module)
  -- CHG : numipos (in and out)

  -- NOTE: if "isubboodwn" is "false" then we run upwards and check
  --       upwards, thus with incoming position "numipos"=10 we start checking
  --       at positions 11,(12,10), with incoming "isubnumlim"=10 we will no
  --       longer check positions 23,(24,22) but will check 21,(22,20) ... we
  --       need 3 chars margin at the top of range

  -- NOTE: if "isubboodwn" is "true" then we run downwards but still check
  --       upwards, thus with incoming position "numipos"=10 we start checking
  --       at positions 11,(12,10), with incoming "isubnumlim"=10 we will no
  --       longer check positions -01,(00,-02) but will check 01,(02,00) ... we
  --       need 3 chars margin at the top of range

  -- NOTE: we are supposed to safely ignore single occurrences (ie continue
  --       searching), as opposed to that triple and longer
  --       occurrences are prohibited

  local searchdblchr = function ()
    osubboofnd = true     -- pre-assume that we will find our dblchr
    local usubnumsrch = 0 -- search position checker counting always up
    local numokkt = 0     -- single char (giving a f**k in UTF8)
    local usubnumincr = 2 -- "+2" or "-2"
    if (isubboodwn==true) then
      usubnumincr = -2
    end--if
    while (true) do -- iterate through octets searching for dblchr (up or dwn)
      if (usubnumsrch>isubnumlim) then
        osubboofnd = false -- give up, tabl broken, "numipos" irrelevant now
        break
      end--if
      numokkt = string.byte (constrtbl,(numipos+2),(numipos+2)) ; -- "+1" actual
      if (numokkt==isubnumchr) then
        numokkt = string.byte (constrtbl,(numipos+3),(numipos+3)) ; -- "+2" above
        if (numokkt==isubnumchr) then
          numipos = numipos + 1 ;
          break ; -- found and "numipos" valid ... otherwise try to look blw
        end--if
        numokkt = string.byte (constrtbl,(numipos+1),(numipos+1)) ; -- "ZERO" blw
        if (numokkt==isubnumchr) then
          break ; -- found and "numipos" valid ... otherwise continue search
        end--if
      end--if
      usubnumsrch = usubnumsrch + 2
      numipos = numipos + usubnumincr -- "+2" or "-2"
    end--while
  end--function searchdblchr

  ---- BUILT-IN GOSUB-STYLE FUNCTION "CHK2OR3LIM" ----

  -- PURPOSE: performs a wild guess whether the found y-index word
  --          has 2 letters or 3 letters, lacks thorough checks,
  --          result will be ZERO if we would hit the limit

  -- IN  : numipos, numtbllen
  -- OUT : N/A
  -- USE : constrtbl (acts as a constant in the module)
  -- CHG : numfoulen (in and out)

  local chk2or3lim = function ()
    local usubnum1ch = 0 -- single char
    if ((numipos+6)>=numtbllen) then
      numfoulen = 0 -- peek +4 only but need 6 for [[aa]] or 7 for [[aaa]]
    else
      usubnum1ch = string.byte (constrtbl,(numipos+5),(numipos+5)) -- "+4" act
      if (lftestlc(usubnum1ch)==true) then
        numfoulen = 3
      else
        numfoulen = 2
      end--if
    end--if
  end--function chk2or3lim

  ---- BUILT-IN GOSUB-STYLE FUNCTION "CMP2OR3WORDEQ" ----

  -- PURPOSE: performs a comparison of 2 or 3 char:s testing for equality only

  -- IN  : numipos, numinxlen, numfoulen
  -- OUT : osubbooequal ("true" if equal)
  -- USE : constrtbl, numiwo (acts as a constant in the module)
  -- CHG : N/A (in and out)

  -- NOTE: it is the caller's responsibility to ensure
  --       that "numinxlen" and "numfoulen" are 2 or 3 !!!

  -- NOTE: it is the caller's responsibility to ensure
  --       that we don't hit the limit here in

  local cmp2or3wordeq = function ()
    osubbooequal = true -- pre-assume found, likely abort after 1 or 2 compa
    if (numinxlen~=numfoulen) then
      osubbooequal = false ; -- NOT found
    else
      if ((string.byte (constrtbl,numipos+3,numipos+3)) ~= numiwo0) then
        osubbooequal = false ; -- NOT found
      else
        if ((string.byte (constrtbl,numipos+4,numipos+4)) ~= numiwo1) then
          osubbooequal = false ; -- NOT found
        else
          if (numinxlen==3) then
            if ((string.byte (constrtbl,numipos+5,numipos+5)) ~= numiwo2) then
              osubbooequal = false ; -- NOT found
            end--if
          end--if
        end--if
      end--if
    end--if
  end--function cmp2or3wordeq

  ---- BUILT-IN GOSUB-STYLE FUNCTION "CMP2OR3WORDBI" ----

  -- PURPOSE: performs a comparison of 2 or 3 char:s testing for "bigger"

  -- IN  : numipos, numinxlen, numfoulen, numiwo
  -- OUT : osubboobiger ("true" if found index word is bigger than "numiwo")
  -- USE : constrtbl (acts as a constant in the module)
  -- CHG : N/A

  -- NOTE: it is the caller's responsibility to ensure
  --       that "numinxlen" and "numfoulen" are 2 or 3 !!!

  -- NOTE: it is the caller's responsibility to ensure
  --       that we don't hit the limit here in

  -- NOTE: the 2 strings are expected not to be equal on entry here,
  --       but single letters may be, thus ("grc" and "grc") is impossible,
  --       but ("grc" and "gro") or ("grc" and "gr") can occur, actually,
  --       the code here itself tests for "bigger" vs "smaller or equal"

  local cmp2or3wordbi = function ()
    local usubnum1char = 0 ; -- single char
    osubboobiger = false ; -- pre-assume smaller or equal, likely abort soon
    usubnum1char = (string.byte (constrtbl,numipos+3,numipos+3)) ;
    if (usubnum1char>numiwo0) then
      osubboobiger = true ; -- bigger
    else
      if (usubnum1char==numiwo0) then
        usubnum1char = (string.byte (constrtbl,numipos+4,numipos+4)) ;
        if (usubnum1char>numiwo1) then
          osubboobiger = true ; -- bigger
        else
          if ((usubnum1char==numiwo1) and ((numinxlen+numfoulen)>4)) then
            if (numfoulen>numinxlen) then
              osubboobiger = true -- (3:2 - found:previous) and bigger
            else
              if (numfoulen==3) then
                usubnum1char = (string.byte (constrtbl,numipos+5,numipos+5)) ;
              else
                usubnum1char = 0
              end--if
              if (usubnum1char > numiwo2) then
                osubboobiger = true -- bigger
              end--if
            end--if
          end--if
        end--if (usubnum1char>numiwo1) else
      end--if
    end--if
  end--function cmp2or3wordbi

  ---- CHECK THE HUGE TABLE ----

  if (type(constrtbl)=="string") then -- important check
    numtbllen = string.len (constrtbl) ;
    if ((numtbllen>=(2*conmaxwidth)) and (numtbllen<=1000000)) then
      booerr = false ; -- was preset to true
    end--if
  end--if

  ---- SEIZE 2 OBLIGATORY ARGUMENTS FROM THE CALLER (2 MORE ARE OPTIONAL) ----

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

  if ((arxourown[1]==nil) or (arxourown[2]==nil)) then
    booerr = true
  end--if
  if (booerr==false) then
    striywo = arxourown[1] -- y-index word (2 or 3 lowercase chars)
    numinxlen = string.len (striywo)
    if ((numinxlen<2) or (numinxlen>3)) then
      booerr = true
    else
      numiwo0 = string.byte (striywo,1,1)
      if (lftestlc(numiwo0)==false) then
        booerr = true
      end--if
      numiwo1 = string.byte (striywo,2,2)
      if (lftestlc(numiwo1)==false) then
        booerr = true
      end--if
      if (numinxlen==3) then
        numiwo2 = string.byte (striywo,3,3)
        if (lftestlc(numiwo2)==false) then
          booerr = true
        end--if
      end--if
    end--if
  end--if
  if (booerr==false) then
    strtmp = arxourown[2] -- x-index number (1 digit, 0...9, ZERO-based)
    numlong = string.len (strtmp) -- temp for decimal conversion
    if (numlong==1) then
      numxin = string.byte (strtmp,1,1)
      if (numxin==43) then
        numxin = 11 -- special "+" (complete) special value 11
      else
        if (numxin==45) then
          numxin = 22 -- special "-" (binary) special value 22
        else
          numxin = lfdec1digit (numxin) -- 255 if invalid
        end--if
      end--if
    end--if
    if (numxin==255) then
      booerr = true -- damn: no valid x-index number
    end--if
  end--if
  if (booerr==false) then
    if (type(arxourown[3])=="string") then
      strtmp = arxourown[3] -- optional "0" or "1" (default) strip flag
      numlong = string.len (strtmp) -- temp
      if (numlong==1) then
        numoct = string.byte (strtmp,1,1)
        if (numoct==48) then
          boostrip = false -- was preset to true
        end--if
        if ((numoct~=48) and (numoct~=49)) then
          booerr = true -- damn
        end--if
      else
        booerr = true -- damn
      end--if
    end--if (type(arxourown[3])=="string") then
    if (type(arxourown[4])=="string") then
      strtmp = arxourown[4] -- 1...64 char:s alterna string to replace "-"
      numlong = string.len (strtmp) -- temp
      if ((numlong<1) or (numlong>64)) then
        booerr = true -- damn
      else
        stroutdsh = strtmp -- was preset to "-"
      end--if
    end--if (type(arxourown[4])=="string") then
  end--if

  ---- SEIZE NAMED PARAMETER EVEN IF WE ALREADY SUCK ----

  -- try to pick named parameter "err=" even if we already have "booerr==true"

  if (type(arxourown["err"])=="string") then
    strtmp = arxourown["err"] -- 1...64 char:s alterna string to replace "="
    numlong = string.len (strtmp) -- temp
    if ((numlong<1) or (numlong>64)) then
      booerr = true -- damn
    else
      strerrequ = strtmp -- was preset to "="
    end--if
  end--if (type(arxourown["err"])=="string") then

  ---- PRESET ----

  booyxfnd = false -- set to "true" as soon as specified y-index word found

  ---- SEARCH FOR THE TABLE BEGIN AKA THE 0TH Y-INDEX WORD ----

  -- will succeed if we find "[[" within "maxwidth"

  -- note that minimum table size guaranteed from above
  -- is (2 * "maxwidth") but the table may contain much padding
  -- and shrink considerably after padding is trimmed off

  if (booerr==false) then
    numipos = 0              -- ZERO-based position in "constrtbl"
    isubnumlim = conmaxwidth -- do NOT subtract here
    isubnumchr = 91          -- search for "[" ie "[["
    isubboodwn = false
    searchdblchr () -- OUT : osubboofnd | USE : constrtbl | CHG : numipos
    if (osubboofnd==false) then
      booerr = true -- give up, table is broken, "numipos" irrelevant now
    end--if
  end--if

  -- now ZERO-based "numipos" maybe points to the found "[["

  ---- COMPARE THE 0TH Y-INDEX WORD ----

  if (booerr==false) then
    chk2or3lim () -- IN: numipos, numtbllen | USE: constrtbl | CHG: numfoulen
    if (numfoulen==0) then
      booerr = true -- barely can occur
    else
      cmp2or3wordeq () -- OUT: osubbooequal | USE: constrtbl, numiwo
      if (osubbooequal==true) then
        numfndpos = numipos
        booyxfnd = true -- found the y-index word !!!
      else
        numbinlow = numipos -- points to found "[[", will need this later
      end--if
    end--if
  end--if

  -- now ZERO-based "numfndpos" maybe points to the found "[[...]]"
  -- now "numipos" is irrelevant

  ---- SEARCH FOR THE LAST Y-INDEX WORD ----

  -- will succeed if we find "[[" within "maxwidth"

  -- if we have only one line then found last index word will
  -- be the same as the found 0th index word

  if ((booerr==false) and (booyxfnd==false)) then
    numipos = numtbllen - conminwidth          -- ZERO-based positi in "constrtbl"
    isubnumlim = 2 * conmaxwidth - conminwidth -- allow full "maxwidth" of garb
    isubnumchr = 91                            -- search for "[" ie "[["
    isubboodwn = true                          -- downwards
    searchdblchr () -- OUT : osubboofnd | USE : constrtbl | CHG : numipos
    if (osubboofnd==false) then
      booerr = true -- give up, table is broken, "numipos" irrelevant now
    end--if
  end--if

  -- now ZERO-based "numipos" maybe points to the found "[["

  ---- COMPARE THE LAST Y-INDEX WORD ----

  if ((booerr==false) and (booyxfnd==false)) then
    chk2or3lim () -- IN: numipos, numtbllen | USE: constrtbl | CHG: numfoulen
    if (numfoulen==0) then
      booerr = true -- barely can occur
    else
      cmp2or3wordeq () ; -- OUT: osubbooequal | USE: constrtbl, numiwo
      if (osubbooequal==true) then
        numfndpos = numipos
        booyxfnd = true ; -- found the y-index word !!!
      else
        numbinhaj = numipos ; -- points to found "[[", will need this later
      end--if
    end--if
  end--if

  -- now ZERO-based "numfndpos" maybe points to the found "[[...]]"
  -- now "numipos" is irrelevant

  ---- PERFORM THE BINARY SEARCH ----

  -- ZERO-based "numbinlow" and "numbinhaj" always point to begi of "[[...]]"

  -- note that here SUB "searchdblchr" can fail with "osubboofnd==false"
  -- if the table exceeds "maxwidth", this is an error

  -- the other risk with SUB "searchdblchr" is that could hit "numbinhaj"
  -- and find the "[[" there, this is highly undesirable as this would
  -- cause a subsequent invalid comparison with random result, we prevent
  -- this by aborting the binary search at this point

  if ((booerr==false) and (booyxfnd==false)) then
    while (true) do -- reduce size by halving until it becomes too small
      numipos = math.floor ((numbinlow + numbinhaj) / 2) -- ZERO-based positi
      if ((numipos+conmaxwidth+conminwidth)>numbinhaj) then
        break -- NOT found, continue with desperate last step linear search
      end--if
      isubnumlim = conmaxwidth -- do NOT subtract here
      isubnumchr = 91          -- search for "[" ie "[["
      isubboodwn = false       -- upwards
      searchdblchr () -- OUT : osubboofnd | USE : constrtbl | CHG : numipos
      if (osubboofnd==false) then
        booerr = true
        break ; -- give up, not found or table brokn, "numipos" irrelevant now
      end--if
      chk2or3lim () ; -- IN: numipos, numtbllen | USE: constrtbl | CHG: numfoulen
      cmp2or3wordeq () ; -- OUT: osubbooequal | USE: constrtbl, numiwo
      if (osubbooequal==true) then
        numfndpos = numipos ;
        booyxfnd = true ;
        break ; -- found the y-index word !!!
      end--if
      cmp2or3wordbi () -- OUT: osubboobiger | USE: constrtbl, numiwo
      if (osubboobiger==true) then -- "true" if found y-index word > "numiwo"
        numbinhaj = numipos -- was too high, check below, reduce "numbinhaj"
      else
        numbinlow = numipos -- was too low, check above, increas "numbinlow"
      end--if
    end--while
  end--if

  -- below look at "booerr", then at "booyxfnd",
  -- then at "numfndpos" or ("binlow" and "binhaj")

  ---- PERFORM THE DESPERATE LAST STEP LINEAR SEARCH ----

  -- search through range "binlow" to "binhaj", this can be more than
  -- "maxwidth" (almost double size in worst case)

  -- there definitely is "[[" at both "binlow" and "binhaj" and there can
  -- be ZERO, ONE or several further "[[" in the range

  -- so we indeed subtract "minwidth" from the range size two times

  if ((booerr==false) and (booyxfnd==false)) then
    numipos = numbinlow ;
    while (true) do -- there can be several lines left
      numipos = numipos + conminwidth ;
      isubnumlim = numbinhaj - numipos - conminwidth ; -- is "[[" at "binhaj"
      if (isubnumlim<conminwidth) then
        booerr = true
        break ; -- give up, not found or table brokn, "numipos" irrelevant now
      end--if
      isubnumchr = 91    -- search for "[" ie "[["
      isubboodwn = false -- upwards
      searchdblchr ()    -- OUT : osubboofnd | USE : constrtbl | CHG : numipos
      if (osubboofnd==false) then
        booerr = true
        break ; -- give up, not found or table brokn, "numipos" irrelevant now
      end--if
      chk2or3lim () ; -- IN: numipos, numtbllen | USE: constrtbl | CHG: numfoulen
      cmp2or3wordeq () ; -- OUT: osubbooequal | USE: constrtbl, numiwo
      if (osubbooequal==true) then
        numfndpos = numipos ;
        break ; -- found the y-index word but "booyxfnd" not needed anymore !!
      end--if
    end--while
  end--if

  -- below not look at "booyxfnd", look at "booerr" only and maybe "numfndpos"

  ---- RETURN ONE ELEMENT PICKED ACCORDING TO X-INDEX NUMBER IF 0...9 ----

  -- This is done in 3 + 1 steps:
  -- * skip possible unsuitable elements
  -- * skip possible whitespace preceding the searched element
  -- * copy the searched element (takes a char from previous step)
  -- * strip off rl-enclosement if requested (boostrip=true) and it is present

  -- this is a copy of module "mpiksubstrind" with minimal modifications

  if ((booerr==false) and (numxin<10)) then
      booxyfnd = false
      numipos = numfndpos + 4 + numinxlen -- ZERO-based index in "constrtbl"
      numite = numxin -- count down
      while (true) do -- iterate through elements in order to skip them
        if (numite==0) then -- nothing to skip anymore
          booxyfnd = true ;
          break ; -- exit the outer loop, nothing to skip anymore
        end--if
        numite = numite - 1
        booxyfnd = false
        boouch = false
        while (true) do -- iterate through whspc & chars mix looking for comma
          if (numipos>=numtbllen) then
            break ; -- exit the inner loop, NOT found, give up
          end--if
          numipos = numipos + 1 ;
          numoct = string.byte (constrtbl,numipos,numipos) ;
          if ((numoct<32) and (numoct~=9)) then
            break -- EOL: exit the inner loop, NOT found, give up
          end--if
          if ((numoct>32) and (numoct~=44)) then
            boouch = true ; -- found a valid char (empty field is an error)
          end--if
          if (numoct==44) then
            if (boouch==true) then
              booxyfnd = true ; -- field was not empty
            end--if
            break ; -- exit the inner loop, found a comma, this is good or bad
          end--if
        end--while
        if (booxyfnd==false) then
          break -- exit the outer loop, NOT found or empty field, give up
        end--if
      end--while
      if (booxyfnd==true) then
        booxyfnd = false ;
        while (true) do -- iterate through chars skipping whitespace
          if (numipos>=numtbllen) then
            break ; -- exit the loop, NOT found, give up
          end--if
          numipos = numipos + 1 ;
          numoct = string.byte (constrtbl,numipos,numipos)
          if ((numoct<32) and (numoct~=9)) then
            break -- EOL: exit the loop, NOT found, give up
          end--if
          if (numoct>32) then
            if (numoct==44) then
              break ; -- exit loop, found comma, give up according to rules
            end--if
            booxyfnd = true ;
            break ; -- exit the loop, found valid char, start copying now
          end--if
        end--while
      end--if
      if (booxyfnd==true) then
        while (true) do -- iterate through chars copying the found element
          if ((numoct==32) or (numoct==9)) then
            boospc=true
          else
            if (boospc==true) then
              strret = strret .. " " -- was preset to empty
              boospc = false
            end--if
            strret = strret .. string.char (numoct)
          end--if
          if (numipos>=numtbllen) then
            break ; -- exit the loop, done
          end--if
          numipos = numipos + 1 ;
          numoct = string.byte (constrtbl,numipos,numipos)
          if ((numoct<32) and (numoct~=9)) then
            break ; -- EOL: exit the loop, done
          end--if
          if (numoct==44) then
            break -- comma: exit the loop, done
          end--if
        end--while
      end--if
      if (booxyfnd==false) then
        booerr = true -- damn: failed in the x-search
      end--if
  end--if

  -- strip off rl-enclosement if requested (boostrip=true) and it is present

  if ((booerr==false) and (numxin<10) and (boostrip==true)) then
    strret = lfrlstrip (strret)
  end--if

  ---- RETURN COMPLETE LINE IF SPECIAL "+" AKA 11 ----

  -- we do reduce excessive whitespace

  if ((booerr==false) and (numxin==11)) then
      boospc = false
      numipos = 0 -- limit width again
      while (true) do -- iterate through chars copying the found line
        if (numipos>=conmaxwidth) then
          booerr = true
          break -- damn: violated "maxwidth"
        end--if
        numoct = string.byte (constrtbl,(numfndpos+1),(numfndpos+1)) ;
        if ((numoct<32) and (numoct~=9)) then
          break -- done (anything < 32 other than TAB counts as EOL)
        end--if
        if ((numoct==32) or (numoct==9)) then
          boospc=true
        else
          if (boospc==true) then
            strret = strret .. " " -- was preset to empty
            boospc = false
          end--if
          strret = strret .. string.char (numoct) -- was preset to empty
        end--if
        numipos = numipos + 1
        numfndpos = numfndpos + 1
      end--while
  end--if

  ---- CARE ABOUT PROHIBITED EQUAL SIGN ----

  if (strret=='=') then
    strret = '-' -- string "=" is prohibited, punishment is conversion to "-"
  end--if

  ---- CARE ABOUT ERRORS ----

  -- this is NOT final or valid for input x-index number "-" AKA 22

  if (booerr==true) then
    strret = strerrequ -- string "strret" was preset to empty
  end--if

  ---- CARE ABOUT DASH TRANSLATION ----

  if (strret=='-') then
    strret = stroutdsh
  end--if

  ---- RETURN BINARY DIGIT IF SPECIAL X-INDEX NUMBER "-" AKA 22 ----

  if (numxin==22) then
    if (booerr==true) then
      strret = "0" -- y-index word NOT found or error
    else
      strret = "1" -- y-index word found
    end--if
  end--if

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

  return strret

end--function

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

return piktbllki