--[===[
MODULE "MLILI" (lingvokodo ligilo)
"eo.wiktionary.org/wiki/Modulo:mlili" <!--2024-Oct-10-->
Purpose: converts langcode to langname (with some bonus features) and
optionally brews a link according to one of many available types
Utilo: konvertas lingvokodon al lingvomono (kun kelkaj bonusaj funkcioj)
kaj opcie kreas ligilon laux unu inter multaj disponeblaj tipoj
Manfaat: mengonversi kode bahasa ke nama bahasa (dengan beberapa fungsi
tambah) dan ...
Syfte: konverterar spraakkod till spraaknamn (med naagra extrafunktioner)
och ...
Used by templates / Uzata far sxablonoj:
* only "lili" (not to be called from any other place)
Required submodules / Bezonataj submoduloj /
Submodul yang diperlukan / Behoevda submoduler:
* "loaddata-tbllingvoj" T76 in turn requiring template "tbllingvoj" (EO)
* "loaddata-tblbahasa" T76 in turn requiring template "tblbahasa" (ID)
This module can accept parameters whether sent to itself (own frame) or
to the caller (caller's frame). If there is a parameter "caller=true"
on the own frame then that own frame is discarded in favor of the
caller's one. Empty parameters and parameters longer than 160 octet:s
(except "noc=") are inherently invalid (#E09), further checks follow.
Parameters: * 1 anonymous obligatory parameter
* langcode ("??" permitted) !!!FIXME!!!
* 0...9 named optional parameters
- "tip=" - base type of output or link, 3 possible values: "LA",
"LK" (visible link to category), "KE" (cat insertion,
adding page into category), default is "raw" plain
text no link
- "nem=" - one possible value: "1", avoid wall in the link,
show it plain and honest, default is wall with type
"LA" or "LK" but not with "KE", only legal with
base type "LA" or "LK" (otherwise error), not
together with "mon=" or "maj=1" (otherwise error)
- "mon=" - type of langname, 5 possible values: "la" (add
"la" if appropriate), "aj" (brew adjective), "sf"
("senfinajxa" ie without ending for example "kore",
does not work with all languages), "av" (brew adverb,
if one word then this is "mon=" type "sf" plus "e",
else this is string "en" plus space + "mon=" type
"la"), "pl" (brew plural adjective, works for sane
multiword langnames too), default is native ie
SB or AJ and no "la", only legal with base type
"LA" or "LK" or "raw" (otherwise error), not together
with "nem=1" or "prf=" (otherwise error)
- "maj=" - one possible value: "1", force begin uppercase,
default false ie native case for "mon=" types native
and "la", and lowercase for "mon=" types "aj" "sf"
"av", only legal with base type "LA" or "LK" or
"raw" (otherwise error), not together
with "nem=1" (otherwise error)
- "hin=" - string (2...80 octet:s), name of category, language
name will become the sorting hint/key all lowercase
and without spaces and dashes, name of category
is fixed, default no hint, only legal with base
type "KE" (otherwise error), not together with
"prf=" (otherwise error)
- "prf=" - string (2...80 octet:s), add prefix before language
name and brackets, default no prefix, only legal with
base type "LA" or "LK" or "KE" (otherwise error), not
together with "mon=" or "hin=" (otherwise error)
- "noc=" - one possible value: "true" (any other value ignored), !!!FIXME!!! obsolete
"true" causes empty result with "KE" ie suppresses
categorization, only useful with base type "KE"
(otherwise ignored), forward "nocat=" to this
one if desired
- "per=" - one possible value: "1", keep link or category if
langcode is bad (obviously invalid or unknown),
default is off and means to switch base type
of task "LA" or "LK" to type "raw", base
type "KE" to empty result, only legal with
base type "LA" or "LK" or "KE" (otherwise error)
- "err=" - string (2...80 octet:s), common placeholder, by
default the errors are "evidente nevalida lingvokodo"
and "nekonata lingvokodo"
* parameter "noc=" cannot cause an error
* parameters "mon=" "maj=1" and on the other side "hin=" indirectly exclude
each other absolutely via the base type
* for base type "KE" the language can be in the cat insertion target or
in the hint, but not in both
* for types "LA" and "LK" the language can be in the single common field
(with "nem=1"), or in both, but separately processed ("mon=" and "maj=1
affect only the visible part)
* wikilink target or category name for "LA" "LK" "KE" always gets
uppercase beginning letter
* sorting hint/key is always converted to lowercase (all letters) and junk
char:s (particularly spaces and dashes) are removed
* if langcode is bad (obviously invalid or unknown) then by default
both "tip=" and "mon=" are force-switched to default values "raw" and
"native", yet with "per=1" the result is constructed with "tip="
unaffected but "mon=" still force-switched to "native"
Returned: * one moderately long string with raw name or link, can be empty
in some cases, or red error message
This module is unbreakable (when called with correct module name
and function name). Every imaginable input from the caller and
from the imported modules will output either a useful result or
at least a helpful error string.
Cxi tiu modulo estas nerompebla (kiam vokita kun gxustaj nomo de modulo
kaj nomo de funkcio). Cxiu imagebla enigo de la vokanto kaj
de la importataj moduloj eldonos aux utilan rezulton aux
almenaux helpeman eraranoncan signocxenon.
Following errors are possible:
* <<#E01 Internal error in module "mlili">>
Possible causes:
* strings not uncommented
* <<#E02 Malica eraro en subprogramaro uzata far sxablono "lili">>
Possible causes:
* submodule not found
* submodule caused unspecified failure
* <<#E03 Nombrigita eraro en subprogramaro uzata far sxablono "lili">>
Possible causes:
* submodule failed and returned valid error code
* <<#E08 Erara uzo de sxablono "lili", legu gxian dokumentajxon>>
Possible causes (early detected obvious problems with parameters):
* one obligatory anonymous parameter missing
* more than one anonymous parameter supplied
* <<#E09>>
* empty parameters or parameters longer than 160 octet:s (except for "noc=")
* <<#E14 Nevalida baza tipo "tip=" en sxablono "lili">>
* <<#E15 Nevalida signocxeno "hin=" "prf=" "err=" en sxablono "lili">>
Possible causes:
* string length out of range (2...80 octet:s)
* <<#E16 Erara uzo de sxablono "lili" pro parametroj>>
Possible causes (later detected more clandestine problems with parameters):
* bad value of a single parameter not caught by #E09 #E14 #E15
* conflicting parameters
Note that obviously invalid or unknown langcode is NOT an error here.
{{hr3}} <!-------------------------------->
* #T00 (no params, bad)
* parameters: ""
* expected result: #E08
* actual result: "{{#invoke:mlili|ek}}"
::* #T01 (two anon parameters, too many)
::* parameters: "|eo|io"
::* expected result: #E08
::* actual result: "{{#invoke:mlili|ek|eo|io}}"
* #T02 (simplest example, native SB)
* parameters: "|vo"
* expected result: "Volapuko"
* actual result: "{{#invoke:mlili|ek|vo}}"
::* #T03 (simplest example, native AJ)
::* parameters: "|ko"
::* expected result: "korea"
::* actual result: "{{#invoke:mlili|ek|ko}}"
* #T04 ("io|mon=la", raw, add "la" if needed from native SB)
* expected result: "Ido"
* actual result: "{{#invoke:mlili|ek|io|mon=la}}"
::* #T05 ("sv|mon=la", raw, add "la" if needed from native AJ)
::* expected result: "la sveda"
::* actual result: "{{#invoke:mlili|ek|sv|mon=la}}"
* #T06 ("sma|mon=la", raw, add "la" if needed from native AJ multiword)
* expected result: "la samea suda"
* actual result: "{{#invoke:mlili|ek|sma|mon=la}}"
{{hr3}} <!-------------------------------->
* #T10 ("io|mon=aj", raw, force AJ from native SB)
* expected result: "ida"
* actual result: "{{#invoke:mlili|ek|io|mon=aj}}"
::* #T11 ("sv|mon=aj", raw, force AJ from native AJ)
::* expected result: "sveda"
::* actual result: "{{#invoke:mlili|ek|sv|mon=aj}}"
* #T12 ("sma|mon=aj", raw, force AJ from native AJ multiword)
* expected result: "samea suda"
* actual result: "{{#invoke:mlili|ek|sma|mon=aj}}"
::* #T13 ("io|mon=sf", raw, force root from native SB)
::* expected result: "id" (note that this is name "Ido", not code "id")
::* actual result: "{{#invoke:mlili|ek|io|mon=sf}}"
* #T14 ("sv|mon=sf", raw, force root from native AJ)
* expected result: "sved"
* actual result: "{{#invoke:mlili|ek|sv|mon=sf}}"
::* #T15 ("sma|mon=sf", raw, force root from native AJ multiword)
::* expected result: "samea sud" (useless)
::* actual result: "{{#invoke:mlili|ek|sma|mon=sf}}"
* #T16 ("sv|mon=pl", raw, force AJ and plural from native AJ)
* expected result: "svedaj"
* actual result: "{{#invoke:mlili|ek|sv|mon=pl}}"
::* #T17 ("sma|mon=pl", raw, force AJ and plural from native AJ multiword)
::* expected result: "sameaj sudaj"
::* actual result: "{{#invoke:mlili|ek|sma|mon=pl}}"
* #T18 ("sa|mon=pl", raw, force AJ and plural from native SB)
* expected result: "sanskritaj"
* actual result: "{{#invoke:mlili|ek|sa|mon=pl}}"
{{hr3}} <!-------------------------------->
* #T20 ("io|mon=av", raw, force AV from native SB)
* expected result: "ide"
* actual result: "{{#invoke:mlili|ek|io|mon=av}}"
::* #T21 ("sv|mon=av", raw, force AV from native AJ)
::* expected result: "svede"
::* actual result: "{{#invoke:mlili|ek|sv|mon=av}}"
* #T22 ("sma|mon=av", raw, force AV from native AJ multiword)
* expected result: "en la samea suda" (fake AV by PP "en", is useful again)
* actual result: "{{#invoke:mlili|ek|sma|mon=av}}"
::* #T23 ("io|mon=av|maj=1", raw, force AV from native SB and uppercase)
::* expected result: "Ide"
::* actual result: "{{#invoke:mlili|ek|io|mon=av|maj=1}}"
* #T24 ("sv|mon=av|maj=1", raw, force AV from native AJ and uppercase)
* expected result: "Svede"
* actual result: "{{#invoke:mlili|ek|sv|mon=av|maj=1}}"
::* #T25 ("sma|mon=av|maj=1", raw, force AV from native AJ multiword and uppercase)
::* expected result: "En la samea suda" (fake AV by PP "en", is useful again)
::* actual result: "{{#invoke:mlili|ek|sma|mon=av|maj=1}}"
{{hr3}} <!-------------------------------->
* #T30 ("eo|tip=LA", simple example, native SB)
* expected result: link to "Aldono:Esperanto" with text "Esperanto"
* actual result: "{{#invoke:mlili|ek|eo|tip=LA}}"
::* #T31 ("ko|tip=LA", simple example, native AJ)
::* expected result: link to "Aldono:Korea" with text "korea" (note the letter case)
::* actual result: "{{#invoke:mlili|ek|ko|tip=LA}}"
* #T32 ("eo|tip=LK", simple example, native SB)
* expected result: link to "Kategorio:Esperanto" with hidden colon ":"
* actual result: "{{#invoke:mlili|ek|eo|tip=LK}}"
* actual result via debu: "{{debu|{{#invoke:mlili|ek|eo|tip=LK}}|outctl=nw}}"
::* #T33 ("ko|tip=LK", simple example, native AJ)
::* expected result: link to "Kategorio:Korea" with hidden colon ":"
::* actual result: "{{#invoke:mlili|ek|ko|tip=LK}}"
::* actual result via debu: "{{debu|{{#invoke:mlili|ek|ko|tip=LK}}|outctl=nw}}"
* #T34 ("sma|tip=LK|mon=pl", force AJ and plural from native AJ multiword)
* expected result: link to "Kategorio:Samea suda" with hidden colon ":" and text "sameaj sudaj"
* actual result: "{{#invoke:mlili|ek|sma|tip=LK|mon=pl}}"
* actual result via debu: "{{debu|{{#invoke:mlili|ek|sma|tip=LK|mon=pl}}|outctl=nw}}"
{{hr3}} <!-------------------------------->
* #T40 ("vo|tip=KE", simple example, native SB)
* expected result: sube "Kategorio:Volapuko"
* actual result: "{ {#invoke:mlili|ek|vo|tip=KE} }" (blocked)
* actual result via debu: "{{debu|{{#invoke:mlili|ek|vo|tip=KE}}|outctl=nw}}"
::* #T41 ("ko|tip=KE", simple example, native AJ)
::* expected result: sube "Kategorio:Korea"
::* actual result: "{ {#invoke:mlili|ek|ko|tip=KE} }" (blocked)
::* actual result via debu: "{{debu|{{#invoke:mlili|ek|ko|tip=KE}}|outctl=nw}}"
* #T42 ("ia|tip=KE|hin=Fivortaro", native SB, supply cat name and use hint)
* expected result: sube "Kategorio:Fivortaro" with hint "interlingvao"
* actual result: "{ {#invoke:mlili|ek|ia|tip=KE|hin=Fivortaro} }" (blocked)
* actual result via debu: "{{debu|{{#invoke:mlili|ek|ia|tip=KE|hin=Fivortaro}}|outctl=nw}}"
::* #T43 ("ko|tip=KE|hin=Fivortaro", native AJ, supply cat name and use hint)
::* expected result: sube "Kategorio:Fivortaro" with hint "korea"
::* actual result: "{ {#invoke:mlili|ek|ko|tip=KE|hin=Fivortaro} }" (blocked)
::* actual result via debu: "{{debu|{{#invoke:mlili|ek|ko|tip=KE|hin=Fivortaro}}|outctl=nw}}"
{{hr3}} <!-------------------------------->
* note that tests #T32 ... #T34 and #T40 ... #T43 depend on "debu"
* note that tests #T40 ... #T43 cannot be reasonably executed on the docs subpage without help of "pate" or "debu"
{{hr3}} <!-------------------------------->
]===]
local exporttable = {}
require('strict')
------------------------------------------------------------------------
---- CONSTANTS [O] ----
------------------------------------------------------------------------
-- uncommentable EO vs ID constant strings (core site-related features)
local constringvoj = "Modulo:loaddata-tbllingvoj" -- EO
-- local constringvoj = "Modul:loaddata-tblbahasa" -- ID
-- 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
-- surrogate
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 constrelabg = '<span class="error"><b>' -- lagom whining begin
local constrelaen = '</b></span>' -- lagom whining end
local constrlaxhu = ' ** ' -- lagom -> huge circumfix " ** "
-- uncommentable EO vs ID constant table
-- note that #E00 and #E01 are NOT supposed to be included here
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[08] = 'Erara uzo de \\@, legu gxian dokumentajxon' -- EO #E08
-- contaberaroj[08] = 'Penggunaan salah \\@, bacalah dokumentasinya' -- ID #E08
contaberaroj[14] = 'Nevalida baza tipo "tip=" en \\@' -- EO #E14
-- contaberaroj[14] = 'Tipe dasar salah "tip=" di \\@' -- ID #E14
contaberaroj[15] = 'Nevalida signocxeno "hin=" "prf=" "err=" en \\@' -- EO #E15
-- contaberaroj[15] = 'String salah "hin=" "prf=" "err=" di \\@' -- ID #E15
contaberaroj[16] = 'Erara uzo de \\@ pro parametroj' -- EO #E16
-- contaberaroj[16] = 'Penggunaan salah \\@ oleh karena parameter' -- ID #E16
-- uncommentable EO vs ID constant strings (misc)
local constrevid = "evidente nevalida lingvokodo" -- EO replacement
-- local constrevid = "kode bahasa jelas-jelas salah" -- ID replacement
local constrneli = "nekonata lingvokodo" -- EO replacement
-- local constrneli = "kode bahasa tidak dikenal" -- ID replacement
-- constant table (3 integers for preliminary parameter check)
local contabparam = {}
contabparam[0] = 1 -- minimal number of anon parameters
contabparam[1] = 1 -- maximal number of anon parameters
contabparam[2] = 160 -- maximal length of single para (min is hardcoded as ONE)
-- constants to control behaviour from source AKA semi-hardcoded parameters
local conbookodlng = false -- "true" to allow long codes like "zh-min-nan"
local conboomiddig = false -- "true" to allow middle digit "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['indprefi'] = 'Indekso' -- "Index"
-- contabovrd['indprefi'] = 'Indeks'
-- contabovrd['apxprefi'] = 'Aldono' -- "Appendix"
-- contabovrd['apxprefi'] = 'Lampiran'
-- contabovrd['parentfn'] = string.char(0xC5,0x9C) .. 'ablono:nope' -- "Template:nope" (!!! no surr translation !!!)
------------------------------------------------------------------------
---- SPECIAL STUFF OUTSIDE MAIN [B] ----
------------------------------------------------------------------------
---- SPECIAL VAR:S ----
local qldingvoj = {} -- type "table" and nested
local qbooguard = false -- only for the guard test, pass to other var ASAP
---- GUARD AGAINST INTERNAL ERROR AND IMPORT ONE VIA LOADDATA ----
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
------------------------------------------------------------------------
---- 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
------------------------------------------------------------------------
-- Local function MATHBITWRIT
-- Write bit selected by ZERO-based index assigning it to "1" or "0".
-- Depends on functions :
-- [E] mathdiv mathmod
local function mathbitwrit (numinkoming, numbityndex, boowrite)
local numpatched = 0
local numcountup = 0
local numweight = 1 -- single bit value 1 -> 2 -> 4 -> 8 ...
local boosinglebit = false
while true do
if ((numinkoming==0) and (numcountup>numbityndex)) then
break -- we have run out of bits on BOTH possible sources
end--if
if (numcountup==numbityndex) then
boosinglebit = boowrite -- overwrite bit
else
boosinglebit = (mathmod(numinkoming,2)==1) -- pick bit
end--if
numinkoming = mathdiv(numinkoming,2) -- shift right
if (boosinglebit) then
numpatched = numpatched + numweight -- add one bit rtl only if true
end--if
numcountup = numcountup + 1 -- count up here until we run out of bits
numweight = numweight * 2
end--while
return numpatched
end--function mathbitwrit
------------------------------------------------------------------------
---- NUMBER CONVERSION FUNCTIONS [N] ----
------------------------------------------------------------------------
-- Local function LFNUMTO2DIGIT
-- Convert integer 0...99 to decimal ASCII string always 2 digits "00"..."99".
-- Depends on functions :
-- [E] mathisintrange mathdiv mathmod
local function lfnumto2digit (numzerotoninetynine)
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 lfnumto2digit
------------------------------------------------------------------------
---- LOW LEVEL STRING FUNCTIONS [G] ----
------------------------------------------------------------------------
-- Local function LFGSTRINGRANGE
local function lfgstringrange (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 lfgstringrange
------------------------------------------------------------------------
-- Local function LFGPOKESTRING
-- 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
------------------------------------------------------------------------
-- test whether char is an ASCII digit "0"..."9", return boolean
local function lfgtestnum (numkaad)
local boodigit = false
boodigit = ((numkaad>=48) and (numkaad<=57))
return boodigit
end--function lfgtestnum
------------------------------------------------------------------------
-- test whether char is an ASCII uppercase letter, return boolean
local function lfgtestuc (numkode)
local booupperc = false
booupperc = ((numkode>=65) and (numkode<=90))
return booupperc
end--function lfgtestuc
------------------------------------------------------------------------
-- test whether char is an ASCII lowercase letter, return boolean
local function lfgtestlc (numcode)
local boolowerc = false
boolowerc = ((numcode>=97) and (numcode<=122))
return boolowerc
end--function lfgtestlc
------------------------------------------------------------------------
---- 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 LFUTRISTLETR
-- Evaluate char (from ASCII + selectable extra set from UTF8) to
-- tristate result (no letter vs uppercase letter vs lowercase letter).
-- Input : * strin5trist : single unicode char (1 or 2 octet:s) or
-- longer string
-- * strsel5set : "ASCII" (default, empty string or type "nil"
-- will do too) "eo" "sv" (value "GENE" NOT here)
-- Output : * numtype5x : 0 no letter or invalid UTF8 -- 1 upper -- 2 lower
-- Depends on functions : (this is LFUTRISTLETR)
-- [U] lfulnutf8char
-- [G] lfgtestuc lfgtestlc
-- [E] mathdiv mathmod mathbitwrit
-- Possible further char:s or fragments of such are disregarded, the
-- question answered is "Is there one uppercase or lowercase letter
-- available at begin?".
-- Defined sets:
-- "eo" 2 x 6 uppercase and lowercase (CX GX HX JX SX UX cx gx hx jx sx ux)
-- upper CX $0108 GX $011C HX $0124 JX $0134 SX $015C UX $016C lower +1
-- "sv" 2 x 4 uppercase and lowercase (AE AA EE OE ae aa ee oe)
-- upper AE $00C4 AA $00C5 EE $00C9 OE $00D6 lower +$20
local function lfutristletr (strin5trist, strsel5set)
local numtype5x = 0 -- preASSume invalid
local numlong5den = 0 -- actual length of input string
local numlong5bor = 0 -- expected length of single char
local numcha5r = 0 -- UINT8 beginning char
local numcha5s = 0 -- UINT8 later char (BIG ENDIAN, lower value here above)
local numcxa5rel = 0 -- UINT8 code relative to beginning of block $00...$FF
local numtem5p = 0
local boois5uppr = false
local boois5lowr = false
while true do -- fake loop -- this is LFUTRISTLETR
numlong5den = string.len (strin5trist)
if (numlong5den==0) then
break -- bad string length
end--if
numcha5r = string.byte (strin5trist,1,1)
numlong5bor = lfulnutf8char(numcha5r)
if ((numlong5bor==0) or (numlong5den<numlong5bor)) then
break -- truncated char or invalid
end--if
if (numlong5bor==1) then
boois5uppr = lfgtestuc(numcha5r)
boois5lowr = lfgtestlc(numcha5r)
break -- success with ASCII, almost done
end--if
numcha5s = string.byte (strin5trist,2,2) -- only $80 to $BF
numcxa5rel = (mathmod(numcha5r,4)*64) + (numcha5s-128) -- 4 times 64
if ((strsel5set=='eo') and ((numcha5r==196) or (numcha5r==197))) then
numtem5p = mathbitwrit (numcxa5rel,0,false) -- bad way to do AND $FE
if ((numtem5p==8) or (numtem5p==28) or (numtem5p==36) or (numtem5p==52) or (numtem5p==92) or (numtem5p==108)) then
boois5uppr = (numtem5p==numcxa5rel) -- UC below, block of 1
boois5lowr = not boois5uppr
break -- success with -eo-, almost done
end--if
end--if ((strsel5set=='eo') and ...
if ((strsel5set=='sv') and (numcha5r==195)) then
numtem5p = mathbitwrit (numcxa5rel,5,false) -- bad way to do AND $DF
if ((numtem5p==196) or (numtem5p==197) or (numtem5p==201) or (numtem5p==214)) then
boois5uppr = (numtem5p==numcxa5rel) -- UC below, block of 32
boois5lowr = not boois5uppr
break -- success with -sv-, almost done
end--if
end--if ((strsel5set=='sv') and ...
break -- finally to join mark -- unknown non-ASCII char is a fact :-(
end--while -- fake loop -- join mark
if (boois5uppr) then
numtype5x = 1
end--if
if (boois5lowr) then
numtype5x = 2
end--if
return numtype5x
end--function lfutristletr
------------------------------------------------------------------------
-- Local function LFUCASEREST
-- Adjust (restricted) case of a single letter (from ASCII + selectable
-- extra set from UTF8) or longer string. (this is REST)
-- Input : * strinco6cs : single unicode letter (1 or 2 octet:s) or
-- longer string
-- * booup6cas : for desired output uppercase "true" and for
-- lowercase "false"
-- * boodo6all : "true" to adjust all letters, "false"
-- only beginning letter
-- * strsel6set : "ASCII" (default, empty string or type "nil"
-- will do too) "eo" "sv" (value "GENE" NOT here)
-- Depends on functions : (this is REST)
-- [U] lfulnutf8char
-- [G] lfgpokestring lfgtestuc lfgtestlc
-- [E] mathdiv mathmod mathbitwrit
-- 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 valid char:s (1-octet ... 4-octet) are copied. Broken UTF8
-- stream results in remaining part of the output string (from 1 char to
-- complete length of the incoming string) filled by "Z".
-- Defined sets:
-- "eo" 2 x 6 uppercase and lowercase (CX GX HX JX SX UX cx gx hx jx sx ux)
-- upper CX $0108 GX $011C HX $0124 JX $0134 SX $015C UX $016C lower +1
-- "sv" 2 x 4 uppercase and lowercase (AE AA EE OE ae aa ee oe)
-- upper AE $00C4 AA $00C5 EE $00C9 OE $00D6 lower +$20
-- 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 function.
local function lfucaserest (strinco6cs, booup6cas, boodo6all, strsel6set)
local numlong6den = 0 -- actual length of input string
local numokt6index = 0
local numlong6bor = 0 -- expected length of single char
local numdel6ta = 0 -- quasi-signed +32 or -32 or +1 or -1 or ZERO
local numcha6r = 0 -- UINT8 beginning char
local numcha6s = 0 -- UINT8 later char (BIG ENDIAN, lower value here above)
local numcxa6rel = 0 -- UINT8 code relative to beginning of block $00...$FF
local numtem6p = 0
local boowan6tlowr = false
local boois6uppr = false
local boois6lowr = false
local boodo6adj = true -- preASSume innocence -- continue changing
local boobotch6d = false -- preASSume innocence -- NOT yet botched
booup6cas = not (not booup6cas)
boowan6tlowr = (not booup6cas)
numlong6den = string.len (strinco6cs)
while true do -- 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
boois6uppr = false -- preASSume on every iteration
boois6lowr = false -- preASSume on every iteration
numdel6ta = 0 -- preASSume on every iteration
numlong6bor = 1 -- preASSume on every iteration
while true do -- 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)
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
boois6uppr = lfgtestuc(numcha6r)
boois6lowr = lfgtestlc(numcha6r)
if (boois6uppr and boowan6tlowr) then
numdel6ta = 32 -- ASCII UPPER->lower
end--if
if (boois6lowr and booup6cas) then
numdel6ta = -32 -- ASCII lower->UPPER
end--if
break -- success with ASCII and one char almost done
end--if
numcha6s = string.byte (strinco6cs,(numokt6index+2),(numokt6index+2)) -- only $80 to $BF
numcxa6rel = (mathmod(numcha6r,4)*64) + (numcha6s-128) -- 4 times 64
if ((strsel6set=='eo') and ((numcha6r==196) or (numcha6r==197))) then
numtem6p = mathbitwrit (numcxa6rel,0,false) -- bad way to do AND $FE
if ((numtem6p==8) or (numtem6p==28) or (numtem6p==36) or (numtem6p==52) or (numtem6p==92) or (numtem6p==108)) then
boois6uppr = (numtem6p==numcxa6rel) -- UC below, block of 1
boois6lowr = not boois6uppr
if (boois6uppr and boowan6tlowr) then
numdel6ta = 1 -- UPPER->lower
end--if
if (boois6lowr and booup6cas) then
numdel6ta = -1 -- lower->UPPER
end--if
break -- success with -eo- and one char almost done
end--if
end--if ((strsel6set=='eo') and ...
if ((strsel6set=='sv') and (numcha6r==195)) then
numtem6p = mathbitwrit (numcxa6rel,5,false) -- bad way to do AND $DF
if ((numtem6p==196) or (numtem6p==197) or (numtem6p==201) or (numtem6p==214)) then
boois6uppr = (numtem6p==numcxa6rel) -- UC below, block of 32
boois6lowr = not boois6uppr
if (boois6uppr and boowan6tlowr) then
numdel6ta = 32 -- UPPER->lower
end--if
if (boois6lowr and booup6cas) then
numdel6ta = -32 -- lower->UPPER
end--if
break -- success with -sv- and one char almost done
end--if
end--if ((strsel6set=='sv') and ...
break -- finally to join mark -- unknown non-ASCII char is a fact :-(
end--while -- 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 -- genuine loop over incoming string (this is REST)
return strinco6cs
end--function lfucaserest
------------------------------------------------------------------------
---- HIGH LEVEL STRING FUNCTIONS [I] ----
------------------------------------------------------------------------
-- Local function LFIBREWCATHINT
-- Brew sorting hint/key for wiki category by lowering all letters and
-- removing junk chars other than known letters and numbers. All ASCII and
-- selected non-ASCII letters do count as such. Particularly ban spaces
-- and dashes. Controllably UTF8-aware.
-- Input : * strhinthink -- empty is useless but cannot
-- cause major harm
-- * strsignaro -- "ASCII" (default, empty string or type "nil"
-- will do too) "eo" "sv" NOPE "GENE"
-- * bookeepuk -- keep unknown non-ASCII (by default dropped
-- for sets other than "GENE", whereas
-- for NOPE "GENE" always kept)
-- Output : * strhasiil -- risk of empty
-- Depends on functions : (restricted LFUCASEREST)
-- [U] lfulnutf8char lfutristletr lfucaserest
-- [G] lfgtestnum lfgtestuc ...
-- [E] mathdiv mathmod mathbitwrit
-- Simplified strategy:
-- * numbers unchanged
-- * ASCII lowercase unchanged
-- * ASCII uppercase lowered
-- * unknown non-ASCII dropped for sets other than "GENE" unless bookeepuk
-- * non-ASCII sent to case sub with attempt to lower
-- * everything else dropped
-- * broken stream aborts and gives empty result
local function lfibrewcathint (strhinthink, strsignaro, bookeepuk)
local strhasiil = ''
local strnew7char = ''
local numstrleon = 0
local numeindx = 1 -- ONE-based
local numczaar = 0
local numczanx = 0 -- pre-picked next char
local numettfyra = 0
numstrleon = string.len (strhinthink)
while true do -- outer genuine loop over source string
if (numeindx>numstrleon) then
break -- empty input is useless but cannot cause major harm
end--if
numczaar = string.byte (strhinthink,numeindx,numeindx)
numeindx = numeindx + 1 -- do INC here
numettfyra = lfulnutf8char (numczaar) -- 1...4 or ZERO on error
if (numettfyra==0) then
strhasiil = ''
break -- broken stream -> bugger all -- exit outer loop
end--if
numczanx = 0 -- preASSume none
if (numeindx<=numstrleon) then -- pick but do NOT INC
numczanx = string.byte (strhinthink,numeindx,numeindx)
end--if
while true do -- inner fake loop
if (numettfyra==1) then
if (lfgtestnum(numczaar) or lfgtestlc(numczaar)) then
strnew7char = string.char (numczaar)
break -- numbers and ASCII lowercase pass unchanged
end--if
if (lfgtestuc(numczaar)) then
strnew7char = string.char (numczaar+32) -- lower ASCII letter
break -- lower it
end--if
end--if (numettfyra==1) then
if ((numettfyra==2) and ((strsignaro=='eo') or (strsignaro=='sv') or (strsignaro=='GENE'))) then
strnew7char = string.char(numczaar,numczanx) -- preASSume unchanged
if ((not bookeepuk) and (strsignaro~='GENE')) then -- drop unknown
if (lfutristletr(strnew7char,strsignaro)==0) then -- no known letter
strnew7char = '' -- discard char
break
end--if
end--if
-- if (strsignaro=='GENE') then -- below: want lower, do ONE only
-- strnew7char = lfucasegene (strnew7char,false,false)
-- else
strnew7char = lfucaserest (strnew7char,false,false,strsignaro)
-- end--if
break -- done with lowercased or unchanged char
end--if ((numettfyra==2) and ...
strnew7char = '' -- anything else -> discard char
break -- finally to join mark
end--while -- inner fake loop -- join mark
strhasiil = strhasiil .. strnew7char -- ASCII char or UTF8 char or ""
numeindx = numeindx + numettfyra - 1 -- do ADD here
end--while -- outer genuine loop over source string
return strhasiil
end--function lfibrewcathint
------------------------------------------------------------------------
-- 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 functions :
-- [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
------------------------------------------------------------------------
-- Local function LFIFILLINX
-- Replace placeholders "\@" "\\@" or "\~" "\\~" by given substitute string.
-- 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, 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...60
-- Output : * strafterfill
-- Depends on functions :
-- [G] lfgstringrange
local function lfifillinx (strbeforfill, numaskikodo, varsupstitu)
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==92) 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 (lfgstringrange(varpfiller,1,60)) then -- !!!FIXME!!! nowiki and other sanitization
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 lfifillinx
------------------------------------------------------------------------
-- Local function LFIKODEOSG
-- 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 functions :
-- [E] mathdiv mathmod
-- Depends on constants :
-- * table "contabtransluteo" inherently holy
-- To be called ONLY from "lfhfillsurrstrtab".
-- * 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 lfikodeosg (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 lfikodeosg
------------------------------------------------------------------------
-- Local function LFIVARILINGVONOMO
-- Input : * strlang29name : such as "Ido" or "dana" or "samea suda"
-- * numtip29mon : 0 native -- 1 la (AJ SB) -- 2 aj -- 3 sf (root)
-- 4 av (AV real or surrogate) -- 5 pl (AJ and PL)
-- * boomaju
-- Depends on functions :
-- [U] lfulnutf8char lfucaserest
-- [G] lfgpokestring lfgtestuc lfgtestlc
-- [E] mathdiv mathmod mathbitwrit
-- incoming multiword SB such as "Malnova Volapuko" is bad, we
-- can't process such
-- note that for "numtip29mon" 1 ie "la" we will add the article to
-- native AJ only, never to native SB (but type 4 ie "av" can force AJ
-- and subsequently add "la")
-- note that we MUST NOT change the word class to AJ
-- for "numtip29mon" 4 ie "av" if multiword
-- for "numtip29mon" 5 ie "pl" we change the word class to AJ too
local function lfivarilingvonomo (strlang29name, numtip29mon, boomaju)
local strpluralizator = ''
local num29lon = 0
local num29plindex = 0
local nummychar = 0
local nummyches = 0
local booisnoun = false
local boomulwords = false
local booaddprepen = false
local booaddartla = false
if ((numtip29mon>=1) and (numtip29mon<=5)) then
num29lon = string.len (strlang29name)
nummychar = string.byte (strlang29name,num29lon,num29lon) -- last
booisnoun = (nummychar==111) -- "o"
boomulwords = (string.find (strlang29name, ' ', 1, true)~=nil) -- plain tx
booaddprepen = (numtip29mon==4) and boomulwords -- surrogate AV with "en"
booaddartla = (booisnoun==false) and ((numtip29mon==1) or booaddprepen)
if ((numtip29mon>=2) and (booaddprepen==false)) then
strlang29name = string.sub (strlang29name,1,-2) -- cut off last letter
strlang29name = lfucaserest (strlang29name,false,false,'eo') -- lower it
end--if
if (booaddartla) then
strlang29name = 'la ' .. strlang29name -- we will NOT pluralize this
end--if
if ((numtip29mon==2) or (numtip29mon==5)) then
strlang29name = strlang29name .. "a" -- AJ (pluralize later if needed)
end--if
if (numtip29mon==4) then
if (boomulwords) then
strlang29name = "en " .. strlang29name -- surrog AV from PP "en" + ...
else
strlang29name = strlang29name .. "e" -- AV
end--if
end--if
if (numtip29mon==5) then
if (boomulwords) then
strpluralizator = strlang29name
strlang29name = '' -- we will rebuild it
num29lon = string.len (strpluralizator)
num29plindex = 0 -- ZERO-based
while true do -- pluralize all words except the last one
if (num29plindex==num29lon) then
break
end--if
nummychar = string.byte (strpluralizator,(num29plindex+1),(num29plindex+1))
num29plindex = num29plindex + 1 -- ZERO-based
nummyches = 0
if (num29plindex~=num29lon) then
nummyches = string.byte (strpluralizator,(num29plindex+1),(num29plindex+1))
end--if
if ((nummychar==97) and (nummyches==32)) then
strlang29name = strlang29name .. 'aj '
num29plindex = num29plindex + 1 -- eaten 2 char:s, written 3
else
strlang29name = strlang29name .. string.char(nummychar) -- copy ch
end--if
end--while
end--if (boomulwords) then
strlang29name = strlang29name .. "j" -- pluralize last or only one AJ
end--if (numtip29mon==5) then
end--if ((numtip29mon>=1) and (numtip29mon<=5)) then
if (boomaju) then
strlang29name = lfucaserest (strlang29name,true,false,'eo') -- upper, one, eo
end--if
return strlang29name
end--function lfivarilingvonomo
------------------------------------------------------------------------
---- HIGH LEVEL FUNCTIONS [H] ----
------------------------------------------------------------------------
-- Local function LFHVALI1STATUS99CODE
-- Depends on functions :
-- [E] mathisintrange
local function lfhvali1status99code (varvalue)
local boovalid = false -- preASSume guilt
while true do -- fake loop
if (varvalue==0) then
break -- success thus keep false since no valid error code ;-)
end--if
if (mathisintrange(varvalue,1,99)) 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 lfhvali1status99code
------------------------------------------------------------------------
-- Local function LFHCONSTRUCTERAR
-- Input : * numerar6code -- 1 ... 99 or 2 ... 99 (resistent against invalid
-- data type, giving "??" on such)
-- * boopeek6it -- do peek description #E02...#E99 from table
-- Depends on functions :
-- [N] lfnumto2digit
-- [E] mathisintrange mathdiv mathmod
-- Depends on constants :
-- * maybe table contaberaroj TWO-based (holes permitted)
-- To be called ONLY from lfhbrewerror, lfhbrewerrsm,
-- lfhbrewerrsvr, lfhbrewerrinsi.
local function lfhconstructerar (numerar6code, boopeek6it)
local vardes6krip = 0
local numbottom6limit = 1
local stryt6sux = '#E'
if (boopeek6it) then
numbottom6limit = 2 -- #E01 is a valid code for submodule only
end--if
if (mathisintrange(numerar6code,numbottom6limit,99)) then
stryt6sux = stryt6sux .. lfnumto2digit(numerar6code)
if (boopeek6it) then
vardes6krip = contaberaroj[numerar6code] -- risk of type "nil"
if (type(vardes6krip)=='string') then
stryt6sux = stryt6sux .. ' ' .. vardes6krip
else
stryt6sux = stryt6sux .. ' ??' -- no text found
end--if
end--if (boopeek6it) then
else
stryt6sux = stryt6sux .. '??' -- no valid error code
end--if
return stryt6sux
end--function lfhconstructerar
------------------------------------------------------------------------
-- Local function LFHBREWERRSM
-- Input : * numerar7code -- TWO-based error code 2 ... 99 (resistant
-- against invalid data type, giving "??" on such)
-- * numsubkodo -- 1 ... 99 (resistant against invalid data
-- type, send type "nil" if no submodule involved)
-- Depends on functions :
-- [H] lfhconstructerar
-- [N] lfnumto2digit
-- [E] mathisintrange mathdiv mathmod
-- Depends on constants :
-- * 3 strings constrelabg constrelaen constrlaxhu
-- * table contaberaroj TWO-based (holes permitted)
-- We DO NOT eat the name of the guilty submodule since it is included
-- in the error code #E03 #E05 and its message.
local function lfhbrewerrsm (numerar7code, numsubkodo)
local stryt7sux = ''
local strfromsubo = ''
stryt7sux = constrlaxhu .. constrelabg .. lfhconstructerar (numerar7code,true) .. constrelaen .. constrlaxhu
if (mathisintrange(numsubkodo,1,99)) then
strfromsubo = 'Submodule reports ' .. lfhconstructerar (numsubkodo,false)
stryt7sux = stryt7sux .. '<br>' .. constrlaxhu .. constrelabg .. strfromsubo .. constrelaen .. constrlaxhu
end--if
return stryt7sux
end--function lfhbrewerrsm
------------------------------------------------------------------------
-- Local function LFHFILLSURRSTRTAB
-- Process (fill in, transcode surr) either a single string, or all string
-- items in a table (even nested) using any type of keys/indexes (such as
-- a holy number sequence and non-numeric ones). Items with a non-string
-- value are kept as-is. For filling in own name, and converting eo and
-- NOPE sv surrogates (via 3 separate sub:s).
-- Input : * varinkommen -- type "string" or "table"
-- * varfyllo -- string, or type "nil" if no filling-in desired
-- * strlingkod -- "eo" or NOPE "sv" to convert surrogates, anything
-- else (preferably type "nil") to skip this
-- Depends on functions :
-- [I] lfifillinx (only if filling-in desired)
-- [I] lfikodeosg (only if converting of eo X-surrogates desired)
-- [I] NOPE lfikodsvsg
-- [E] mathdiv mathmod (via "lfikodeosg" and NOPE "lfikodsvsg")
-- Depends on constants :
-- * table "contabtransluteo" inherently holy (via "lfikodeosg")
-- * NOPE table "contabtranslutsv"
local function lfhfillsurrstrtab (varinkommen, varfyllo, strlingkod)
local varkey = 0 -- variable without type
local varele = 0 -- variable without type
local varutmatning = 0
local boodone = false
if (type(varinkommen)=='string') then
if (type(varfyllo)=='string') then
varinkommen = lfifillinx (varinkommen,64,varfyllo) -- fill-in
end--if
if (strlingkod=='eo') then
varinkommen = lfikodeosg (varinkommen) -- surr
end--if
-- if (strlingkod=='sv') then
-- varinkommen = lfikodsvsg (varinkommen) -- surr
-- end--if
varutmatning = varinkommen -- copy, risk for no change
boodone = true
end--if
if (type(varinkommen)=='table') then
varutmatning = {} -- brew new table
varkey = next (varinkommen) -- try to pick 0:th (in no order) key/index
while true do
if (varkey==nil) then
break -- empty table or end reached
end--if
varele = varinkommen[varkey] -- pick element of unknown type
if ((type(varele)=='string') or (type(varele)=='table')) then
varele = lfhfillsurrstrtab (varele, varfyllo, strlingkod) -- RECURSION
end--if
varutmatning[varkey] = varele -- write at same place in dest table
varkey = next (varinkommen, varkey) -- try to pick next key/index
end--while
boodone = true
end--if
if (not boodone) then
varutmatning = varinkommen -- copy as-is whatever it is
end--if
return varutmatning
end--function lfhfillsurrstrtab
------------------------------------------------------------------------
---- VARIABLES [R] ----
------------------------------------------------------------------------
function exporttable.ek (arxframent)
-- general unknown type
local vartymp = 0 -- variable without type
-- special type "args" AKA "arx"
local arxsomons = 0 -- metaized "args" from our own or caller's "frame"
-- general "tab"
local tablg76yleft = {} -- y-index -> leftmost column (langcode to langname)
-- peeked stuff
local strpiklangcode = '' -- "en" privileged site language
local strpikkatns = '' -- "Category"
local strpikindns = '' -- "Index"
local strpikapxns = '' -- "Appendix"
local strpikparent = '' -- "Template:nope" FULLPAGENAME
-- general "str"
local strnambah = '' -- langname (without prefix "Bahasa")
local strnambauc = '' -- langname uppercased begin ("Angla")
local strnambaty = '' -- langname processed according to "mon=" and "maj=1"
local strtymp = ''
local strvisgud = '' -- visible output or cat insertion on success
local strviserr = '' -- visible error message on error (no tracking cat)
local strret = '' -- result string
-- parameters "str"
local strkodbah = '' -- langcode (2 or 3 lowercase) from arxsomons[1]
local strhinhin = '' -- name of category KE (langcode will brew the hint)
local strprfprf = '' -- prefix before langname
local strerarpl = '' -- custom but common placeholder
-- general "num"
local numerr = 0 -- 1 inter 2 mali 3 nombri 8 tip 15 cxeno3 16 misc
local num2statcode = 0
local numpindex = 0 -- number of anon params
local numlangsta = 0 -- 2 known -- 1 unknown -- 0 obviously invalid
-- parameters "num"
local numbasetipe = 0 -- 0 raw -- 1 LA -- 2 LK -- 3 KE -- 4 empty
local nummontip = 0 -- 0 native -- 1 la -- 2 aj -- 3 sf -- 4 av -- 5 pl
-- general boo
local bootimp = false
-- parameters boo
local boonem = false -- avoid wall in visible link of type LA LK
local boomaj = false -- force uppercase
local boonoc = false -- infamous "nocat" (cannot cause an error)
local booper = false -- keep link or cat insertion on error
local boohavehin = false
local boohaveprf = false
local boohaveerr = false
------------------------------------------------------------------------
---- MAIN [Z] ----
------------------------------------------------------------------------
---- GUARD AGAINST INTERNAL ERROR AGAIN ----
-- later reporting of #E01 must NOT depend on uncommentable stuff
if (qbooguard) then
numerr = 1 -- #E01 internal
end--if
---- PEEK STUFF THAT IS NOT OVERRIDDEN SEMIGENEROUS ----
-- 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
-- no "strpikpareuf" here
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
strpikapxns = contabovrd['apxprefi'] or (mw.site.namespaces[102] or {})['name'] or 'Appendix' -- custom namespace
strpikparent = contabovrd['parentfn'] or arxframent:getParent():getTitle() or 'Template:nope' -- fullpagename
if ((type(strpiklangcode)~='string') or (type(strpikkatns)~='string') or (type(strpikapxns)~='string') or (type(strpikparent)~='string')) then
numerr = 1 -- #E01 internal (unlikely)
end--if
end--if (numerr==0) then
---- PROCESS MESSAGES, FILL IN ALWAYS, SURR ONLY IF NEEDED ----
-- needed for all errors except #E01
-- placeholder "\@" "\\@" is replaced by name of the caller from "strpikparent"
-- "strpikparent" in any case, for example "SXablono:nope" or "Templat:nope"
-- only for some languages the surr-transcoding is subsequently performed
if (numerr==0) then
contaberaroj = lfhfillsurrstrtab (contaberaroj, strpikparent, strpiklangcode)
end--if
---- PICK ONE SUBTABLE T76 ----
-- 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 = lfhvali1status99code (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['T76'] -- from "loaddata-tbllingvoj"
if (type(vartymp)~='table') then -- important check
numerr = 2 -- #E02 malica
break -- to join mark
end--if
tablg76yleft = vartymp -- y-index -> leftmost column (langcode to langname)
break -- finally to join mark
end--while -- fake loop -- join mark
---- GET THE ARX (ONE OF TWO) ----
-- must be seized independently on "numerr" even if we already suck
-- give a f**k in possible params other than "caller=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['caller']=='true') then
arxsomons = arxframent:getParent().args -- "args" from caller's "frame"
end--if
if (type(arxsomons)~='table') then
arxsomons = {} -- guard against indexing error again
numerr = 1 -- #E01 internal
end--if
---- WHINE IF YOU MUST #E01 ----
-- reporting of this error #E01 must NOT depend on
-- uncommentable stuff such as "strpikparent" and "contaberaroj"
-- do NOT use sub "lfhbrewerror", report our name (NOT of template), in EN
if (numerr==1) then
strtymp = '#E01 Internal error in module "mlili".'
strviserr = constrlaxhu .. constrelabg .. strtymp .. constrelaen .. constrlaxhu
end--if
---- PRELIMINARILY ANALYZE ANONYMOUS PARAMETERS ----
-- this will catch holes, empty parameters, too long parameters,
-- and wrong number of parameters
-- this depends on 3 constants:
-- * contabparam[0] minimal number
-- * contabparam[1] maximal number
-- * contabparam[2] maximal length (default 160)
if (numerr==0) then
numpindex = 0 -- ZERO-based
while true do
vartymp = arxsomons [numpindex+1] -- can be "nil"
if ((type(vartymp)~='string') or (numpindex>contabparam[1])) then
break -- good or bad
end--if
if (not lfgstringrange (vartymp,1,contabparam[2])) then
numerr = 9 -- #E09
break -- only bad here
end--if
numpindex = numpindex + 1 -- on exit has number of valid parameters
end--while
if ((numpindex<contabparam[0]) or (numpindex>contabparam[1])) then
numerr = 8 -- #E08
end--if
end--if
---- PROCESS ONE OBLIGATORY ANONYMOUS PARAM INTO ONE STRING AND ONE NUM ----
-- now var "numpindex" sudah contains number of prevalidated params
-- and is always 1 and is useless
-- here we prevalidate and assign "strkodbah" and "numlangsta"
-- this depends directly on 2 boolean constant:s and indirectly
-- on constant table "contabisbanned" via "lfhvalidatelnkoadv"
if (numerr==0) then
numlangsta = 2 -- this is just weak hope ...
strkodbah = arxsomons[1] -- langcode (obligatory, "??" permitted)
if (not lfivalidatelnkoadv(strkodbah,false,true,conbookodlng,conboomiddig,false)) then
numlangsta = 0 -- 2 known -- 1 unknown -- 0 obviously invalid
end--if
end--if
---- PROCESS 0...9 OPTIONAL NAMED PARAMS ----
-- data type "boo" (3+1) (assign a "boo") :
-- * "nem=" -- "1" -> avoid wall in visible link of type LA LK
-- * "maj=" -- "1" -> force uppercase
-- * "noc=" -- "true" -> no cat (this is "nocat", no error possible)
-- * "per=" -- "1" -> keep link or category if unknown
-- multiple choice (2) (assign a "num") :
-- * "tip=" - base type of task, 3 -> 4 possible values (later 5)
-- (0 raw) -- 1 LA -- 2 LK -- 3 KE -- (later also: 4 empty)
-- * "mon=" - type of langname, 5 -> 6 possible values
-- (0 native) -- 1 la -- 2 aj -- 3 sf -- 4 av -- 5 pl
-- string (2...80 octet:s) (3) (fill string and assign a "boo" to "true") :
-- * "hin=" - name of category KE (langcode will brew the hint)
-- * "prf=" - prefix before langname
-- * "err=" - common placeholder
if (numerr==0) then
while true do -- fake loop
boonem = false
vartymp = arxsomons['nem'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then
if (vartymp=='1') then
boonem = true
else
numerr = 16 -- #E16 other param crime
break
end--if
end--if
boomaj = false
vartymp = arxsomons['maj'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then
if (vartymp=='1') then
boomaj = true
else
numerr = 16 -- #E16 other param crime
break
end--if
end--if
boonoc = (arxsomons['noc']=='true') -- this one needs word "true" and CANNOT cause an error
booper = false
vartymp = arxsomons['per'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then
if (vartymp=="1") then
booper = true
else
numerr = 16 -- #E16 other param crime
break
end--if
end--if
numbasetipe = 0
vartymp = arxsomons['tip'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then
if (vartymp=="LA") then
numbasetipe = 1
end--if
if (vartymp=="LK") then
numbasetipe = 2
end--if
if (vartymp=="KE") then
numbasetipe = 3
end--if
if (numbasetipe==0) then
numerr = 14 -- #E14 -- faulty base type
break
end--if
end--if
nummontip = 0 -- default "raw" / "native"
vartymp = arxsomons['mon'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then
if (vartymp=='la') then
nummontip = 1
end--if
if (vartymp=='aj') then
nummontip = 2
end--if
if (vartymp=='sf') then
nummontip = 3
end--if
if (vartymp=='av') then
nummontip = 4
end--if
if (vartymp=='pl') then
nummontip = 5
end--if
if (nummontip==0) then
numerr = 16 -- #E16 other param crime
break
end--if
end--if
boohavehin = false
vartymp = arxsomons['hin'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then -- do NOT merge if:s
if (lfgstringrange (vartymp,2,80)) then
strhinhin = vartymp
boohavehin = true
else
numerr = 15 -- #E15 -- crime with "hin=" "prf=" "err="
break
end--if
end--if
boohaveprf = false
vartymp = arxsomons['prf'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then -- do NOT merge if:s
if (lfgstringrange (vartymp,2,80)) then
strprfprf = vartymp
boohaveprf = true
else
numerr = 15 -- #E15 -- crime with "hin=" "prf=" "err="
break
end--if
end--if
boohaveerr = false
vartymp = arxsomons['err'] -- optional, NOT prevalidated
if (type(vartymp)=='string') then -- do NOT merge if:s
if (lfgstringrange (vartymp,2,80)) then
strerarpl = vartymp
boohaveerr = true
else
numerr = 15 -- #E15 -- crime with "hin=" "prf=" "err="
break
end--if
end--if
break -- finally to join mark
end--while -- fake loop -- join mark
end--if
---- CHECK FOR CONFLICTING PARAMETERS ----
-- "tip=" no conflicts possible (only values 0...3 can be
-- requested, value 4 not directly)
-- default is fixed to "raw" 0
-- may be changed later from "LA" 1 "LK" 2 to "raw" 0 (for 1 reason)
-- or from "KE" 2 to "empty" 4 (for 2 reasons)
-- "nem=1" is illegal for base type "KE" 3 or "raw" 0
-- default is fixed to false (wall with base type "KE" is separate)
-- is negative (no-default "1" means "no wall")
-- "mon=" is illegal for base type "KE" 3
-- is illegal together with "nem=1"
-- default is fixed to "native" 0
-- "maj=1" is illegal for base type "KE" 3
-- is illegal together with "nem=1"
-- default is fixed to false (lowercasing separate from this type)
-- "hin=" is illegal for base type other than "KE" 3
-- default is fixed to false and empty
-- "prf=" is illegal for base type "raw" 0
-- is illegal together with "mon="
-- is illegal together with "hin="
-- default is fixed to false and empty
-- "per=1" is illegal for base type "raw" 0
-- default is fixed to OFF
-- "err=" no conflicts possible
if (numerr==0) then
if (boonem and ((numbasetipe==0) or (numbasetipe==3))) then
numerr = 16 -- #E16 other param crime
end--if
if ((nummontip~=0) and (numbasetipe==3)) then
numerr = 16 -- #E16 other param crime
end--if
if ((nummontip~=0) and boonem) then
numerr = 16 -- #E16 other param crime
end--if
if (boomaj and (numbasetipe==3)) then
numerr = 16 -- #E16 other param crime
end--if
if (boomaj and boonem) then
numerr = 16 -- #E16 other param crime
end--if
if (boohavehin and (numbasetipe~=3)) then
numerr = 16 -- #E16 other param crime
end--if
if (boohaveprf and (numbasetipe==0)) then
numerr = 16 -- #E16 other param crime
end--if
if (boohaveprf and (nummontip~=0)) then
numerr = 16 -- #E16 other param crime
end--if
if (boohaveprf and boohavehin) then
numerr = 16 -- #E16 other param crime
end--if
if (booper and (numbasetipe==0)) then
numerr = 16 -- #E16 other param crime
end--if
end--if
---- CHANGE BASE TYPE IF NEEDED DUE TO NOCAT ----
if ((numerr==0) and boonoc and (numbasetipe==3)) then
numbasetipe = 4 -- switch to empty result pseudo type 4
end--if
---- PEEK THE LANGNAME ----
-- * tristate "numlangsta" : 2 known -- 1 unknown -- 0 obviously invalid
-- * from above 2 or 0, now confirm 2 or downgrade to 1 or skip this
-- for langname in site language ("c0"):
-- * type "nil" can become (numlangsta=1) (unknown code) if the site
-- langcode works, otherwise #E02 (broken submodule)
-- * "-" is unconditionally evil with #E02 (broken submodule)
-- here we depend on "strpiklangcode" and submodule "loaddata-tbllingvoj"
if ((numerr==0) and (numbasetipe~=4) and (numlangsta==2)) then
while true do -- fake loop
vartymp = tablg76yleft[strkodbah] -- pick langname
if (type(vartymp)~='string') then
if (type(tablg76yleft[strpiklangcode])=='string') then
numlangsta = 1 -- unknown code given (site code works)
else
numerr = 2 -- #E02 broken submodule (site code does NOT work either)
end--if
break
end--if
if (not lfgstringrange (vartymp,2,60)) then -- less than 2 lett not legal
numerr = 2 -- #E02 broken submodule
break
end--if
strnambah = vartymp -- got langname :-)
break -- finally to join mark
end--while -- fake loop -- join mark
end--if
---- WHINE IF YOU MUST #E02...#E99 ----
-- reporting depends on uncommentable strings
if (numerr>1) then
if (numerr==3) then -- #E03
strviserr = lfhbrewerrsm(numerr,num2statcode) -- 2 lines
else
strviserr = lfhbrewerrsm(numerr) -- 1 line
end--if
end--if
---- CHANGE BASE TYPE AND MON TYPE TO RAW IF NEEDED DUE TO BAD CODE ----
-- only if code is bad (obviously invalid 0 or unknown 1) and
-- "per=1" was NOT used then change base type "LA" 1 or "LK" 2 to type
-- "raw" 0, and base type "KE" 3 to empty result AKA pseudo type 4
-- if code is bad then always reset "mon=" type to "raw" 0
if ((numerr==0) and (numlangsta~=2) and (not booper)) then
if ((numbasetipe==1) or (numbasetipe==2)) then
numbasetipe = 0 -- switch to type "raw"
end--if
if (numbasetipe==3) then
numbasetipe = 4 -- switch to empty result AKA pseudo type 4
end--if
end--if
if ((numerr==0) and (numlangsta~=2)) then
nummontip = 0 -- default "raw" / "native"
end--if
---- APPLY MESSAGES FOR BAD CODES ----
if ((numerr==0) and (numbasetipe~=4)) then
if (numlangsta==0) then
if (boohaveerr) then -- have "err="
strnambah = strerarpl -- common placeholder, custom message
else
strnambah = constrevid -- invalid langcode, fixed message
end--if
end--if
if (numlangsta==1) then
if (boohaveerr) then -- have "err="
strnambah = strerarpl -- common placeholder, custom message
else
strnambah = constrneli -- unknown langcode, fixed message
end--if
end--if
end--if
---- BREW THE VISIBLE PART FOR RAW OR FOR LINK ----
-- strkodbah : langcode (not needed anymore here)
-- strnambah : langname (without prefix "Bahasa")
-- always >= 2 letters (from above)
-- strnambauc : langname uppercased begin ("Angla") (brew here)
-- strnambaty : langname processed according to "mon="
-- and "maj=1" (brew here)
-- numbasetipe : 0 raw -- 1 LA -- 2 LK colon YES -- 3 KE -- 4 empty
-- nummontip : 0 native -- 1 la -- 2 aj -- 3 sf -- 4 av -- 5 pl
-- boomaj
if ((numerr==0) and (numbasetipe~=4)) then
strnambauc = lfucaserest (strnambah,true,false,'eo') -- make upper one letter
strnambaty = lfivarilingvonomo (strnambah, nummontip, boomaj)
end--if
---- CARRY OUT THE TRIVIAL WORK WITH BASE TYPE (0) RAW ----
if ((numerr==0) and (numbasetipe==0)) then
strvisgud = strnambaty
end--if
---- CARRY OUT THE HARD WORK WITH TYPE (1,2,3) LINK OR CAT INSERTION ----
-- numbasetipe : 0 raw -- 1 LA -- 2 LK colon YES -- 3 KE -- 4 empty
-- "prf=" is legal for all LA LK KE but not together with "hin="
do -- scope
local strbasepagename = ''
local strprefix = '' -- "Appendix:" 1 or ":Category:" 2 or "Category:" 3
local strbefore = '' -- before wall (link target)
local strafteer = '' -- aft wall (visible link text) (no wall if this empty)
if ((numerr==0) and (numbasetipe~=0) and (numbasetipe~=4)) then
if (numbasetipe==1) then
strprefix = strpikapxns .. ':' -- LA "Appendix:"
end--if
if (numbasetipe==2) then
strprefix = ":" .. strpikkatns .. ':' -- LK ":Category:"
end--if
if (numbasetipe==3) then
strprefix = strpikkatns .. ':' -- KE "Category:"
end--if
if (boohaveprf) then
strbasepagename = strprfprf .. " (" .. strnambah .. ")" -- no force uppercase
else
strbasepagename = strnambauc -- force uppercased begin
end--if
if (numbasetipe==3) then
if (boohavehin) then
strbefore = strhinhin
strafteer = lfibrewcathint (strnambah,'eo',false)
else
strbefore = strbasepagename
strafteer = '' -- no wall is tolerable
end--if
else
strbefore = strbasepagename
if (boonem) then
strafteer = '' -- no wall is tolerable in visible link of type LA LK
else
strafteer = strnambaty -- augmented langname
end--if
end--if (numbasetipe==3) else
strvisgud = "[[" .. strprefix .. strbefore -- prefix ends with colon ":"
if (strafteer~='') then
strvisgud = strvisgud .. "|" .. strafteer
end--if
strvisgud = strvisgud .. "]]"
end--if ((numerr==0) and (numbasetipe~=0) and (numbasetipe~=4)) then
end--do scope
---- RETURN THE JUNK STRING ----
if (numerr==0) then -- no separate string for cat:s here
strret = strvisgud
else
strret = strviserr
end--if
return strret -- can be empty
end--function
---- RETURN THE JUNK LUA TABLE ----
return exporttable