MODULO
Memtesto disponeblas sur la dokumentaĵa subpaĝo.
Ĉi tiu modulo estas uzata sur la ĉefpaĝo kaj protektitaVi povas inspekti la protokolon pri protektoj.
Se vi konas la eblajn sekvojn kaj havas sufiĉajn rajtojn, tiam vi povas zorgeme ekredakti.
Se vi ne kuraĝas aŭ ne rajtas redakti tiam vi povas proponi la deziratan ŝanĝon en la diskutejo.



--[===[

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