Modulo:mgrup
MODULO | ||
Memtesto ne disponeblas. |
- Ĉi tiu modulo efektivigas laboron de ŝablono
{{vfvg}}
. - Dediĉita memtesto ne disponeblas, sed eblas uzi paĝojn -an, api, sun, time, esti, fajro, vipero.
--[===[
MODULE "MGRUP" (ligiloj vortfarado vortgrupigado)
"eo.wiktionary.org/wiki/Modulo:mgrup" <!--2024-Aug-29-->
Purpose: checks categories related to a word or root and brews
either links to those categories or directly lists
of entries limited in size
Utilo: inspektas kategoriojn rilatajn al vorto aux radiko kaj kreas
aux ligilojn al tiaj kategorioj aux rekte ...
Used by templates / Uzata far sxablonoj / Digunakan oleh templat:
* vfvg (EO)
Required submodules / Bezonataj submoduloj /
Submodul yang diperlukan / Behoevda submoduler:
* none
Incoming: * one obligatory anonymous parameter
* langcode
* 0...7 optional anonymous additional parameters
- each holding a morpheme type letter, optionally followed
by dash "-" and adjustment code, or colon ":" and explicit
morpheme, both optionally followed by percent "%"
and script code
* adjustment codes:
- "1" drop last letter
- "2" lowercase begin
- "3" lowercase begin and drop last letter
- "4" uppercase begin
- "5" uppercase begin and drop last letter
* explicit morpheme (length 1...40 octet:s)
* default is "M" and "W" (becomes internally M W Y)
* multiple morpheme types must be in this order: C I M N P U W
* examples of multiple mortyps with langcode attached:
- "eo|N-1|W"
- "eo|N:viper|N:vipur|W:viper|W:vipur"
- "ja|N%K"
* 2 optional hidden named parameters
* "pagenameoverridetestonly="
* "detrc="
Returned: * one string that is inherently "HTML-block-type" and can span
substantial (but protected from insane) height
Maximally 7 morphemes can be specified, but type "W" later counts double
(can be both group of words and sentence, both will be showed), and the
"post-expand" limit is 9, thus for example if 7 morphemes are given then
maximally 2 of them may be of type "W".
Possible category syntaxes:
* a) M "Vorto -id- enhavanta morfemon M (api)" (api, perapian)
* b) M "Vorto -en- enhavanta morfemon M (sun)" (sun, Sun, sundown)
* c) C I N P U "Vorto -id- enhavanta morfemon N (endap)" (pengendapan)
* d) N !!! "Vorto -eo- enhavanta morfemon N (kapt)" (kapti, kapto)
* e) W "Vortgrupo -id- enhavanta (api)" (kereta api, senjata api)
* f) W "Vortgrupo -id- enhavanta (kereta api)" (kereta api,
stasiun kereta api)
* g) Y "Frazo -id- enhavanta vorton (api)" (Ada asap, ada api.)
There is a problem with self-categorization and risk of showing a useless
box containing nothing but a self-link. It is the lemma pagename that can
cause problems, not necessarily the root used in the category name (in
the case "d)" they are different). We cannot drop (in other module) the
self-categorization since as exemplified here they both are crucial and main
pages of the category, see cases "b)" (standalone) and "d)" (non-standalone).
Still we do not want a box with just one word identical to the pagename
(that is "kapti" or "kapto", not "kapt").
In the 7 above cases following applies:
* a) M -> self-categorization occurs
* b) M -> self-categorization occurs
* c) C I N P U -> mutually exclusive groups, no self-categorization
(lemma page "endap" exists but is NOT in "Vorto -id-
enhavanta morfemon N (endap)", lemma page "pengendapan"
exists and is in "Vorto -id- enhavanta morfemon N (endap)",
but doesn't show words based on the root "endap")
* d) N !!! -> self-categorization occurs
(lemma page "kapt" doesn't exist, but both "kapti" and
"kapto" are in "Vorto -eo- enhavanta morfemon N (kapt)"
and both show words based on the root "kapt")
* e) W -> mutually exclusive groups, no self-categorization
(since "api" is NOT a word group)
* f) W -> self-categorization occurs
* g) Y -> mutually exclusive groups, no self-categorization
The problem occurs in 4 of 7 cases namely "a)" "b)" "d)" "f)". If we find out
that the lemma page (read out via "mw.title.getCurrentTitle().text") is inside
the cat constructed (via mw.title.new + ".categories"), then we increase the
number of members in the cat required for showing the box from ONE to TWO.
Thus the box is showed only if the cat page is created, and contains the
minimal number of members.
If it contains the minimal number of members but is not created, then we
show a "preload" red link to brew the cat.
]===]
local exporttable = {}
------------------------------------------------------------------------
---- CONSTANTS [O] ----
------------------------------------------------------------------------
-- uncommentable EO vs ID constant strings (core site-related features)
local constrpriv = "eo" -- EO (privileged site language)
-- local constrpriv = "id" -- ID (privileged site language)
local constrkatq = "Kategorio" -- EO !!!FIXME!!!
-- local constrkatq = "Kategori" -- ID !!!FIXME!!!
-- constant table -- ban list -- add obviously invalid access codes (2-letter or 3-letter) only
-- length of the list is NOT stored anywhere
-- "en.wikipedia.org/wiki/Spurious_languages"
-- "iso639-3.sil.org/code/art" only valid in ISO 639-2
-- "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
-- constant table (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 constrelabg = '<span class="error"><b>' -- lagom whining begin
local constrelaen = '</b></span>' -- lagom whining end
local constrlaxhu = ' ** ' -- lagom -> huge circumfix " ** "
-- constant strings (HTML)
-- note that '<categorytree>' generates "strip markers" only
local constrdivxx = '<div style="width:92%; margin-top:0.15em; margin-bottom:0.15em; margin-left:4%; border:1px solid; background-color:#'
local constrdivbg = 'E8E8FF; padding:0.15em; text-align:center;">'
local constrdivbk = 'E8FFE8; padding:0.15em; text-align:center;">'
local constrdiven = '</div>'
local constrcatbk = '<categorytree mode="pages" hideroot="on" style="column-count:2; background-color:#E8FFE8; font-size:90%; text-align:center;">'
local constrcaten = '</categorytree>'
-- uncommentable EO vs ID strings
local constrbuggerall = '(neniuj)' -- EO
-- local constrbuggerall = '(tidak ada)' -- ID
local constrmissingcat = 'Mankanta kategorio por' -- EO
-- local constrmissingcat = 'Belum ada kategori untuk' -- ID
-- uncommentable EO vs ID string (caller name for error messages)
local constrkoll = 'sxablono "vfvg"' -- EO augmented name of the caller (semi-hardcoded, we do NOT peek it) !!!FIXME!!
-- local constrkoll = 'templat "vfvg"' -- ID augmented name of the caller (semi-hardcoded, we do NOT peek it) !!!FIXME!!
-- uncommentable EO vs ID constant table (error messages)
-- #E02...#E99, note that #E00 and #E01 are NOT supposed to be included here
local contaberaroj = {}
contaberaroj[ 2] = 'Erara uzo de \\@, legu gxian dokumentajxon' -- EO #E02
contaberaroj[ 2] = 'Penggunaan salah \\@, bacalah dokumentasinya' -- ID #E02
contaberaroj[ 4] = 'Evidente nevalida lingvokodo en \\@' -- EO #E04
contaberaroj[ 4] = 'Kode bahasa jelas-jelas salah dalam \\@' -- ID #E04
contaberaroj[15] = 'Erara uzo de \\@ pro nedevigaj aldonaj parametroj' -- EO #E15
contaberaroj[15] = 'Penggunaan salah \\@ oleh parameter opsional tambah' -- ID #E15
-- constant table (3 integers for preliminary parameter check)
local contabparam = {}
contabparam[0] = 1 -- minimal number of anon parameters
contabparam[1] = 8 -- maximal number of anon parameters (1 + 7)
contabparam[2] = 160 -- maximal length of single para (min is hardcoded 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"
------------------------------------------------------------------------
---- SPECIAL STUFF OUTSIDE MAIN [B] ----
------------------------------------------------------------------------
---- VAR:S ----
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 & sub:s, debug report request by "detrc="
---- GUARD AGAINST INTERNAL ERROR ----
qbooguard = ((type(constrpriv)~='string') or (type(constrkatq)~='string') or (type(constrkoll)~='string'))
------------------------------------------------------------------------
---- DEBUG FUNCTIONS [D] ----
------------------------------------------------------------------------
-- Local function LFDTRACEMSG
-- Enhance upvalue "qstrtrace" with fixed text.
-- for variables the other sub "lfdshowvar" is preferable but in exceptional
-- cases it can be justified to send text with values of variables to this sub
-- no size limit
-- upvalue "qstrtrace" must NOT be type "nil" on entry (is inited to "<br>")
-- uses upvalue "qboodetrc"
local function lfdtracemsg (strshortline)
if (qboodetrc and (type(strshortline)=='string')) then
qstrtrace = qstrtrace .. strshortline .. '.<br>' -- dot added !!!
end--if
end--function lfdtracemsg
------------------------------------------------------------------------
-- Local function LFDMINISANI
-- Input : * strdangerous -- must be type "string", empty legal
-- * numlimitdivthree
-- Output : * strsanitized -- can happen to be quasi-empty with <<"">>
-- To be called from "lfdshowvcore" <- "lfdshowvar" only.
-- * we absolutely must disallow: cross "#" 35 | apo "'" 39 |
-- star "*" 42 | dash 45 | colon 58 | "<" 60 | ">" 62 | "[" 91 | "]" 93
-- * spaces are showed as "{32}" if repetitive or at begin or at end
local function lfdminisani (strdangerous, numlimitdivthree)
local strsanitized = '"' -- begin quot
local num38len = 0
local num38index = 1 -- ONE-based
local num38signo = 0
local num38prev = 0
local boohtmlenc = false
local boovisienc = false
num38len = string.len (strdangerous)
while true do
boohtmlenc = false -- % reset on
boovisienc = false -- % every iteration
if (num38index>num38len) then -- ONE-based
break -- done string char after char
end--if
num38signo = string.byte (strdangerous,num38index,num38index)
if ((num38signo<43) or (num38signo==45) or (num38signo==58) or (num38signo==60) or (num38signo==62) or (num38signo==91) or (num38signo==93) or (num38signo>122)) then
boohtmlenc = true
end--if
if ((num38signo<32) or (num38signo>126)) then
boovisienc = true -- overrides "boohtmlenc"
end--if
if ((num38signo==32) and ((num38prev==32) or (num38index==1) or (num38index==num38len))) then
boovisienc = true -- overrides "boohtmlenc"
end--if
if (boovisienc) then
strsanitized = strsanitized .. '{' .. tostring (num38signo) .. '}'
else
if (boohtmlenc) then
strsanitized = strsanitized .. '&#' .. tostring (num38signo) .. ';'
else
strsanitized = strsanitized .. string.char (num38signo)
end--if
end--if
if ((num38len>(numlimitdivthree*3)) and (num38index==numlimitdivthree)) then
num38index = num38len - numlimitdivthree -- jump forwards
strsanitized = strsanitized .. '" ... "'
else
num38index = num38index + 1 -- ONE-based
end--if
num38prev = num38signo
end--while
strsanitized = strsanitized .. '"' -- don't forget final quot
return strsanitized
end--function lfdminisani
------------------------------------------------------------------------
-- Local function LFDSHOWVCORE
-- Prebrew report about content of a variable including optional full
-- listing of a table with numerical and string indexes. !!!FIXME!!!
-- Input : * vardubious -- content (any type including "nil" is acceptable)
-- * str77name -- name of the variable (string)
-- * vardescri -- optional comment, default empty, begin with "@" to
-- place it before name of the variable, else after
-- * vartablim -- optional limit, default ZERO -> no listing, max 20
-- Depends on functions :
-- [D] lfdminisani
local function lfdshowvcore (vardubious, str77name, vardescri, vartablim)
local taballkeystring = {}
local strtype = ''
local strreport = ''
local numindax = 0
local numlencx = 0
local numkeynumber = 0
local numkeystring = 0
local numkeycetera = 0
local numkey77min = 999999
local numkey77max = -999999
local boobe77fore = false
if (type(str77name)~='string') then
str77name = '??' -- bite the bullet
else
str77name = '"' .. str77name .. '"'
end--if
if (type(vardescri)~='string') then
vardescri = '' -- omit comment
end--if
if (string.len(vardescri)>=2) then
boobe77fore = (string.byte(vardescri,1,1)==64) -- prefix "@"
if (boobe77fore) then
vardescri = string.sub(vardescri,2,-1) -- CANNOT become empty
end--if
end--if
if (type(vartablim)~='number') then
vartablim = 0 -- deactivate listing of a table
end--if
if ((vardescri~='') and (not boobe77fore)) then
str77name = str77name .. ' (' .. vardescri .. ')' -- now a combo
end--if
strtype = type(vardubious)
if (strtype=='table') then
for k,v in pairs(vardubious) do
if (type(k)=='number') then
numkey77min = math.min (numkey77min,k)
numkey77max = math.max (numkey77max,k)
numkeynumber = numkeynumber + 1
else
if (type(k)=='string') then
taballkeystring [numkeystring] = k
numkeystring = numkeystring + 1
else
numkeycetera = numkeycetera + 1
end--if
end--if
end--for
strreport = 'Table ' .. str77name
if ((numkeynumber==0) and (numkeystring==0) and (numkeycetera==0)) then
strreport = strreport .. ' is empty'
else
strreport = strreport .. ' contains '
if (numkeynumber==0) then
strreport = strreport .. 'NO numeric keys'
end--if
if (numkeynumber==1) then
strreport = strreport .. 'a single numeric key equal ' .. tostring (numkey77min)
end--if
if (numkeynumber>=2) then
strreport = strreport .. tostring (numkeynumber) .. ' numeric keys ranging from ' .. tostring (numkey77min) .. ' to ' .. tostring (numkey77max)
end--if
strreport = strreport .. ' and ' .. tostring (numkeystring) .. ' string keys and ' .. tostring (numkeycetera) .. ' other keys'
end--if
if ((numkeynumber~=0) and (vartablim~=0)) then -- !!!FIXME!!!
strreport = strreport .. ' ### content num keys :'
numindax = numkey77min
while true do
if ((numindax>vartablim) or (numindax>numkey77max)) then
break -- done table
end--if
strreport = strreport .. ' ' .. tostring(numindax) .. ' -> ' .. lfdminisani(tostring(vardubious[numindax]),30)
numindax = numindax + 1
end--while
end--if
if ((numkeystring~=0) and (vartablim~=0)) then -- !!!FIXME!!!
strreport = strreport .. ' ### content string keys :'
end--if
else
strreport = 'Variable ' .. str77name .. ' has type "' .. strtype .. '"'
if (strtype=='string') then
numlencx = string.len (vardubious)
strreport = strreport .. ' and length ' .. tostring (numlencx)
if (numlencx~=0) then
strreport = strreport .. ' and content ' .. lfdminisani (vardubious,30)
end--if
else
if (strtype~='nil') then
strreport = strreport .. ' and content "' .. tostring (vardubious) .. '"'
end--if
end--if (strtype=='string') else
end--if (strtype=='table') else
if ((vardescri~='') and boobe77fore) then
strreport = vardescri .. ' : ' .. strreport -- very last step
end--if
return strreport
end--function lfdshowvcore
------------------------------------------------------------------------
-- Local function LFDSHOWVAR
-- Enhance upvalue "qstrtrace" with report about content of a
-- variable including optional full listing of a table with numerical
-- and string indexes. !!!FIXME!!!
-- Depends on functions :
-- [D] lfdminisani lfdshowvcore
-- upvalue "qstrtrace" must NOT be type "nil" on entry (is inited to "<br>")
-- uses upvalue "qboodetrc"
local function lfdshowvar (varduubious, strnaame, vardeskkri, vartabljjm)
if (qboodetrc) then
qstrtrace = qstrtrace .. lfdshowvcore (varduubious, strnaame, vardeskkri, vartabljjm) .. '.<br>' -- dot added !!!
end--if
end--function lfdshowvar
------------------------------------------------------------------------
---- 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 MATHBITTEST
-- Find out whether single bit selected by ZERO-based index is "1" / "true".
-- Result has type "boolean".
-- Depends on functions :
-- [E] mathdiv mathmod
local function mathbittest (numincoming, numbitindex)
local boores = false
while true do
if ((numbitindex==0) or (numincoming==0)) then
break -- we have either reached our bit or run out of bits
end--if
numincoming = mathdiv(numincoming,2) -- shift right
numbitindex = numbitindex - 1 -- count down to ZERO
end--while
boores = (mathmod(numincoming,2)==1) -- pick bit
return boores
end--function mathbittest
------------------------------------------------------------------------
---- LOW LEVEL STRING FUNCTIONS [G] ----
------------------------------------------------------------------------
-- 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
------------------------------------------------------------------------
---- 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
------------------------------------------------------------------------
---- 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 -- number 1...4 or ZERO if invalid
-- Does NOT thoroughly check the validity, looks at 1 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 LFUCASEGENE
-- Adjust (generous) case of a single letter (from ASCII + limited extra
-- set from UTF8 with some common ranges) or longer string. (this is GENE)
-- Input : * strinco7cs : single unicode letter (1 or 2 octet:s) or
-- longer string
-- * booup7cas : for desired output uppercase "true" and for
-- lowercase "false"
-- * boodo7all : "true" to adjust all letters, "false"
-- only beginning letter
-- Output : * strinco7cs
-- Depends on functions : (this is GENE)
-- [U] lfulnutf8char
-- [G] lfgpokestring lfgtestuc lfgtestlc
-- [E] mathdiv mathmod mathbittest
-- 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".
-- * lowercase is usually above uppercase, but not always, letters can be
-- only misaligned (UC even vs UC odd), and rarely even swapped (French "Y")
-- * case delta can be 1 or $20 or $50 other
-- * case pair distance can span $40-boundary or even $0100-boundary
-- * in the ASCII range lowercase is $20 above uppercase, b5 reveals
-- the case (1 is lower)
-- * the same is valid in $C3-block
-- * this is NOT valid in $C4-$C5-block, lowercase is usually 1 above
-- uppercase, but nothing reveals the case reliably
-- ## $C2-block $0080 $C2,$80 ... $00BF $C2,$BF no letters (OTOH NBSP mm)
-- ## $C3-block $00C0 $C3,$80 ... $00FF $C3,$BF (SV mm) delta $20 UC-LC-UC-LC
-- upper $00C0 $C3,$80 ... $00DF $C3,$9F
-- lower $00E0 $C3,$A0 ... $00FF $C3,$BF
-- AA AE EE NN OE UE mm
-- $D7 $DF $F7 excluded (not letters)
-- $FF excluded (here LC, UC is $0178)
-- ## $C4-$C5-block $0100 $C4,$80 ... $017F $C5,$BF (EO mm)
-- delta 1 and UC even, but messy with many exceptions
-- EO $0108 ... $016D case delta 1
-- for example SX upper $015C $C5,$9C -- lower $015D $C5,$9D
-- $0138 $0149 $017F excluded (not letters)
-- $0178 excluded (here UC, LC is $FF)
-- $0100 ... $0137 UC even
-- $0139 ... $0148 misaligned (UC odd) note that case delta is NOT reversed
-- $014A ... $0177 UC even again
-- $0179 ... $017E misaligned (UC odd) note that case delta is NOT reversed
-- ## $CC-$CF-block $0300 $CC,$80 ... $03FF $CF,$BF (EL mm) delta $20
-- EL $0370 ... $03FF (officially)
-- strict EL base range $0391 ... $03C9 case delta $20
-- $0391 $CE,$91 ... $03AB $CE,$AB upper
-- $03B1 $CE,$B1 ... $03CB $CD,$8B lower
-- for example "omega" upper $03A9 $CE,$A9 -- lower $03C9 $CF,$89
-- ## $D0-$D3-block $0400 $D0,$80 ... $04FF $D3,$BF (RU mm)
-- * delta $20 $50 1
-- * strict RU base range $0410 ... $044F case delta $20 but there
-- is 1 extra char outside !!!
-- * $0410 $D0,$90 ... $042F $D0,$AF upper
-- * $0430 $D0,$B0 ... $044F $D1,$8F lower
-- * for example "CCCP-gamma" upper $0413 $D0,$93 -- lower $0433 $D0,$B3
-- * extra base char and exception is special "E" with horizontal doubledot
-- case delta $50 (upper $0401 $D0,$81 -- lower $0451 $D1,$91)
-- * same applies for ranges $0400 $D0,$80 ... $040F $D0,$8F upper
-- and $0450 $D1,$90 ... $045F $D1,$9F lower
-- * range $0460 $D1,$A0 ... $04FF $D3,$BF (ancient RU, UK, RUE, ...) case
-- delta 1 and UC usually even, but messy with many exceptions $048x
-- $04Cx (combining decorations and misaligned)
-- Variables "numdel7abs" and "numdel7ta" must be at least 16-bit to avoid
-- misevaluation or wrong wrapping when fitting into the range 128...191,
-- even if no deltas exceeding +-127 are supported (there are very few pairs
-- of char:s exceeding this). Also both can be declared unsigned since only
-- addition and subtraction are performed on them.
-- 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 lfucasegene (strinco7cs, booup7cas, boodo7all)
local numlong7den = 0 -- actual length of input string
local numokt7index = 0
local numlong7bor = 0 -- expected length of single char
local numdel7abs = 0 -- at least 16-bit, absolute posi delta
local numdel7ta = 0 -- quasi-signed at least 16-bit, can be negative
local numdel7car = 0 -- quasi-signed 8-bit, can be negative
local numcha7r = 0 -- UINT8 beginning char
local numcha7s = 0 -- UINT8 later char (BIG ENDIAN, lower value here above)
local numcxa7rel = 0 -- UINT8 code relative to beginning of block $00...$FF
local boowan7tlowr = false
local boois7uppr = false
local boois7lowr = false
local boomy7bit0x = false -- single relevant bits picked -- b0
local boomy7bit5x = false -- single relevant bits picked -- b5
local boopen7din = false -- only fake loop
local boodo7adj = true -- preASSume innocence -- continue changing
local boobotch7d = false -- preASSume innocence -- NOT yet botched
local booc3block = false -- $C3 only $00C0...$00FF SV mm delta 32
local booc4c5blk = false -- $C4 $C5 $0100...$017F EO mm delta 1
local boocccfblk = false -- $CC $CF $0300...$03FF EL mm delta 32
local bood0d3blk = false -- $D0 $D3 $0400...$04FF RU mm delta 32 80
booup7cas = not (not booup7cas)
boowan7tlowr = (not booup7cas)
numlong7den = string.len (strinco7cs)
while true do -- genuine loop over incoming string (this is GENE)
if (numokt7index>=numlong7den) then
break -- done complete string
end--if
if ((not boodo7all) and (numokt7index~=0)) then -- loop can skip index ONE
boodo7adj = false
end--if
boois7uppr = false -- preASSume on every iteration
boois7lowr = false -- preASSume on every iteration
numdel7ta = 0 -- preASSume on every iteration
numlong7bor = 1 -- preASSume on every iteration
while true do -- fake loop (this is GENE)
numcha7r = string.byte (strinco7cs,(numokt7index+1),(numokt7index+1))
if (boobotch7d) then
numdel7ta = 90 - numcha7r -- "Z" -- delta must be non-ZERO to write
break -- fill with "Z" char:s
end--if
if (not boodo7adj) then
break -- copy octet after octet
end--if
numlong7bor = lfulnutf8char(numcha7r)
if ((numlong7bor==0) or ((numokt7index+numlong7bor)>numlong7den)) then
numlong7bor = 1 -- reassign to ONE !!!
numdel7ta = 90 - numcha7r -- "Z" -- delta must be non-ZERO to write
boobotch7d = true
break -- truncated char or broken stream
end--if
if (numlong7bor>=3) then
break -- copy UTF8 char, no chance for adjustment
end--if
if (numlong7bor==1) then
boois7uppr = lfgtestuc(numcha7r)
boois7lowr = lfgtestlc(numcha7r)
if (boois7uppr and boowan7tlowr) then
numdel7ta = 32 -- ASCII UPPER->lower
end--if
if (boois7lowr and booup7cas) then
numdel7ta = -32 -- ASCII lower->UPPER
end--if
break -- success with ASCII and one char almost done
end--if
booc3block = (numcha7r==195) -- case delta is 32
booc4c5blk = ((numcha7r==196) or (numcha7r==197)) -- case delta is 1
boocccfblk = ((numcha7r>=204) and (numcha7r<=207)) -- case delta is 32
bood0d3blk = ((numcha7r>=208) and (numcha7r<=211)) -- case delta is 32 80 1
numcha7s = string.byte (strinco7cs,(numokt7index+2),(numokt7index+2)) -- only $80 to $BF
numcxa7rel = (mathmod(numcha7r,4)*64) + (numcha7s-128) -- 4 times 64
boomy7bit0x = ((mathmod(numcxa7rel,2))==1)
boomy7bit5x = mathbittest(numcxa7rel,5)
if (booc3block) then
boopen7din = true -- pending flag
if ((numcxa7rel==215) or (numcxa7rel==223) or (numcxa7rel==247)) then
boopen7din = false -- not a letter, we are done
end--if
if (numcxa7rel==255) then
boopen7din = false -- special LC silly "Y" with horizontal doubledot
if (booup7cas) then
numdel7ta = 121 -- lower->UPPER (distant and reversed order)
end--if
end--if
if (boopen7din) then
boois7lowr = boomy7bit5x -- mostly regular block, look at b5
boois7uppr = not boois7lowr
if (boois7uppr and boowan7tlowr) then
numdel7ta = 32 -- UPPER->lower
end--if
if (boois7lowr and booup7cas) then
numdel7ta = -32 -- lower->UPPER
end--if
end--if (boopen7din) then
break -- to join mark
end--if (booc3block) then
if (booc4c5blk) then
boopen7din = true -- pending flag
if ((numcxa7rel==56) or (numcxa7rel==73) or (numcxa7rel==127)) then
boopen7din = false -- not a letter, we are done
end--if
if (numcxa7rel==120) then
boopen7din = false -- special UC silly "Y" with horizontal doubledot
if (boowan7tlowr) then
numdel7ta = -121 -- UPPER->lower (distant and reversed order)
end--if
end--if
if (boopen7din) then
if (((numcxa7rel>=57) and (numcxa7rel<=73)) or (numcxa7rel>=121)) then
boois7lowr = not boomy7bit0x -- UC odd (misaligned)
else
boois7lowr = boomy7bit0x -- UC even (ordinary align)
end--if
boois7uppr = not boois7lowr
if (boois7uppr and boowan7tlowr) then
numdel7ta = 1 -- UPPER->lower
end--if
if (boois7lowr and booup7cas) then
numdel7ta = -1 -- lower->UPPER
end--if
end--if (boopen7din) then
break -- to join mark
end--if (booc4c5blk) then
if (boocccfblk) then
boois7uppr = ((numcxa7rel>=145) and (numcxa7rel<=171))
boois7lowr = ((numcxa7rel>=177) and (numcxa7rel<=203))
if (boois7uppr and boowan7tlowr) then
numdel7ta = 32 -- UPPER->lower
end--if
if (boois7lowr and booup7cas) then
numdel7ta = -32 -- lower->UPPER
end--if
break -- to join mark
end--if (boocccfblk) then
if (bood0d3blk) then
if (numcxa7rel<=95) then -- messy layout but no exceptions
boois7lowr = (numcxa7rel>=48) -- delta $20 or $50
boois7uppr = not boois7lowr
numdel7abs = 32 -- $20
if ((numcxa7rel<=15) or (numcxa7rel>=80)) then
numdel7abs = 80 -- $50
end--if
end--if
if ((numcxa7rel>=96) and (numcxa7rel<=129)) then -- no exceptions here
boois7lowr = boomy7bit0x -- UC even (ordinary align)
boois7uppr = not boois7lowr
numdel7abs = 1
end--if
if (numcxa7rel>=138) then -- some misaligns here !!!FIXME!!!
boois7lowr = boomy7bit0x -- UC even (ordinary align)
boois7uppr = not boois7lowr
numdel7abs = 1
end--if
if (boois7uppr and boowan7tlowr) then
numdel7ta = numdel7abs -- UPPER->lower
end--if
if (boois7lowr and booup7cas) then
numdel7ta = -numdel7abs -- lower->UPPER
end--if
break -- to join mark
end--if (bood0d3blk) then
break -- finally to join mark -- unknown non-ASCII char is a fact :-(
end--while -- fake loop -- join mark (this is GENE)
if ((numlong7bor==1) and (numdel7ta~=0)) then -- no risk of carry here
strinco7cs = lfgpokestring (strinco7cs,numokt7index,(numcha7r+numdel7ta))
end--if
if ((numlong7bor==2) and (numdel7ta~=0)) then -- no risk of carry here
numdel7car = 0
while true do -- inner genuine loop
if ((numcha7s+numdel7ta)<192) then
break
end--if
numdel7ta = numdel7ta - 64 -- get it down into range 128...191
numdel7car = numdel7car + 1 -- BIG ENDIAN 6 bits with carry
end--while
while true do -- inner genuine loop
if ((numcha7s+numdel7ta)>127) then
break
end--if
numdel7ta = numdel7ta + 64 -- get it up into range 128...191
numdel7car = numdel7car - 1 -- BIG ENDIAN 6 bits with carry
end--while
if (numdel7car~=0) then -- in-place change only if needed
strinco7cs = lfgpokestring (strinco7cs,numokt7index,(numcha7r+numdel7car))
end--if
if (numdel7ta~=0) then -- in-place change only if needed
strinco7cs = lfgpokestring (strinco7cs,(numokt7index+1),(numcha7s+numdel7ta))
end--if
end--if
numokt7index = numokt7index + numlong7bor -- advance in incoming string
end--while -- genuine loop over incoming string (this is GENE)
return strinco7cs
end--function lfucasegene
------------------------------------------------------------------------
---- HIGH LEVEL STRING FUNCTIONS [I] ----
------------------------------------------------------------------------
-- Local function LFBREWERROR !!!FIXME!!! and move me too
-- #E02...#E99, note that #E00 and #E01 are NOT supposed to be included here.
-- We need 3 const strings "constrelabg", "constrelaen",
-- "constrlaxhu" and const table "contaberaroj".
local function lfbrewerror (numerrorcode)
local vardeskrip = 0
local strytsux = '#E'
vardeskrip = contaberaroj[numerrorcode] -- risk of type "nil"
if (type(vardeskrip)=='string') then
strytsux = strytsux .. lfnumto2digit(numerrorcode) .. ' ' .. vardeskrip
else
strytsux = strytsux .. '??'
end--if
strytsux = constrlaxhu .. constrelabg .. strytsux .. constrelaen .. constrlaxhu
return strytsux
end--function lfbrewerror
------------------------------------------------------------------------
-- 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 LFIFILLNAME
-- Replace placeholder "\@" "\\@" by augmented name of the caller.
-- To be called ONLY from "lfhfillsurrstrtab".
-- The name of the caller is submitted to us as a parameter thus we
-- do NOT access any constants and do NOT have to peek it either.
local function lfifillname (strmessage, strcaller)
local strhasill = ''
local numstrloen = 0
local numindfx = 1 -- ONE-based
local numcjar = 0
local numcjnext = 0
numstrloen = string.len (strmessage)
while true do
if (numindfx>numstrloen) then
break -- empty input is useless but cannot cause major harm
end--if
numcjar = string.byte (strmessage,numindfx,numindfx)
numindfx = numindfx + 1
numcjnext = 0 -- preASSume no char
if (numindfx<=numstrloen) then
numcjnext = string.byte (strmessage,numindfx,numindfx)
end--if
if ((numcjar==92) and (numcjnext==64)) then
strhasill = strhasill .. strcaller -- invalid input is caller's risk
numindfx = numindfx + 1 -- skip 2 octet:s of the placeholder
else
strhasill = strhasill .. string.char (numcjar)
end--if
end--while
return strhasill
end--function lfifillname
------------------------------------------------------------------------
-- 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 lficolonindent (strkarhu)
return '<dl><dd>' .. strkarhu .. '</dd></dl>'
end--function -- lficolonindent
------------------------------------------------------------------------
---- HIGH LEVEL FUNCTIONS [H] ----
------------------------------------------------------------------------
-- 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
-- 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 "sv" to convert surrogates, anything
-- else (preferably type "nil") to skip this
-- Depends on functions :
-- [I] lfifillname (only if filling-in desired)
-- [I] lfikodeosg (only if converting of eo X-surrogates desired)
-- [I] lfikodsvsg (only if converting of sv blackslash-surrogates desired)
-- [E] mathdiv mathmod (via "lfikodeosg" and "lfikodsvsg")
-- Depends on constants :
-- * table "contabtransluteo" inherently holy (via "lfikodeosg")
-- * table "contabtranslutsv" inherently holy (via "lfikodsvsg")
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 = lfifillname (varinkommen,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
------------------------------------------------------------------------
---- MEDIAWIKI INTERACTION FUNCTIONS [W] ----
------------------------------------------------------------------------
-- Local function LFWIFEXISIM
-- Simple check whether a wiki page exists. The caller must use "pcall". Here
-- we can crash on the spot if we violate the limit of 500 expensive requests.
-- Input : * strpgnamsi -- fullpagename (default NS 0, not template NS 10)
-- Output : * boomemangada -- "true" on success
local function lfwifexisim (strpgnamsi)
local boomemangada = false
local metaa = 0
metaa = mw.title.new (strpgnamsi) -- 1 param
boomemangada = metaa.exists -- expensive here
return boomemangada
end--function lfwifexisim
------------------------------------------------------------------------
-- Local function LFWISINCAT
-- mw.title.new + ".categories" gives a table with list of cat:s (without
-- ns prefix) a page is inserted in at indexes [1] [2] ...
local function lfwisincat (strfullpagename, strkattname)
local varmeta = 0
local varte53mp = 0
local tabcats = {}
local num53gindex = 1
local booitisin = false
varmeta = mw.title.new ( strfullpagename ) -- 1 param
tabcats = varmeta.categories -- expensive, type "nil" if page non-existent
if (type(tabcats)=='table') then
while true do
varte53mp = tabcats[num53gindex]
if (type(varte53mp)~='string') then
break
end--if
if (varte53mp==strkattname) then
booitisin = true
break
end--if
num53gindex = num53gindex + 1
end--while
end--if (type(tabcats)=='table') then
return booitisin
end--function lfwisincat
------------------------------------------------------------------------
---- MAIN [Z] ----
------------------------------------------------------------------------
function exporttable.ek (arxframent)
-- general unknown type
local vartmp = 0 -- variable without type multipurpose
-- special type "args" AKA "arx"
local arxsomons = 0 -- metaized "args" from our own or caller's "frame"
-- general tab
local tabtriple = {} -- 0...8 and 10...18 and 20...28
-- general str
local strpagenam = '' -- "{{PAGENAME}}" o "pagenameoverridetestonly"
local strkodbah = '' -- obligatory param
local strmurf = ''
local strtmp = '' -- temp
local strviserr = '' -- visible error
local strvisgud = '' -- visible good output
local strret = '' -- final result string
-- general num
local numerr = 0 -- 1 inter 2 param 4 evidente 5 additional params
local numpindex = 0 -- number of anon params
local numtamp = 0
local numtump = 0
local numoct = 0
local numodt = 0
local numlong = 0
local numprev = 0
local nummrtyp = 0 -- mortyp
local numskrip = 0 -- script code
local numspesl = 0 -- adjustment code ZERO or ONE or 49...53 ie "1"..."5"
-- general boo
local boofake = false -- if no optional params then we must fake them
---- GUARD AGAINST INTERNAL ERROR AGAIN ----
-- later reporting of #E01 may NOT depend on uncommentable strings
lfdtracemsg ('This is "mgrup", requested "detrc" report.')
if (qbooguard) then
numerr = 1 -- #E01 internal
end--if
---- PROCESS MESSAGES, FILL IN ALWAYS, SURR ONLY IF NEEDED ----
-- needed for all errors except #E01
-- placeholder "\@" "\\@" is replaced by name of the caller from "constrkoll"
-- "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, constrkoll, constrpriv)
end--if
---- GET THE ARX (ONE OF TWO) ----
-- must be seized independently on "numerr" even if we already suck
arxsomons = arxframent.args -- "args" from our own "frame"
if (type(arxsomons)~="table") then
arxsomons = {} -- guard against indexing error
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
---- PROCESS 2 HIDDEN NAMED PARAMS INTO 1 STRING AND 1 BOOLEAN ----
-- 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
-- "detrc=" and "nocat=" must be seized independently on "numerr"
-- even if we already suck, but type "table" must be ensured !!!
strpagenam = ''
if (numerr==0) then
vartmp = arxsomons['pagenameoverridetestonly']
if (type(vartmp)=='string') then
numtamp = string.len(vartmp)
if ((numtamp>=1) and (numtamp<=120)) then
strpagenam = vartmp -- empty is not legal
else
numerr = 1 -- #E01 internal
end--if
end--if
end--if
if (arxsomons["detrc"]=="true") then
lfdtracemsg ('Param "detrc=true" seized')
else
qboodetrc = false -- was preassigned to "true"
qstrtrace = '' -- shut up now
end--if
lfdshowvar (numerr,'numerr','done with hidden parameters')
---- SEIZE THE PAGENAME FROM MW AND CHECK IT ----
-- later reporting of #E01 may NOT depend on uncommentable strings
-- must be 1...120 octet:s keep consistent with "pagenameoverridetestonly="
if ((numerr==0) and (strpagenam=='')) then
vartmp = mw.title.getCurrentTitle().text -- without namespace prefix
if (type(vartmp)=='string') then
numtamp = string.len(vartmp)
if ((numtamp>=1) and (numtamp<=120)) then
strpagenam = vartmp -- pagename here (empty is NOT legal)
else
numerr = 1 -- #E01 internal
end--if
end--if
end--if
if ((numerr==0) and (strpagenam=='')) then
numerr = 1 -- #E01 internal
end--if
lfdshowvar (strpagenam,'strpagenam','@Pagename finally seized')
lfdshowvar (numerr,'numerr')
---- WHINE IF YOU MUST #E01 ----
-- reporting of this error #E01 may NOT depend on
-- uncommentable strings as "constrkoll" and "contaberaroj"
-- do NOT use sub "lfbrewerror", report our name (NOT of template) and in EN
if (numerr==1) then
strtmp = '#E01 Internal error in module "mgrup".'
strviserr = constrlaxhu .. constrelabg .. strtmp .. constrelaen .. constrlaxhu
end--if
---- PRELIMINARILY ANALYZE ANONYMOUS PARAMETERS ----
-- this will catch holes, empty parameters, too long parameters,
-- and wrong number of parameters
-- below on exit var "numpindex" will contain number of
-- prevalidated anonymous params
-- 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
numtamp = contabparam[1] -- maximal number of params
while true do
vartmp = arxsomons [numpindex+1] -- can be "nil"
if ((type(vartmp)~='string') or (numpindex>numtamp)) then
break -- good or bad
end--if
numlong = string.len (vartmp)
if ((numlong==0) or (numlong>contabparam[2])) then
numerr = 2 -- #E02 param/RTFD
break -- only bad here
end--if
numpindex = numpindex + 1 -- on exit has number of valid parameters
end--while
if ((numpindex<contabparam[0]) or (numpindex>numtamp)) then
numerr = 2 -- #E02 param/RTFD
end--if
end--if
---- PROCESS 1 ANONYMOUS PARAM INTO 1 STRING ----
-- now var "numpindex" sudah contains number of prevalidated
-- params (incl langcode) and is equal 1 ... 8
-- this depends indirectly on const table "contabisbanned" via "lfivalidatelnkoadv"
if (numerr==0) then
strkodbah = arxsomons[1] -- langcode (obligatory)
if (not lfivalidatelnkoadv(strkodbah,false,false,conbookodlng,conboomiddig,false)) then
numerr = 4 -- #E04
end--if
end--if
lfdtracemsg ('Seized ONE anon param langcode')
lfdshowvar (numpindex,'numpindex')
lfdshowvar (strkodbah,'strkodbah')
lfdshowvar (numerr,'numerr')
---- PROCESS 0...7 ANONYMOUS PARAMS INTO TABLE ----
-- now var "numpindex" sudah contains number of prevalidated
-- params (incl langcode) and is equal 1 ... 8
-- mortyp -- (1)
-- mortyp | percent "%" | script code -- (3)
-- mortyp | dash "-" | adjustment code 1...5 -- (3)
-- mortyp | dash "-" | adjustment code 1...5 | percent "%" | script code -- (5)
-- mortyp | colon ":" | explicit morpheme -- (3...42)
-- mortyp | colon ":" | explicit morpheme | percent "%" | script code -- (5...44)
-- percent "%" 37 -- dash "-" 45 -- colon ":" 58
-- length of explicit morpheme 1...40 octet:s
-- mortyp goes into "nummrtyp" (7 possible num values, must be valid)
-- adjustment code goes into "numspesl" (ZERO (as-is) or ONE (expl) or 49...53)
-- script goes into "numskrip" (all uppercase possible 65...90, or ZERO none)
-- "tabtriple":
-- 0... 8 (num) mortyp:s (7 possible num values, must be valid, "nil" EOF)
-- 10...18 (str) translated (no limit) or explicit (1...40) morphemes
-- 20...28 (num) script codes (ZERO if none specified)
-- cannot be empty after while-loop due to faking
numtamp = 2 -- TWO-based index in ARX 2...8
numtump = 0 -- ZERO-based index in "tabtriple" step 1 or 2 !!!
numprev = 0 -- previous mortyp
boofake = (numpindex==1)
if (boofake) then
numpindex = 3 -- part of faking
end--if
while true do
if (numerr~=0) then
break -- jaevlar
end--if
if (numtump>=9) then
numerr = 15 -- #E15 too many (0...8, index 9 is NOT valid anymore)
break -- done
end--if
if (numtamp>numpindex) then -- ZERO iterations NOT possible
break -- done
end--if
if (boofake) then
if (numtamp==2) then
strtmp = "M" -- faked index 2
else
strtmp = "W" -- faked index 3
end--if
else
strtmp = arxsomons[numtamp] -- guaranteed to be nonempty string
end--if
numtamp = numtamp + 1
numlong = string.len (strtmp)
if ((numlong==2) or (numlong>44)) then
numerr = 15 -- #E15 length 2 is blatantly invalid (1 and 3 are valid)
lfdtracemsg ('Invalid length 2 or >44')
break
end--if
nummrtyp = string.byte (strtmp,1,1)
if (nummrtyp<numprev) then
numerr = 15 -- #E15 not ascending (equality is legal)
lfdtracemsg ('Not ascending: ' .. tostring(nummrtyp) .. '<' .. tostring(numprev))
break
end--if
numprev = nummrtyp
if ((nummrtyp~=67) and (nummrtyp~=73) and (nummrtyp~=77) and (nummrtyp~=78) and (nummrtyp~=80) and (nummrtyp~=85) and (nummrtyp~=87)) then
numerr = 15 -- #E15 illegal type C I M N P U W
break
end--if
numspesl = 0 -- preASSume take pagename as-is
numskrip = 0 -- preASSume none
if (numlong>=3) then
numoct = string.byte (strtmp,(numlong-1),(numlong-1)) -- maybe "%"
numodt = string.byte (strtmp,(numlong ),(numlong )) -- maybe uc
if ((numoct==37) and lfgtestuc(numodt)) then
numskrip = numodt -- otherwise ZERO
strtmp = string.sub (strtmp,1,(numlong-2)) -- saw off 2 char:s
numlong = numlong - 2 -- at least ONE left
end--if
end--if
if (numlong>=3) then -- BEWARE we could have cut above, new eval needed
numoct = string.byte (strtmp,2,2) -- legal is "-" 45 or ":" 58 only
if ((numoct~=45) and (numoct~=58)) then
numerr = 15 -- #E15 invalid separator
lfdtracemsg ('Invalid separator after mortyp char')
break
end--if
if (numoct==58) then
numspesl = 1 -- explicit morpheme (seize it later)
else
numspesl = string.byte (strtmp,3,3) -- number 1...5 after the dash "-"
if ((numlong~=3) or (numspesl<49) or (numspesl>53)) then
numerr = 15 -- #E15 only "1"..."5" legal take -- adjusted pagename
lfdtracemsg ('Invalid length <>3(+2) with dash or invalid number after dash')
break
end--if
end--if (numoct==58) else
end--if (numlong>=3) then
if (numspesl==1) then
strmurf = string.sub (strtmp,3,numlong) -- explicit, at least 1 ch left
else
strmurf = strpagenam -- not explicit as-is or with adjustment code
end--if
numlong = string.len (strmurf) -- refresh !!!
if ((numspesl==49) or (numspesl==51) or (numspesl==53)) then
strmurf = string.sub (strmurf,1,(numlong-1)) -- saw off last lett 1 3 5
end--if
if ((numspesl==50) or (numspesl==51)) then
strmurf = lfucasegene (strmurf,false,false) -- lc for 2 and 3
end--if
if ((numspesl==52) or (numspesl==53)) then
strmurf = lfucasegene (strmurf,true,false) -- uc for 4 and 5
end--if
tabtriple [numtump] = nummrtyp -- store mortyp
tabtriple [numtump+10] = strmurf -- store morpheme
tabtriple [numtump+20] = numskrip -- store script
numtump = numtump + 1
if (nummrtyp==87) then -- "W" counts double: grupo + frazo
tabtriple [numtump] = 89 -- store pseudo-type "Y" frazo
tabtriple [numtump+10] = strmurf -- store morpheme
tabtriple [numtump+20] = numskrip -- store script
numtump = numtump + 1
end--if
end--while
lfdshowvar (tabtriple,'tabtriple','after parameters seized',29)
lfdshowvar (numerr,'numerr')
---- WHINE IF YOU MUST #E02...#E99 ----
-- reporting of errors #E02...#E99 depends on uncommentable strings
-- and name of the caller filled in from "constrkoll"
if (numerr>1) then
strviserr = lfbrewerror(numerr)
end--if
---- BREW THE LIST ----
-- Need string "constrkatq" and it is cat prefix and excludes the
-- colon ":" but must NOT be fed into "mw.site.stats.pagesInCategory"
-- nor into "<categorytree>" not into "lfwisincat".
-- "Vorto -zh- enhavanta morfemon M (#) S" ("#" is Chinese simplified lett)
-- "Vorto -id- enhavanta morfemon M (api)"
-- "Vortgrupo -id- enhavanta (api)"
-- "Vortgrupo -id- enhavanta (kereta api)"
-- "Frazo -id- enhavanta vorton (api)"
-- * for >=19 brew : "constrdivxx" + "constrdivbg" + link to cat with
-- description and number + "constrdiven"
-- * for 1 or 2 ... : "constrdivxx" + "constrdivbk" + description and
-- 18 brew number + "<br>" + "constrcatbk" +
-- raw cat name + "constrcaten" + "constrdiven"
-- * for < 1 or 2 brew : nothing for now
-- if nothing else brewed after exhaustive
-- search, then finally brew ..."(neniuj)"... via "constrbuggerall"
-- we have a pseudo-type 89 AKA "Y" for "frazo" whereas 87 AKA
-- "W" is restricted to "vortgrupo"
-- check whether we are in the own cat, if YES then rise the minimum
-- "numonetwo" from ONE to TWO
if (numerr==0) then
do -- scope
local var7tmp = 0
local str7murf = ''
local str7kato = ''
local str7visi = ''
local stronebox = ''
local num7tymp = 0 -- ZERO-based index in "tabtriple"
local num7skri = 0
local numpaink = 0 -- number from "mw.site.stats.pagesInCategory"
local numonetwo = 0 -- minimal number for showing the box at all
local booisinowncat = false
local boocatpageexi = false
while true do
lfdshowvar (num7tymp,'num7tymp','@Index in iteration trying to brew a box')
var7tmp = tabtriple [num7tymp ] -- pick mortyp with risk of type "nil"
if (type(var7tmp)~="number") then
lfdtracemsg ('Done due to type "nil" reached')
break -- done
end--if
nummrtyp = var7tmp
str7murf = tabtriple [num7tymp+10] -- pick morpheme
num7skri = tabtriple [num7tymp+20] -- pick script
num7tymp = num7tymp + 1
lfdshowvar (nummrtyp,'nummrtyp')
lfdshowvar (str7murf,'str7murf')
lfdshowvar (num7skri,'num7skri')
str7kato = "??" -- fed into "mw.site.stats.pagesInCategory" and more
str7visi = "??" -- visible text
if (nummrtyp<87) then
str7kato = "Vorto"
str7visi = "Vortfaradoj"
end--if
if (nummrtyp==87) then
str7kato = "Vortgrupo"
str7visi = "Vortgrupoj"
end--if
if (nummrtyp==89) then
str7kato = "Frazo"
str7visi = "Frazoj"
end--if
str7kato = str7kato .. ' -' .. strkodbah .. '- enhavanta'
str7visi = str7visi .. ' kun'
if (nummrtyp==89) then
str7kato = str7kato .. ' vorton' -- YES for "frazo" NO for "vortgrupo"
end--if
if (nummrtyp<87) then
str7kato = str7kato .. ' morfemon ' .. string.char(nummrtyp)
str7visi = str7visi .. ' ' .. string.char(nummrtyp)
end--if
str7kato = str7kato .. ' (' .. str7murf .. ')'
str7visi = str7visi .. ' "' .. str7murf .. '"'
if (num7skri~=0) then
str7kato = str7kato .. ' ' .. string.char(num7skri)
str7visi = str7visi .. ' ' .. string.char(num7skri)
end--if
lfdshowvar (str7kato,'str7kato','@Cat name brewed')
lfdshowvar (str7visi,'str7visi','@Boasting text brewed')
booisinowncat = lfwisincat (strpagenam, str7kato)
lfdshowvar (booisinowncat,'booisinowncat','@Page is in own cat')
boocatpageexi = lfwifexisim (constrkatq .. ':' .. str7kato)
lfdshowvar (boocatpageexi,'boocatpageexi','@Cat page exists')
var7tmp = mw.site.stats.pagesInCategory(str7kato,'pages')
lfdshowvar (var7tmp,'var7tmp','@After "mw.site.stats.pagesInCategory"')
numpaink = 0
if (type(var7tmp)=='number') then
numpaink = var7tmp -- risk for negative values due to stupid MediaWiki
end--if
lfdshowvar (numpaink,'numpaink','@After "mw.site.stats.pagesInCategory" (negative legal)')
numonetwo = 1
if (booisinowncat) then
numonetwo = 2
lfdtracemsg ('Rising minimum count from 1 to 2')
end--if
if (numpaink>=numonetwo) then
lfdtracemsg ('YES count is eligible')
str7visi = str7visi .. ' (' .. tostring (numpaink) .. ')' -- visible text
if (boocatpageexi) then
if (numpaink>=19) then
str7kato = '[[:' .. constrkatq .. ':' .. str7kato .. '|' .. str7visi .. ']]' -- !!!FIXME!!! use sub
stronebox = constrdivxx .. constrdivbg .. str7kato .. constrdiven
else
str7kato = arxframent:preprocess (constrcatbk .. str7kato .. constrcaten) -- !!!FIXME!!! use tag-function
stronebox = constrdivxx .. constrdivbk .. str7visi .. '<br>' .. str7kato .. constrdiven
end--if
else
stronebox = lficolonindent (constrmissingcat .. ' <b>' .. str7visi .. '</b> [[:' .. constrkatq .. ':' .. str7kato .. ']].') -- !!!FIXME!!! preload
end--if (boocatpageexi) else
strvisgud = strvisgud .. stronebox
end--if (numpaink>=numonetwo) then
end--while
if (strvisgud=='') then
strvisgud = lficolonindent(constrbuggerall) -- nothing found
end--if
end--do scope
end--if (numerr==0) then
---- RETURN THE JUNK STRING ----
strret = strviserr .. strvisgud
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