--[===[
MODULE "MPICKLINES" (pick lines)
"eo.wiktionary.org/wiki/Modulo:mpicklines" <!--2024-Nov-03-->
Purpose: picks a part of a text defined by line indexes, intended
for news but usable for other purposes as well
Utilo: elprenas parton de teksto difinita per linioindeksoj, intencita
por novajxoj sed uzebla ankaux alimaniere
Manfaat: mengambil bagian teks ...
Syfte: plockar fram en del av en text definierad med hjaelp av radindex,
avsett foer nyheter men anvaendbar aeven foer andra syften
Used by templates / Uzata far sxablonoj:
* novajxoj
Required submodules / Bezonataj submoduloj:
* none / neniuj
Incoming: * 3 anonymous obligatory parameters
- name of the source template holding the
incoming text (5...100 octet:s) with namespace
prefix, for example "Templat:kabar-sumber"
- earliest line to pick (ZERO-based, 0...99'999)
- last line to pick (ZERO-based, 0...99'999)
* 1 named optional parameter "err="
- alternative output string to replace the "=" error
message (1...64 char:s, default is "=") (this works even
for errors coming from anonymous parameters)
Returned: * picked text or (customizable) error message
An error is generated if:
- more or less than 3 anonymous obligatory parameters have been supplied
- the template name is obviously faulty
- earliest line index or last line index is faulty or out of range
- "last line index" < "earliest line index" (but they may be equal)
- pointed source template does not exist
- text from the source template, even after stripping of blank
lines, is empty (<4 octet:s)
- text from the source template is faulty (see below)
- text from the source template is too short and end of
text is reached before earliest line index, ie
"amount of lines" <= "earliest line index" (must be bigger)
It is NOT per se an error if "amount of lines" < "last line index".
Example:
- given 3 incoming lines
- earliest line index can be ZERO to 2
- (0,2) returns all 3 lines
- (0,5) returns all 3 lines
- (2,5) returns ONE line
- (3,5) is an error
Text structure:
Every line must begin with "* " (star and space) and end with an EOL.
Trailing spaces are NOT tolerated. Minimum line length is 3 octet:s
including the "* " but excluding EOL, maximum line length is 400 octet:s.
Blank lines, even multiple, are allowed at beginning and end of the text.
Single blank lines are allowed anywhere in the text. All blank lines
are skipped from counting. Multiple blank lines are prohibited inside
the text. All text, even outside of the selection is checked.
]===]
local exporttable = {}
require('strict')
------------------------------------------------------------------------
---- 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
------------------------------------------------------------------------
---- NUMBER CONVERSION FUNCTIONS [N] ----
------------------------------------------------------------------------
-- Local function LFNDECINP
-- Convert string (1...13 octet:s) with decimal ASCII digits to a
-- positive (UINT32) integer number (0...4'000'000'000) optionally
-- skipping possible inner apo:s, optionally tolerating leading ZERO:s.
-- Input : * stridn -- string, empty tolerable (gives -1), but type
-- other than "string" is NOT
-- * booalwapo -- allow apo:s
-- * booalwlez -- allow leading ZERO:s
-- Output : * numaout -- -1 on error
-- 65'536 good and maybe accepted
-- 655'36 ugly but maybe accepted -- 6''''55''''36 ugly but maybe accepted
-- '65536 rejected -- 65536' rejected
local function lfndecinp (stridn, booalwapo, booalwlez)
local numaout = 0
local numleen = 0
local numinxx = 1 -- ONE-based -- counts up
local numokkt = 0
numleen = string.len (stridn)
while true do
if ((numleen<1) or (numleen>13)) then
numaout = -1 -- damn
break
end--if
if (stridn=='0') then
break -- bypass check for leading ZERO:s
end--if
numokkt = string.byte (stridn,numinxx,numinxx)
if (numokkt==39) then
if ((not booalwapo) or (numinxx==1) or (numinxx==numleen)) then
numaout = -1
break -- damn (must NOT begin or end with apo)
end--if
else
if ((numokkt<48) or (numokkt>57) or (numaout>400000000) or ((numokkt==48) and (numinxx==1) and (not booalwlez))) then
numaout = -1
break -- damn (bad char or out of range or bad leading)
end--if
numaout = numaout * 10 + (numokkt - 48)
end--if
if (numinxx==numleen) then
break -- done (hopefully success, but not yet sure, risk 4'000'000'009)
end--if
numinxx = numinxx + 1
end--while
if (numaout>4000000000) then
numaout = -1 -- damn (out of range)
end--if
return numaout
end--function lfndecinp
------------------------------------------------------------------------
---- MAIN [Z] ----
------------------------------------------------------------------------
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 "str"
local strtplnam = '' -- name of the source template from args[1]
local strerrequ = '=' -- default or customized string returned on error
local strtymp = ''
local strtext = '' -- huge string from the source template
local strret = '' -- output string
-- general "num"
local numerr = 0 -- fatal error flag
local numearl = 0 -- earliest line from args[2]
local numlast = 0 -- last line from args[3]
local numbegwh = 0 -- ONE-based -- of whole text after stripping
local numlaswh = 0 -- ONE-based -- of whole text after stripping
local numbegse = 0 -- ONE-based -- of selection
local numlasse = 0 -- ONE-based -- of selection
local numlinx = 0 -- line index -- ZERO-based -- counts up
local numokix = 0 -- overall octet index -- ONE-based -- counts up
local numokyx = 0 -- additional octet index -- ONE-based -- counts up
local numoct = 0 -- temp some cool char
local numokt = 0 -- temp some silly char
local numoqt = 0 -- temp some great char
---- 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
---- SEIZE 3 OBLIGATORY ANONYMOUS PARAMETERS ----
while true do -- fake loop
if ((arxsomons[1]==nil) or (arxsomons[2]==nil) or (arxsomons[3]==nil) or (arxsomons[4])) then
numerr = 8 -- #E08 need 3 obligatory params, 4 are not appreciated
break -- to join mark
end--if
strtplnam = arxsomons[1] -- string 5...100 -- args[1]
if (not (lfgstringrange(strtplnam,5,100))) then
numerr = 9 -- #E09 must be 5...100 octet:s
break -- to join mark
end--if
strtymp = arxsomons[2] -- string 1...6 -- args[2]
if (not (lfgstringrange(strtymp,1,6))) then
numerr = 1 -- must be 1...6 octet:s
break -- to join mark
end--if
numearl = lfndecinp (strtymp,true,true)
if ((numearl<0) or (numearl>99999)) then
numerr = 1 -- damn again
break -- to join mark
end--if
strtymp = arxsomons[3] -- string 1...6 -- args[3]
if (not (lfgstringrange(strtymp,1,6))) then
numerr = 1 -- must be 1...6 octet:s
break -- to join mark
end--if
numlast = lfndecinp (strtymp,true,true)
if ((numlast<numearl) or (numlast>99999)) then
numerr = 1 -- damn again
break -- to join mark
end--if
break -- finally to join mark
end--while -- fake loop -- join mark
---- SEIZE ONE OPTIONAL NAMED PARAMETER ----
if (numerr==0) then
vartymp = arxsomons['err']
if (lfgstringrange(vartymp,1,64)) then
strerrequ = vartymp -- 1...64 octet:s
end--if
end--if
---- CHECK WHETHER THE POINTED TEMPLATE EXISTS AT ALL AND EXPAND IT ----
-- do NOT assign "numerr" to non-ZERO but may leave "strtext" empty instead
if (numerr==0) then
strtext = ''
strtymp = arxframent:callParserFunction ('#ifexist:'..strtplnam,'1','0')
if (strtymp=='1') then
vartymp = arxframent:expandTemplate { title = strtplnam }
if ((type(vartymp))=='string') then
strtext = vartymp -- may be empty
end--if
end--if (strtymp=='1') then
end--if
---- STRIP OFF SOME BLANK LINES AND REJECT POSSIBLE EMPTY STUFF ----
-- note that incoming "strtext" may be empty as hell, or become empty
-- or too short only here during stripping
-- we always add an EOL to the text and keep one EOL left at
-- the end after stripping
-- numbegwh, numlaswh -- positions of whole stripped text -- assigned here
-- "+3" check means at least 4 octet:s inclusive
if (numerr==0) then
strtext = strtext .. string.char (10)
numbegwh = 1 -- ONE-based
numlaswh = string.len (strtext) -- ONE-based -- may NOT be 0 due added EOL
while true do -- shrink from both sides
if ((numbegwh+3)>numlaswh) then
numerr = 1 -- damn again -- empty NOT appreciated !!!
break
end--if
numoct = string.byte (strtext,numbegwh,numbegwh)
numokt = string.byte (strtext,(numlaswh-1),(numlaswh-1)) -- keep 1 EOL
if ((numoct~=10) and (numokt~=10)) then
break -- done
end--if
if (numoct==10) then
numbegwh = numbegwh + 1
end--if
if (numokt==10) then
numlaswh = numlaswh - 1
end--if
end--while -- shrink from both sides
end--if
---- CARRY OUT THE HARD SEARCH WORK ----
-- trailing spaces $20 are prohibited
-- trailing UTF8 NBSP-spaces $A0 ($C2,$A0) are prohibited
-- numbegwh, numlaswh -- positions of whole stripped text -- from above
-- numbegse, numlasse -- positions of selection -- assigned here
-- both "numokix" and "numokyx" are ONE-based for "string.byte"
-- "+3" check means at least 4 octet:s inclusive
if (numerr==0) then
numlinx = 0 -- line index -- ZERO-based
numokix = numbegwh -- octet index -- ONE-based -- overall
while true do
if ((numokix+3)>numlaswh) then
numerr = 1 -- damn -- need at least 4 octet:s left
break
end--if
numoct = string.byte (strtext,numokix,numokix) -- "*"
numokt = string.byte (strtext,(numokix+1),(numokix+1)) -- " "
numoqt = string.byte (strtext,(numokix+2),(numokix+2)) -- NOT EOL, " " ,"*"
if ((numoct~=42) or (numokt~=32) or (numoqt==10) or (numoqt==32) or (numoqt==42)) then
numerr = 1 -- damn
break -- outer loop
end--if
numokyx = numokix + 3 -- 3 char:s already done
while true do -- inner loop -- looking for EOL terminating the line
numoct = string.byte (strtext,numokyx,numokyx)
if (numoct==10) then
numokt = string.byte (strtext,(numokyx-1),(numokyx-1)) -- no underfl
if ((numokt==32) or (numokt==160)) then
numerr = 1 -- damn -- trailing whitespace
end--if
break -- inner loop -- good or bad -- found an EOL here
end--if
if ((numokyx-numokix)==400) then
numerr = 1 -- damn -- line too long
break -- inner loop
end--if
numokyx = numokyx + 1
end--while -- inner loop -- looking for EOL terminating the line
if (numerr~=0) then
break -- outer loop -- damn
end--if
if (numlinx==numearl) then
numbegse = numokix -- note that we have "numlasse" if have "numbegse"
end--if
if ((numlinx>=numearl) and (numlinx<=numlast)) then
numlasse = numokyx -- last inclusive, it is always an EOL, repeatedly
end--if
numlinx = numlinx + 1 -- one line checked and counted
if (numokyx==numlaswh) then
break -- outer loop -- this is THE ONLY HAPPY EXIT from the outer loop
end--if
numokix = numokyx + 1 -- jump over the EOL
numoct = string.byte (strtext,numokix,numokix) -- maybe one more EOL
if (numoct==10) then
numokix = numokix + 1 -- jump over the extra EOL, legal blank line
end--if
end--while
if (numbegse~=0) then -- note that we have "numlasse" if have "numbegse"
strtext = string.sub (strtext,numbegse,numlasse) -- perform the cut
else
numerr = 1 -- damn -- final bad luck
end--if
end--if (numerr==0)
---- PREPARE ----
if (numerr~=0) then -- string "strret" was preset to empty
strret = strerrequ -- error
else
strret = strtext -- cool
end--if
---- RETURN THE JUNK STRING ----
return strret
end--function
---- RETURN THE JUNK LUA TABLE ----
return exporttable