Modulo:eht
Aspekto
Memtesto disponeblas sur la paĝo Ŝablono:eht. | ||
- Ĉi tiu modulo efektivigas laboron de ŝablono
{{eht}}kaj estas vokata sole de tie. - Dependas de:
- modulo
((loaddata-tbllingvoj))(tabelo T80) siavice de permodule legata ŝablono{{tbllingvoj}} - ŝablonoj
{{KategorioEHT-etiopia-skribo}}kaj{{eht-kat-alfa}}
- modulo
--[===[
MODULE "EHT" (enhavtabelo)
"eo.wiktionary.org/wiki/Modulo:eht" <!--2025-Aug-16-->
Purpose: displays TOC of a cat only if there are at least 300
pages or at least 300 subcategories, and automatically picks
correct alphabet based on langname read out from pagename
Utilo: montras enhavtabelon de kategorio nur se disponeblas almenaux 300
pagxoj aux almenaux 300 subkategorioj, kaj auxtomate elektas
gxustan alfabeton surbaze de lingvonomo ellegita el pagxonomo
Manfaat: menlihatkan daftar isi kategori ...
Syfte: visar ...
Used by templates / Uzata far sxablonoj /
Digunakan oleh templat / Anvaent av mallar:
* only "eht"
Required submodules / Bezonataj submoduloj /
Submodul yang diperlukan / Behoevda submoduler:
* "loaddata-tbllingvoj" T80 in turn requiring template "tbllingvoj" (EO)
* "loaddata-tblbahasa" T80 in turn requiring template "tblbahasa" (ID)
* "loaddata-tblalfabetoj" !!!FIXME!!!
* "ind12dim" !!!FIXME!!!
Required templates:
* "KategorioEHT-etiopia-skribo" !!!FIXME!!!
* "eht-kat-alfa" !!!FIXME!!!
This module can accept parameters whether sent to itself (own frame) or
to the parent (parent's frame). If there is a parameter "parentframe=true"
on the own frame then that own frame is discarded in favor of the
parent's one.
Incoming: * no ordinary parameters
* 4 hidden named and optional parameters
* "pagenameoverridetestonly=" -- can directly cause #E01
* "nsnumberoverridetestonly="
* "tocforceoverridetestonly=" -- "on" or "off"
* "detrc=" no error possible
Returned: * either a box or empty or error message, tracking cat:s
only on error
------------------------------------------------------------------------
Supported and prohibited types of cats and resulting
langcodes and error codes, eval in this order:
* full types (catname is a valid langname, comparison or fetch must be
case-insensitive on leftmost char):
* "Sveda" -> #E16 (number of members too low, thus TOC never needed)
* "Greka antikva" -> #E16 (number of members too low, thus TOC never needed)
* sandwiched types:
* "Vorto -en- enhavanta morfemon U (-ist)" -> en
* "Frazo -en- enhavanta vorton (nope)" -> en
* "Vortgrupo -en- enhavanta (nope)" -> en
* suffixed types:
* "Geografio laux lingvo" -> eo (langnames consist of Esperanto letters)
* full single exceptions (only needed if NOT "mul" or rule-out essential):
* "Aldona pago pri unuopa lingvo" -> eo (langnames consist of Esperanto letters)
* "Sablonaro pri specifa lingvo" -> en (langcodes consist of ASCII letters)
* "Fundamenta elemento" -> Esperanto (consist of Esperanto letters)
* bracketed types:
* "Verbo (sveda)" -- word class and lang -> sv
* "Fiziko (indonezia)" -- field and lang -> id
* "Tradukoj (franca)" -> fr
* "Vortfarado (angla)" -> en
* dialect types:
* "Oseta digora" -> os !!!FIXME!!! not yet
* anything else:
* "Verbo" -- word class -> mul
* "Fiziko" -- field -> mul
This module does NOT bother about word classes or fields, it just
looks at the bracketed part.
Dialect types are difficult to parse, since:
* "Oseta digora" must give os (dialect)
* "Germana auxstra" must give de (dialect)
whereas
* "Greka antikva" must give #E16 (language)
Notes on structure (NOT provided by this module):
* "Kategorio:Oseta digora" is in "Kategorio:Dialekto (oseta)" with
hint "digora"
* "Kategorio:Oseta irona" is in "Kategorio:Dialekto (oseta)" with
hint "irona"
* "Kategorio:Germana auxstra" is in "Kategorio:Dialekto (germana)" with
hint "auxstra"
Proposal A:
* use list of dialects
* check full catname (after check against possible langname) against
possible dialect (comparison or fetch must be case-insensitive
on leftmost char)
* if dialect found then fetch the language belonging to it
* can identify unknown dialect
Proposal B:
* check full catname against possible langname (needed to rule
out "Kategorio:Greka antikva")
* drop word after word from right until either valid langname found
or nothing left, ie take the longest substring from left that
is a valid langname
* if langname found then take it
* cannot identify unknown dialect
------------------------------------------------------------------------
Possible errors:
* <<#E01 Internal error in module "eht">>
Possible causes:
* strings not uncommented
* function "mw.title.getCurrentTitle().text" AKA "{{PAGENAME}}" failed
* <<#E02 Malica eraro en subprogramaro uzata far sxablono "eht">>
Possible causes:
* submodule "loaddata-tbllingvoj" not found
* submodule "loaddata-tbllingvoj" caused unspecified failure
* <<#E03 Nombrigita eraro en subprogramaro uzata far sxablono "eht">>
Possible causes:
* submodule failed and returned valid error code
* <<#E10 Erara uzo de sxablono (eht), uzebla nur en nomspaco 14 (kategorio)>>
* <<#E11 Evidente nevalida lingvokodo en pagxonomo>>
* <<#E14 Ne esperanta majuskla komenclitero ...
* <<#E15 Erara uzo de sxablono (eht), nevalida aux nekonata
lingvonomo en pagxonomo>>
* <<#E16 Uzo cxe malpermesita tipo de kategorio>>
* <<#E19 SXablono ne redonis validan rezulton>> !!!FIXME!!!
Possible tracking cat:s:
* [[Kategorio:Evidente nevalida lingvokodo]] #E11
* [[Kategorio:Nekonata lingvonomo]] #E15
* [[Kategorio:Erara uzo de sxablono]] #E10 #E19
* [[Kategorio:Erara uzo de sxablono (eht)]] #E10 #E19
* [[Kategorio:Erara uzo de sxablono (eht, E19)]] #E10 #E19
]===]
local exporttable = {}
require('strict')
-- ***********************
-- * CONSTANTS [O] * ---------------------------------------------
-- ***********************
-- constant table -- ban list -- add obviously invalid access codes (2-letter or 3-letter) only
-- length of the list is NOT stored anywhere, the processing stops
-- when type "nil" is encountered, used by "lfivalidatelnkoadv" only
-- controversial codes (sh sr hr), (zh cmn)
-- "en.wiktionary.org/wiki/Wiktionary:Language_treatment" excluded languages
-- "en.wikipedia.org/wiki/Spurious_languages"
-- "iso639-3.sil.org/code/art" only valid in ISO 639-2
-- "iso639-3.sil.org/code/gem" only valid in ISO 639-2 and 639-5, "collective"
-- "iso639-3.sil.org/code/zxx" "No linguistic content"
local contabisbanned = {}
contabisbanned = {'by','dc','ll','jp','art','deu','eng','epo','fra','gem','ger','ido','lat','por','rus','spa','swe','tup','zxx'} -- 1...19
-- uncommentable (site-related features)
local constringvoj = 'Modulo:loaddata-tbllingvoj' -- EO
-- local constringvoj = 'Modul:loaddata-tblbahasa' -- ID
local constrbetoj = 'Modulo:loaddata-tblalfabetoj' -- EO
-- local constrbetoj = 'Modul:loaddata-tblabjad" -- ID
-- uncommentable constant table (error messages)
-- #E02...#E98, holes permitted
-- note that #E0 #E01 #E99 are NOT supposed to be included here
-- separate "strpikparent" needed for "%@"
local contaberaroj = {}
contaberaroj[02] = 'Malica eraro en subprogramaro uzata far %@' -- EO #E02
-- contaberaroj[02] = 'Kesalahan jahat dalam subprogram digunakan oleh %@' -- ID #E02
contaberaroj[03] = 'Nombrigita eraro en subprogramaro uzata far %@' -- EO #E03
-- contaberaroj[03] = 'Kesalahan ternomor dalam subprogram digunakan oleh %@' -- ID #E03
contaberaroj[10] = 'Erara uzo de %@, uzebla nur en nomspaco 14 (kategorio)' -- EO #E10
-- contaberaroj[10] = 'Penggunaan salah %@, hanya bisa digunakan dalam ruang nama 14 (kategori)' -- ID #E10
contaberaroj[11] = 'Evidente nevalida lingvokodo sendita al %@' -- EO #E11
-- contaberaroj[11] = 'Kode bahasa jelas-jelas salah dikirim ke %@' -- ID #E11
contaberaroj[16] = 'Uzo de %@ cxe malpermesita tipo de kategorio' -- EO #E16
-- contaberaroj[16] = 'Penggunaan %@ di tipe kategori yang tidak diperbolehkan' -- ID #E16
-- uncommentable constant table (tracking cat:s)
local contabtrako = {}
contabtrako['E11'] = 'Evidente nevalida lingvokodo'
contabtrako['E15'] = 'Nekonata lingvonomo'
contabtrako.cetere = 'Erara uzo de sxablono'
-- uncommentable patterns for cat names for lfhgetlangfromcat
local contabfarado = {} -- 3 types -- there can follow space and script code
contabfarado['Vorto -' ] = '- enhavanta morfemon ' -- "Vorto -en- enhavanta morfemon U (-ist)" -- BEWARE ends with space
contabfarado['Frazo -' ] = '- enhavanta vorton (' -- "Frazo -en- enhavanta vorton (nope)"
contabfarado['Vortgrupo -'] = '- enhavanta (' -- "Vortgrupo -en- enhavanta (nope)"
local contabfullcat = {}
contabfullcat['Aldona pagxo pri unuopa lingvo'] = 'eo'
contabfullcat['Fundamenta elemento' ] = 'eo'
contabfullcat['SXablonaro pri specifa lingvo' ] = 'en'
local contabsuffcat = {}
contabsuffcat[' laux lingvo'] = 'eo' -- BEWARE begins with space
-- surrogate transcoding table (only needed for EO)
local contabtransluteo = {}
contabtransluteo[ 67] = 0xC488 -- CX
contabtransluteo[ 99] = 0xC489 -- cx
contabtransluteo[ 71] = 0xC49C -- GX
contabtransluteo[103] = 0xC49D -- gx
contabtransluteo[ 74] = 0xC4B4 -- JX
contabtransluteo[106] = 0xC4B5 -- jx
contabtransluteo[ 83] = 0xC59C -- SX
contabtransluteo[115] = 0xC59D -- sx
contabtransluteo[ 85] = 0xC5AC -- UX breve
contabtransluteo[117] = 0xC5AD -- ux breve
-- constant strings (error circumfixes)
local contabfel = {}
contabfel.mibg = '<span class="error">' -- mini whining begin
contabfel.labg = '<b>' .. contabfel.mibg -- lagom whining begin
contabfel.hubg = '<big>' .. contabfel.labg -- huge whining begin
contabfel.mien = '</span>' -- mini whining end
contabfel.laen = contabfel.mien .. '</b>' -- lagom whining end
contabfel.huen = contabfel.laen .. '</big>' -- huge whining end
-- langcodes with fallbacks
local contabfall = {} -- left column for supported codes and possible targets, other columns fallback codes
contabfall [ 1] = {'sv', 'da', 'fi', 'fit', 'no', 'nb', 'nn'}
contabfall [ 2] = {'ru', 'be', 'bg', 'sr', 'uk'}
contabfall [ 3] = {'de', 'bar', 'lb', 'vo'}
contabfall [ 4] = {'etio', 'am', 'gez', 'om', 'ti', 'tig', 'har'}
contabfall [ 5] = {'en'}
contabfall [ 6] = {'cv'}
contabfall [ 7] = {'eo'}
contabfall [ 8] = {'hy'}
contabfall [ 9] = {'mul'}
contabfall [10] = {'os'}
contabfall [11] = {'rue'}
contabfall [12] = {'sud'}
contabfall [13] = {'tg'}
-- diverse tuning values in separate variables
local conbookodlng = false -- "true" to allow long codes like "zh-min-nan"
local conboomiddig = false -- "true" to allow middle digit like "s7a"
-- uncommentable (override)
-- * name of table MUST always be defined, OTOH elements are usually NOT
-- * for testing only, values automatically peeked otherwise
local contabovrd = {}
-- contabovrd.sitelang = 'eo' -- "en"
-- contabovrd.sitelang = 'id'
-- contabovrd.katprefi = 'Kategorio' -- "Category"
-- contabovrd.katprefi = 'Kategori'
-- contabovrd.parentfn = string.char(0xC5,0x9C) .. 'ablono:eht' -- "Template:eht" (!!! no surr translation !!!)
-- contabovrd.defortrc = true -- force "detrc=true"
-- ****************************************
-- * SPECIAL STUFF OUTSIDE MAIN [B] * ----------------------------
-- ****************************************
-- SPECIAL VAR:S
local qldingvoj = {} -- type "table" but metaized with some subtables
local qldbetoj = {} -- type "table" but metaized with some subtables
local qbooguard = false -- only for the guard test, pass to other var ASAP
local qboodetrc = true -- from "detrc=true" but default is "true" !!!
local qstrtrace = '<br>' -- for main & proc, debug report request by "detrc="
---- GUARD AGAINST INTERNAL ERROR AND IMPORT ONE VIA LOADDATA ---- !!!FIXME!!! betoj parsecatname
qbooguard = (type(constringvoj)~='string')
if (not qbooguard) then
qldingvoj = mw.loadData(constringvoj) -- can crash here
qbooguard = (type(qldingvoj)~='table') -- seems to be always false
end--if
-- ******************************
-- * DEBUG PROCEDURES [D] * --------------------------------------
-- ******************************
-- Enhance upvalue "qstrtrace" with fixed text.
-- for variables the other "lfdshowvar" is preferable but in exceptional
-- cases it can be justified to send text with values of variables to this
-- no size limit
-- upvalue "qstrtrace" must NOT be type "nil" on entry (is inited to "<br>")
-- uses upvalue "qboodetrc"
local function prdtracemsg (strshortline)
if (qboodetrc and (type(strshortline)=='string')) then
qstrtrace = qstrtrace .. strshortline .. '.<br>' -- dot added !!!
end--if
end--function prdtracemsg
------------------------------------------------------------------------
---- MATH FUNCTIONS [E] ----
------------------------------------------------------------------------
local function mathisintrange (numzjinput, numzjmin, numzjmax)
local booisclean = false -- preASSume guilt
if (type(numzjinput)=='number') then -- no non-numbers, thanks
if (numzjinput==math.floor(numzjinput)) then -- no transcendental
booisclean = ((numzjinput>=numzjmin) and (numzjinput<=numzjmax)) -- rang
end--if
end--if
return booisclean
end--function mathisintrange
local function mathdiv (xdividens, xdivisero)
local resultdiv = 0 -- DIV operator lacks in LUA :-(
resultdiv = math.floor (xdividens / xdivisero)
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
------------------------------------------------------------------------
---- NUMBER CONVERSION FUNCTIONS [N] ----
------------------------------------------------------------------------
local function prnnumto2digit (numzerotoninetynine)
-- Convert integer 0...99 to decimal ASCII string always 2 digits "00"..."99".
-- Depends on procedures :
-- [E] mathisintrange mathdiv mathmod
local strtwodig = '??' -- always 2 digits
if (mathisintrange(numzerotoninetynine,0,99)) then
strtwodig = tostring(mathdiv(numzerotoninetynine,10)) .. tostring(mathmod(numzerotoninetynine,10))
end--if
return strtwodig
end--function prnnumto2digit
-- *****************************************
-- * LOW LEVEL STRING PROCEDURES [G] * ---------------------------
-- *****************************************
local function prgstringrange (varvictim, nummini, nummaxi)
local nummylengthofstr = 0
local booveryvalid = false -- preASSume guilt
if (type(varvictim)=='string') then
nummylengthofstr = string.len(varvictim)
booveryvalid = ((nummylengthofstr>=nummini) and (nummylengthofstr<=nummaxi))
end--if
return booveryvalid
end--function prgstringrange
------------------------------------------------------------------------
-- Local function LFGPOKESTRING
-- Replace single octet in a string.
-- Input : * strinpokeout -- empty legal
-- * numpokepoz -- ZERO-based, out of range legal
-- * numpokeval -- new value
-- This is inefficient by design of LUA. The caller is responsible to
-- minimize the number of invocations of this, in particular, not to
-- call if the new value is equal the existing one.
local function lfgpokestring (strinpokeout, numpokepoz, numpokeval)
local numpokelen = 0
numpokelen = string.len(strinpokeout)
if ((numpokelen==1) and (numpokepoz==0)) then
strinpokeout = string.char(numpokeval) -- totally replace
end--if
if (numpokelen>=2) then
if (numpokepoz==0) then
strinpokeout = string.char(numpokeval) .. string.sub (strinpokeout,2,numpokelen)
end--if
if ((numpokepoz>0) and (numpokepoz<(numpokelen-1))) then
strinpokeout = string.sub (strinpokeout,1,numpokepoz) .. string.char(numpokeval) .. string.sub (strinpokeout,(numpokepoz+2),numpokelen)
end--if
if (numpokepoz==(numpokelen-1)) then
strinpokeout = string.sub (strinpokeout,1,(numpokelen-1)) .. string.char(numpokeval)
end--if
end--if (numpokelen>=2) then
return strinpokeout
end--function lfgpokestring
------------------------------------------------------------------------
local function lfgtestnum (numkaad)
local boodigit = false
boodigit = ((numkaad>=48) and (numkaad<=57))
return boodigit
end--function lfgtestnum
local function lfgtestuc (numkode)
local booupperc = false
booupperc = ((numkode>=65) and (numkode<=90))
return booupperc
end--function lfgtestuc
local function lfgtestlc (numcode)
local boolowerc = false
boolowerc = ((numcode>=97) and (numcode<=122))
return boolowerc
end--function lfgtestlc
------------------------------------------------------------------------
-- Local function LFGCMPBEG
-- Check whether a given substring can be found at begin of a longer
-- string (equality optionally valid).
-- Input : * strbig, strtiny
-- * booalso6ekv -- allow equality
local function lfgcmpbeg (strbig, strtiny, booalso6ekv)
local numlen6big = 0
local numlen6tiny = 0
local boof6ound = false
numlen6big = string.len (strbig)
numlen6tiny = string.len (strtiny)
if (numlen6tiny>0) then
if ((numlen6tiny<numlen6big) or (booalso6ekv and (numlen6tiny==numlen6big))) then
boof6ound = ( strtiny == (string.sub (strbig,1,numlen6tiny)) )
end--if
end--if
return boof6ound
end--function lfgcmpbeg
------------------------------------------------------------------------
-- Local function LFGCMPEND
-- Check whether a given substring can be found at end of a longer
-- string (equality optionally valid).
-- Input : * strbig, strtiny
-- * booalso7ekv -- allow equality
local function lfgcmpend (strbig, strtiny, booalso7ekv)
local numlen7big = 0
local numlen7tiny = 0
local boof7ound = false
numlen7big = string.len (strbig)
numlen7tiny = string.len (strtiny)
if (numlen7tiny>0) then
if ((numlen7tiny<numlen7big) or (booalso7ekv and (numlen7tiny==numlen7big))) then
boof7ound = ( strtiny == (string.sub (strbig,(numlen7big-numlen7tiny+1),numlen7big)) )
end--if
end--if
return boof7ound
end--function lfgcmpend
------------------------------------------------------------------------
---- UTF8 FUNCTIONS [U] ----
------------------------------------------------------------------------
-- Local function LFULNUTF8CHAR
-- Evaluate length of a single UTF8 char in octet:s.
-- Input : * numbgoctet -- beginning octet of a UTF8 char
-- Output : * numlen1234x -- unit octet, number 1...4, or ZERO if invalid
-- Does NOT thoroughly check the validity, looks at ONE octet only.
local function lfulnutf8char (numbgoctet)
local numlen1234x = 0
if (numbgoctet<128) then
numlen1234x = 1 -- $00...$7F -- ANSI/ASCII
end--if
if ((numbgoctet>=194) and (numbgoctet<=223)) then
numlen1234x = 2 -- $C2 to $DF
end--if
if ((numbgoctet>=224) and (numbgoctet<=239)) then
numlen1234x = 3 -- $E0 to $EF
end--if
if ((numbgoctet>=240) and (numbgoctet<=244)) then
numlen1234x = 4 -- $F0 to $F4
end--if
return numlen1234x
end--function lfulnutf8char
------------------------------------------------------------------------
local function lfusearchcasepair (strmyset, num16valin)
-- Search pair of undecoded UTF8 values (UPPER, lower) based on ONE
-- value (unrolled loop).
-- Input : * strmyset -- "eo" or "sv" or (no "GENE" no "ASCII" here)
-- * num16valin -- undecoded UINT16BE value, $C200... $DEFF
-- Output : * num16upper, num16lower -- ZERO if nothing found
-- Called from lfucompareutf8wci lfutristletr lfucaseallinone
-- lfucomparecibegin lficaseadvjaem.
local num16upper = 0
local num16lower = 0
local function xxxdicompare (xxxupper, xxxlower) -- only 3 upvalues used
local xxxfound = false -- preASSume no hit
if ((num16valin==xxxupper) or (num16valin==xxxlower)) then
num16upper = xxxupper
num16lower = xxxlower
xxxfound = true
end--if
end--function xxxdicompare
while true do -- fake loop
if (strmyset~='eo') then
break -- do NOT check
end--if
if (xxxdicompare(0xC488,0xC489)) then
break -- found it
end--if
if (xxxdicompare(0xC49C,0xC49D)) then
break -- found it
end--if
if (xxxdicompare(0xC4A4,0xC4A5)) then
break -- found it
end--if
if (xxxdicompare(0xC4B4,0xC4B5)) then
break -- found it
end--if
if (xxxdicompare(0xC59C,0xC59D)) then
break -- found it
end--if
if (xxxdicompare(0xC5AC,0xC5AD)) then
break -- found it
end--if
break -- finally
end--while -- fake loop
while true do -- fake loop
if (strmyset~='sv') then
break -- do NOT check
end--if
if (xxxdicompare(0xC384,0xC3A4)) then
break -- found it
end--if
if (xxxdicompare(0xC385,0xC3A5)) then
break -- found it
end--if
if (xxxdicompare(0xC389,0xC3A9)) then
break -- found it
end--if
if (xxxdicompare(0xC396,0xC3B6)) then
break -- found it
end--if
break -- finally
end--while -- fake loop
return num16upper, num16lower
end--function lfusearchcasepair
------------------------------------------------------------------------
local function lfutristletr (strsel4set, strin4trist)
-- Evaluate char to tristate result (no letter vs uppercase letter
-- vs lowercase letter) within defined charset (ASCII + selectable
-- extra subset of UTF8).
-- Input : * strsel4set : "ASCII" (default, empty string or type "nil"
-- will do too) "eo" "sv" (value "GENE" NOT here) !!!FIXME!!! is GENE supposed to be supp or not ??
-- * strin4trist : single unicode char (1 or 2 octet:s) or
-- longer string
-- Output : * numtype4x : 0 no letter or invalid UTF8 -- 1 upper -- 2 lower
-- Depends on procedures : (this is LFUTRISTLETR)
-- [U] lfulnutf8char lfusearchcasepair
-- [G] lfgtestuc lfgtestlc
-- Possible further char:s or fragments of such are disregarded, the
-- question answered is "Is there one uppercase or lowercase letter
-- available at begin?".
local numlong4den = 0 -- actual length of input string
local numcxa4unde = 0 -- undecoded UINT16BE of incoming
local numw4upper = 0 -- undecoded UINT16BE of found lower
local numw4lower = 0 -- undecoded UINT16BE of found UPPER
local numlong4bor = 0 -- expected length of single char
local numcha4r = 0 -- UINT8 beginning char
local numcha4s = 0 -- UINT8 later char (BIG ENDIAN, lower value here above)
local numtype4x = 0 -- final result to be returned, preASSume invalid
while true do -- fake loop -- this is LFUTRISTLETR
numlong4den = string.len (strin4trist)
if (numlong4den==0) then
break -- bad string length
end--if
numcha4r = string.byte (strin4trist,1,1)
numlong4bor = lfulnutf8char(numcha4r)
if ((numlong4bor==0) or (numlong4den<numlong4bor)) then
break -- truncated char or invalid
end--if
if (numlong4bor==1) then
if (lfgtestuc(numcha4r)) then
numtype4x = 1
end--if
if (lfgtestlc(numcha4r)) then
numtype4x = 2
end--if
break -- success ASCII
end--if
if (numlong4bor==2) then
numcha4s = string.byte (strin4trist,2,2) -- only $80 to $BF cannot ovrfl
numcxa4unde = numcha4r * 256 + numcha4s -- UINT16BE
numw4upper, numw4lower = lfusearchcasepair (strsel4set,numcxa4unde)
if (numcxa4unde==numw4upper) then
numtype4x = 1
end--if
if (numcxa4unde==numw4lower) then
numtype4x = 2
end--if
end--if
break -- finally
end--while -- fake loop -- join mark
return numtype4x
end--function lfutristletr
------------------------------------------------------------------------
local function lfucaserest (strsel6set, strinco6cs, boowup6cas, boodo6all)
-- Adjust (restricted) case of a single letter or longer string within
-- defined charset (ASCII + selectable minimal subset of UTF8). (this is REST)
-- Input : * strsel6set : "ASCII" (default, empty string or type "nil"
-- will do too) "eo" "sv" (value "GENE" NOT here)
-- * strinco6cs : single unicode letter (1 or 2 octet:s) or
-- longer string
-- * boowup6cas : for desired output uppercase "true" and for
-- lowercase "false"
-- * boodo6all : "true" to adjust all letters, "false"
-- only beginning letter
-- Output : * strinco6cs
-- Depends on procedures : (this is REST)
-- [U] lfulnutf8char lfusearchcasepair
-- [G] lfgpokestring lfgtestuc lfgtestlc
-- This process never changes the length of a string in octet:s. Empty string
-- on input is legal and results in an empty string returned. When case is
-- adjusted, a 1-octet or 2-octet letter is replaced by another letter of same
-- length. Unknown seemingly valid char:s (1-octet ... 4-octet) are copied.
-- Broken UTF8 stream results in remaining part of the output string (from
-- one char to complete length of the incoming string) filled by "Z".
-- We peek max 2 values per iteration, and change the string in-place, doing
-- so strictly only if there indeed is a change. This is important for LUA
-- where the in-place write access must be emulated by means of a less
-- efficient procedure.
local numlong6den = 0 -- actual length of input string
local numokt6index = 0
local numcxa6unde = 0 -- undecoded UINT16BE of incoming
local numw6upper = 0 -- undecoded UINT16BE of found lower
local numw6lower = 0 -- undecoded UINT16BE of found UPPER
local numlong6bor = 0 -- expected length of single char
local numdel6ta = 0 -- quasi-signed ZERO or +1 or -1 or +32 or -32 or other
local numcha6r = 0 -- UINT8 beginning char
local numcha6s = 0 -- UINT8 later char (BIG ENDIAN, lower value here above)
local boowan6tlowr = false
local boodo6adj = true -- preASSume innocence -- continue changing
local boobotch6d = false -- preASSume innocence -- NOT yet botched
boowup6cas = (boowup6cas==true)
boodo6all = (boodo6all==true)
boowan6tlowr = (not boowup6cas)
numlong6den = string.len (strinco6cs)
while true do -- outer genuine loop over incoming string (this is REST)
if (numokt6index>=numlong6den) then
break -- done complete string
end--if
if ((not boodo6all) and (numokt6index~=0)) then -- loop can skip index ONE
boodo6adj = false
end--if
numdel6ta = 0 -- preASSume on every iteration
numlong6bor = 1 -- preASSume on every iteration
while true do -- inner fake loop (this is REST)
numcha6r = string.byte (strinco6cs,(numokt6index+1),(numokt6index+1))
if (boobotch6d) then
numdel6ta = 90 - numcha6r -- "Z" -- delta must be non-ZERO to write
break -- fill with "Z" char:s
end--if
if (not boodo6adj) then
break -- copy octet after octet
end--if
numlong6bor = lfulnutf8char(numcha6r) -- now 1 ... 4 or ZERO
if ((numlong6bor==0) or ((numokt6index+numlong6bor)>numlong6den)) then
numlong6bor = 1 -- reassign to ONE !!!
numdel6ta = 90 - numcha6r -- "Z" -- delta must be non-ZERO to write
boobotch6d = true
break -- truncated char or broken stream
end--if
if (numlong6bor>=3) then
break -- copy UTF8 char, no chance for adjustment
end--if
if (numlong6bor==1) then
if (lfgtestuc(numcha6r) and boowan6tlowr) then
numdel6ta = 32 -- ASCII UPPER->lower
end--if
if (lfgtestlc(numcha6r) and boowup6cas) then
numdel6ta = -32 -- ASCII lower->UPPER
end--if
break -- success with ASCII and one char almost done
end--if (numlong6bor==1) then
if (numlong6bor==2) then
numcha6s = string.byte (strinco6cs,(numokt6index+2),(numokt6index+2)) -- only $80 to $BF
numcxa6unde = numcha6r * 256 + numcha6s -- UINT16BE
numw6upper, numw6lower = lfusearchcasepair (strsel6set,numcxa6unde)
if ((numcxa6unde==numw6upper) and boowan6tlowr) then
numdel6ta = numw6lower-numw6upper -- UPPER->lower
end--if
if ((numcxa6unde==numw6lower) and boowup6cas) then
numdel6ta = numw6upper-numw6lower -- lower->UPPER
end--if
end--if (numlong6bor==2) then
break -- finally -- unknown non-ASCII char is a fact :-(
end--while -- inner fake loop -- join mark (this is REST)
if ((numlong6bor==1) and (numdel6ta~=0)) then -- no risk of carry here
strinco6cs = lfgpokestring (strinco6cs,numokt6index,(numcha6r+numdel6ta))
end--if
if ((numlong6bor==2) and (numdel6ta~=0)) then -- no risk of carry here
strinco6cs = lfgpokestring (strinco6cs,(numokt6index+1),(numcha6s+numdel6ta))
end--if
numokt6index = numokt6index + numlong6bor -- advance in incoming string
end--while -- outer genuine loop over incoming string (this is REST)
return strinco6cs
end--function lfucaserest
------------------------------------------------------------------------
---- HIGH LEVEL STRING FUNCTIONS [I] ----
------------------------------------------------------------------------
-- Local function LFIKATALDIGU !!!FIXME!!! use LFIKATPALDIGU
local function lfikataldigu (strprefixx, strkataldnomo, strhintvisi)
local strrbkma = ''
if (type(strhintvisi)=='string') then
strrbkma = '[[' .. strprefixx .. ':' .. strkataldnomo .. '|' .. strhintvisi .. ']]'
else
strrbkma = '[[' .. strprefixx .. ':' .. strkataldnomo .. ']]'
end--if
return strrbkma
end--function lfikataldigu
------------------------------------------------------------------------
-- Local function LFISEPBRACKET
-- Separate bracketed part of a string and return the inner and outer
-- part, the outer one with the brackets. There must be exactly ONE "("
-- and exactly ONE ")" in correct order.
-- Input : * strsep33br
-- * numxmin33len -- minimal length of inner part, must be >= 1
-- Output : * boosaxes, strinner, strouter
-- Note that for length of hit ZERO ie "()" we would have "begg" + 1 = "endd"
-- and for length of hit ONE ie "(x)" we have "begg" + 2 = "endd".
-- Example: "crap (NO)" -> len = 9
-- 123456789
-- "begg" = 6 and "endd" = 9
-- Expected result: "NO" and "crap ()"
-- Example: "(XX) YES" -> len = 8
-- 12345678
-- "begg" = 1 and "endd" = 4
-- Expected result: "XX" and "() YES"
local function lfisepbracket (strsep33br, numxmin33len)
local strinner = ''
local strouter = ''
local num33idx = 1 -- ONE-based
local numdlong = 0
local num33wesel = 0
local numbegg = 0 -- ONE-based, ZERO invalid
local numendd = 0 -- ONE-based, ZERO invalid
local boosaxes = false -- preASSume guilt
numdlong = string.len (strsep33br)
while true do
if (num33idx>numdlong) then
break -- ONE-based -- if both "numbegg" "numendd" non-ZERO then maybe
end--if
num33wesel = string.byte(strsep33br,num33idx,num33idx)
if (num33wesel==40) then -- "("
if (numbegg==0) then
numbegg = num33idx -- pos of "("
else
numbegg = 0
break -- damn: more than 1 "(" present
end--if
end--if
if (num33wesel==41) then -- ")"
if ((numendd==0) and (numbegg~=0) and ((numbegg+numxmin33len)<num33idx)) then
numendd = num33idx -- pos of ")"
else
numendd = 0
break -- damn: more than 1 ")" present or ")" precedes "("
end--if
end--if
num33idx = num33idx + 1
end--while
if ((numbegg~=0) and (numendd~=0)) then
boosaxes = true
strouter = string.sub(strsep33br,1,numbegg) .. string.sub(strsep33br,numendd,-1)
strinner = string.sub(strsep33br,(numbegg+1),(numendd-1))
end--if
return boosaxes, strinner, strouter
end--function lfisepbracket
------------------------------------------------------------------------
-- Local function LFIVALIDATELNKOADV
-- Advanced test whether a string (intended to be a langcode) is valid
-- containing only 2 or 3 lowercase letters, or 2...10 char:s and with some
-- dashes, 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 cannot cause any major harm)
-- * booyesdsh -- "true" to allow special code dash "-"
-- * booyesqst -- "true" to allow special code doublequest "??"
-- * booloonkg -- "true" to allow long codes such as "zh-min-nan"
-- * boodigit -- "true" to allow digit in middle position
-- * boonoban -- (inverted) "true" to skip test against ban table
-- Output : * booisvaladv -- true if string is valid
-- Depends on procedures :
-- [G] lfgtestnum lfgtestlc
-- Depends on constants :
-- * table "contabisbanned"
-- Incoming empty string is safe but type "nil" is NOT.
-- Digit is tolerable only ("and" applies):
-- * if boodigit is "true"
-- * if length is 3 char:s
-- * in middle position
-- Dashes are tolerable (except in special code "-") only ("and" applies):
-- * if length is at least 4 char:s (if this is permitted at all)
-- * in inner positions
-- * NOT adjacent
-- * maximally TWO totally
-- There may be maximally 3 adjacent letters, this makes at least ONE dash
-- obligatory for length 4...7, and TWO dashes for length 8...10.
local function lfivalidatelnkoadv (strqooq, booyesdsh, booyesqst, booloonkg, boodigit, boonoban)
local varomongkosong = 0 -- for check against the ban list
local numchiiar = 0
local numukurran = 0
local numindeex = 0 -- ZERO-based -- two loops
local numadjlet = 0 -- number of adjacent letters (max 3)
local numadjdsh = 0 -- number of adjacent dashes (max 1)
local numtotdsh = 0 -- total number of dashes (max 2)
local booislclc = false
local booisdigi = false
local booisdash = false
local booisvaladv = true -- preASSume innocence -- later final verdict here
while true do -- fake (outer) loop
if (strqooq=='-') then
booisvaladv = booyesdsh
break -- to join mark -- good or bad
end--if
if (strqooq=='??') then
booisvaladv = booyesqst
break -- to join mark -- good or bad
end--if
numukurran = string.len (strqooq)
if ((numukurran<2) or (numukurran>10)) then
booisvaladv = false
break -- to join mark -- evil
end--if
if (not booloonkg and (numukurran>3)) then
booisvaladv = false
break -- to join mark -- evil
end--if
numindeex = 0
while true do -- inner genuine loop over char:s
if (numindeex>=numukurran) then
break -- done -- good
end--if
numchiiar = string.byte (strqooq,(numindeex+1),(numindeex+1))
booisdash = (numchiiar==45)
booisdigi = lfgtestnum(numchiiar)
booislclc = lfgtestlc(numchiiar)
if (not (booislclc or booisdigi or booisdash)) then
booisvaladv = false
break -- to join mark -- inherently bad char
end--if
if (booislclc) then
numadjlet = numadjlet + 1
else
numadjlet = 0
end--if
if (booisdigi and ((numukurran~=3) or (numindeex~=1) or (not boodigit))) then
booisvaladv = false
break -- to join mark -- illegal digit
end--if
if (booisdash) then
if ((numukurran<4) or (numindeex==0) or ((numindeex+1)==numukurran)) then
booisvaladv = false
break -- to join mark -- illegal dash
end--if
numadjdsh = numadjdsh + 1
numtotdsh = numtotdsh + 1 -- total
else
numadjdsh = 0 -- do NOT zeroize the total !!!
end--if
if ((numadjlet>3) or (numadjdsh>1) or (numtotdsh>2)) then
booisvaladv = false
break -- to join mark -- evil
end--if
numindeex = numindeex + 1 -- ZERO-based
end--while -- inner genuine loop over char:s
if (not boonoban) then -- if "yesban" then
numindeex = 0
while true do -- lower inner genuine loop
varomongkosong = contabisbanned[numindeex+1] -- number of elem unknown
if (type(varomongkosong)~='string') then
break -- abort inner loop (then outer fake loop) due to end of table
end--if
numukurran = string.len (varomongkosong)
if ((numukurran<2) or (numukurran>3)) then
break -- abort inner loop (then outer fake loop) due to faulty table
end--if
if (strqooq==varomongkosong) then
booisvaladv = false
break -- abort inner loop (then outer fake loop) due to violation
end--if
numindeex = numindeex + 1 -- ZERO-based
end--while -- lower inner genuine loop
end--if (not boonoban) then
break -- finally to join mark
end--while -- fake loop -- join mark
return booisvaladv
end--function lfivalidatelnkoadv
-- *******************************************
-- * HIGH LEVEL STRING PROCEDURES [I7] * -- placeholderism
-- *******************************************
local function pripl2altwre (strbeforfill, numaskikodo, varsupstitu)
-- Process all anon and fixed placeholders "%@" or "%~".
-- Input : * strbeforfill -- request string with placeholders to be filled
-- in, no placeholders or empty input is useless
-- but cannot cause major harm
-- * numaskikodo -- ASCII code of placeholder type, 64 for "%@" or
-- 126 for "%~"
-- * varsupstitu -- substitute, either string (same content reused
-- if multiple placeholders), or ZERO-based table
-- (with one element per placeholder such as
-- {[0]="none","neniu"}), length 1...80, further
-- sanitization must be done elsewhere
-- Output : * strafterfill
-- Depends on procedures :
-- [G] prgstringrange
local varpfiller = 0 -- risky picking
local strufiller = '' -- final validated filler
local strafterfill = ''
local numlenbigtext = 0 -- len of strbeforfill
local numsfrcindex = 0 -- char index ZERO-based
local numinsrtinde = 0 -- index in table ZERO-based
local numtecken0d = 0
local numtecken1d = 0
numlenbigtext = string.len (strbeforfill)
while true do
if (numsfrcindex>=numlenbigtext) then
break -- empty input is useless but cannot cause major harm
end--if
numtecken0d = string.byte(strbeforfill,(numsfrcindex+1),(numsfrcindex+1))
numsfrcindex = numsfrcindex + 1 -- INC here
numtecken1d = 0 -- preASSume none
if (numsfrcindex<numlenbigtext) then -- pick but do NOT INC
numtecken1d = string.byte(strbeforfill,(numsfrcindex+1),(numsfrcindex+1))
end--if
if ((numtecken0d==37) and (numtecken1d==numaskikodo)) then -- "%@" "%~"
numsfrcindex = numsfrcindex + 1 -- INC more, now totally + 2
varpfiller = 0 -- preASSume nothing available
strufiller = '??' -- preASSume nothing available
if (type(varsupstitu)=='string') then
varpfiller = varsupstitu -- take it as-is (length check below)
end--if
if (type(varsupstitu)=='table') then
varpfiller = varsupstitu [numinsrtinde] -- risk of type "nil"
numinsrtinde = numinsrtinde + 1 -- INC tab index on every placeholder
end--if
if (prgstringrange(varpfiller,1,80)) then -- restrict
strufiller = varpfiller -- now the substitute is finally accepted
end--if
else
strufiller = string.char (numtecken0d) -- no placeholder -> copy octet
end--if
strafterfill = strafterfill .. strufiller -- add one of 4 possible cases
end--while
return strafterfill
end--function pripl2altwre
------------------------------------------------------------------------
-- Transcode eo X-surrogates to cxapeloj in a single string (eo only).
-- Input : * streosurr -- ANSI string (empty is useless but cannot
-- cause major harm)
-- Output : * strutf8eo -- UTF8 string
-- Depends on procedures :
-- [E] mathdiv mathmod
-- Depends on constants :
-- * table "contabtransluteo" inherently holy
-- To be called ONLY from "prhrecusurrstrtab".
-- * the "x" in a surr pair is case insensitive,
-- for example both "kacxo" and "kacXo" give same result
-- * avoid "\", thus for example "ka\cxo" would get converted but the "\" kept
-- * double "x" (both case insensitive) prevents conversion and becomes
-- reduced to single "x", for example "kacxxo" becomes "kacxo"
local function prikodeosg (streosurr)
local vareopeek = 0
local strutf8eo = ''
local numeoinplen = 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
numeoinplen = string.len(streosurr)
while true do
if (numinpinx>=numeoinplen) then
break
end--if
numknar0k = string.byte(streosurr,(numinpinx+1),(numinpinx+1))
numknaf1x = 0 -- preASSume no char
numknaf2x = 0 -- preASSume no char
if ((numinpinx+1)<numeoinplen) then
numknaf1x = string.byte(streosurr,(numinpinx+2),(numinpinx+2))
end--if
if ((numinpinx+2)<numeoinplen) then
numknaf2x = string.byte(streosurr,(numinpinx+3),(numinpinx+3))
end--if
boonext1x = ((numknaf1x==88) or (numknaf1x==120)) -- case insensitive
boonext2x = ((numknaf2x==88) or (numknaf2x==120)) -- case insensitive
boosudahdone = false
if (boonext1x and boonext2x) then -- got "xx"
strutf8eo = strutf8eo .. 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"
vareopeek = contabtransluteo[numknar0k] -- UINT16 or type "nil"
if (type(vareopeek)=='number') then
strutf8eo = strutf8eo .. string.char(mathdiv(vareopeek,256),mathmod(vareopeek,256)) -- add UTF8 char
numinpinx = numinpinx + 2 -- eaten 2 written 2
boosudahdone = true
end--if
end--if
if (not boosudahdone) then
strutf8eo = strutf8eo .. string.char(numknar0k) -- copy char
numinpinx = numinpinx + 1 -- eaten 1 written 1
end--if
end--while
return strutf8eo
end--function prikodeosg
-- ***********************************
-- * HIGH LEVEL PROCEDURES [H] * ---------------------------------
-- ***********************************
-- Depends on procedures :
-- [E] mathisintrange
local function lfhvali1status98code (varvalue)
local boovalid = false -- preASSume guilt
while true do -- fake loop
if (varvalue==0) then
break -- success thus keep false since no valid ;-)
end--if
if (mathisintrange(varvalue,1,98)) then
boovalid = true -- got an error and valid error code returned
else
varvalue = 255 -- failed to return valid status code
end--if
break -- finally to join mark
end--while -- fake loop -- join mark
return varvalue, boovalid
end--function lfhvali1status98code
------------------------------------------------------------------------
local function prhrecusurrstrtab (varinkommen, strlingkod, bookeys)
-- Process (transcode) either a single string, or all string items in a
-- table (even nested) using any type of keys/indexes (such as a holey
-- number sequence and non-numeric ones). Items with a non-string non-table
-- value are kept unchanged. Optional transcoding of eo and NOPE sv surrogates
-- (via 2 separate procedures). Optionally string keys/indexes are transcoded
-- as well.
-- Input : * varinkommen -- type "string" or "table"
-- * strlingkod -- langcode "eo"
-- * bookeys -- transcode keys too (preferably either "true"
-- or type "nil")
-- Depends on procedures :
-- [I5] prikodeosg (only if trans of eo X-surrogates desired)
-- [I5] NOPE prikodsvsg
-- [E] mathdiv mathmod (via "prikodeosg" and NOPE "prikodsvsg")
-- Depends on constants :
-- * table "contabtransluteo" inherently holey (via "prikodeosg")
-- * NOPE table "contabtranslutsv"
-- We always fully rebrew tables from scratch, thus do NOT replace
-- single elements (doing so would break "in pairs").
local varnky = 0 -- variable without type
local varutmatning = 0
local boodone = false
if (type(varinkommen)=='string') then
if (strlingkod=='eo') then
varutmatning = prikodeosg (varinkommen) -- surr
boodone = true
end--if
-- if (strlingkod=='sv') then
-- varutmatning = prikodsvsg (varinkommen) -- surr
-- boodone = true
-- end--if
end--if
if (type(varinkommen)=='table') then
varutmatning = {} -- brew new table from scratch
for k4k,v4v in pairs(varinkommen) do -- nothing done if table empty
if ((bookeys==true) and (type(k4k)=='string')) then
varnky = prhrecusurrstrtab (k4k, strlingkod, nil) -- RECURSION
else
varnky = k4k
end--if
if ((type(v4v)=='string') or (type(v4v)=='table')) then
v4v = prhrecusurrstrtab (v4v, strlingkod, bookeys) -- RECURSION
end--if
varutmatning[varnky] = v4v -- write same or diff place in dest table
end--for
boodone = true
end--if
if (not boodone) then
varutmatning = varinkommen -- copy as-is whatever it is, useless
end--if
return varutmatning
end--function prhrecusurrstrtab
-- ************************************ error handling
-- * HIGH LEVEL PROCEDURES [H4] * --------------------------------
-- ************************************
local function prhconstructerar (numerar3code, boopeek3it)
-- Construct partial error message maybe peeking description.
-- Input : * numerar3code -- 1 ... 98 or 2 ... 98 (resistant against
-- invalid data type, giving "??" on such)
-- * boopeek3it -- do peek description #E02...#E98 from table
-- Depends on procedures :
-- [N] prnnumto2digit
-- [E] mathisintrange mathdiv mathmod
-- Depends on constants :
-- * maybe table contaberaroj TWO-based (holes permitted)
-- To be called ONLY from PRHBREWERR4HUNP PRHBREWERR5HUPA
-- PRHBREWERR6SLNP PRHBREWERR7SLPA PRHBREWERR8SUBM PRHBREWERR9DETA.
local vardes3krip = 0
local numbottom3limit = 1
local stryt3sux = '#E'
if (boopeek3it) then
numbottom3limit = 2 -- #E01 is a valid code for submodule only
end--if
if (mathisintrange(numerar3code,numbottom3limit,98)) then
stryt3sux = stryt3sux .. prnnumto2digit(numerar3code)
if (boopeek3it) then
vardes3krip = contaberaroj[numerar3code] -- risk of type "nil"
if (type(vardes3krip)=='string') then
stryt3sux = stryt3sux .. ' ' .. vardes3krip
else
stryt3sux = stryt3sux .. ' ??' -- no text found
end--if
end--if (boopeek3it) then
else
stryt3sux = stryt3sux .. '??' -- no valid error code
end--if
return stryt3sux
end--function prhconstructerar
------------------------------------------------------------------------
local function prhbrewerr5hupa (numeror5code, strparent5nm)
-- Brew error sev huge, one line, insertable parent.
-- Input : * numeror5code -- TWO-based error code 2 ... 98 (resistant
-- against invalid data type, giving "??" on such)
-- * strparent5nm -- name of parent (not used and should be type
-- "nil" if message does NOT contain "%@")
-- Output : * stryt5sux -- message with HTML
-- Depends on procedures :
-- [H4] prhconstructerar
-- [I7] pripl2altwre
-- [G] prgstringrange
-- [N] prnnumto2digit
-- [E] mathisintrange mathdiv mathmod
-- Depends on constants :
-- * table contabfel with 2 elements .hubg .huen
-- * table contaberaroj TWO-based (holes permitted)
-- #E02...#E98, note that #E00 #E01 #E99 are NOT supposed to be included here.
local stryt5sux = ''
stryt5sux = contabfel.hubg .. pripl2altwre(prhconstructerar(numeror5code,true),64,strparent5nm) .. contabfel.huen
return stryt5sux
end--function prhbrewerr5hupa
-- ************************************
-- * HIGH LEVEL PROCEDURES [H6] * --------------------------------
-- ************************************
local function lfhgetlangfromcat(strcatname)
-- Input : * strcatname -- without ns prefix
-- Output : * strlingvo -- nothing or langcode or langname
-- * numtristato -- ZERO nothing | ONE langcode (2...10) |
-- TWO langname (>=3)
-- Depends on procedures :
-- [I] lfisepbracket
-- [G] lfgcmpend
-- [E] mathisintrange
-- Depends on constants :
-- * contabfarado contabfullcat contabsuffcat
-- Chain of rules applied here (part of the main parsing work):
-- * two fragments of catname found in contabfarado -> get langcode
-- (len 2...10) sandwiched beween them
-- * full catname is found in contabfullcat -> get langcode from there
-- * catname is suffixed by item found contabsuffcat -> get langcode
-- from there
-- * there is bracketed part (len >= 3 char:s) -> take it as langname
-- * else nothing found
local vartpm = 0
local str7tomp = ''
local str7tump = ''
local strlingvo = ''
local num7lencleft = 0
local num7posirajt = 0
local num7sandwitch = 0
local numtristato = 0 -- preASSume nothing found
local boopmt = false
while true do -- fake loop
for k7k,v7v in pairs(contabfarado) do -- nothing done if table empty
if ((type(k7k)~='string') or (type(v7v)~='string')) then
break -- protect from terrorism
end--if
if (lfgcmpbeg(strcatname,k7k,false)) then -- equality NOT appreci
num7lencleft = string.len(k7k)
vartpm = string.find(strcatname,v7v,1,true)
if (type(vartpm)=='number') then
num7posirajt = vartpm
num7sandwitch = num7posirajt - num7lencleft - 1
if (mathisintrange(num7sandwitch,2,10)) then
strlingvo = string.sub(strcatname,(num7lencleft+1),(num7posirajt-1))
numtristato = 1
break -- got langcode (validity NOT certified yet)
end--if
end--if
end--if (lfgcmpbeg(strcatname,k7k,false)) then
end--for
if (numtristato==1) then
break -- got langcode, exit fake loop too
end--if
vartpm = contabfullcat[strcatname] -- single query gives the verdict
if (type(vartpm)=='string') then
strlingvo = vartpm
numtristato = 1
break -- got langcode
end--if
for k7k,v7v in pairs(contabsuffcat) do -- nothing done if table empty
if ((type(k7k)~='string') or (type(v7v)~='string')) then
break -- protect from terrorism
end--if
if (lfgcmpend(strcatname,k7k,false)) then -- equality NOT appreci
strlingvo = v7v
numtristato = 1
break -- got langcode
end--if
end--for
if (numtristato==1) then
break -- got langcode, exit fake loop too
end--if
boopmt, str7tomp, str7tump = lfisepbracket(strcatname,3) -- succ innr outr
if (boopmt) then -- langname found (validity NOT certified yet)
strlingvo = str7tomp
numtristato = 2 -- got langname
end--if
break -- finally to join mark
end--while -- fake loop -- join mark
return strlingvo, numtristato
end--function lfhgetlangfromcat
------------------------------------------------------------------------
-- Local function LFHFALLBACK
-- Output : * str55rezult -- empty string if nothing found
-- Depends on constants :
-- * table contabfall
local function lfhfallback (str55incom)
local var55target = 0
local var55nonleft = 0
local varone55line = 0
local str55rezult = ''
local num55outer = 1 -- ONE-based
local num55inner = 0 -- ONE-based but starts from TWO
while true do
varone55line = contabfall [num55outer]
if (type(varone55line)~='table') then
break -- we have run out of outer table, nothing found, abort outer loop
end--if
var55target = varone55line[1]
if (type(var55target)~='string') then
break -- should be impossible, abort outer loop too
end--if
if (str55incom==var55target) then
str55rezult = str55incom -- supported as-is, abort outer loop
break
end--if
num55inner = 2
while true do
var55nonleft = varone55line[num55inner]
if (type(var55nonleft)~='string') then
break -- no fallback in this line, abort inner loop only
end--if
if (str55incom==var55nonleft) then
str55rezult = var55target -- fallback success
break -- abort inner loop only
end--if
num55inner = num55inner + 1
end--while
num55outer = num55outer + 1
end--while
return str55rezult
end--function lfhfallback
------------------------------------------------------------------------
---- MEDIAWIKI INTERACTION FUNCTIONS [W] ----
------------------------------------------------------------------------
-- Local function LFWKATROLSIM
-- Peek summary of a category.
-- Input : * strcat8name
-- Output : * numpages, numsubcats -- 2 values, value -1 for unknown
-- Always expensive, the caller must use "pcall".
local function lfwkatrolsim (strcat8name)
local metab = 0
local numpages = -1 -- preASSume unknown
local numsubcats = -1 -- preASSume unknown
metab = mw.site.stats.pagesInCategory ( strcat8name, '*' ) -- expensive here
if (type(metab)=='table') then -- risk of type "number" or "nil"
numpages = metab.pages
numsubcats = metab.subcats
if (numpages<0) then
numpages = -1 -- YES MediaWiki is stupid
end--if
if (numsubcats<0) then
numsubcats = -1 -- YES MediaWiki is stupid
end--if
end--if
return numpages, numsubcats
end--function lfwkatrolsim
-- ***********************
-- * VARIABLES [R] * ---------------------------------------------
-- ***********************
function exporttable.ek (arxframent)
-- general unknown type
local vartymp = 0 -- variable without type multipurpose
-- special type "args" AKA "arx"
local arxsomons = 0 -- metaized "args"
-- general tab
local tablg80lefty = {}
-- peeked stuff
local strpiklangcode = '' -- "en" privileged site language
local strpikkatns = '' -- "Category"
local strpikparent = '' -- "Template:attack" FULLPAGENAME
local strpikpareuf = '' -- "attack" PAGENAME unfull
-- override
local strtocoverride = '' -- from "tocforceoverridetestonly="
-- general str
local strpagenam = '' -- {{PAGENAME}} or "pagenameoverridetestonly="
local strruangna = '' -- {{NAMESPACENUMBER}} or "nsnumberoverridetestonly="
local strkodbah = '' -- langcode
local strtump = '' -- temp
local strvisgud = '' -- visible output on success
local strviserr = '' -- visible error message on error
local strtrakat = '' -- invisible tracking categories on error
local strret = '' -- final result string
-- general num
local numerr = 0 -- 0 OK | 1 inter | 2 sub fail | 3 sub statuscode
local num2statcode = 0
local numpages = 0
local numsubkatt = 0
-- general boo
local boobigenough = false
local bootimp = false
------------------------------------------------------------------------
---- MAIN [Z] ----
------------------------------------------------------------------------
---- GUARD AGAINST INTERNAL ERROR AGAIN ----
-- later reporting of #E01 must NOT depend on uncommentable stuff
prdtracemsg ('This is "Module:eht", requested "detrc" report')
if (qbooguard) then
numerr = 1 -- #E01 internal
end--if
---- PEEK STUFF THAT IS NOT OVERRIDDEN GENEROUS ----
-- this depends on "arxframent" (only if parent requested) but NOT on "arx"
-- "strpikkatns" and "strpikindns" and "strpikapxns" do NOT
-- include a trailing ":" colon, and are for "lfykattlaenk"
-- and "lfyapxindlaenk" and "lfikatpaldigu"
-- full "strpikparent" is used for error messages
-- unfull "strpikpareuf" is used for tracking cat:s
if (numerr==0) then
strpiklangcode = contabovrd.sitelang or mw.getContentLanguage():getCode() or 'en' -- privileged site language
strpikkatns = contabovrd.katprefi or (mw.site.namespaces[ 14] or {})['name'] or 'Category' -- standard namespace
strpikparent = contabovrd.parentfn or arxframent:getParent():getTitle() or 'Template:eht' -- fullpagename
if ((type(strpiklangcode)~='string') or (type(strpikkatns)~='string') or (type(strpikparent)~='string')) then
numerr = 1 -- #E01 internal (unlikely)
end--if
vartymp = string.find(strpikparent,':',1,true)
if (mathisintrange(vartymp,2,(string.len(strpikparent)-1))) then
strpikpareuf = string.sub(strpikparent,(vartymp+1),-1) -- make unfull
else
strpikpareuf = strpikparent -- dubi call from ns ZERO or misplaced ":"
end--if
end--if (numerr==0) then
---- GET THE ARX (ONE OF TWO) ----
-- must be seized independently on "numerr" even if we
-- already suck due to possible "detrc=true"
-- give a f**k in possible params other than "parentframe=true"
arxsomons = arxframent.args -- "args" from our own "frame"
if (type(arxsomons)~='table') then
arxsomons = {} -- guard against indexing error from our own
numerr = 1 -- #E01 internal
end--if
if (arxsomons['parentframe']=='true') then
arxsomons = arxframent:getParent().args -- "args" from parent's "frame"
end--if
if (type(arxsomons)~='table') then
arxsomons = {} -- guard against indexing error again
numerr = 1 -- #E01 internal
end--if
---- PROCESS MESSAGES ----
if (numerr==0) then
contabfullcat = prhrecusurrstrtab (contabfullcat, strpiklangcode, true) -- also keys
contabsuffcat = prhrecusurrstrtab (contabsuffcat, strpiklangcode, true) -- also keys
contaberaroj = prhrecusurrstrtab (contaberaroj, strpiklangcode, nil)
contabtrako = prhrecusurrstrtab (contabtrako, strpiklangcode, nil)
end--if
prdtracemsg ('Messages processed')
---- PICK SUBTABLE T80 FROM ONE IMPORT ----
-- here risk of #E02 #E03
-- on error we assign "numerr" and maybe "num2statcode" both used far below
while true do -- fake loop
if (numerr~=0) then -- #E01 possible
break -- to join mark
end--if
num2statcode, bootimp = lfhvali1status98code (qldingvoj[2])
if (num2statcode~=0) then
if (bootimp) then
numerr = 3 -- #E03 nombrigita
else
numerr = 2 -- #E02 malica
end--if
break -- to join mark
end--if
vartymp = qldingvoj['T80'] -- from "loaddata-tbllingvoj"
if (type(vartymp)~='table') then -- important check
numerr = 2 -- #E02 malica
break -- to join mark
end--if
tablg80lefty = vartymp -- leftmost column -> y-index (langname to langcode)
break -- finally to join mark
end--while -- fake loop -- join mark
---- PROCESS 3 HIDDEN NAMED PARAMS INTO 3 STRING:S ----
-- this may override "mw.title.getCurrentTitle().text" and
-- stipulate content in "strpagenam", empty is NOT valid
-- bad "pagenameoverridetestonly=" can give #E01
-- no error is possible from other hidden parameters
strpagenam = '' -- using vartymp here
if (numerr==0) then -- get pagename (error if bad, silent if absent)
vartymp = arxsomons['pagenameoverridetestonly']
if (type(vartymp)=='string') then
if (prgstringrange(vartymp,1,200)) then -- empty or too long NOT legal
strpagenam = vartymp
else
numerr = 1 -- #E01 internal
end--if
end--if
end--if
strruangna = '' -- using vartymp here
if (numerr==0) then -- get namespace (silent if bad, silent if absent)
vartymp = arxsomons['nsnumberoverridetestonly']
if (prgstringrange(vartymp,1,4)) then -- empty or too long NOT legal
strruangna = vartymp
end--if
end--if
if (numerr==0) then
vartymp = arxsomons['tocforceoverridetestonly']
if ((vartymp=='on') or (vartymp=='off')) then
strtocoverride = vartymp
end--if
end--if
if (contabovrd.defortrc) then
prdtracemsg ('Force "detrc=true"')
else
if (arxsomons['detrc']=='true') then
prdtracemsg ('Param "detrc=true" seized')
else
qboodetrc = false -- was preassigned to "true"
qstrtrace = '' -- shut up now
end--if
end--if
---- SEIZE PAGENAME AND NS FROM MW ----
-- "pagenameoverridetestonly=" "nsnumberoverridetestonly=" processed above
-- later reporting of #E01 must NOT depend on uncommentable
-- or peekable stuff
-- pagename must be 1...200 octet:s keep consistent
-- with "pagenameoverridetestonly="
if ((numerr==0) and (strpagenam=='')) then -- get pagename (error if bad)
vartymp = mw.title.getCurrentTitle().text -- without namespace prefix
if (prgstringrange(vartymp,1,200)) then -- empty or too long NOT legal
strpagenam = vartymp -- cannot be left empty
else
numerr = 1 -- #E01 internal
end--if
end--if
if ((numerr==0) and (strruangna=='')) then -- get namespace (silent if bad)
vartymp = mw.title.getCurrentTitle().namespace -- type is "number"
if (mathisintrange(vartymp,0,9999)) then -- negative NOT legal but silent
strruangna = tostring(vartymp) -- can be left empty, check below required
end--if
end--if
---- CHECK NS ----
if ((numerr==0) and (strruangna~='14')) then -- must be "Category:"
numerr = 10 -- #E10 called from wrong ns
end--if
prdtracemsg ('Seized pagename and ns, numerr=' .. tostring(numerr))
---- WHINE IF YOU MUST #E01 ----
if (numerr==1) then
strtump = '#E01 Internal error in "Module:eht".'
strviserr = contabfel.hubg .. strtump .. contabfel.huen
end--if
---- CHECK WHETHER NON-UPPPER #E14 OR FULL LANGNAME #E16 ----
-- from above strpagenam
if ((numerr==0) and (lfutristletr('eo',strpagenam)~=1)) then
numerr = 14 -- #E14 catname does not begin with eo uppercase
end--if
prdtracemsg ('Checked required uppercase, numerr=' .. tostring(numerr))
if (numerr==0) then
vartymp = tablg80lefty[strpagenam] -- try reverse query as-is
if (type(vartymp)~='string') then
vartymp = tablg80lefty[lfucaserest('eo',strpagenam,false,false)] -- try reverse query lowered
end--if
if (type(vartymp)=='string') then
numerr = 16 -- #E16 sorry this type of cat is prohibited
end--if
end--if
prdtracemsg ('Checked for prohibited type, numerr=' .. tostring(numerr))
---- CHECK WHETHER SPECIAL OR LANGNAME AVAILABLE OR TRANSLINGUAL CAT ----
-- from above strpagenam, "sveda" or "Greka antikva" ruled out
-- strkodbah is empty string so far, assign it based on a chain of rules:
-- * two fragments of catname found in contabfarado -> get langcode
-- sandwiched beween them, BEWARE needs strict validation
-- * full catname is found in contabfullcat -> get langcode from there
-- * catname is suffixed by item found contabsuffcat -> get langcode
-- from there (for example "Kategorio:Biologio laux lingvo" look at
-- last 12 char:s and from them get "eo" via that table)
-- * there is bracketed part >= 3 char:s -> take it as langname and
-- do reverse query
-- * else translingual cat -> langcode is "mul"
-- here call [H] lfhgetlangfromcat and maybe peek tablg80lefty
-- numerr, strpagenam -> numerr, strkodbah
if (numerr==0) then
do -- scope
local varmpt = 0
local strmylang = ''
local numwhat = 0 -- ZERO nothing | ONE langcode | TWO langname
strmylang, numwhat = lfhgetlangfromcat(strpagenam)
if (numwhat==0) then
strkodbah = 'mul' -- nothing found -> assume translingual cat
end--if
if (numwhat==1) then -- must validate !!!FIXME!!! forward query needed too
if (lfivalidatelnkoadv(strmylang,false,false,conbookodlng,conboomiddig,false)) then
strkodbah = strmylang
else
numerr = 11 -- #E11 obviously invalid langcode
end--if
end--if
if (numwhat==2) then -- get langcode by reverse query
varmpt = tablg80lefty[strmylang] -- reverse query
if (type(varmpt)=='string') then
strkodbah = varmpt -- got ordinary langcode from (...)
else
numerr = 15 -- #E15 invalid or unknown langname
end--if
end--if (numwhat==2) then
end--do scope
end--if (numerr==0) then
prdtracemsg ('After "lfhgetlangfromcat" strkodbah="' .. strkodbah .. '", numerr=' .. tostring(numerr))
---- CHECK WHETHER IT IS BIG ENOUGH ----
-- if it's too big to fail then it's too big but here we
-- require at least 300 pages or at least 300 subcategories
if (numerr==0) then
boobigenough = (strtocoverride=='on')
if ((not boobigenough) and (strtocoverride~='off')) then
numpages, numsubkatt = lfwkatrolsim(strpagenam) -- without namespace prefix
boobigenough = ((numpages>=300) or (numsubkatt>=300))
end--if
end--if
prdtracemsg ('Size check, boobigenough=' .. tostring(boobigenough))
---- PERFORM POSSIBLE FALLBACK ----
-- everything not listed fallbacks here to "en", this is good for "io"
-- and "id" and possibly a few more, but desperate for many others
if ((numerr==0) and boobigenough) then
strkodbah = lfhfallback(strkodbah) -- risk of empty "" or special "etio"
if (strkodbah=='') then
strkodbah = 'en'
end--if
end--if
---- FIRE THE TEMPLATE ---- !!!FIXME!!!
if ((numerr==0) and boobigenough) then
do -- scope
local strforwardajxo = ''
local boo3crap = false
strforwardajxo = 'pagenameoverridetestonly=' .. strpagenam .. '|fullpanaoverridetestonly=' .. strpikkatns .. ':' .. strpagenam .. '|nsnumberoverridetestonly=14'
if (strkodbah=='etio') then
strvisgud = arxframent:preprocess ('{{KategorioEHT-etiopia-skribo|'..strforwardajxo..'}}')
else
strvisgud = arxframent:preprocess ('{{eht-kat-alfa|ling='..strkodbah..'|'..strforwardajxo..'}}')
end--if
if (string.len(strvisgud)<50) then
boo3crap = true
else
boo3crap = (string.byte(strvisgud,1,1)==91) or (string.sub(strvisgud,1,5)=='[')
end--if
if (boo3crap) then
numerr = 19 -- #E19 template failed
end--if
end--do scope
end--if
------------------------------------------------------------------------
---- WHINE IF YOU MUST #E02...#E98 SIMPLE THERE IS A PARENT ----
if ((numerr>=2) and (numerr<=98)) then
strviserr = prhbrewerr5hupa(numerr,('"'..strpikparent..'"'))
end--if
------------------------------------------------------------------------
---- TRACKING CAT:S ON #E10 #E11 #E15 #E19 ----
-- here we use "strpikpareuf" ie the UNFULL name of the parent
while true do -- fake loop
if (numerr<10) then -- #E10
break
end--if
if (numerr==11) then -- #E11
strtrakat = lfikataldigu(strpikkatns,contabtrako['E11'])
break
end--if
if (numerr==15) then -- #E15
strtrakat = lfikataldigu(strpikkatns,contabtrako['E15'])
break
end--if
strtrakat = lfikataldigu(strpikkatns,contabtrako['cetere'])
strtrakat = strtrakat .. lfikataldigu(strpikkatns,contabtrako['cetere'] .. ' (' .. strpikpareuf .. ')')
strtrakat = strtrakat .. lfikataldigu(strpikkatns,contabtrako['cetere'] .. ' (' .. strpikpareuf .. ', E' .. prnnumto2digit(numerr) .. ')')
break -- finally
end--while -- fake loop -- join mark
------------------------------------------------------------------------
---- RETURN THE JUNK STRING ----
-- on #E02 and higher we risk partial results in "strvisgud"
if (numerr==0) then
strret = strvisgud
else
strret = strviserr .. strtrakat
end--if
if (qboodetrc) then -- "qstrtrace" declared separately outside main function
strret = '<br>' .. qstrtrace .. '<br><br>' .. strret
end--if
return strret
------------------------------------------------------------------------
end--function
---- RETURN THE JUNK LUA TABLE ----
return exporttable