1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00
This commit is contained in:
gnosygnu
2014-07-06 22:58:35 -04:00
parent 57f65b4d0c
commit ecbe2918d8
187 changed files with 4184 additions and 2286 deletions

View File

@@ -440,7 +440,7 @@ public class Xoa_ttl { // EX.WP: http://en.wikipedia.org/wiki/Help:Link; REF.MW:
int full_txt_len = full_txt.length;
if (page_end > full_txt_len) // ttl is too too short for 1st multi-byte char; EX: [[%D0]] is 208 but in utf8, 208 requires at least another char; DATE:2013-11-11
return false; // ttl is invalid
else { // ttl is long enough for 1st mult-byte char; need to use platform uppercasing; Xol_case_itm_.Universal is not sufficient
else { // ttl is long enough for 1st mult-byte char; need to use platform uppercasing; Xol_case_mgr_.Utf_8 is not sufficient
Bry_bfr upper_1st = wiki.Utl_bry_bfr_mkr().Get_b512();
byte[] page_txt = wiki.Lang().Case_mgr().Case_build_1st_upper(upper_1st, full_txt, page_bgn, full_txt_len); // always build; never reuse; (multi-byte character will expand array)
if (page_bgn == 0) // page only; EX: A

View File

@@ -19,7 +19,7 @@ package gplx.xowa; import gplx.*;
import gplx.xowa.gui.*; import gplx.xowa.xtns.lst.*;
import gplx.xowa.xtns.scribunto.*;
import gplx.xowa.xtns.wdatas.*;
import gplx.xowa.parsers.apos.*; import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*; import gplx.xowa.parsers.logs.*;
import gplx.xowa.parsers.apos.*; import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*; import gplx.xowa.parsers.logs.*; import gplx.xowa.html.modules.popups.keeplists.*;
public class Xop_ctx {
private Xop_ctx_wkr[] wkrs = new Xop_ctx_wkr[] {};
Xop_ctx(Xow_wiki wiki, Xoa_page page) {
@@ -49,6 +49,7 @@ public class Xop_ctx {
public boolean Tmpl_load_enabled() {return tmpl_load_enabled;} public void Tmpl_load_enabled_(boolean v) {tmpl_load_enabled = v;} private boolean tmpl_load_enabled = true;
public int Tmpl_tkn_max() {return tmpl_tkn_max;} public void Tmpl_tkn_max_(int v) {tmpl_tkn_max = v;} private int tmpl_tkn_max = Int_.MaxValue;
public Xop_keeplist_wiki Tmpl_keeplist() {return tmpl_keeplist;} public void Tmpl_keeplist_(Xop_keeplist_wiki v) {this.tmpl_keeplist = v;} private Xop_keeplist_wiki tmpl_keeplist;
public boolean Tmpl_args_parsing() {return tmpl_args_parsing;} public Xop_ctx Tmpl_args_parsing_(boolean v) {tmpl_args_parsing = v; return this;} private boolean tmpl_args_parsing;
public Bry_bfr Tmpl_output() {return tmpl_output;} public Xop_ctx Tmpl_output_(Bry_bfr v) {tmpl_output = v; return this;} private Bry_bfr tmpl_output;
public Xot_defn_trace Defn_trace() {return defn_trace;} public Xop_ctx Defn_trace_(Xot_defn_trace v) {defn_trace = v; return this;} private Xot_defn_trace defn_trace = Xot_defn_trace_null._;
@@ -83,7 +84,7 @@ public class Xop_ctx {
for (Xop_ctx_wkr wkr : wkrs) wkr.Page_bgn(this, root);
}
public void Page_end(Xop_root_tkn root, byte[] src, int src_len) {
Stack_pop_til(root, src, 0, true, src_len, src_len);
Stack_pop_til(root, src, 0, true, src_len, src_len, Xop_tkn_itm_.Tid_txt);
for (Xop_ctx_wkr wkr : wkrs) wkr.Page_end(this, root, src, src_len);
}
public boolean Lxr_make() {return lxr_make;} public Xop_ctx Lxr_make_(boolean v) {lxr_make = v; return this;} private boolean lxr_make = false;
@@ -230,35 +231,35 @@ public class Xop_ctx {
}
}
}
public Xop_tkn_itm Stack_pop_til(Xop_root_tkn root, byte[] src, int til_idx, boolean include, int bgn_pos, int cur_pos) {
public Xop_tkn_itm Stack_pop_til(Xop_root_tkn root, byte[] src, int til_idx, boolean include, int bgn_pos, int cur_pos, int closing_tkn_tid) {
if (stack_len == 0) return null;
int min_idx = include ? til_idx - 1 : til_idx;
if (min_idx < -1) min_idx = -1;
Xop_tkn_itm rv = null;
for (int i = stack_len - 1; i > min_idx; i--) {
rv = stack[i];
Stack_autoClose(root, src, rv, bgn_pos, cur_pos);
Stack_autoClose(root, src, rv, bgn_pos, cur_pos, closing_tkn_tid);
}
Stack_pop_idx(til_idx);
return include ? rv : stack[stack_len]; // if include, return poppedTkn; if not, return tkn before poppedTkn
}
public Xop_tkn_itm Stack_pop_before(Xop_root_tkn root, byte[] src, int til_idx, boolean include, int bgn_pos, int cur_pos) { // used by Xop_tblw_lxr to detect \n| in lnki; seems useful as well
public Xop_tkn_itm Stack_pop_before(Xop_root_tkn root, byte[] src, int til_idx, boolean include, int bgn_pos, int cur_pos, int closing_tkn_tid) { // used by Xop_tblw_lxr to detect \n| in lnki; seems useful as well
if (stack_len == 0) return null;
int min_idx = include ? til_idx - 1 : til_idx;
if (min_idx < -1) min_idx = -1;
Xop_tkn_itm rv = null;
for (int i = stack_len - 1; i > min_idx; i--) {
rv = stack[i];
Stack_autoClose(root, src, rv, bgn_pos, cur_pos);
Stack_autoClose(root, src, rv, bgn_pos, cur_pos, closing_tkn_tid);
}
return include ? rv : stack[stack_len]; // if include, return poppedTkn; if not, return tkn before poppedTkn
}
public void Stack_autoClose(Xop_root_tkn root, byte[] src, Xop_tkn_itm tkn, int bgn_pos, int cur_pos) {
public void Stack_autoClose(Xop_root_tkn root, byte[] src, Xop_tkn_itm tkn, int bgn_pos, int cur_pos, int closing_tkn_tid) {
int src_len = src.length;
switch (tkn.Tkn_tid()) {
case Xop_tkn_itm_.Tid_newLine: break; // NOOP: just a marker
case Xop_tkn_itm_.Tid_list: list.AutoClose(this, app.Tkn_mkr(), root, src, src_len, bgn_pos, cur_pos, tkn); break;
case Xop_tkn_itm_.Tid_xnde: xnde.AutoClose(this, root, src, src_len, bgn_pos, cur_pos, tkn); break;
case Xop_tkn_itm_.Tid_xnde: xnde.AutoClose(this, root, src, src_len, bgn_pos, cur_pos, tkn, closing_tkn_tid); break;
case Xop_tkn_itm_.Tid_apos: apos.AutoClose(this, src, src_len, bgn_pos, cur_pos, tkn); break;
case Xop_tkn_itm_.Tid_lnke: lnke.AutoClose(this, src, src_len, bgn_pos, cur_pos, tkn); break;
case Xop_tkn_itm_.Tid_hdr: hdr.AutoClose(this, app.Tkn_mkr(), root, src, src_len, bgn_pos, cur_pos, tkn); break;
@@ -291,7 +292,7 @@ public class Xop_ctx {
if (stop) break;
}
if (stack_pos == -1) return;
ctx.Stack_pop_til(root, src, stack_pos, true, bgn_pos, cur_pos);
ctx.Stack_pop_til(root, src, stack_pos, true, bgn_pos, cur_pos, Xop_tkn_itm_.Tid_txt);
}
public void Tmpl_prepend_nl(Bry_bfr cur, byte[] val, int val_len) { // cur=current bfr; tmpl_output=main bfr that cur will eventually be appended to; val=result of template
if ( val_len == 0 // val is empty

View File

@@ -57,8 +57,9 @@ public class Xop_fxt {
ctx.Clear();
ctx.App().Free_mem(false);
ctx.Cur_page().Clear();
ctx.Wiki().Db_mgr().Load_mgr().Clear();
ctx.App().Wiki_mgr().Clear();
wiki.Db_mgr().Load_mgr().Clear();
app.Wiki_mgr().Clear();
Io_mgr._.InitEngine_mem(); // clear created pages
return this;
}
public Xop_fxt Reset_for_msgs() {
@@ -373,4 +374,11 @@ public class Xop_fxt {
separator_mgr.Set(gplx.xowa.langs.numbers.Xol_num_mgr.Separators_key__dec, Bry_.new_utf8_(dec_spr));
return this;
}
public void Init_lang_kwds(int kwd_id, boolean case_match, String... kwds) {Init_lang_kwds(wiki.Lang(), kwd_id, case_match, kwds);}
public void Init_lang_kwds(Xol_lang lang, int kwd_id, boolean case_match, String... kwds) {
Xol_kwd_mgr kwd_mgr = lang.Kwd_mgr();
Xol_kwd_grp kwd_grp = kwd_mgr.Get_or_new(kwd_id);
kwd_grp.Srl_load(case_match, Bry_.Ary(kwds));
}
public void Clear_ref_mgr() {this.Page().Ref_mgr().Grps_clear();} // clear to reset count
}

View File

@@ -18,49 +18,40 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package gplx.xowa; import gplx.*;
import gplx.xowa.html.*;
public class Xop_redirect_mgr {
public Xop_redirect_mgr(Xow_wiki wiki) {this.wiki = wiki; this.log_mgr = wiki.App().Msg_log();} private Xow_wiki wiki; Gfo_msg_log log_mgr; ByteTrieMgr_slim trie;
private Hash_adp_bry redirect_hash;
public Xop_redirect_mgr(Xow_wiki wiki) {this.wiki = wiki;} private Xow_wiki wiki;
public void Clear() {redirect_hash = null;} // TEST:
public boolean Is_redirect(byte[] text, int text_len) {return this.Extract_redirect(text, text_len) != null;}
public Xoa_ttl Extract_redirect_loop(byte[] src) {
Xoa_ttl rv = null;
for (int i = 0; i < Extract_redirect_loop_max; i++) {
for (int i = 0; i < Redirect_max_allowed; i++) {
rv = Extract_redirect(src, src.length);
if (rv != null) return rv;
}
return null;
}
public Xoa_ttl Extract_redirect(byte[] src) {return Extract_redirect(src, src.length);}
public static final Xoa_ttl Extract_redirect_is_null = null;
public static final int Extract_redirect_loop_max = 4;
public Xoa_ttl Extract_redirect(byte[] src, int src_len) {
public Xoa_ttl Extract_redirect(byte[] src, int src_len) { // NOTE: this proc is called by every page. be careful of changes; DATE:2014-07-05
if (src_len == 0) return Redirect_null_ttl;
int bgn = Bry_finder.Find_fwd_while_not_ws(src, 0, src_len);
if (bgn == src_len) return Redirect_null_ttl; // article is entirely whitespace
if (trie == null) trie = Xol_kwd_mgr.trie_(wiki.Lang().Kwd_mgr(), Xol_kwd_grp_.Id_redirect);
if (trie.MatchAtCur(src, bgn, src_len) == null) return Redirect_null_ttl;
int cur_pos = trie.Match_pos();
if (cur_pos == src_len) {log_mgr.Add_itm_none(Xop_redirect_log.Lnki_not_found, src, 0, cur_pos); return Redirect_null_ttl;} // occurs when just #REDIRECT
switch (src[cur_pos]) { // REF.MW: Ttl.php|newFromRedirectInternal; see regx
case Byte_ascii.NewLine:
case Byte_ascii.Space:
case Byte_ascii.Tab:
case Byte_ascii.Brack_bgn:
case Byte_ascii.Colon:
break;
default:
log_mgr.Add_itm_none(Xop_redirect_log.False_match, src, 0, cur_pos);
return Redirect_null_ttl;
}
int bgn_pos = Bry_finder.Find_fwd(src, Xop_tkn_.Lnki_bgn, cur_pos);
if (bgn_pos == Bry_.NotFound) {log_mgr.Add_itm_none(Xop_redirect_log.Lnki_not_found, src, 0, cur_pos); return Redirect_null_ttl;}
bgn_pos += Xop_tkn_.Lnki_bgn.length;
int end_pos = Bry_finder.Find_fwd(src, Xop_tkn_.Lnki_end, bgn_pos);
if (end_pos == Bry_.NotFound) {log_mgr.Add_itm_none(Xop_redirect_log.Lnki_not_found, src, 0, cur_pos); return Redirect_null_ttl;}
byte[] redirect_ary = Bry_.Mid(src, bgn_pos, end_pos);
int kwd_end = Xop_redirect_mgr_.Get_kwd_end_or_end(src, bgn, src_len);
if (kwd_end == src_len) return Redirect_null_ttl;
if (redirect_hash == null) redirect_hash = Xol_kwd_mgr.hash_(wiki.Lang().Kwd_mgr(), Xol_kwd_grp_.Id_redirect);
Object redirect_itm = redirect_hash.Get_by_mid(src, bgn, kwd_end);
if (redirect_itm == null) return Redirect_null_ttl; // not a redirect kwd
int ttl_bgn = Xop_redirect_mgr_.Get_ttl_bgn_or_neg1(src, kwd_end, src_len);
if (ttl_bgn == Bry_.NotFound) return Redirect_null_ttl;
ttl_bgn += Xop_tkn_.Lnki_bgn.length;
int ttl_end = Bry_finder.Find_fwd(src, Xop_tkn_.Lnki_end, ttl_bgn);
if (ttl_end == Bry_.NotFound) return Redirect_null_ttl;
byte[] redirect_ary = Bry_.Mid(src, ttl_bgn, ttl_end);
return Xoa_ttl.parse_(wiki, redirect_ary);
}
public static final Xoa_ttl Extract_redirect_is_null = null;
public static final int Redirect_max_allowed = 4;
public static final Xoa_ttl Redirect_null_ttl = null;
public static final byte[] Redirect_null_bry = Bry_.Empty;
public static final int Redirect_max_allowed = 4;
private static final byte[] Redirect_bry = Bry_.new_ascii_("#REDIRECT ");
public static byte[] Make_redirect_text(byte[] redirect_to_ttl) {
return Bry_.Add
@@ -96,3 +87,38 @@ public class Xop_redirect_mgr {
return fmt_bfr.XtoAryAndClear();
} private static byte[] Bry_redirect_dlm = Bry_.new_ascii_(" <--- "), Bry_redirect_arg = Bry_.new_ascii_("?redirect=no");
}
class Xop_redirect_mgr_ {
public static int Get_kwd_end_or_end(byte[] src, int bgn, int end) { // get end of kwd
for (int i = bgn; i < end; ++i) {
switch (src[i]) {
case Byte_ascii.NewLine: case Byte_ascii.Space: case Byte_ascii.Tab:
case Byte_ascii.Brack_bgn: case Byte_ascii.Colon:
return i; // ASSUME: kwd does not have these chars
default:
break;
}
}
return end;
}
public static int Get_ttl_bgn_or_neg1(byte[] src, int bgn, int end) { // get bgn of ttl
boolean colon_null = true;
for (int i = bgn; i < end; ++i) {
switch (src[i]) {
case Byte_ascii.NewLine: case Byte_ascii.Space: case Byte_ascii.Tab: break; // skip all ws
case Byte_ascii.Colon: // allow 1 colon
if (colon_null)
colon_null = false;
else
return Bry_.NotFound;
break;
default:
break;
case Byte_ascii.Brack_bgn:
int nxt_pos = i + 1;
if (nxt_pos >= end) return Bry_.NotFound; // [ at eos
return src[nxt_pos] == Byte_ascii.Brack_bgn ? i : Bry_.NotFound;
}
}
return Bry_.NotFound;
}
}

View File

@@ -17,34 +17,39 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa; import gplx.*;
import org.junit.*;
public class Xop_redirect_mgr_tst {
private Xop_fxt fxt = new Xop_fxt();
@Test public void Basic() {tst_Redirect("#REDIRECT [[a]]", "A");}
@Test public void Basic_colon() {tst_Redirect("#REDIRECT:[[a]]", "A");}
@Test public void Ns_help() {tst_Redirect("#REDIRECT [[Help:a]]", "Help:A");}
@Test public void First() {tst_Redirect("#REDIRECT [[a]] [[b]]", "A");}
@Test public void Exc_false_match() {tst_Redirect("#REDIRECTA [[a]]", Xop_redirect_log.False_match);}
@Test public void Exc_lnki_not_found() {tst_Redirect("#REDIRECT test", Xop_redirect_log.Lnki_not_found);}
@Test public void Ws() {tst_Redirect("\n#REDIRECT [[a]]", "A");} // EX.WP:Germany; {{Template group}} -> \n#REDIRECT [[Template:Navboxes]]
private void tst_Redirect(String src_str, Object expd) {
Xop_redirect_mgr redirect_mgr = new Xop_redirect_mgr(fxt.Ctx().Wiki());
fxt.Log_clear();
byte[] src = Bry_.new_utf8_(src_str);
Xoa_ttl actl_ttl = redirect_mgr.Extract_redirect(src, src.length);
byte[] actl = actl_ttl == null ? Bry_.Empty : actl_ttl.Full_txt();
String expd_str = String_.as_(expd);
if (actl == Bry_.Empty) {
if (expd_str != null) throw Err_.new_("result is null; expecting " + expd);
Gfo_msg_itm itm = (Gfo_msg_itm)expd;
String[] actl_ary = fxt.Log_xtoAry();
Tfds.Eq_ary_str(new String[] {String_.new_utf8_(itm.Owner().Path()) + "." + String_.new_utf8_(itm.Key_bry())}, actl_ary);
return;
}
if (expd_str == null) {
Gfo_msg_itm expd_hdr = (Gfo_msg_itm)expd;
throw Err_.new_("result is valued; expecting error " + expd_hdr.Path_str());
}
Tfds.Eq(expd_str, String_.new_utf8_(actl));
public class Xop_redirect_mgr_tst {
@Before public void init() {fxt.Clear();} private Xop_redirect_mgr_fxt fxt = new Xop_redirect_mgr_fxt();
@Test public void Basic() {fxt.Test_redirect("#REDIRECT [[a]]", "A");}
@Test public void Basic_colon() {fxt.Test_redirect("#REDIRECT:[[a]]", "A");}
@Test public void Ns_help() {fxt.Test_redirect("#REDIRECT [[Help:a]]", "Help:A");}
@Test public void First() {fxt.Test_redirect("#REDIRECT [[a]] [[b]]", "A");}
@Test public void Exc_false_match() {fxt.Test_redirect("#REDIRECTA [[a]]", "");}
@Test public void Exc_lnki_not_found() {fxt.Test_redirect("#REDIRECT test", "");}
@Test public void Ws() {fxt.Test_redirect("\n#REDIRECT [[a]]", "A");} // EX.WP:Germany; {{Template group}} -> \n#REDIRECT [[Template:Navboxes]]
@Test public void Utf8() {
fxt.Init_utf8();
fxt.Init_kwds(Bool_.N, "#REDIRECT", "#перенаправление");
fxt.Test_redirect("#REDIRECT [[A]]", "A");
fxt.Test_redirect("#reDirect [[A]]", "A");
fxt.Test_redirect("#перенаправление [[A]]", "A");
fxt.Test_redirect("#ПЕРЕНАПРАВЛЕНИЕ [[A]]", "A");
}
}
class Xop_redirect_mgr_fxt {
private Xop_fxt fxt = new Xop_fxt();
public void Clear() {
fxt.Reset();
}
public void Init_kwds(boolean case_match, String... kwds) {fxt.Init_lang_kwds(Xol_kwd_grp_.Id_redirect, case_match, kwds);}
public void Init_utf8() {
fxt.Wiki().Lang().Case_mgr_utf8_();
}
public void Test_redirect(String raw_str, String expd_str) {
Xop_redirect_mgr redirect_mgr = fxt.Ctx().Wiki().Redirect_mgr();
redirect_mgr.Clear();
byte[] raw_bry = Bry_.new_utf8_(raw_str);
Xoa_ttl actl_ttl = redirect_mgr.Extract_redirect(raw_bry, raw_bry.length);
byte[] actl_bry = actl_ttl == null ? Bry_.Empty : actl_ttl.Full_txt();
Tfds.Eq(expd_str, String_.new_utf8_(actl_bry));
}
}