mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
'v3.8.5.1'
This commit is contained in:
115
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_itm.java
Normal file
115
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_itm.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*; import gplx.xowa.parsers.hdrs.*;
|
||||
import gplx.xowa.wikis.nss.*; import gplx.xowa.wikis.pages.wtxts.*;
|
||||
public class Lst_pfunc_itm {
|
||||
public Lst_pfunc_itm(byte[] itm_src, Lst_section_nde_mgr sec_mgr, Xopg_toc_mgr toc_mgr) {
|
||||
this.itm_src = itm_src; this.sec_mgr = sec_mgr; this.toc_mgr = toc_mgr;
|
||||
}
|
||||
public byte[] Itm_src() {return itm_src;} private final byte[] itm_src;
|
||||
public Lst_section_nde_mgr Sec_mgr() {return sec_mgr;} private final Lst_section_nde_mgr sec_mgr;
|
||||
public Xopg_toc_mgr Toc_mgr() {return toc_mgr;} private final Xopg_toc_mgr toc_mgr;
|
||||
|
||||
public static Lst_pfunc_itm New_sect_or_null(Xop_ctx ctx, byte[] ttl_bry) {
|
||||
// init wiki, ttl
|
||||
Xowe_wiki wiki = ctx.Wiki();
|
||||
Xoa_ttl ttl = wiki.Ttl_parse(ttl_bry); if (ttl == null) return null; // EX:{{#lst:<>}} -> ""
|
||||
|
||||
// get from cache
|
||||
Lst_pfunc_itm rv = (Lst_pfunc_itm)wiki.Cache_mgr().Lst_cache().Get_by_bry(ttl_bry);
|
||||
if (rv == null) { // cache transclusions to prevent multiple parsings; DATE:2014-02-22
|
||||
// get sub_src;
|
||||
Xop_ctx sub_ctx = Xop_ctx.New__top(wiki).Ref_ignore_(true);
|
||||
sub_ctx.Page().Ttl_(ctx.Page().Ttl()); // NOTE: must set ttl on page, else test fails;
|
||||
byte[] sub_src = wiki.Cache_mgr().Page_cache().Get_or_load_as_src(ttl); if (sub_src == null) return null; // {{#lst:missing}} -> ""
|
||||
|
||||
// parse page; note adding to stack to prevent circular recursions
|
||||
if (!wiki.Parser_mgr().Tmpl_stack_add(ttl.Full_db())) return null;
|
||||
Xot_defn_tmpl tmpl = wiki.Parser_mgr().Main().Parse_text_to_defn_obj(sub_ctx, sub_ctx.Tkn_mkr(), ttl.Ns(), ttl_bry, sub_src); // NOTE: parse as tmpl to ignore <noinclude>
|
||||
wiki.Parser_mgr().Tmpl_stack_del(); // take template off stack; evaluate will never recurse, but will fail if ttl is still on stack; DATE:2014-03-10
|
||||
|
||||
// eval tmpl
|
||||
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
|
||||
tmpl.Tmpl_evaluate(sub_ctx, Xot_invk_temp.Page_is_caller, tmp_bfr);
|
||||
sub_src = tmp_bfr.To_bry_and_rls();
|
||||
|
||||
// parse again
|
||||
if (!wiki.Parser_mgr().Tmpl_stack_add(ttl.Full_db())) return null; // put template back on stack;
|
||||
sub_ctx.Page().Wtxt().Toc().Clear(); // HACK: must clear toc hdrs; should probably create a new top sub_ctx; DATE:2016-08-17
|
||||
Xop_root_tkn root = wiki.Parser_mgr().Main().Parse_text_to_wdom(sub_ctx, sub_src, true); // NOTE: pass sub_ctx as old_ctx b/c entire document will be parsed, and references outside the section should be ignored;
|
||||
wiki.Parser_mgr().Tmpl_stack_del();
|
||||
sub_src = root.Data_mid(); // NOTE: must set src to root.Data_mid() which is result of parse; else <nowiki> will break text; DATE:2013-07-11
|
||||
|
||||
// add to cache
|
||||
rv = new Lst_pfunc_itm(sub_src, Clone(sub_ctx.Lst_section_mgr()), Clone(sub_ctx.Page().Wtxt().Toc(), sub_src, ttl_bry));
|
||||
wiki.Cache_mgr().Lst_cache().Add(ttl_bry, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
public static Lst_pfunc_itm New_hdr_or_null(Xop_ctx ctx, byte[] ttl_bry) {
|
||||
// init wiki, ttl
|
||||
Xowe_wiki wiki = ctx.Wiki();
|
||||
Xoa_ttl ttl = wiki.Ttl_parse(ttl_bry); if (ttl == null) return null; // EX:{{#lst:<>}} -> ""
|
||||
|
||||
// get from cache
|
||||
Lst_pfunc_itm rv = (Lst_pfunc_itm)wiki.Cache_mgr().Lst_cache().Get_by_bry(ttl_bry);
|
||||
if (rv == null) { // cache transclusions to prevent multiple parsings; DATE:2014-02-22
|
||||
// get sub_ctx: note new ctx is needed b/c sub_page objects must not get added to owner_page; for example, references / hdrs / lnki.files
|
||||
Xop_ctx sub_ctx = Xop_ctx.New__top(wiki).Ref_ignore_(true);
|
||||
sub_ctx.Page().Ttl_(ctx.Page().Ttl()); // NOTE: must set ttl on page, else test fails;
|
||||
byte[] sub_src = wiki.Cache_mgr().Page_cache().Get_or_load_as_src(ttl); if (sub_src == null) return null; // {{#lst:missing}} -> ""
|
||||
|
||||
// parse sub_src; note adding to page's stack to prevent circular recursions
|
||||
if (!wiki.Parser_mgr().Tmpl_stack_add(ttl.Full_db())) return null;
|
||||
Xop_root_tkn root = wiki.Parser_mgr().Main().Parse_text_to_wdom(sub_ctx, sub_src, true); // NOTE: parse as defn will drop <onlyinclude>; PAGE:en.w:10s_BC; DATE:2016-08-13
|
||||
wiki.Parser_mgr().Tmpl_stack_del();
|
||||
|
||||
// HACK: parse sub_src again b/c transcluded templates will add their hdrs to toc_mgr; PAGE:en.w:Germany_national_football_team DATE:2016-08-13
|
||||
sub_src = root.Data_mid(); // NOTE: must set src to root.Data_mid() which is result of parse; else <nowiki> will break text; DATE:2013-07-11
|
||||
sub_ctx.Page().Wtxt().Toc().Clear(); // HACK: must clear toc hdrs; should probably create a new top sub_ctx; DATE:2016-08-17
|
||||
root = wiki.Parser_mgr().Main().Parse_text_to_wdom(sub_ctx, sub_src, true);
|
||||
sub_src = root.Data_mid(); // NOTE: must call root.Data_mid() again b/c previous src may have nowiki which will get removed in 2nd pass; see TEST:Tmpl_w_nowiki; DATE:2016-08-13
|
||||
|
||||
// add to cache
|
||||
rv = new Lst_pfunc_itm(sub_src, Clone(sub_ctx.Lst_section_mgr()), Clone(sub_ctx.Page().Wtxt().Toc(), sub_src, ttl_bry));
|
||||
wiki.Cache_mgr().Lst_cache().Add(ttl_bry, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Xopg_toc_mgr Clone(Xopg_toc_mgr prime, byte[] src, byte[] ttl_bry) {
|
||||
Xopg_toc_mgr rv = new Xopg_toc_mgr();
|
||||
int len = prime.Len();
|
||||
int src_len = src.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
Xop_hdr_tkn hdr = prime.Get_at(i);
|
||||
if (hdr.Src_bgn() > src_len || hdr.Src_end() > src_len) // DEBUG:handle random cases where hdr is out of bounds of source; PAGE:en.w:Germany_national_football_team DATE:2016-08-13
|
||||
Gfo_usr_dlg_.Instance.Warn_many("", "", "lst:headers are not in bounds of source; ttl=~{0} src=~{1} hdr_bgn=~{2} hdr_end=~{3}", ttl_bry, src_len, hdr.Src_bgn(), hdr.Src_end());
|
||||
rv.Add(hdr);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Lst_section_nde_mgr Clone(Lst_section_nde_mgr src) {
|
||||
Lst_section_nde_mgr rv = new Lst_section_nde_mgr();
|
||||
int len = src.Len();
|
||||
for (int i = 0; i < len; ++i)
|
||||
rv.Add(src.Get_at(i));
|
||||
return rv;
|
||||
}
|
||||
public static final byte[] Null_arg = null;
|
||||
}
|
||||
@@ -23,11 +23,16 @@ public class Lst_pfunc_lst extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_lst;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Lst_pfunc_lst().Name_(name);}
|
||||
@Override public void Func_evaluate(Bry_bfr bfr, Xop_ctx ctx, Xot_invk caller, Xot_invk self, byte[] src) {
|
||||
byte[] src_ttl_bry = Eval_argx(ctx, src, caller, self); if (Bry_.Len_eq_0(src_ttl_bry)) return; // {{#lst:}} -> ""
|
||||
// get args
|
||||
byte[] page_ttl = Eval_argx(ctx, src, caller, self); if (Bry_.Len_eq_0(page_ttl)) return; // {{#lst:}} -> ""
|
||||
int args_len = self.Args_len();
|
||||
byte[] sect_bgn = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 0, Lst_pfunc_wkr.Null_arg);
|
||||
byte[] sect_end = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 1, Lst_pfunc_wkr.Null_arg);
|
||||
new Lst_pfunc_wkr().Init_include(src_ttl_bry, sect_bgn, sect_end).Exec(bfr, ctx);
|
||||
byte[] sect_bgn = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 0, Lst_pfunc_itm.Null_arg);
|
||||
byte[] sect_end = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 1, Lst_pfunc_itm.Null_arg);
|
||||
|
||||
// parse
|
||||
Lst_pfunc_itm itm = Lst_pfunc_itm.New_sect_or_null(ctx, page_ttl); if (itm == null) return;
|
||||
Lst_pfunc_lst_.Sect_include(bfr, itm.Sec_mgr(), itm.Itm_src(), sect_bgn, sect_end);
|
||||
}
|
||||
public static final Lst_pfunc_lst Instance = new Lst_pfunc_lst(); Lst_pfunc_lst() {}
|
||||
|
||||
public static final Lst_pfunc_lst Prime = new Lst_pfunc_lst(); Lst_pfunc_lst() {}
|
||||
}
|
||||
|
||||
72
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lst_.java
Normal file
72
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lst_.java
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
|
||||
public class Lst_pfunc_lst_ {
|
||||
private static final byte Include_between = 0, Include_to_eos = 1, Include_to_bos = 2;
|
||||
public static void Sect_include(Bry_bfr bfr, Lst_section_nde_mgr sec_mgr, byte[] src, byte[] lst_bgn, byte[] lst_end) {
|
||||
if (lst_end == Lst_pfunc_itm.Null_arg) { // no end arg; EX: {{#lst:page|bgn}}; NOTE: different than {{#lst:page|bgn|}}
|
||||
if (lst_bgn == Lst_pfunc_itm.Null_arg) { // no bgn arg; EX: {{#lst:page}}
|
||||
bfr.Add(src); // write all and exit
|
||||
return;
|
||||
}
|
||||
else // bgn exists; set end to bgn; EX: {{#lst:page|bgn}} is same as {{#lst:page|bgn|bgn}}; NOTE: {{#lst:page|bgn|}} means write from bgn to eos
|
||||
lst_end = lst_bgn;
|
||||
}
|
||||
byte include_mode = Include_between;
|
||||
if (Bry_.Len_eq_0(lst_end))
|
||||
include_mode = Include_to_eos;
|
||||
else if (Bry_.Len_eq_0(lst_bgn))
|
||||
include_mode = Include_to_bos;
|
||||
int bgn_pos = 0; boolean bgn_found = false; int src_page_bry_len = src.length;
|
||||
int sections_len = sec_mgr.Len();
|
||||
for (int i = 0; i < sections_len; i++) {
|
||||
Lst_section_nde section = sec_mgr.Get_at(i);
|
||||
byte section_tid = section.Name_tid();
|
||||
byte[] section_key = section.Section_name();
|
||||
if (section_tid == Lst_section_nde.Xatr_bgn && Bry_.Eq(section_key, lst_bgn)) {
|
||||
int sect_bgn_rhs = section.Xnde().Tag_close_end();
|
||||
if (include_mode == Include_to_eos) { // write from cur to eos; EX: {{#lst:page|bgn|}}
|
||||
bfr.Add_mid(src, sect_bgn_rhs, src_page_bry_len);
|
||||
return;
|
||||
}
|
||||
else { // bgn and end
|
||||
if (!bgn_found) { // NOTE: !bgn_found to prevent "resetting" of dupe; EX: <s begin=key0/>a<s begin=key0/>b; should start from a not b
|
||||
bgn_pos = sect_bgn_rhs;
|
||||
bgn_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (section_tid == Lst_section_nde.Xatr_end && Bry_.Eq(section_key, lst_end)) {
|
||||
int sect_end_lhs = section.Xnde().Tag_open_bgn();
|
||||
if (include_mode == Include_to_bos) { // write from bos to cur; EX: {{#lst:page||end}}
|
||||
bfr.Add_mid(src, 0, sect_end_lhs);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (bgn_found) { // NOTE: bgn_found to prevent writing from bos; EX: a<s end=key0/>b should not write anything
|
||||
bfr.Add_mid(src, bgn_pos, sect_end_lhs);
|
||||
bgn_found = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bgn_found) // bgn_found, but no end; write to end of page; EX: "a <section begin=key/> b" -> " b"
|
||||
bfr.Add_mid(src, bgn_pos, src_page_bry_len);
|
||||
}
|
||||
}
|
||||
37
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lsth.java
Normal file
37
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lsth.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.langs.*; import gplx.xowa.langs.kwds.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
|
||||
import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Lst_pfunc_lsth extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_lsth;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Lst_pfunc_lsth().Name_(name);}
|
||||
@Override public void Func_evaluate(Bry_bfr bfr, Xop_ctx ctx, Xot_invk caller, Xot_invk self, byte[] src) {
|
||||
// get args
|
||||
byte[] page_ttl = Eval_argx(ctx, src, caller, self); if (Bry_.Len_eq_0(page_ttl)) return; // {{#lsth:}} -> ""
|
||||
int args_len = self.Args_len();
|
||||
byte[] hdr_bgn = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 0, Lst_pfunc_itm.Null_arg);
|
||||
byte[] hdr_end = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 1, Lst_pfunc_itm.Null_arg);
|
||||
|
||||
// parse
|
||||
Lst_pfunc_itm itm = Lst_pfunc_itm.New_hdr_or_null(ctx, page_ttl); if (itm == null) return;
|
||||
Lst_pfunc_lsth_.Hdr_include(bfr, itm.Itm_src(), itm.Toc_mgr(), hdr_bgn, hdr_end);
|
||||
}
|
||||
public static final Lst_pfunc_lsth Prime = new Lst_pfunc_lsth(); Lst_pfunc_lsth() {}
|
||||
}
|
||||
73
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lsth_.java
Normal file
73
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lsth_.java
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.wikis.pages.wtxts.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.hdrs.*;
|
||||
class Lst_pfunc_lsth_ {
|
||||
public static void Hdr_include(Bry_bfr bfr, byte[] src, Xopg_toc_mgr toc_mgr, byte[] lhs_hdr, byte[] rhs_hdr) {// REF.MW:LabeledSectionTransclusion.class.php|pfuncIncludeHeading; MW does regex on text; XO uses section_itms
|
||||
// get <hdr> idxs
|
||||
int len = toc_mgr.Len();
|
||||
int lhs_idx = Match_or_neg1(toc_mgr, len, src, lhs_hdr, 0) ; if (lhs_idx == -1) return;
|
||||
int rhs_idx = Match_or_neg1(toc_mgr, len, src, rhs_hdr, lhs_idx + 1);
|
||||
|
||||
// get snip_bgn
|
||||
Xop_hdr_tkn lhs_tkn = toc_mgr.Get_at(lhs_idx);
|
||||
int snip_bgn = lhs_tkn.Src_end();
|
||||
|
||||
// get snip_end
|
||||
int snip_end = -1;
|
||||
if (rhs_idx == -1) { // rhs_idx missing or not supplied
|
||||
rhs_idx = lhs_idx + 1;
|
||||
if (rhs_idx < len) { // next hdr after lhs_hdr exists; try to get next "matching" hdr; EX: h2 should match next h2; PAGE:en.w:10s_BC; DATE:2016-08-13
|
||||
for (int i = rhs_idx; i < len; ++i) {
|
||||
Xop_hdr_tkn rhs_tkn = toc_mgr.Get_at(i);
|
||||
if (rhs_tkn.Num() == lhs_tkn.Num()) {
|
||||
snip_end = rhs_tkn.Src_bgn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (snip_end == -1) // no matching rhs exists, or rhs is last; get till EOS
|
||||
snip_end = src.length;
|
||||
}
|
||||
else {
|
||||
Xop_hdr_tkn rhs_tkn = toc_mgr.Get_at(rhs_idx);
|
||||
snip_end = rhs_tkn.Src_bgn();
|
||||
}
|
||||
bfr.Add_mid(src, snip_bgn, snip_end);
|
||||
}
|
||||
private static int Match_or_neg1(Xopg_toc_mgr toc_mgr, int hdrs_len, byte[] src, byte[] match, int hdrs_bgn) {
|
||||
for (int i = hdrs_bgn; i < hdrs_len; ++i) {
|
||||
Xop_hdr_tkn hdr = toc_mgr.Get_at(i);
|
||||
int txt_bgn = hdr.Src_bgn() + hdr.Num(); // skip "\n=="; 1=leading \n
|
||||
if (hdr.Src_bgn() != Xop_parser_.Doc_bgn_char_0)
|
||||
++txt_bgn;
|
||||
|
||||
// get txt_end; note that this needs to handle multiple trailing \n which is included in hdr.Src_end()
|
||||
int txt_end = Bry_find_.Find_fwd(src, Bry__hdr_end, txt_bgn); // find "=\n"
|
||||
txt_end = Bry_find_.Find_bwd__skip(src, txt_end, txt_bgn, Byte_ascii.Eq); // skip bwd to get to pos before 1st "="; EX: "===\n" -> find "=="
|
||||
|
||||
// remove ws
|
||||
txt_bgn = Bry_find_.Find_fwd_while_ws(src, txt_bgn, txt_end);
|
||||
txt_end = Bry_find_.Find_bwd__skip_ws(src, txt_end, txt_bgn);
|
||||
if (Bry_.Eq(src, txt_bgn, txt_end, match)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
private static final byte[] Bry__hdr_end = Bry_.new_a7("=\n");
|
||||
}
|
||||
132
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lsth_tst.java
Normal file
132
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lsth_tst.java
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import org.junit.*;
|
||||
public class Lst_pfunc_lsth_tst {
|
||||
private final Lst_pfunc_lst_fxt fxt = new Lst_pfunc_lst_fxt();
|
||||
private final String src_str_dflt = String_.Concat_lines_nl_skip_last
|
||||
( "txt_0"
|
||||
, "== hdr_1 =="
|
||||
, "txt_1"
|
||||
, "== hdr_2 =="
|
||||
, "txt_2"
|
||||
, "== hdr_3 =="
|
||||
, "txt_3"
|
||||
);
|
||||
@Before public void init() {fxt.Clear();}
|
||||
@Test public void Bgn__missing() { // PURPOSE: return ""
|
||||
fxt.Page_txt_(src_str_dflt).Test_lst("{{#lsth:section_test|hdr_x}}", "");
|
||||
}
|
||||
@Test public void End__exists() {
|
||||
fxt.Page_txt_(src_str_dflt).Test_lst("{{#lsth:section_test|hdr_1|hdr_3}}", String_.Concat_lines_nl_skip_last
|
||||
( "txt_1"
|
||||
, ""
|
||||
, "<h2> hdr_2 </h2>"
|
||||
, "txt_2"
|
||||
));
|
||||
}
|
||||
@Test public void End__missing() { // PURPOSE: read to end of next section
|
||||
String expd = String_.Concat_lines_nl_skip_last
|
||||
( "txt_1"
|
||||
);
|
||||
fxt.Clear().Page_txt_(src_str_dflt).Test_lst("{{#lsth:section_test|hdr_1}}" , expd); // argument not given
|
||||
fxt.Clear().Page_txt_(src_str_dflt).Test_lst("{{#lsth:section_test|hdr_1|hdr_x}}", expd); // argument is wrong
|
||||
}
|
||||
@Test public void End__missing_eos() { // PURPOSE: read to EOS if last
|
||||
String expd = String_.Concat_lines_nl_skip_last
|
||||
( "txt_3"
|
||||
);
|
||||
fxt.Clear().Page_txt_(src_str_dflt).Test_lst("{{#lsth:section_test|hdr_3}}" , expd); // argument not given
|
||||
fxt.Clear().Page_txt_(src_str_dflt).Test_lst("{{#lsth:section_test|hdr_3|hdr_x}}", expd); // argument is wrong
|
||||
}
|
||||
@Test public void End__missing__match__len() { // PURPOSE:match next hdr with same length; PAGE:en.w:10s_BC; DATE:2016-08-13
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "txt_0"
|
||||
, "== hdr_1 =="
|
||||
, "txt_1"
|
||||
, "=== hdr_1a ==="
|
||||
, "txt_1a"
|
||||
, "== hdr_2 =="
|
||||
, "txt_2"
|
||||
);
|
||||
fxt.Page_txt_(src_str).Test_lst("{{#lsth::section_test|hdr_1}}", String_.Concat_lines_nl_skip_last
|
||||
( "txt_1"
|
||||
, ""
|
||||
, "<h3> hdr_1a </h3>"
|
||||
, "txt_1a"
|
||||
));
|
||||
}
|
||||
@Test public void Extra_nl() { // PURPOSE: hdr.Src_end() includes trailing nl; PAGE:en.w:10s_BC; DATE:2016-08-13
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "txt_0"
|
||||
, "== hdr_1 =="
|
||||
, ""
|
||||
, "txt_1"
|
||||
, "== hdr_2 =="
|
||||
, "txt_2"
|
||||
);
|
||||
fxt.Clear().Page_txt_(src_str).Test_lst("{{#lsth:section_test|hdr_1}}" , "txt_1");
|
||||
}
|
||||
@Test public void Only_include() { // PAGE:en.w:10s_BC; DATE:2016-08-13
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "txt_0"
|
||||
, "== hdr_1 =="
|
||||
, "<onlyinclude>txt_1</onlyinclude>"
|
||||
, "== hdr_2 =="
|
||||
, "txt_2"
|
||||
, "== hdr_3 =="
|
||||
, "txt_3"
|
||||
);
|
||||
fxt.Page_txt_(src_str).Test_lst("{{#lsth::section_test|hdr_1}}", "txt_1");
|
||||
}
|
||||
@Test public void Bos() { // PURPOSE.defensive:handle == at BOS; DATE:2016-08-13
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "==hdr_1 =="
|
||||
, "txt_1"
|
||||
, "== hdr_2 =="
|
||||
, "txt_2"
|
||||
);
|
||||
fxt.Clear().Page_txt_(src_str).Test_lst("{{#lsth:section_test|hdr_1}}", "txt_1");
|
||||
}
|
||||
@Test public void Nested__lst() { // PURPOSE:lst inside lsth will add its toc_mgr to lsth; PAGE:en.w:Germany_national_football_team; DATE:2016-08-13
|
||||
fxt.Fxt().Init_page_create("Nested_lst", String_.Concat_lines_nl_skip_last
|
||||
( "test"
|
||||
, "==hdr_1=="
|
||||
, "txt_1"
|
||||
));
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "{{#lst:Nested_lst}}"
|
||||
, "==hdr_2=="
|
||||
, "txt_2"
|
||||
, "==hdr_3=="
|
||||
, "txt_3"
|
||||
);
|
||||
fxt.Page_txt_(src_str).Test_lst("{{#lsth::section_test|hdr_1}}", "txt_1"); // will fail with idx_out_of_bounds b/c hdr_1.Src_bgn / hdr_1.Src_end will be for Nested_lst's src
|
||||
}
|
||||
@Test public void Tmpl_w_nowiki() { // ISSUE:nowiki inside template can cause wrong offsets; PAGE:en.w:Germany_national_football_team; DATE:2016-08-13
|
||||
fxt.Fxt().Init_page_create("Template:Nested_nowiki", "<nowiki>test</nowiki>");
|
||||
String src_str = String_.Concat_lines_nl_skip_last
|
||||
( "{{Nested_nowiki}}"
|
||||
, "==hdr_2=="
|
||||
, "txt_2"
|
||||
, "==hdr_3=="
|
||||
, "txt_3"
|
||||
);
|
||||
fxt.Page_txt_(src_str).Test_lst("{{#lsth::section_test|hdr_2}}", "txt_2"); // will fail with "" b/c <nowiki> requires a 2nd "sub_src = root.Data_mid()"
|
||||
}
|
||||
}
|
||||
@@ -23,11 +23,14 @@ public class Lst_pfunc_lstx extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_lstx;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Lst_pfunc_lstx().Name_(name);}
|
||||
@Override public void Func_evaluate(Bry_bfr bfr, Xop_ctx ctx, Xot_invk caller, Xot_invk self, byte[] src) {
|
||||
byte[] src_ttl_bry = Eval_argx(ctx, src, caller, self); if (Bry_.Len_eq_0(src_ttl_bry)) return; // {{#lst:}} -> ""
|
||||
byte[] page_ttl = Eval_argx(ctx, src, caller, self); if (Bry_.Len_eq_0(page_ttl)) return; // {{#lst:}} -> ""
|
||||
int args_len = self.Args_len();
|
||||
byte[] sect_exclude = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 0, Lst_pfunc_wkr.Null_arg);
|
||||
byte[] sect_replace = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 1, Lst_pfunc_wkr.Null_arg);
|
||||
new Lst_pfunc_wkr().Init_exclude(src_ttl_bry, sect_exclude, sect_replace).Exec(bfr, ctx);
|
||||
byte[] sect_exclude = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 0, Lst_pfunc_itm.Null_arg);
|
||||
byte[] sect_replace = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 1, Lst_pfunc_itm.Null_arg);
|
||||
|
||||
// parse
|
||||
Lst_pfunc_itm itm = Lst_pfunc_itm.New_sect_or_null(ctx, page_ttl); if (itm == null) return;
|
||||
Lst_pfunc_lstx_.Sect_exclude(bfr, itm.Sec_mgr(), itm.Itm_src(), sect_exclude, sect_replace);
|
||||
}
|
||||
public static final Lst_pfunc_lstx Instance = new Lst_pfunc_lstx(); Lst_pfunc_lstx() {}
|
||||
public static final Lst_pfunc_lstx Prime = new Lst_pfunc_lstx(); Lst_pfunc_lstx() {}
|
||||
}
|
||||
|
||||
44
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lstx_.java
Normal file
44
400_xowa/src/gplx/xowa/xtns/lst/Lst_pfunc_lstx_.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.parsers.*;
|
||||
class Lst_pfunc_lstx_ {
|
||||
public static void Sect_exclude(Bry_bfr bfr, Lst_section_nde_mgr sec_mgr, byte[] src, byte[] sect_exclude, byte[] sect_replace) {
|
||||
if (Bry_.Len_eq_0(sect_exclude)) { // no exclude arg; EX: {{#lstx:page}} or {{#lstx:page}}
|
||||
bfr.Add(src); // write all and exit
|
||||
return;
|
||||
}
|
||||
int sections_len = sec_mgr.Len();
|
||||
int bgn_pos = 0;
|
||||
for (int i = 0; i < sections_len; i++) {
|
||||
Lst_section_nde section = sec_mgr.Get_at(i);
|
||||
byte section_tid = section.Name_tid();
|
||||
byte[] section_key = section.Section_name();
|
||||
if (section_tid == Lst_section_nde.Xatr_bgn && Bry_.Eq(section_key, sect_exclude)) { // exclude section found
|
||||
bfr.Add_mid(src, bgn_pos, section.Xnde().Tag_open_bgn()); // write everything from bgn_pos up to exclude
|
||||
}
|
||||
else if (section_tid == Lst_section_nde.Xatr_end && Bry_.Eq(section_key, sect_exclude)) { // exclude end found
|
||||
if (sect_replace != null)
|
||||
bfr.Add(sect_replace); // write replacement
|
||||
bgn_pos = section.Xnde().Tag_close_end(); // reset bgn_pos
|
||||
}
|
||||
}
|
||||
bfr.Add_mid(src, bgn_pos, src.length);
|
||||
}
|
||||
public static final byte[] Null_arg = null;
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.wikis.nss.*;
|
||||
import gplx.xowa.parsers.*; import gplx.xowa.parsers.tmpls.*;
|
||||
public class Lst_pfunc_wkr {
|
||||
private boolean mode_include = true;
|
||||
private byte[] src_ttl_bry;
|
||||
private byte[] sect_bgn, sect_end;
|
||||
private byte[] sect_exclude, sect_replace;
|
||||
public Lst_pfunc_wkr Init_include(byte[] src_ttl_bry, byte[] sect_bgn, byte[] sect_end) {
|
||||
this.mode_include = Bool_.Y; this.src_ttl_bry = src_ttl_bry; this.sect_bgn = sect_bgn; this.sect_end = sect_end; return this;
|
||||
}
|
||||
public Lst_pfunc_wkr Init_exclude(byte[] src_ttl_bry, byte[] sect_exclude, byte[] sect_replace) {
|
||||
this.mode_include = Bool_.N; this.src_ttl_bry = src_ttl_bry; this.sect_exclude = sect_exclude; this.sect_replace = sect_replace; return this;
|
||||
}
|
||||
|
||||
public void Exec(Bry_bfr bfr, Xop_ctx ctx) {
|
||||
Xowe_wiki wiki = ctx.Wiki();
|
||||
Xoa_ttl src_ttl = Xoa_ttl.Parse(wiki, src_ttl_bry); if (src_ttl == null) return; // {{#lst:<>}} -> ""
|
||||
Xot_defn_tmpl defn_tmpl = (Xot_defn_tmpl)wiki.Cache_mgr().Lst_cache().Get_by_key(src_ttl_bry);
|
||||
Xop_ctx sub_ctx = null;
|
||||
byte[] src = null;
|
||||
if (defn_tmpl == null) { // cache transclusions to prevent multiple parsings; DATE:2014-02-22
|
||||
sub_ctx = Xop_ctx.New__sub__reuse_page(ctx).Ref_ignore_(true);
|
||||
byte[] src_page_bry = wiki.Cache_mgr().Page_cache().Get_or_load_as_src(src_ttl);
|
||||
if (src_page_bry == null) return; // {{#lst:missing}} -> ""
|
||||
Xoae_page page = ctx.Page();
|
||||
if (!page.Tmpl_stack_add(src_ttl.Full_db())) return;
|
||||
defn_tmpl = wiki.Parser_mgr().Main().Parse_text_to_defn_obj(sub_ctx, sub_ctx.Tkn_mkr(), src_ttl.Ns(), src_ttl_bry, src_page_bry); // NOTE: parse as tmpl to ignore <noinclude>
|
||||
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_m001();
|
||||
page.Tmpl_stack_del(); // take template off stack; evaluate will never recurse, and will fail if ttl is still on stack; DATE:2014-03-10
|
||||
defn_tmpl.Tmpl_evaluate(sub_ctx, Xot_invk_temp.Page_is_caller, tmp_bfr);
|
||||
src = tmp_bfr.To_bry_and_rls();
|
||||
if (!page.Tmpl_stack_add(src_ttl.Full_db())) return; // put template back on stack;
|
||||
Xop_root_tkn root = wiki.Parser_mgr().Main().Parse_text_to_wdom(sub_ctx, src, true); // NOTE: pass sub_ctx as old_ctx b/c entire document will be parsed, and references outside the section should be ignored;
|
||||
src = root.Data_mid(); // NOTE: must set src to root.Data_mid() which is result of parse; else <nowiki> will break text; DATE:2013-07-11
|
||||
wiki.Cache_mgr().Lst_cache().Add(defn_tmpl, Xow_ns_case_.Tid__all);
|
||||
page.Tmpl_stack_del();
|
||||
defn_tmpl.Data_mid_(src);
|
||||
defn_tmpl.Ctx_(sub_ctx);
|
||||
}
|
||||
else {
|
||||
src = defn_tmpl.Data_mid();
|
||||
sub_ctx = defn_tmpl.Ctx();
|
||||
}
|
||||
if (mode_include) Write_include(bfr, sub_ctx, src, sect_bgn, sect_end);
|
||||
else Write_exclude(bfr, sub_ctx, src, sect_exclude, sect_replace);
|
||||
}
|
||||
private static final byte Include_between = 0, Include_to_eos = 1, Include_to_bos = 2;
|
||||
private static void Write_include(Bry_bfr bfr, Xop_ctx sub_ctx, byte[] src, byte[] lst_bgn, byte[] lst_end) {
|
||||
if (lst_end == Null_arg) { // no end arg; EX: {{#lst:page|bgn}}; NOTE: different than {{#lst:page|bgn|}}
|
||||
if (lst_bgn == Null_arg) { // no bgn arg; EX: {{#lst:page}}
|
||||
bfr.Add(src); // write all and exit
|
||||
return;
|
||||
}
|
||||
else // bgn exists; set end to bgn; EX: {{#lst:page|bgn}} is same as {{#lst:page|bgn|bgn}}; NOTE: {{#lst:page|bgn|}} means write from bgn to eos
|
||||
lst_end = lst_bgn;
|
||||
}
|
||||
byte include_mode = Include_between;
|
||||
if (Bry_.Len_eq_0(lst_end))
|
||||
include_mode = Include_to_eos;
|
||||
else if (Bry_.Len_eq_0(lst_bgn))
|
||||
include_mode = Include_to_bos;
|
||||
int bgn_pos = 0; boolean bgn_found = false; int src_page_bry_len = src.length;
|
||||
Lst_section_nde_mgr section_mgr = sub_ctx.Lst_section_mgr(); // get section_mgr from Parse
|
||||
int sections_len = section_mgr.Count();
|
||||
for (int i = 0; i < sections_len; i++) {
|
||||
Lst_section_nde section = section_mgr.Get_at(i);
|
||||
byte section_tid = section.Name_tid();
|
||||
byte[] section_key = section.Section_name();
|
||||
if (section_tid == Lst_section_nde.Xatr_bgn && Bry_.Eq(section_key, lst_bgn)) {
|
||||
int sect_bgn_rhs = section.Xnde().Tag_close_end();
|
||||
if (include_mode == Include_to_eos) { // write from cur to eos; EX: {{#lst:page|bgn|}}
|
||||
bfr.Add_mid(src, sect_bgn_rhs, src_page_bry_len);
|
||||
return;
|
||||
}
|
||||
else { // bgn and end
|
||||
if (!bgn_found) { // NOTE: !bgn_found to prevent "resetting" of dupe; EX: <s begin=key0/>a<s begin=key0/>b; should start from a not b
|
||||
bgn_pos = sect_bgn_rhs;
|
||||
bgn_found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (section_tid == Lst_section_nde.Xatr_end && Bry_.Eq(section_key, lst_end)) {
|
||||
int sect_end_lhs = section.Xnde().Tag_open_bgn();
|
||||
if (include_mode == Include_to_bos) { // write from bos to cur; EX: {{#lst:page||end}}
|
||||
bfr.Add_mid(src, 0, sect_end_lhs);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (bgn_found) { // NOTE: bgn_found to prevent writing from bos; EX: a<s end=key0/>b should not write anything
|
||||
bfr.Add_mid(src, bgn_pos, sect_end_lhs);
|
||||
bgn_found = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bgn_found) // bgn_found, but no end; write to end of page; EX: "a <section begin=key/> b" -> " b"
|
||||
bfr.Add_mid(src, bgn_pos, src_page_bry_len);
|
||||
}
|
||||
private static void Write_exclude(Bry_bfr bfr, Xop_ctx sub_ctx, byte[] src, byte[] sect_exclude, byte[] sect_replace) {
|
||||
if (Bry_.Len_eq_0(sect_exclude)) { // no exclude arg; EX: {{#lstx:page}} or {{#lstx:page}}
|
||||
bfr.Add(src); // write all and exit
|
||||
return;
|
||||
}
|
||||
Lst_section_nde_mgr section_mgr = sub_ctx.Lst_section_mgr(); // get section_mgr from Parse
|
||||
int sections_len = section_mgr.Count();
|
||||
int bgn_pos = 0;
|
||||
for (int i = 0; i < sections_len; i++) {
|
||||
Lst_section_nde section = section_mgr.Get_at(i);
|
||||
byte section_tid = section.Name_tid();
|
||||
byte[] section_key = section.Section_name();
|
||||
if (section_tid == Lst_section_nde.Xatr_bgn && Bry_.Eq(section_key, sect_exclude)) { // exclude section found
|
||||
bfr.Add_mid(src, bgn_pos, section.Xnde().Tag_open_bgn()); // write everything from bgn_pos up to exclude
|
||||
}
|
||||
else if (section_tid == Lst_section_nde.Xatr_end && Bry_.Eq(section_key, sect_exclude)) { // exclude end found
|
||||
if (sect_replace != null)
|
||||
bfr.Add(sect_replace); // write replacement
|
||||
bgn_pos = section.Xnde().Tag_close_end(); // reset bgn_pos
|
||||
}
|
||||
}
|
||||
bfr.Add_mid(src, bgn_pos, src.length);
|
||||
}
|
||||
public static final byte[] Null_arg = null;
|
||||
}
|
||||
@@ -17,7 +17,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.lst; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public class Lst_section_nde_mgr {
|
||||
public int Count() {return list.Count();} private List_adp list = List_adp_.New();
|
||||
private final List_adp list = List_adp_.New();
|
||||
public int Len() {return list.Count();}
|
||||
public Lst_section_nde Get_at(int i) {return (Lst_section_nde)list.Get_at(i);}
|
||||
public void Add(Lst_section_nde xnde) {list.Add(xnde);}
|
||||
public void Clear() {list.Clear();}
|
||||
|
||||
Reference in New Issue
Block a user