mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
v1.6.5.1
This commit is contained in:
56
400_xowa/src_530_pf_str/gplx/xowa/Pf_i18n_tst.java
Normal file
56
400_xowa/src_530_pf_str/gplx/xowa/Pf_i18n_tst.java
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_i18n_tst {
|
||||
@Before public void init() {fxt.Clear();} private Pf_i18n_fxt fxt = new Pf_i18n_fxt();
|
||||
@Test public void Casing() {fxt.lang_("de").Ini().Reg_func("fullurl", false, "VOLLSTÄNDIGE_URL").Load().Fxt().Test_parse_tmpl_str_test("{{vollstÄndige_url:a}}", "{{test}}" , "//de.wikipedia.org/wiki/A");}
|
||||
@Test public void Time() {fxt.lang_("de").Ini().Reg_msg("march", "März").Load().Fxt().Test_parse_tmpl_str_test("{{#time: d F Y|1 Mar 2013}}", "{{test}}" , "01 März 2013");}
|
||||
}
|
||||
class Pf_i18n_fxt {
|
||||
public void Clear() {}
|
||||
public Xop_fxt Fxt() {return fxt;}
|
||||
public Pf_i18n_fxt lang_(String v) {lang_key = v; return this;} private String lang_key;
|
||||
public Pf_i18n_fxt Ini() {
|
||||
if (app == null) app = Xoa_app_fxt.app_();
|
||||
app.Lang_mgr().Clear(); // else lang values retained from last run
|
||||
app.Free_mem(false); // else tmpl_result_cache will get reused from last run for {{test}}
|
||||
lang = app.Lang_mgr().Get_by_key_or_new(Bry_.new_ascii_(lang_key));
|
||||
wiki = Xoa_app_fxt.wiki_(app, lang_key + ".wikipedia.org", lang);
|
||||
fxt = new Xop_fxt(app, wiki);
|
||||
return this;
|
||||
} private Xoa_app app; private Xop_fxt fxt; Xol_lang lang; Xow_wiki wiki;
|
||||
public Pf_i18n_fxt Reg_func(String name, boolean case_match, String word) {
|
||||
Io_url url = Io_url_.mem_fil_("mem/xowa/user/test_user/lang/xowa/" + lang_key + ".gfs");
|
||||
String func = "keywords.load_text('" + name + "|" + (case_match ? "1" : "0") + "|" + name + "~" + word + "~');";
|
||||
Io_mgr._.SaveFilStr(url, func);
|
||||
return this;
|
||||
}
|
||||
public Pf_i18n_fxt Reg_msg(String key, String val) {
|
||||
Io_url url = Io_url_.mem_fil_("mem/xowa/user/test_user/lang/xowa/" + lang_key + ".gfs");
|
||||
String func = "messages.load_text('" + key + "|" + val + "');";
|
||||
Io_mgr._.SaveFilStr(url, func);
|
||||
return this;
|
||||
}
|
||||
public Pf_i18n_fxt Load() {
|
||||
lang.Init_by_load();
|
||||
wiki.Fragment_mgr().Evt_lang_changed(lang);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
31
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_grammar.java
Normal file
31
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_grammar.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
class Pf_intl_grammar extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_i18n_grammar;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_intl_grammar().Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
byte[] argx = Eval_argx(ctx, src, caller, self);
|
||||
byte[] word = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self.Args_len(), 0);
|
||||
Xol_lang lang = ctx.Cur_page().Lang();
|
||||
boolean pass = false;
|
||||
try {pass = lang.Grammar().Grammar_eval(bfr, lang, word, argx);}
|
||||
catch (Exception e) {Err_.Noop(e);}
|
||||
if (!pass) Xot_invk_tkn.Print_not_found(bfr, ctx.Wiki().Ns_mgr(), this.Name());
|
||||
}
|
||||
}
|
||||
57
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_grammar_tst.java
Normal file
57
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_grammar_tst.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_intl_grammar_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void English() {// for now, mark unimplemented langs by returning not_found; [[Template:grammar]]; wait for users to report
|
||||
fxt.Test_parse_tmpl_str_test("{{grammar:a|b}}" , "{{test}}" , "[[:Template:grammar]]");
|
||||
}
|
||||
@Test public void Finnish() {
|
||||
fxt.Lang_by_id_(Xol_lang_itm_.Id_fi);
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:elative|Wikiuutiset}}" , "{{test}}" , "Wikiuutisista");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:talo}}" , "{{test}}" , "");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|talo}}" , "{{test}}" , "talon");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:elative|talo}}" , "{{test}}" , "talosta");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:inessive|talo}}" , "{{test}}" , "talossa");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:partitive|talo}}" , "{{test}}" , "taloa");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:illative|talo}}" , "{{test}}" , "taloon");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|sängy}}" , "{{test}}" , "sängyn");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:elative|sängy}}" , "{{test}}" , "sängystä");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:inessive|sängy}}" , "{{test}}" , "sängyssä");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:partitive|sängy}}" , "{{test}}" , "sängyä");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:illative|sängy}}" , "{{test}}" , "sängyyn");
|
||||
}
|
||||
@Test public void Russian() {
|
||||
fxt.Lang_by_id_(Xol_lang_itm_.Id_ru);
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:unknown}}" , "{{test}}" , "");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aвики}}" , "{{test}}" , "aвики");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aВики}}" , "{{test}}" , "aВики");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aь}}" , "{{test}}" , "aя");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aия}}" , "{{test}}" , "aии");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aка}}" , "{{test}}" , "aки");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aти}}" , "{{test}}" , "aтей");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aды}}" , "{{test}}" , "aдов");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:genitive|aник}}" , "{{test}}" , "aника");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:dative|a}}" , "{{test}}" , "a");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:accusative|a}}" , "{{test}}" , "a");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:instrumental|a}}" , "{{test}}" , "a");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{grammar:prepositional|a}}" , "{{test}}" , "a");
|
||||
}
|
||||
}
|
||||
38
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_int.java
Normal file
38
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_int.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import gplx.php.*;
|
||||
class Pf_intl_int extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_i18n_int;}
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
byte[] msg_key = Eval_argx(ctx, src, caller, self);
|
||||
Xow_wiki wiki = ctx.Wiki();
|
||||
Xol_lang page_lang = ctx.Cur_page().Lang();
|
||||
byte[][] args_ary = Bry_.Ary_empty;
|
||||
int args_len = self.Args_len();
|
||||
if (args_len > 0) {
|
||||
args_ary = new byte[args_len][];
|
||||
for (int i = 0; i < args_len; i++)
|
||||
args_ary[i] = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self.Args_len(), i);
|
||||
}
|
||||
byte[] msg_val = Pf_msg_mgr.Get_msg_val(wiki, page_lang, msg_key, args_ary);
|
||||
bfr.Add(msg_val);
|
||||
}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_intl_int().Name_(name);}
|
||||
}
|
||||
112
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_int_tst.java
Normal file
112
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_int_tst.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_intl_int_tst {
|
||||
@Before public void init() {fxt.Reset();} private Pf_msg_mgr_fxt fxt = new Pf_msg_mgr_fxt();
|
||||
@Test public void Basic() {fxt.Test_parse_en("{{int:january}}" , "January");}
|
||||
@Test public void Upper() {fxt.Test_parse_en("{{int:JANUARY}}" , "January");}
|
||||
@Test public void Unknown() {fxt.Test_parse_en("{{int:unknown_msg}}" , "<unknown_msg>");}
|
||||
@Test public void Fmt() {fxt.Test_parse_en("{{int:pfunc_expr_unrecognised_word|1a}}" , "Expression error: Unrecognised word \"1a\"");}
|
||||
@Test public void Tmpl_txt() {
|
||||
fxt.Init_msg_gfs("tst_msg", "{{#expr:1}}", false, true);
|
||||
fxt.Test_parse_en("{{int:tst_msg}}", "1");
|
||||
}
|
||||
@Test public void Lang_current_defaults_to_en() { // PURPOSE: specifying same language as current returns same; ie: int:january/en -> int:january
|
||||
fxt.Test_parse_en("{{int:january/en}}", "January");
|
||||
}
|
||||
@Test public void Lang_specified_by_page() {
|
||||
fxt.Test_parse_lang("fr", "{{int:Lang}}", "fr"); // NOTE: "Lang" msg is added by Xol_lang; message_mgr.Itm_by_key_or_new(Bry_.new_utf8_("Lang")).Atrs_set(key_bry, false, false);
|
||||
}
|
||||
@Test public void Lang_missing_msg_return_en() { // PURPOSE: if key does not exist in non-english language, use English; EX: la.w:Fasciculus:HannibalFrescoCapitolinec1510.jpg; DATE:2013-09-10
|
||||
fxt.Init_msg_gfs("en_only_key", "en_only_val", false, false);
|
||||
fxt.Test_parse_lang("fr", "{{int:en_only_key}}", "en_only_val");
|
||||
}
|
||||
@Test public void Err_fmt_failed() { // PURPOSE: if no args passed to msg, return "$1", not "~{0}"
|
||||
fxt.Init_msg_gfs("tst_msg", "a~{0}b", true, false);
|
||||
fxt.Test_parse_en("{{int:tst_msg}}" , "a$1b");
|
||||
}
|
||||
@Test public void Mediawiki_overrides_gfs() {
|
||||
fxt.Init_msg_gfs("mw_overrides", "gfs", false, false);
|
||||
fxt.Init_msg_db("mw_overrides", "mw");
|
||||
fxt.Test_parse_en("{{int:mw_overrides}}", "mw");
|
||||
}
|
||||
@Test public void Convert_php() {
|
||||
fxt.Init_msg_db("convert_php", "a\\\\b\\$c$1e");
|
||||
fxt.Test_parse_en("{{int:convert_php|d}}", "a\\b$cde");
|
||||
}
|
||||
@Test public void Convert_php_tilde() { // PURPOSE: tildes should be escaped, else will fail inside ByteAryBfrFmtr; DATE:2013-11-11
|
||||
fxt.Init_msg_db("convert_php_tilde", "$1~u");
|
||||
fxt.Test_parse_en("{{int:convert_php_tilde|a}}", "a~u");
|
||||
}
|
||||
@Test public void Unknown_val_returns_en() { // PURPOSE: if no "january" in "fr.gfs" and no "january/fr" in mw, use january in "en.gfs"; EX:none
|
||||
fxt.Test_parse_lang("fr", "{{int:january/fr}}", "January");
|
||||
}
|
||||
@Test public void Unknown_lang_returns_en() { // PURPOSE: unknown lang default to english; EX:none; DATE:2014-05-09
|
||||
fxt.Test_parse_en("{{int:january/unknown}}", "January");
|
||||
}
|
||||
@Test public void Transclude_mw_do_not_strip_lang() { // PURPOSE: if /lang matches wiki.lang, do not strip it, else stack overflow; EX:pl.d:Wikislownik:Bar/Archiwum_6; newarticletext/pl; DATE:2014-05-13
|
||||
fxt.Init_msg_db("january/en", "January_en");
|
||||
fxt.Test_parse_en("{{MediaWiki:january/en}}", "January_en");
|
||||
}
|
||||
@Test public void Transclude_gfs() { // PURPOSE: transclusion of {{MediaWiki}} pages should call {{int}} instead; EX:zh.w:Main_Page; DATE:2014-05-09
|
||||
fxt.Test_parse_en("{{MediaWiki:january/en}}", "January"); // NOTE: no page exists called "MediaWiki:january/en", but returns "{{int:january/en}}" value
|
||||
}
|
||||
@Test public void Create_msg_in_wiki_not_lang() { // PURPOSE: if two wikis share same language and msg is missing from one, do not mark it missing in the other; EX: home/wiki/Main_Page and en.w:Main_Page; DATE:2014-05-13
|
||||
Xow_wiki enwiktionary = fxt.Make_wiki("en.wiktionary.org");
|
||||
fxt.Init_msg_db(enwiktionary, "wiki_only_msg", "enwiktionary_msg");
|
||||
fxt.Init_msg_gfs("wiki_only_msg", "en_gfs_msg", false, false);
|
||||
fxt.Test_parse_en("{{int:wiki_only_msg}}", "en_gfs_msg");
|
||||
fxt.Test_parse_wiki(enwiktionary, "{{int:wiki_only_msg}}", "enwiktionary_msg");
|
||||
}
|
||||
}
|
||||
class Pf_msg_mgr_fxt {
|
||||
private Xop_fxt fxt;
|
||||
private Xol_lang en_lang;
|
||||
private Xow_wiki en_wiki;
|
||||
public void Reset() {
|
||||
fxt = new Xop_fxt(); // new fxt, else transclude tests will fail
|
||||
en_wiki = fxt.Wiki();
|
||||
en_lang = en_wiki.Lang();
|
||||
}
|
||||
public void Init_msg_gfs(String key, String val, boolean fmt, boolean tmpl) {Init_msg_gfs(en_lang, key, val, fmt, tmpl);}
|
||||
public void Init_msg_gfs(Xol_lang lang, String key, String val, boolean fmt, boolean tmpl) {
|
||||
Xol_msg_itm msg_itm = lang.Msg_mgr().Itm_by_key_or_new(Bry_.new_utf8_(key));
|
||||
msg_itm.Atrs_set(Bry_.new_utf8_(val), fmt, tmpl);
|
||||
}
|
||||
public void Init_msg_db(String ttl, String val) {Init_msg_db(en_wiki, ttl, val);}
|
||||
public void Init_msg_db(Xow_wiki wiki, String ttl, String val) {
|
||||
fxt.Init_page_create(wiki, "MediaWiki:" + ttl, val);
|
||||
}
|
||||
public Xow_wiki Make_wiki(String domain) {return fxt.App().Wiki_mgr().Get_by_key_or_make(Bry_.new_utf8_(domain));}
|
||||
public void Test_parse_en(String raw, String expd) {
|
||||
fxt.Test_parse_tmpl_str_test(raw, "{{test}}" , expd);
|
||||
}
|
||||
public void Test_parse_wiki(Xow_wiki alt_wiki, String raw, String expd) {
|
||||
Xop_fxt alt_fxt = new Xop_fxt(fxt.App(), alt_wiki);
|
||||
alt_fxt.Test_parse_tmpl_str_test(raw, "{{test}}" , expd);
|
||||
}
|
||||
public void Test_parse_lang(String other_lang_id, String raw, String expd) {
|
||||
Xol_lang other_lang = fxt.App().Lang_mgr().Get_by_key_or_new(Bry_.new_ascii_(other_lang_id));
|
||||
other_lang.Init_by_load();
|
||||
fxt.Page().Lang_(other_lang);
|
||||
fxt.Test_parse_tmpl_str_test(raw, "{{test}}", expd);
|
||||
fxt.Page().Lang_(en_lang); // NOTE: must reset back to en_lang, else rest of tests will look up under fr
|
||||
}
|
||||
}
|
||||
|
||||
34
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_language.java
Normal file
34
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_language.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
class Pf_intl_language extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_i18n_language;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_intl_language().Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
byte[] argx = Eval_argx(ctx, src, caller, self);
|
||||
Hash_adp_bry regy = Xol_lang_itm_.Regy();
|
||||
if (argx.length == 0) return; // {{#language:}} should return ""; note that byte[0] will fail in MatchAtCurExact
|
||||
Object o = regy.Get_by_bry(argx);
|
||||
if (o == null)
|
||||
bfr.Add(argx);
|
||||
else {
|
||||
Xol_lang_itm lang_itm = (Xol_lang_itm)o;
|
||||
bfr.Add(lang_itm.Canonical_name());
|
||||
}
|
||||
}
|
||||
}
|
||||
30
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_language_tst.java
Normal file
30
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_language_tst.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_intl_language_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void English() {fxt.Test_parse_tmpl_str_test("{{#language:en}}" , "{{test}}" , "English");}
|
||||
@Test public void English_case() {fxt.Test_parse_tmpl_str_test("{{#language:eN}}" , "{{test}}" , "English");}
|
||||
@Test public void Arabic() {fxt.Test_parse_tmpl_str_test("{{#language:ar}}" , "{{test}}" , "العربية");}
|
||||
@Test public void Unknown() {fxt.Test_parse_tmpl_str_test("{{#language:unknown}}" , "{{test}}" , "unknown");}
|
||||
@Test public void Foreign() {fxt.Test_parse_tmpl_str_test("{{#language:anp}}" , "{{test}}" , "अङ्गिका");}
|
||||
@Test public void Foreign_2() {fxt.Test_parse_tmpl_str_test("{{#language:no}}" , "{{test}}" , "Norsk (bokmål)");} // PURPOSE: Names.php have bookend "pipes" (\xE2\x80\xAA)
|
||||
@Test public void Empty() {fxt.Test_parse_tmpl_str_test("{{#language:}}" , "{{test}}" , "");}
|
||||
}
|
||||
31
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_plural.java
Normal file
31
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_plural.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
class Pf_intl_plural extends Pf_func_base {
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {// REF.MW: CoreParserFunctions.php
|
||||
byte[] number = Eval_argx(ctx, src, caller, self);
|
||||
int self_args_len = self.Args_len();
|
||||
int arg_idx = Pf_func_.Eq_(number, Ary_Num_1) ? 0 : 1;
|
||||
if (arg_idx == 1 && self_args_len == 1) arg_idx = 0; // number is plural, but plural_arg not present; use singular; see test
|
||||
byte[] word = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, arg_idx);
|
||||
bfr.Add(word);
|
||||
} static final byte[] Ary_Num_1 = new byte[] {Byte_ascii.Num_1};
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_i18n_plural;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_intl_plural().Name_(name);}
|
||||
}
|
||||
27
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_plural_tst.java
Normal file
27
400_xowa/src_530_pf_str/gplx/xowa/Pf_intl_plural_tst.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_intl_plural_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Singular() {fxt.Test_parse_tmpl_str_test("{{plural:1|wiki|wikis}}" , "{{test}}" , "wiki");}
|
||||
@Test public void Plural() {fxt.Test_parse_tmpl_str_test("{{plural:2|wiki|wikis}}" , "{{test}}" , "wikis");}
|
||||
@Test public void Plural_but_one_arg() {fxt.Test_parse_tmpl_str_test("{{plural:2|wiki}}" , "{{test}}" , "wiki");}
|
||||
@Test public void Null() {fxt.Test_parse_tmpl_str_test("{{plural:|wiki|wikis}}" , "{{test}}" , "wikis");}
|
||||
}
|
||||
134
400_xowa/src_530_pf_str/gplx/xowa/Pf_msg_mgr.java
Normal file
134
400_xowa/src_530_pf_str/gplx/xowa/Pf_msg_mgr.java
Normal file
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import gplx.php.*; import gplx.xowa.langs.*;
|
||||
public class Pf_msg_mgr {
|
||||
// public static String Get_msg_val_gui_or_null(Xol_lang lang, byte[] pre, byte[] key, byte[] suf) {
|
||||
// String rv = Get_msg_val_gui_or_null(lang, pre, key, suf);
|
||||
// return rv == null ? "<" + String_.new_utf8_(Bry_.Add(pre, key, suf)) + ">" : rv;
|
||||
// }
|
||||
public static String Get_msg_val_gui_or_empty(Xol_lang lang, byte[] pre, byte[] key, byte[] suf) { // get from lang, else get from en; does not use get_msg_val to skip db lookups; should only be used for gui; DATE:2014-05-28
|
||||
String rv = Get_msg_val_gui_or_null(lang, pre, key, suf);
|
||||
return rv == null ? "" : rv;
|
||||
}
|
||||
public static String Get_msg_val_gui_or(Xol_lang lang, byte[] pre, byte[] key, byte[] suf, String or) {
|
||||
String rv = Get_msg_val_gui_or_null(lang, pre, key, suf);
|
||||
return rv == null ? or : rv;
|
||||
}
|
||||
public static String Get_msg_val_gui_or_null(Xol_lang lang, byte[] pre, byte[] key, byte[] suf) { // get from lang, else get from en; does not use get_msg_val to skip db lookups; should only be used for gui; DATE:2014-05-28
|
||||
byte[] msg_key = Bry_.Add(pre, key, suf);
|
||||
Xol_msg_itm msg_itm = lang.Msg_mgr().Itm_by_key_or_null(msg_key);
|
||||
if (msg_itm == null)
|
||||
msg_itm = lang.App().Lang_mgr().Lang_en().Msg_mgr().Itm_by_key_or_null(msg_key);
|
||||
return msg_itm == null ? null : String_.new_utf8_(msg_itm.Val());
|
||||
}
|
||||
public static byte[] Get_msg_val(Xow_wiki wiki, Xol_lang lang, byte[] msg_key, byte[][] fmt_args) {
|
||||
Bry_bfr tmp_bfr = wiki.Utl_bry_bfr_mkr().Get_b512();
|
||||
Xol_msg_itm msg_itm = Get_msg_itm(tmp_bfr, wiki, lang, msg_key);
|
||||
byte[] rv = Get_msg_val(tmp_bfr, wiki, msg_itm, fmt_args);
|
||||
tmp_bfr.Mkr_rls();
|
||||
return rv;
|
||||
} private static final byte[] Missing_bry = Bry_.new_ascii_("$"), Slash_bry = new byte[] {Byte_ascii.Slash};
|
||||
public static byte[] Get_msg_val(Bry_bfr tmp_bfr, Xow_wiki wiki, Xol_msg_itm msg_itm, byte[][] fmt_args) {
|
||||
byte[] msg_val = msg_itm.Val();
|
||||
boolean has_fmt = msg_itm.Has_fmt_arg(), has_tmpl = msg_itm.Has_tmpl_txt();
|
||||
if (!has_fmt && !has_tmpl) // no fmt or tmpl; just add val
|
||||
return msg_val;
|
||||
if (has_fmt) { // fmt exists; fmt first (before tmpl text); EX: Expression error: Unrecognised word "~{0}"
|
||||
Bry_fmtr tmp_fmtr = Bry_fmtr.tmp_().Missing_bgn_(Missing_bry).Missing_end_(Bry_.Empty).Missing_adj_(1);
|
||||
tmp_fmtr.Fmt_(msg_val);
|
||||
tmp_fmtr.Bld_bfr(tmp_bfr, fmt_args);
|
||||
msg_val = tmp_bfr.XtoAryAndClear();
|
||||
}
|
||||
if (has_tmpl) {
|
||||
Xop_ctx sub_ctx = Xop_ctx.new_sub_(wiki); Xop_tkn_mkr tkn_mkr = sub_ctx.Tkn_mkr();
|
||||
Xop_root_tkn sub_root = tkn_mkr.Root(msg_val);
|
||||
msg_val = wiki.Parser().Parse_text_to_wtxt(sub_root, sub_ctx, tkn_mkr, msg_val);
|
||||
}
|
||||
return msg_val;
|
||||
}
|
||||
public static Xol_msg_itm Get_msg_itm(Bry_bfr tmp_bfr, Xow_wiki wiki, Xol_lang lang, byte[] msg_key) {
|
||||
byte[] msg_key_sub_root = msg_key;
|
||||
int slash_pos = Bry_finder.Find_bwd(msg_key, Byte_ascii.Slash);
|
||||
if (slash_pos != Bry_.NotFound) { // key is of format "key/lang"; EX: "January/en"
|
||||
int msg_key_len = msg_key.length;
|
||||
if (slash_pos != msg_key_len) { // get text after slash; EX: "en"
|
||||
Object o = Xol_lang_itm_.Regy().Get_by_mid(msg_key, slash_pos + 1, msg_key_len);
|
||||
if (o != null) { // text is known lang_code;
|
||||
Xol_lang_itm lang_itm = (Xol_lang_itm)o;
|
||||
lang = wiki.App().Lang_mgr().Get_by_key_or_new(lang_itm.Key()); // set lang
|
||||
}
|
||||
msg_key_sub_root = Bry_.Mid(msg_key, 0, slash_pos); // set msg to "a" (discarding "/b")
|
||||
}
|
||||
}
|
||||
Xol_msg_itm msg_in_wiki = wiki.Msg_mgr().Get_or_null(msg_key); // check wiki; used to be check lang, but Search_mediawiki should never be toggled on lang; DATE:2014-05-13
|
||||
if (msg_in_wiki != null) return msg_in_wiki; // NOTE: all new msgs will Search_mediawiki once; EX: de.w:{{int:Autosumm-replace}}; DATE:2013-01-25
|
||||
msg_in_wiki = wiki.Msg_mgr().Get_or_make(msg_key);
|
||||
Xoa_page msg_page = Get_msg_itm_from_db(wiki, lang, msg_key, msg_key_sub_root);
|
||||
byte[] msg_val = Bry_.Empty;
|
||||
if (msg_page.Missing()) { // [[MediaWiki:key/fallback]] still not found; search "lang.gfs";
|
||||
Xol_msg_itm msg_in_lang = Get_msg_itm_from_gfs(wiki, lang, msg_key_sub_root);
|
||||
if (msg_in_lang == null) {
|
||||
msg_val = tmp_bfr.Add_byte(Byte_ascii.Lt).Add(msg_key).Add_byte(Byte_ascii.Gt).XtoAryAndClear(); // set val to <msg_key>
|
||||
msg_in_wiki.Src_(Xol_msg_itm.Src_missing);
|
||||
}
|
||||
else {
|
||||
msg_val = msg_in_lang.Val();
|
||||
msg_in_wiki.Src_(Xol_msg_itm.Src_lang);
|
||||
}
|
||||
}
|
||||
else { // page found; dump entire contents
|
||||
msg_val = gplx.xowa.apps.Xoa_gfs_php_mgr.Xto_gfs(tmp_bfr, msg_page.Data_raw()); // note that MediaWiki msg's use php arg format ($1); xowa.gfs msgs are already converted
|
||||
msg_in_wiki.Src_(Xol_msg_itm.Src_wiki);
|
||||
}
|
||||
Xol_msg_itm_.update_val_(msg_in_wiki, msg_val);
|
||||
return msg_in_wiki;
|
||||
}
|
||||
private static Xoa_page Get_msg_itm_from_db(Xow_wiki wiki, Xol_lang lang, byte[] msg_key, byte[] msg_key_sub_root) {
|
||||
byte[] ns_bry = wiki.Ns_mgr().Ns_mediawiki().Name_db_w_colon();
|
||||
Xoa_ttl ttl = Xoa_ttl.parse_(wiki, Bry_.Add(ns_bry, msg_key)); // ttl="MediaWiki:msg_key"; note that there may be "/lang"; EX:pl.d:Wikislownik:Bar/Archiwum_6 and newarticletext/pl
|
||||
Xoa_page rv = ttl == null ? Xoa_page.Empty : wiki.Data_mgr().Get_page_from_msg(ttl);
|
||||
if (rv.Missing()) { // [[MediaWiki:key]] not found; search for [[MediaWiki:key/fallback]]
|
||||
byte[][] fallback_ary = lang.Fallback_bry_ary();
|
||||
int fallback_ary_len = fallback_ary.length;
|
||||
for (int i = 0; i < fallback_ary_len; i++) {
|
||||
byte[] fallback = fallback_ary[i];
|
||||
ttl = Xoa_ttl.parse_(wiki, Bry_.Add(ns_bry, msg_key_sub_root, Slash_bry, fallback)); // ttl="MediaWiki:msg_key/fallback"
|
||||
rv = ttl == null ? Xoa_page.Empty : wiki.Data_mgr().Get_page_from_msg(ttl);
|
||||
if (!rv.Missing()) break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static Xol_msg_itm Get_msg_itm_from_gfs(Xow_wiki wiki, Xol_lang lang, byte[] msg_key_sub_root) {
|
||||
Xol_msg_itm rv = lang.Msg_mgr().Itm_by_key_or_null(msg_key_sub_root); // NOTE: should always be msg_key_sub_root; EX: "msg/lang" will never be in lang.gfs
|
||||
if (rv == null) { // msg not found; check fallbacks; note that this is different from MW b/c when MW constructs a lang, it automatically adds all fallback msgs to the current lang
|
||||
byte[][] fallback_ary = lang.Fallback_bry_ary();
|
||||
int fallback_ary_len = fallback_ary.length;
|
||||
Xoa_lang_mgr lang_mgr = wiki.App().Lang_mgr();
|
||||
for (int i = 0; i < fallback_ary_len; i++) {
|
||||
byte[] fallback = fallback_ary[i];
|
||||
Xol_lang fallback_lang = lang_mgr.Get_by_key(fallback);
|
||||
if (fallback_lang == null) continue; // NOTE: en has fallback of "false"; ignore bad fallbacks;
|
||||
rv = fallback_lang.Msg_mgr().Itm_by_key_or_null(msg_key_sub_root);
|
||||
if (rv != null) break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
39
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_case.java
Normal file
39
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_case.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
class Pf_str_case extends Pf_func_base { // EX: {{lc:A}} -> a
|
||||
public Pf_str_case(int case_type, boolean first) {this.case_type = case_type; this.first = first;}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_str_lc;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_str_case(case_type, first).Name_(name);}
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr trg) {
|
||||
byte[] val_dat_ary = Eval_argx(ctx, src, caller, self); if (val_dat_ary == Bry_.Empty) return;
|
||||
int val_dat_ary_len = val_dat_ary.length; if (val_dat_ary_len == 0) return; // nothing to uc / lc; just return
|
||||
Xol_lang lang = ctx.Wiki().Lang();
|
||||
boolean upper = case_type == Xol_lang.Tid_upper;
|
||||
if (first) {
|
||||
Bry_bfr tmp_bfr = ctx.App().Utl_bry_bfr_mkr().Get_b512();
|
||||
val_dat_ary = lang.Case_mgr().Case_build_1st(tmp_bfr, upper, val_dat_ary, 0, val_dat_ary_len);
|
||||
tmp_bfr.Mkr_rls();
|
||||
}
|
||||
else
|
||||
val_dat_ary = lang.Case_mgr().Case_build(upper, val_dat_ary, 0, val_dat_ary_len);
|
||||
trg.Add(val_dat_ary);
|
||||
}
|
||||
boolean first; int case_type;
|
||||
}
|
||||
46
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_case_tst.java
Normal file
46
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_case_tst.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
import gplx.xowa.langs.cases.*;
|
||||
public class Pf_str_case_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Lc() {fxt.Test_parse_tmpl_str_test("{{lc:ABC}}" , "{{test}}", "abc");}
|
||||
@Test public void Lc_first() {fxt.Test_parse_tmpl_str_test("{{lcfirst:ABC}}" , "{{test}}", "aBC");}
|
||||
@Test public void Uc() {fxt.Test_parse_tmpl_str_test("{{uc:abc}}" , "{{test}}", "ABC");}
|
||||
@Test public void Uc_first() {fxt.Test_parse_tmpl_str_test("{{ucfirst:abc}}" , "{{test}}", "Abc");}
|
||||
@Test public void Multi_byte() {// NOTE: separate test b/c will sometimes fail in suite
|
||||
Xol_lang lang = fxt.Wiki().Lang();
|
||||
lang.Case_mgr().Clear();
|
||||
lang.Case_mgr().Add_bulk(Xol_case_itm_.Universal);
|
||||
fxt.Test_parse_tmpl_str_test("{{uc:ĉ}}" , "{{test}}", "Ĉ"); // upper all
|
||||
}
|
||||
@Test public void Multi_byte_asymmetric() {
|
||||
Xol_lang lang = fxt.Wiki().Lang();
|
||||
lang.Case_mgr().Clear();
|
||||
lang.Case_mgr().Add_bulk(Xol_case_itm_.Universal);
|
||||
fxt.Test_parse_tmpl_str_test("{{uc:ⱥ}}" , "{{test}}", "Ⱥ"); // handle multi-byte asymmetry (lc is 3 bytes; uc is 2 bytes)
|
||||
}
|
||||
@Test public void Multi_byte_first() {
|
||||
Xol_lang lang = fxt.Wiki().Lang();
|
||||
lang.Case_mgr().Clear();
|
||||
lang.Case_mgr().Add_bulk(Xol_case_itm_.Universal);
|
||||
fxt.Test_parse_tmpl_str_test("{{ucfirst:провинция}}" , "{{test}}", "Провинция"); // upper first; DATE:2014-02-04
|
||||
}
|
||||
}
|
||||
60
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_pad.java
Normal file
60
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_pad.java
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
class Pf_str_pad extends Pf_func_base {
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {// REF.MW: CoreParserFunctions.php|pad
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] val = Eval_argx(ctx, src, caller, self);
|
||||
int val_len = val.length;
|
||||
|
||||
byte[] pad_len = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
|
||||
int pad_len_int = Bry_.X_to_int_or(pad_len, 0, pad_len.length, -1);
|
||||
if (pad_len_int == -1) {bfr.Add(val); return;}// NOTE: if pad_len is non-int, add val and exit silently; EX: {{padleft: a|bad|0}}
|
||||
if (pad_len_int > 500) pad_len_int = 500; // MW: force to be <= 500
|
||||
|
||||
byte[] pad_str = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 1, Ary_pad_dflt);
|
||||
int pad_str_len = pad_str.length;
|
||||
if (pad_str_len == 0) {bfr.Add(val); return;}// NOTE: pad_str is entirely empty or whitespace; add val and return; SEE:NOTE_1
|
||||
|
||||
int pad_idx = 0;
|
||||
if (pad_dir_right) bfr.Add(val);
|
||||
for (int val_idx = val_len; val_idx < pad_len_int; val_idx++) {
|
||||
byte b = pad_str[pad_idx];
|
||||
int b_len = gplx.intl.Utf8_.Len_of_char_by_1st_byte(b);
|
||||
if (b_len == 1)
|
||||
bfr.Add_byte(b);
|
||||
else
|
||||
bfr.Add_mid(pad_str, pad_idx, pad_idx + b_len);
|
||||
pad_idx += b_len;
|
||||
if (pad_idx >= pad_str_len) pad_idx = 0;
|
||||
}
|
||||
if (!pad_dir_right) bfr.Add(val);
|
||||
}
|
||||
boolean pad_dir_right; static final byte[] Ary_pad_dflt = Bry_.new_ascii_("0");
|
||||
public Pf_str_pad(int id, boolean pad_dir_right) {this.id = id; this.pad_dir_right = pad_dir_right;}
|
||||
@Override public int Id() {return id;} private int id;
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_str_pad(id, pad_dir_right).Name_(name);}
|
||||
}
|
||||
/*
|
||||
NOTE_1
|
||||
difference between following:
|
||||
- {{padleft:a|4}} -> 000a
|
||||
Pad_arg omitted: default to 0
|
||||
- {{padleft:a|4| \n\t}} -> a
|
||||
Pad_arg specified, but empty: add val only
|
||||
*/
|
||||
36
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_pad_tst.java
Normal file
36
400_xowa/src_530_pf_str/gplx/xowa/Pf_str_pad_tst.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_str_pad_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void L_len_3() {fxt.Test_parse_tmpl_str_test("{{padleft: a|4|0}}" , "{{test}}" , "000a");}
|
||||
@Test public void L_str_ab() {fxt.Test_parse_tmpl_str_test("{{padleft: a|4|01}}" , "{{test}}" , "010a");}
|
||||
@Test public void L_len_neg1() {fxt.Test_parse_tmpl_str_test("{{padleft: a|-1|01}}" , "{{test}}" , "a");}
|
||||
@Test public void L_val_null() {fxt.Test_parse_tmpl_str_test("{{padleft: |4|0}}" , "{{test}}" , "0000");}
|
||||
@Test public void L_word_3() {fxt.Test_parse_tmpl_str_test("{{padleft: abc|4}}" , "{{test}}" , "0abc");}
|
||||
@Test public void L_exc_len_bad1() {fxt.Test_parse_tmpl_str_test("{{padleft:a|bad|01}}" , "{{test}}" , "a");}
|
||||
@Test public void L_exc_pad_ws() {fxt.Test_parse_tmpl_str_test("{{padleft:a|4|\n \t}}" , "{{test}}" , "a");}
|
||||
@Test public void R_len_3() {fxt.Test_parse_tmpl_str_test("{{padright:a|4|0}}" , "{{test}}" , "a000");}
|
||||
@Test public void R_str_ab() {fxt.Test_parse_tmpl_str_test("{{padright:a|4|01}}" , "{{test}}" , "a010");}
|
||||
@Test public void R_str_intl() {fxt.Test_parse_tmpl_str_test("{{padright:|6|devanā}}" , "{{test}}" , "devanā");}
|
||||
}
|
||||
/*
|
||||
{{padleft: a|4|0}}
|
||||
*/
|
||||
127
400_xowa/src_530_pf_str/gplx/xowa/Pf_tag.java
Normal file
127
400_xowa/src_530_pf_str/gplx/xowa/Pf_tag.java
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import gplx.xowa.html.*;
|
||||
public class Pf_tag extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_misc_tag;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_tag().Name_(name);}
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
byte[] tag_name = Eval_argx(ctx, src, caller, self); if (tag_name.length == 0) return;
|
||||
int args_len = self.Args_len();
|
||||
Xoa_app app = ctx.App();
|
||||
Bry_bfr tmp = app.Utl_bry_bfr_mkr().Get_b512();
|
||||
try {
|
||||
int tag_idx = ctx.Cur_page().Ref_mgr().Tag__next_id();
|
||||
Xop_xnde_tag tag = (Xop_xnde_tag)app.Xnde_tag_regy().XndeNames(ctx.Xnde_names_tid()).MatchAtCurExact(tag_name, 0, tag_name.length);
|
||||
boolean tag_is_ref = tag != null && tag.Id() == Xop_xnde_tag_.Tid_ref;
|
||||
if (tag_is_ref) // <ref>; add <xtag_bgn> to handle nested refs; PAGE:en.w:Battle_of_Midway; DATE:2014-06-27
|
||||
tmp.Add(Xtag_bgn_lhs).Add_int_pad_bgn(Byte_ascii.Num_0, 10, tag_idx).Add(Xtag_rhs);
|
||||
tmp.Add_byte(Byte_ascii.Lt).Add(tag_name);
|
||||
if (args_len > 1) {
|
||||
for (int i = 1; i < args_len; i++) {
|
||||
byte[] arg = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, i);
|
||||
if (arg.length == 0) continue; // if atr is empty, skip; see test
|
||||
tmp.Add_byte(Byte_ascii.Space);
|
||||
if (!AddHtmlArg(arg, tmp)) {
|
||||
ctx.Msg_log().Add_itm_none(Xop_tag_log.Invalid, arg, 0, arg.length);
|
||||
tmp.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
tmp.Add_byte(Byte_ascii.Gt);
|
||||
if (args_len > 0) // TODO: trim should not be called on content; WHEN: adding src[] back to tmpl_eval
|
||||
tmp.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, 0));
|
||||
tmp.Add_byte(Byte_ascii.Lt).Add_byte(Byte_ascii.Slash).Add(tag_name).Add_byte(Byte_ascii.Gt);
|
||||
if (tag_is_ref) // <ref>; add <xtag_end> to handle nested refs; PAGE:en.w:Battle_of_Midway; DATE:2014-06-27
|
||||
tmp.Add(Xtag_end_lhs).Add_int_pad_bgn(Byte_ascii.Num_0, 10, tag_idx).Add(Xtag_rhs);
|
||||
bfr.Add_bfr_and_clear(tmp);
|
||||
}
|
||||
finally {tmp.Mkr_rls();}
|
||||
}
|
||||
private boolean AddHtmlArg(byte[] src, Bry_bfr tmp) {
|
||||
ParseKeyVal(src, kv_bldr);
|
||||
//if (!kv_bldr.Valid()) return false;
|
||||
if (kv_bldr.Key_bgn() != -1)
|
||||
tmp.Add(Bry_.Mid(src, kv_bldr.Key_bgn(), kv_bldr.KeyEnd()));
|
||||
if (kv_bldr.Val_bgn() != -1) {
|
||||
if (kv_bldr.Key_bgn() != -1) {
|
||||
tmp.Add_byte(Byte_ascii.Eq);
|
||||
}
|
||||
tmp.Add_byte(Byte_ascii.Quote);
|
||||
tmp.Add(Bry_.Mid(src, kv_bldr.Val_bgn(), kv_bldr.Val_end()));
|
||||
tmp.Add_byte(Byte_ascii.Quote);
|
||||
}
|
||||
kv_bldr.Clear();
|
||||
return true;
|
||||
} private KeyValBldr kv_bldr = new KeyValBldr();
|
||||
private static void ParseKeyVal(byte[] src, KeyValBldr kv_bldr) {
|
||||
int itm_bgn = -1, itm_end = -1, src_len = src.length;
|
||||
boolean mode_is_key = true;
|
||||
for (int i = 0; i < src_len; i++) {
|
||||
byte b = src[i];
|
||||
switch (b) {
|
||||
case Byte_ascii.Eq:
|
||||
if (mode_is_key) {
|
||||
mode_is_key = false;
|
||||
if (itm_end == -1) itm_end = i;
|
||||
kv_bldr.Key_rng_(itm_bgn, itm_end);
|
||||
itm_bgn = itm_end = -1;
|
||||
}
|
||||
break;
|
||||
case Byte_ascii.Quote:
|
||||
case Byte_ascii.Apos: // NOTE: quotes cannot be escaped; regx takes first two quotes; REF:MW:CoreParserFunctions.php|tagObj
|
||||
if (itm_bgn == -1)
|
||||
itm_bgn = i + 1;
|
||||
else if (itm_end == -1)
|
||||
itm_end = i;
|
||||
break;
|
||||
case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.NewLine:// NOTE: do not need to handle ws, b/c argBldr will trim it EX: {{#tag|a| b = c }}; " b " and " c " are automatically trimmed
|
||||
break;
|
||||
default:
|
||||
if (itm_bgn == -1) itm_bgn = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (itm_end == -1) itm_end = src_len;
|
||||
kv_bldr.Val_rng_(itm_bgn, itm_end);
|
||||
}
|
||||
public static final int
|
||||
Xtag_len = 27 // <xtag_bgn id='1234567890'/>
|
||||
, Xtag_bgn = 14 // <xtag_bgn id='
|
||||
;
|
||||
public static final byte[]
|
||||
Xtag_bgn_lhs = Bry_.new_ascii_("<xtag_bgn id='")
|
||||
, Xtag_end_lhs = Bry_.new_ascii_("<xtag_end id='")
|
||||
, Xtag_rhs = Bry_.new_ascii_("'/>")
|
||||
;
|
||||
}
|
||||
class KeyValBldr {
|
||||
public int Key_bgn() {return key_bgn;} private int key_bgn;
|
||||
public int KeyEnd() {return key_end;} private int key_end;
|
||||
public KeyValBldr Key_rng_(int bgn, int end) {key_bgn = bgn; key_end = end; return this;}
|
||||
public int Val_bgn() {return val_bgn;} private int val_bgn;
|
||||
public int Val_end() {return val_end;} private int val_end;
|
||||
public KeyValBldr Val_rng_(int bgn, int end) {val_bgn = bgn; val_end = end; return this;}
|
||||
public boolean Valid() {
|
||||
return key_bgn != -1 && key_end != -1 && val_bgn != -1 && val_end != -1 && key_bgn <= key_end && val_bgn <= val_end;
|
||||
}
|
||||
public void Clear() {
|
||||
key_bgn = key_end = val_bgn = val_end = -1;
|
||||
}
|
||||
}
|
||||
39
400_xowa/src_530_pf_str/gplx/xowa/Pf_tag_tst.java
Normal file
39
400_xowa/src_530_pf_str/gplx/xowa/Pf_tag_tst.java
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_tag_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Basic() {fxt.Test_html_full_str("{{#tag:pre|a|id=b|style=c}}" , "<pre id=\"b\" style=\"c\">a</pre>");}
|
||||
// @Test public void Missing_val() {fxt.ini_Msg(Mwl_tag_rsc._.Invalid).Test_parse_tmpl_str_test("{{#tag:pre|a|id=}}" , "{{test}}" , "");} // see {{Reflist|colwidth=30em}} -> <ref group=a>a</ref>{{#tag:references||group=}} -> ""
|
||||
@Test public void Atr2_empty() {fxt.Test_html_full_str("{{#tag:pre|a|id=b|}}" , "<pre id=\"b\">a</pre>");} // see {{Reflist|colwidth=30em}} -> <ref group=a>a</ref>{{#tag:references||group=a|}} -> "<references group=a/>"
|
||||
@Test public void Val_apos() {fxt.Test_html_full_str("{{#tag:pre|a|id='b'}}" , "<pre id=\"b\">a</pre>");}
|
||||
@Test public void Val_quote() {fxt.Test_html_full_str("{{#tag:pre|a|id=\"b\"}}" , "<pre id=\"b\">a</pre>");}
|
||||
@Test public void Ws_all() {fxt.Test_html_full_str("{{#tag:pre|a| id = b }}" , "<pre id=\"b\">a</pre>");}
|
||||
@Test public void Ws_quoted() {fxt.Test_html_full_str("{{#tag:pre|a| id = ' b ' }}" , "<pre id=\"_b_\">a</pre>");}
|
||||
@Test public void Err_bad_key() {fxt.Test_html_full_str("{{#tag:pre|a|id=val|b}}" , "<pre id=\"val\">a</pre>");} // PURPOSE: b was failing b/c id was larger and key_end set to 4 (whereas b was len=1)
|
||||
// @Test public void Exc() {
|
||||
// fxt.Test_parse_tmpl_str_test("{{#tag:ref|George Robertson announced in January 2003 that he would be stepping down in December.<ref> {{cite news|title =NATO Secretary General to Leave His Post in December After 4 Years |first = Craig | last = Smith | work = The New York Times | date = January 23, 2003| url = http://www.nytimes.com/2003/01/23/world/nato-secretary-general-to-leave-his-post-in-december-after-4-years.html?scp=2&sq=lord+robertson&st=nyt|accessdate = 2009-03-29}}</ref> Jaap de Hoop Scheffer was selected as his successor, but could not assume the office until January 2004 because of his commitment in the Dutch Parliament.<ref> {{cite news|title = Jaap de Hoop Scheffer | work = Newsmakers | issue = 1 | publisher = Thomson Gale | date = January 1, 2005}}</ref> Robertson was asked to extend his term until Scheffer was ready, but declined, so Minuto-Rizzo, the Deputy Secretary General, took over in the interim.<ref name =\"ncsd\" /> |group=N|}}"
|
||||
// , "{{test}}" , "<pre id=\" b \">a</pre>");}
|
||||
@Test public void Nested_tmpl() { // PURPOSE: nested template must get re-evaluated; EX:de.wikipedia.org/wiki/Freiburg_im_Breisgau; DATE:2013-12-18;
|
||||
fxt.Init_page_create("Template:!", "|");
|
||||
fxt.Init_page_create("Template:A", "{{#ifeq:{{{1}}}|expd|pass|fail}}");
|
||||
fxt.Test_html_full_frag("{{#tag:ref|{{A{{!}}expd}}}}<references/>", "<span class=\"reference-text\">pass</span>");
|
||||
}
|
||||
}
|
||||
103
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_anchorencode.java
Normal file
103
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_anchorencode.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*;
|
||||
public class Pf_url_anchorencode extends Pf_func_base { // EX: {{anchorencode:a b}} -> a+b
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_url_anchorencode;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_url_anchorencode().Name_(name);}
|
||||
public static void Func_init(Xop_ctx ctx) {
|
||||
if (anchor_ctx != null) return;// NOTE: called by Scrib_uri
|
||||
encode_trie.Add(Byte_ascii.Colon, Bry_fmtr_arg_.byt_(Byte_ascii.Colon));
|
||||
encode_trie.Add(Byte_ascii.Space, Bry_fmtr_arg_.byt_(Byte_ascii.Underline));
|
||||
anchor_ctx = Xop_ctx.new_sub_(ctx.Wiki());
|
||||
anchor_ctx.Para().Enabled_n_();
|
||||
anchor_tkn_mkr = anchor_ctx.Tkn_mkr();
|
||||
anchor_parser = ctx.Wiki().Utl_mgr().Anchor_encode_parser();
|
||||
}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
if (anchor_ctx == null) Func_init(ctx);
|
||||
byte[] val_ary = Eval_argx(ctx, src, caller, self); if (val_ary == Bry_.Empty) return;
|
||||
Anchor_encode(val_ary, bfr, ctx.App().Utl_bry_bfr_mkr().Get_b512().Mkr_rls());
|
||||
}
|
||||
public static void Anchor_encode(byte[] src, Bry_bfr bfr, Bry_bfr tmp_bfr) {
|
||||
Xop_root_tkn root = anchor_ctx.Tkn_mkr().Root(src);
|
||||
anchor_parser.Parse_wtxt_to_wdom(root, anchor_ctx, anchor_tkn_mkr, src, Xop_parser_.Doc_bgn_bos);
|
||||
// anchor_parser.Parse_page_tmpl(root, anchor_ctx, anchor_tkn_mkr, src);
|
||||
int subs_len = root.Subs_len();
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Xop_tkn_itm sub = root.Subs_get(i);
|
||||
Tkn(src, sub, root, i, tmp_bfr);
|
||||
}
|
||||
byte[] unencoded = tmp_bfr.XtoAryAndClear();
|
||||
encoder.Encode(tmp_bfr, unencoded);
|
||||
bfr.Add_bfr_and_clear(tmp_bfr);
|
||||
}
|
||||
private static Url_encoder encoder = Url_encoder.new_html_id_();
|
||||
private static void Tkn(byte[] src, Xop_tkn_itm sub, Xop_tkn_grp grp, int sub_idx, Bry_bfr tmp_bfr) {
|
||||
switch (sub.Tkn_tid()) {
|
||||
case Xop_tkn_itm_.Tid_lnke: Lnke(src, (Xop_lnke_tkn)sub, tmp_bfr); break; // FUTURE: need to move number to lnke_tkn so that number will be correct/consistent?
|
||||
case Xop_tkn_itm_.Tid_lnki: Lnki(src, (Xop_lnki_tkn)sub, tmp_bfr); break;
|
||||
case Xop_tkn_itm_.Tid_apos: break; // noop
|
||||
case Xop_tkn_itm_.Tid_xnde: Xnde(src, (Xop_xnde_tkn)sub, tmp_bfr); break;
|
||||
case Xop_tkn_itm_.Tid_html_ncr: tmp_bfr.Add_utf8_int(((Xop_amp_tkn_num)sub).Val()); break;
|
||||
case Xop_tkn_itm_.Tid_html_ref: tmp_bfr.Add_utf8_int(((Xop_amp_tkn_txt)sub).Char_int()); break;
|
||||
case Xop_tkn_itm_.Tid_tmpl_invk:
|
||||
Xot_invk_tkn invk_tkn = (Xot_invk_tkn)sub;
|
||||
Arg_itm_tkn name_tkn = invk_tkn.Name_tkn().Key_tkn();
|
||||
int name_ary_bgn = name_tkn.Src_bgn() + 1, name_ary_end = name_tkn.Src_end();
|
||||
byte[] name_ary = Bry_.Mid(src, name_ary_bgn, name_ary_end); // + 1 to skip :
|
||||
int name_ary_len = name_ary_end - name_ary_bgn;
|
||||
if (name_ary_len > 0 && name_ary[0] == Byte_ascii.Colon) // has initial colon; EX: {{:a}
|
||||
tmp_bfr.Add_mid(name_ary, 1, name_ary_len); // 1 to skip initial colon
|
||||
else // regular tmpl; EX: {{a}}
|
||||
tmp_bfr.Add(anchor_ctx.Wiki().Ns_mgr().Ns_template().Gen_ttl(name_ary));
|
||||
break;
|
||||
default: tmp_bfr.Add_mid(src, sub.Src_bgn_grp(grp, sub_idx), sub.Src_end_grp(grp, sub_idx)); break;
|
||||
}
|
||||
}
|
||||
private static void Lnke(byte[] src, Xop_lnke_tkn lnke, Bry_bfr tmp_bfr) {
|
||||
int subs_len = lnke.Subs_len();
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Xop_tkn_itm lnke_sub = lnke.Subs_get(i);
|
||||
tmp_bfr.Add_mid(src, lnke_sub.Src_bgn_grp(lnke, i), lnke_sub.Src_end_grp(lnke, i));
|
||||
}
|
||||
}
|
||||
private static void Lnki(byte[] src, Xop_lnki_tkn lnki, Bry_bfr tmp_bfr) {
|
||||
int src_end = lnki.Src_end();
|
||||
int trg_end = lnki.Trg_tkn().Src_end();
|
||||
|
||||
if (trg_end == src_end - Xop_tkn_.Lnki_end_len) { // only trg
|
||||
int trg_bgn = lnki.Trg_tkn().Src_bgn();
|
||||
if (lnki.Ttl().ForceLiteralLink()) ++trg_bgn; // literal link; skip colon; EX: [[:a]] -> a
|
||||
tmp_bfr.Add_mid(src, trg_bgn, trg_end);
|
||||
}
|
||||
else {
|
||||
tmp_bfr.Add_mid(src, trg_end + 1, src_end - Xop_tkn_.Lnki_end_len); //+1 is len of pipe
|
||||
}
|
||||
}
|
||||
private static void Xnde(byte[] src, Xop_xnde_tkn xnde, Bry_bfr tmp_bfr) {
|
||||
int subs_len = xnde.Subs_len();
|
||||
for (int i = 0; i < subs_len; i++) {
|
||||
Tkn(src, xnde.Subs_get(i), xnde, i, tmp_bfr);
|
||||
}
|
||||
}
|
||||
private static ByteTrieMgr_fast encode_trie = ByteTrieMgr_fast.cs_();
|
||||
private static Xop_ctx anchor_ctx; static Xop_tkn_mkr anchor_tkn_mkr;
|
||||
private static Xop_parser anchor_parser;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_url_anchorencode_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Lnke() {fxt.Test_parse_tmpl_str_test("{{anchorencode:[irc://a b c]}}" , "{{test}}" , "b_c");}
|
||||
@Test public void Apos_bold() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a ''b'' c}}" , "{{test}}" , "a_b_c");}
|
||||
@Test public void Apos_1() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a 'b c}}" , "{{test}}" , "a_.27b_c");}
|
||||
@Test public void Lnki_trg() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a [[b]] c}}" , "{{test}}" , "a_b_c");}
|
||||
@Test public void Lnki_caption() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a [[b|c]] c}}" , "{{test}}" , "a_c_c");}
|
||||
@Test public void Lnki_file() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a [[Image:b|thumb|c]] d}}" , "{{test}}" , "a_thumb.7Cc_d");}
|
||||
@Test public void Xnde() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a <i>b</i> c}}" , "{{test}}" , "a_b_c");}
|
||||
@Test public void Html_ncr() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a " b}}" , "{{test}}" , "a_.22_b");}
|
||||
@Test public void Html_ref() {fxt.Test_parse_tmpl_str_test("{{anchorencode:a " b}}" , "{{test}}" , "a_.22_b");}
|
||||
@Test public void Tmpl_missing_basic() {fxt.Test_parse_tmpl_str_test("{{anchorencode:{{a}}}}" , "{{test}}" , "Template:a");}
|
||||
@Test public void Tmpl_missing_colon() {fxt.Test_parse_tmpl_str_test("{{anchorencode:{{:a}}}}" , "{{test}}" , "Template:A");}
|
||||
@Test public void Lnki_literal() {fxt.Test_parse_tmpl_str_test("{{anchorencode:[[:a]]}}" , "{{test}}" , "a");}
|
||||
}
|
||||
52
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_filepath.java
Normal file
52
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_filepath.java
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import gplx.xowa.files.*;
|
||||
public class Pf_url_filepath extends Pf_func_base {
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_url_filepath;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_url_filepath().Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {
|
||||
byte[] val_ary = Eval_argx(ctx, src, caller, self); if (val_ary == Bry_.Empty) return;
|
||||
Xow_wiki wiki = ctx.Wiki();
|
||||
val_ary = Bry_.Add(Bry_file, val_ary);
|
||||
Xoa_ttl ttl = Xoa_ttl.new_(wiki, ctx.App().Msg_log_null(), val_ary, val_ary, 0, val_ary.length); if (ttl == null) return; // text is not valid ttl; return;
|
||||
Xoa_page page = Load_page(wiki, ttl);
|
||||
if (page.Missing()) return; // page not found in commons; exit;
|
||||
byte[] ttl_bry = page.Ttl().Page_url();
|
||||
Xofw_file_finder_rslt tmp_rslt = wiki.File_mgr().Repo_mgr().Page_finder_locate(ttl_bry);
|
||||
if (tmp_rslt .Repo_idx() == Byte_.MaxValue_127) return;
|
||||
Xof_repo_itm trg_repo = wiki.File_mgr().Repo_mgr().Repos_get_at(tmp_rslt.Repo_idx()).Trg();
|
||||
xfer_itm.Atrs_by_ttl(ttl_bry, Bry_.Empty); // redirect is empty b/c Get_page does all redirect lookups
|
||||
byte[] url = url_bldr.Set_trg_html_(Xof_repo_itm.Mode_orig, trg_repo, ttl_bry, xfer_itm.Lnki_md5(), xfer_itm.Lnki_ext(), Xof_img_size.Size_null_deprecated, Xof_doc_thumb.Null, Xof_doc_page.Null).Xto_bry();
|
||||
bb.Add(url);
|
||||
} private static final byte[] Bry_file = Bry_.new_ascii_("File:");
|
||||
private static final Xof_xfer_itm xfer_itm = new Xof_xfer_itm();
|
||||
private static final Xof_url_bldr url_bldr = new Xof_url_bldr();
|
||||
public static Xoa_page Load_page(Xow_wiki wiki, Xoa_ttl ttl) {
|
||||
Xoa_page page = wiki.Data_mgr().Get_page(ttl, false);
|
||||
if (page.Missing()) { // file not found in current wiki; try commons;
|
||||
Xow_wiki commons_wiki = wiki.App().Wiki_mgr().Get_by_key_or_null(wiki.Commons_wiki_key());
|
||||
if (commons_wiki != null) {; // commons_wiki not installed; exit; DATE:2013-06-08
|
||||
if (!Env_.Mode_testing()) commons_wiki.Init_assert();// must assert load else page_zip never detected; TODO: move to Xoa_wiki_mgr.New_wiki; DATE:2013-03-10
|
||||
page = commons_wiki.Data_mgr().Get_page(ttl, false);
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
}
|
||||
54
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_filepath_tst.java
Normal file
54
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_filepath_tst.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_url_filepath_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {
|
||||
fxt.Reset();
|
||||
Io_mgr._.InitEngine_mem();
|
||||
Xoa_app app = fxt.App(); en_wiki = fxt.Wiki();
|
||||
mock_wkr.Clear_commons(); // assume all files are in repo 0
|
||||
en_wiki.File_mgr().Repo_mgr().Page_finder_(mock_wkr);
|
||||
commons_wiki = Xoa_app_fxt.wiki_(app, Xow_wiki_.Domain_commons_str);
|
||||
commons_wiki.Db_mgr().Load_mgr().Clear();
|
||||
en_wiki.Db_mgr().Load_mgr().Clear();
|
||||
app.Wiki_mgr().Add(commons_wiki);
|
||||
app.File_mgr().Repo_mgr().Set("src_commons", "mem/xowa/file/commons/src/", commons_wiki.Domain_str()).Ext_rules_(Xoft_rule_grp.Grp_app_default);
|
||||
app.File_mgr().Repo_mgr().Set("trg_commons", "mem/xowa/file/commons/trg/", commons_wiki.Domain_str()).Ext_rules_(Xoft_rule_grp.Grp_app_default);
|
||||
en_wiki.File_mgr().Repo_mgr().Add_repo(Bry_.new_utf8_("src_commons"), Bry_.new_utf8_("trg_commons"));
|
||||
Io_mgr._.CreateDir(Io_url_.new_dir_("mem/xowa/wiki/commons.wikimedia.org/ns/000/page/")); // HACK: create page_dir so Scan_dirs_zip will not identify commons as zipped; FIX: remove; WHEN: after redoing commons.css download logic
|
||||
} private Xow_wiki en_wiki, commons_wiki; Xofw_wiki_wkr_mock mock_wkr = new Xofw_wiki_wkr_mock();
|
||||
@Test public void Wiki_is_local() {
|
||||
fxt.Init_page_create(en_wiki, "File:A.png", "");
|
||||
mock_wkr.Redirect_("A.png", "A.png").Repo_idx_(0);
|
||||
fxt.Test_parse_tmpl_str_test("{{filepath:A.png}}", "{{test}}", "file:///mem/wiki/repo/trg/orig/7/0/A.png");
|
||||
}
|
||||
@Test public void Wiki_is_commons() {
|
||||
fxt.Init_page_create(commons_wiki, "File:A.png", "");
|
||||
commons_wiki.Fsys_mgr().Dir_regy()[Xow_dir_info_.Tid_page].Ext_tid_(gplx.ios.Io_stream_.Tid_file);
|
||||
mock_wkr.Redirect_("A.png", "A.png").Repo_idx_(1);
|
||||
fxt.Test_parse_tmpl_str_test("{{filepath:A.png}}", "{{test}}", "file:///mem/xowa/file/commons/trg/orig/7/0/1/c/A.png");
|
||||
}
|
||||
@Test public void Not_found() {
|
||||
fxt.Test_parse_tmpl_str_test("{{filepath:B.png}}", "{{test}}", "");
|
||||
}
|
||||
@Test public void Invalid() { // PURPOSE: handle invalid ttls; EX:w:Germicidin
|
||||
fxt.Test_parse_tmpl_str_test("{{filepath:{{{ImageFile}}}}}", "{{test}}", "");
|
||||
}
|
||||
}
|
||||
57
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_ns.java
Normal file
57
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_ns.java
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
class Pf_url_ns extends Pf_func_base { // EX: {{ns:6}} -> File
|
||||
public Pf_url_ns(boolean encode) {this.encode = encode; if (canonical == null) canonical_();}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_url_ns;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_url_ns(encode).Name_(name);}
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {
|
||||
byte[] val_dat_ary = Eval_argx(ctx, src, caller, self); if (val_dat_ary == Bry_.Empty) return;
|
||||
|
||||
int val_dat_ary_len = val_dat_ary.length;
|
||||
int ns_id = Bry_.X_to_int_or(val_dat_ary, 0, val_dat_ary_len, -1);
|
||||
if (ns_id == -1) {
|
||||
Object o = ctx.Wiki().Ns_mgr().Names_get_or_null(val_dat_ary, 0, val_dat_ary_len);
|
||||
if (o == null
|
||||
&& !Bry_.Eq(ctx.Lang().Key_bry(), Xol_lang_.Key_en)) // foreign language; english canonical names are still valid; REF.MW: Language.php|getNsIndex
|
||||
o = canonical.Get_by_mid(val_dat_ary, 0, val_dat_ary_len);
|
||||
if (o != null) {
|
||||
Xow_ns itm = (Xow_ns)o;
|
||||
if (itm.Id() == Xow_ns_.Id_file) itm = ctx.Wiki().Ns_mgr().Ns_file(); // handles "Image" -> "File"
|
||||
bb.Add(encode ? itm.Name_enc() : itm.Name_txt());
|
||||
}
|
||||
}
|
||||
else {
|
||||
Xow_ns itm = (Xow_ns)ctx.Wiki().Ns_mgr().Ids_get_or_null(ns_id);
|
||||
if (itm == null) return; // occurs when ns_id is not known; EX: {{ns:999}}; SEE: Wiktionary:Grease pit archive/2007/October; "{{ns:114}}"
|
||||
bb.Add(encode ? itm.Name_enc() : itm.Name_txt());
|
||||
}
|
||||
}
|
||||
boolean encode;
|
||||
private static Hash_adp_bry canonical;
|
||||
private static void canonical_add(int ns_id, byte[] ns_name) {
|
||||
Xow_ns ns = new Xow_ns(ns_id, Xow_ns_case_.Id_all, ns_name, false);
|
||||
canonical.Add(ns_name, ns);
|
||||
}
|
||||
private static void canonical_() {
|
||||
canonical = Hash_adp_bry.ci_();
|
||||
for (Xow_ns ns : Xow_ns_.Canonical)
|
||||
canonical_add(ns.Id(), ns.Name_bry());
|
||||
}
|
||||
}
|
||||
37
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_ns_tst.java
Normal file
37
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_ns_tst.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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_url_ns_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Ns_0() {fxt.Test_parse_tmpl_str_test("{{ns:0}}" , "{{test}}", "");}
|
||||
@Test public void Ns_10() {fxt.Test_parse_tmpl_str_test("{{ns:10}}" , "{{test}}", "Template");}
|
||||
@Test public void Ns_11() {fxt.Test_parse_tmpl_str_test("{{ns:11}}" , "{{test}}", "Template talk");}
|
||||
@Test public void Ns_11_ws() {fxt.Test_parse_tmpl_str_test("{{ns: 11 }}" , "{{test}}", "Template talk");}
|
||||
@Test public void Ns_Template() {fxt.Test_parse_tmpl_str_test("{{ns:Template}}" , "{{test}}", "Template");}
|
||||
@Test public void Ns_invalid() {fxt.Test_parse_tmpl_str_test("{{ns:252}}" , "{{test}}", "");}
|
||||
@Test public void Nse_10() {fxt.Test_parse_tmpl_str_test("{{nse:10}}" , "{{test}}", "Template");}
|
||||
@Test public void Nse_11() {fxt.Test_parse_tmpl_str_test("{{nse:11}}" , "{{test}}", "Template_talk");}
|
||||
@Test public void Ns_Image() {fxt.Test_parse_tmpl_str_test("{{ns:Image}}" , "{{test}}", "File");}
|
||||
@Test public void Ns_Templatex() {fxt.Test_parse_tmpl_str_test("{{ns:Templatex}}" , "{{test}}", "");}
|
||||
@Test public void Ns_Talk() { // PURPOSE: non-English wikis may have parameterized Project Talk ($1 talk); swap out with ns:4; REF.MW: Language.php!fixVariableInNamespace
|
||||
fxt.Wiki().Ns_mgr_(new Xow_ns_mgr().Add_new(4, "wiki").Add_new(5, "$1 talk").Add_new(10, "Template").Init());
|
||||
fxt.Test_parse_tmpl_str_test("{{ns:5}}" , "{{test}}", "wiki talk");
|
||||
}
|
||||
}
|
||||
29
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlencode.java
Normal file
29
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlencode.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
class Pf_url_urlencode extends Pf_func_base { // EX: {{urlencode:a b}} -> a+b
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {
|
||||
byte[] val_ary = Eval_argx(ctx, src, caller, self); if (val_ary == Bry_.Empty) return;
|
||||
ctx.App().Url_converter_url().Encode(urlEncodeBfr, val_ary);
|
||||
bb.Add_bfr(urlEncodeBfr);
|
||||
urlEncodeBfr.Clear();
|
||||
} private Bry_bfr urlEncodeBfr = Bry_bfr.new_(128);
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_url_urlencode;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_url_urlencode().Name_(name);}
|
||||
}
|
||||
30
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlencode_tst.java
Normal file
30
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlencode_tst.java
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_url_urlencode_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Numbers() {fxt.Test_parse_tmpl_str_test("{{urlencode:0123456789}}" , "{{test}}", "0123456789");}
|
||||
@Test public void Ltrs_lower() {fxt.Test_parse_tmpl_str_test("{{urlencode:abcdefghijklmnopqrstuvwxyz}}" , "{{test}}", "abcdefghijklmnopqrstuvwxyz");}
|
||||
@Test public void Ltrs_upper() {fxt.Test_parse_tmpl_str_test("{{urlencode:ABCDEFGHIJKLMNOPQRSTUVWXYZ}}" , "{{test}}", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");}
|
||||
@Test public void Syms_allowed() {fxt.Test_parse_tmpl_str_test("{{urlencode:-_.}}" , "{{test}}", "-_.");}
|
||||
@Test public void Space() {fxt.Test_parse_tmpl_str_test("{{urlencode:a b}}" , "{{test}}", "a+b");}
|
||||
@Test public void Syms() {fxt.Test_parse_tmpl_str_test("{{urlencode:!?^~:}}" , "{{test}}", "%21%3F%5E%7E%3A");}
|
||||
@Test public void Extended() {fxt.Test_parse_tmpl_str_test("{{urlencode:aéb}}" , "{{test}}", "a%C3%A9b");}
|
||||
}
|
||||
63
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlfunc.java
Normal file
63
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlfunc.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
public class Pf_url_urlfunc extends Pf_func_base { // EX: {{lc:A}} -> a
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {
|
||||
byte[] val_dat_ary = Eval_argx(ctx, src, caller, self); if (val_dat_ary.length == 0) return;
|
||||
byte[] qry_arg = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self.Args_len(), 0);
|
||||
UrlString(ctx, tid, encode, val_dat_ary, bb, qry_arg);
|
||||
}
|
||||
public static void UrlString(Xop_ctx ctx, byte tid, boolean encode, byte[] src, Bry_bfr trg, byte[] qry_arg) {
|
||||
Xow_wiki wiki = ctx.Wiki();
|
||||
Xoa_ttl ttl = Xoa_ttl.new_(wiki, ctx.Msg_log(), src, src, 0, src.length);
|
||||
if (ttl == null) return; // NOTE: guard against null ttl; EX: {{fullurl:{{transclude|{{{1}}}}}|action=edit}} -> {{fullurl:Template:{{{1}}}|action=edit}} -> Template:{{{1}}} will be a null ttl
|
||||
byte[] ttl_ary = ttl.Full_url();// NOTE: Full_url does encoding; don't encode again
|
||||
Xow_xwiki_itm xwiki = ttl.Wik_itm();
|
||||
if (xwiki != null) { // xwiki exists; add as //commons.wikimedia.org/wiki/A#b?c=d
|
||||
if (tid == Tid_canonical)
|
||||
trg.Add(Xoh_href_parser.Href_http_bry); // "http://"
|
||||
else
|
||||
trg.Add(Xoa_consts.Url_relative_prefix); // "//"
|
||||
trg.Add(xwiki.Domain()) // "commons.wikimedia.org"
|
||||
.Add(Xoh_href_parser.Href_wiki_bry) // "/wiki/"
|
||||
.Add_mid(ttl_ary, xwiki.Key().length + 1, ttl_ary.length); // "A#b?c=d"; +1 for colon after "commons:"; NOTE: ugly way of getting rest of url, but ttl currently does not have Full_wo_wiki
|
||||
}
|
||||
else {
|
||||
Bry_bfr tmp_bfr = ctx.App().Utl_bry_bfr_mkr().Get_b512().Mkr_rls();
|
||||
switch (tid) {
|
||||
case Tid_local: tmp_bfr.Add(ctx.Wiki().Props().ArticlePath());break;
|
||||
case Tid_full: tmp_bfr.Add(Bry_relative_url).Add(ctx.Wiki().Props().ServerName()).Add(ctx.Wiki().Props().ArticlePath()); break;
|
||||
case Tid_canonical: tmp_bfr.Add(ctx.Wiki().Props().Server()).Add(ctx.Wiki().Props().ArticlePath()); break;
|
||||
default: throw Err_.unhandled(tid);
|
||||
}
|
||||
tmp_bfr.Add(ttl_ary);
|
||||
trg.Add_bfr_and_clear(tmp_bfr);
|
||||
}
|
||||
if (qry_arg != Bry_.Empty) trg.Add_byte(Byte_ascii.Question).Add(qry_arg);
|
||||
}
|
||||
public Pf_url_urlfunc(int id, byte tid, boolean encode) {this.id = id; this.tid = tid; this.encode = encode;} private byte tid; boolean encode;
|
||||
@Override public int Id() {return id;} private int id;
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_url_urlfunc(id, tid, encode).Name_(name);}
|
||||
public static final byte Tid_local = 0, Tid_full = 1, Tid_canonical = 2;
|
||||
public static final byte[] Bry_relative_url = Bry_.new_ascii_("//");
|
||||
}
|
||||
/*
|
||||
NOTE: Both fullurle: and localurle: performed additional character escaping on the resulting link, but no example is known where that still has any additional effect.
|
||||
http://meta.wikimedia.org/wiki/Help:Parser_function
|
||||
*/
|
||||
42
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlfunc_tst.java
Normal file
42
400_xowa/src_530_pf_str/gplx/xowa/Pf_url_urlfunc_tst.java
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_url_urlfunc_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Localurl() {fxt.Test_parse_tmpl_str_test("{{localurl:a&b! c}}" , "{{test}}", "/wiki/A%26b!_c");}
|
||||
@Test public void Fullurl() {fxt.Test_parse_tmpl_str_test("{{fullurl:a&b! c}}" , "{{test}}", "//en.wikipedia.org/wiki/A%26b!_c");}
|
||||
@Test public void Canonicalurl() {fxt.Test_parse_tmpl_str_test("{{canonicalurl:a&b! c}}" , "{{test}}", "http://en.wikipedia.org/wiki/A%26b!_c");}
|
||||
@Test public void Canonicalurl_case() {fxt.Test_parse_tmpl_str_test("{{CANONICALURL:a&b! c}}" , "{{test}}", "http://en.wikipedia.org/wiki/A%26b!_c");}
|
||||
@Test public void Localurle() {fxt.Test_parse_tmpl_str_test("{{localurle:a&b! c}}" , "{{test}}", "/wiki/A%26b!_c");}
|
||||
@Test public void Fullurle() {fxt.Test_parse_tmpl_str_test("{{fullurle:a&b! c}}" , "{{test}}", "//en.wikipedia.org/wiki/A%26b!_c");}
|
||||
@Test public void Canonicalurle() {fxt.Test_parse_tmpl_str_test("{{canonicalurle:a&b! c}}" , "{{test}}", "http://en.wikipedia.org/wiki/A%26b!_c");}
|
||||
@Test public void Fullurl_arg() {fxt.Test_parse_tmpl_str_test("{{fullurle:a&b! c|action=edit}}" , "{{test}}", "//en.wikipedia.org/wiki/A%26b!_c?action=edit");}
|
||||
@Test public void Random() {fxt.Test_parse_tmpl_str_test("{{fullurle:a&b! c|action=edit}}" , "{{test|a|b|c}}", "//en.wikipedia.org/wiki/A%26b!_c?action=edit");}
|
||||
@Test public void Xwiki() {
|
||||
fxt.Wiki().Xwiki_mgr().Add_full("commons", "commons.wikimedia.org");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{localurl:commons:A}}" , "{{test}}", "//commons.wikimedia.org/wiki/A");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{fullurl:commons:A}}" , "{{test}}", "//commons.wikimedia.org/wiki/A");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{canonicalurl:commons:A}}" , "{{test}}", "http://commons.wikimedia.org/wiki/A");
|
||||
}
|
||||
@Test public void Xwiki_qarg_fix() {
|
||||
fxt.Wiki().Xwiki_mgr().Add_full("commons", "commons.wikimedia.org");
|
||||
fxt.Reset().Test_parse_tmpl_str_test("{{fullurl:commons:A|key=val}}" , "{{test}}", "//commons.wikimedia.org/wiki/A?key=val");
|
||||
}
|
||||
}
|
||||
182
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_rel2abs.java
Normal file
182
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_rel2abs.java
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
public class Pf_xtn_rel2abs extends Pf_func_base {
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
private static final byte[] Ary_dot_slash = Bry_.new_ascii_("./"), Ary_dot_dot = Bry_.new_ascii_(".."), Ary_dot_dot_slash = Bry_.new_ascii_("../");
|
||||
private static void qry_bgns_with_init() {
|
||||
qry_bgns_with = ByteTrieMgr_fast.cs_();
|
||||
qry_bgns_with.Add(Byte_ascii.Slash, Int_obj_ref.new_(Id_slash));
|
||||
qry_bgns_with.Add(Byte_ascii.Dot, Int_obj_ref.new_(Id_dot));
|
||||
qry_bgns_with.Add(Ary_dot_slash, Int_obj_ref.new_(Id_dot_slash));
|
||||
qry_bgns_with.Add(Ary_dot_dot, Int_obj_ref.new_(Id_dot_dot));
|
||||
qry_bgns_with.Add(Ary_dot_dot_slash, Int_obj_ref.new_(Id_dot_dot_slash));
|
||||
} static ByteTrieMgr_fast qry_bgns_with;
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {// REF.MW:ParserFunctions_body.php
|
||||
byte[] qry = Eval_argx(ctx, src, caller, self);
|
||||
byte[] orig = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self.Args_len(), 0);
|
||||
if (orig.length == 0) orig = ctx.Cur_page().Ttl().Full_txt();
|
||||
bb.Add(Rel2abs(ctx.App().Utl_bry_bfr_mkr().Get_b512().Mkr_rls(), qry, orig));
|
||||
}
|
||||
public static boolean Rel2abs_ttl(byte[] ttl, int bgn, int end) {
|
||||
int last = end - 1;
|
||||
if (end - bgn > Xoa_ttl.Max_len) return false; // NOTE: some tmpls have long #if statements; quicker to fail here than wait for invalid char below
|
||||
boolean rv = false;
|
||||
for (int i = bgn; i < end; ++i) {
|
||||
switch (ttl[i]) {
|
||||
case Byte_ascii.Gt: case Byte_ascii.Pipe: // simplified version of Xoa_ttl parse; note that Xoa_ttl accepts these if anchor is seen; this proc assumes that anything with anchor and invalid char is an invalid rel2abs; EX: "A../b#c[d" is not valid; DATE:2013-03-31
|
||||
case Byte_ascii.Brack_bgn: case Byte_ascii.Brack_end: case Byte_ascii.Curly_bgn: case Byte_ascii.Curly_end:
|
||||
return false;
|
||||
case Byte_ascii.Slash:
|
||||
if ( !rv &&
|
||||
( (i == bgn) // bgns with "/"
|
||||
|| (i > bgn && ttl[i - 1] == Byte_ascii.Dot) // "./"
|
||||
|| (i < last && ttl[i + 1] == Byte_ascii.Dot) // "/."
|
||||
)
|
||||
) rv = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
private static final Int_obj_ref ignore_rel2abs_tid = Int_obj_ref.zero_();
|
||||
public static byte[] Rel2abs(Bry_bfr tmp_bfr, byte[] qry, byte[] src) {return Rel2abs(tmp_bfr, qry, src, ignore_rel2abs_tid);}
|
||||
public static byte[] Rel2abs(Bry_bfr tmp_bfr, byte[] qry, byte[] src, Int_obj_ref rel2abs_tid) {
|
||||
if (qry_bgns_with == null) qry_bgns_with_init();
|
||||
int qry_len = qry.length, src_len = src.length;
|
||||
|
||||
// qry_len = RTrim(qry, Byte_ascii.Slash, qry_bgn, qry_len); // not needed, but test anyway
|
||||
if (qry_len == 0) return src;// no qry; return src; EX:{{#rel2abs:|a/b}} -> a/b
|
||||
|
||||
byte[] tmp = src;
|
||||
int tmp_adj = 0, i = 0, prv_slash_end = 0, tmp_len = src_len, seg_pos = 0;
|
||||
boolean tmp_is_1st = true;
|
||||
Object o = qry_bgns_with.MatchAtCur(qry, 0, qry_len); // check if qry begins with ".", "/", "./", "../"; if it doesn't return;
|
||||
if (o != null) {
|
||||
int id = ((Int_obj_ref)o).Val();
|
||||
rel2abs_tid.Val_(id);
|
||||
switch (id) {
|
||||
case Id_dot: // "."
|
||||
break;
|
||||
case Id_slash: // "/"
|
||||
case Id_dot_slash: // "./"
|
||||
case Id_dot_dot_slash: // "../"
|
||||
break; // qry is relative to src; noop
|
||||
case Id_dot_dot: // ".."
|
||||
int match_end = qry_bgns_with.Match_pos();
|
||||
if (match_end < qry_len && qry[match_end] == Byte_ascii.Dot) // NOTE: handles "..."; if "...*" then treat as invalid and return; needed for en.wiktionary.org/wiki/Wiktionary:Requests for cleanup/archive/2006
|
||||
return qry;
|
||||
break;
|
||||
default:
|
||||
return qry; // NOTE: lnki parsing currently has fuzzy logic to try to detect rel2abs; for now, if false match, then return original
|
||||
}
|
||||
}
|
||||
else { // qry is not relative to src; src is ignored; EX:{{#rel2abs:c|a/b}} -> c
|
||||
src_len = 0;
|
||||
tmp = qry;
|
||||
tmp_len = qry_len;
|
||||
tmp_is_1st = false;
|
||||
}
|
||||
// create segs; see NOTE_1 for approach
|
||||
byte b = Byte_.Zero;
|
||||
boolean loop = true, dot_mode = true;
|
||||
while (loop) {
|
||||
if (i == tmp_len) { // finished an ary (either src or qry)
|
||||
if (tmp_is_1st) { // finished src; EX: A/b
|
||||
tmp_is_1st = false;
|
||||
tmp = qry;
|
||||
tmp_adj = src_len + 1;
|
||||
tmp_len = src_len + 1 + qry_len;
|
||||
}
|
||||
else // finished qry; EX: ../c
|
||||
loop = false;
|
||||
b = Byte_ascii.Slash; // fake a slash between ary and src
|
||||
}
|
||||
else // inside ary
|
||||
b = tmp[i - tmp_adj];
|
||||
switch (b) {
|
||||
case Byte_ascii.Dot: // "."; ignore; note that dot_mode defaults to true
|
||||
break;
|
||||
default: // something else besides dot or slash; reset dot_mode
|
||||
dot_mode = false;
|
||||
break;
|
||||
case Byte_ascii.Slash: // "/"; seg finished
|
||||
int seg_len = i - prv_slash_end; // EX: "a/b/c" prv_slash_end = 2; i = 3; len = 1
|
||||
boolean create_seg = false;
|
||||
switch (seg_len) {
|
||||
case 0: // "//"; ignore
|
||||
break;
|
||||
case 1: // "/?/"
|
||||
if (dot_mode) {} // "/./"; current seg; ignore;
|
||||
else create_seg = true; // something else (EX: /A/); create seg;
|
||||
break;
|
||||
case 2:
|
||||
if (dot_mode) { // "/../"; pop seg_ary
|
||||
seg_pos -= 2;
|
||||
if (seg_pos < 0) return Bry_.Empty; // FUTURE: return MediaWiki error
|
||||
}
|
||||
else create_seg = true; // something else; create seg
|
||||
break;
|
||||
default: // something else; create seg
|
||||
create_seg = true;
|
||||
break;
|
||||
}
|
||||
if (create_seg) {
|
||||
seg_ary[seg_pos++] = prv_slash_end;
|
||||
seg_ary[seg_pos++] = i;
|
||||
}
|
||||
prv_slash_end = i + 1; // +1: place after slash
|
||||
dot_mode = true; // reset dot_mode
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// write segs
|
||||
tmp = src; tmp_adj = 0; tmp_is_1st = true; tmp_len = src_len;
|
||||
if (src_len == 0) {
|
||||
tmp = qry;
|
||||
tmp_len = qry_len;
|
||||
tmp_is_1st = false;
|
||||
}
|
||||
for (int j = 0; j < seg_pos; j += 2) {
|
||||
if (j != 0) tmp_bfr.Add_byte(Byte_ascii.Slash);
|
||||
if (seg_ary[j] >= tmp_len) {
|
||||
tmp = qry;
|
||||
tmp_adj = src_len + 1;
|
||||
}
|
||||
tmp_bfr.Add_mid(tmp, seg_ary[j] - tmp_adj, seg_ary[j+1] - tmp_adj);
|
||||
}
|
||||
return tmp_bfr.XtoAryAndClear();
|
||||
}
|
||||
private static int[] seg_ary = new int[Xoa_ttl.Max_len];
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_rel2abs;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_xtn_rel2abs().Name_(name);}
|
||||
public static final int Id_null = 0, Id_slash = 1, Id_dot = 2, Id_dot_slash = 3, Id_dot_dot = 4, Id_dot_dot_slash = 5;
|
||||
}
|
||||
/*
|
||||
NOTE_1:approach (easiest explained with an example)
|
||||
given qry = "../C/./D" and src = "A/B"
|
||||
. combine two into a pseudo-array: "A/B/../C/./D"
|
||||
. iterate over every slash to create "segs_ary"
|
||||
A -> [A] add
|
||||
B -> [A, B] add
|
||||
.. -> [A] pop
|
||||
C -> [A, C] add
|
||||
. -> [A, C] noop
|
||||
D -> [A, C, D] add
|
||||
*/
|
||||
68
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_rel2abs_tst.java
Normal file
68
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_rel2abs_tst.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_xtn_rel2abs_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Slash_lvl3() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/d|a/b/c}}" , "{{test}}" , "a/b/c/d");}
|
||||
@Test public void Cur_lvl1() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:./d|a}}" , "{{test}}" , "a/d");}
|
||||
@Test public void Cur_lvl2() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:./d|a/b}}" , "{{test}}" , "a/b/d");}
|
||||
@Test public void Cur_lvl3() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:./d|a/b/c}}" , "{{test}}" , "a/b/c/d");}
|
||||
@Test public void Owner_lvl3() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:../d|a/b/c}}" , "{{test}}" , "a/b/d");}
|
||||
@Test public void Owner_cur_lvl3() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:../.|a/b/c}}" , "{{test}}" , "a/b");}
|
||||
@Test public void Text_lvl3() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:d|a/b/c}}" , "{{test}}" , "d");}
|
||||
@Test public void Slash_mult() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/d//e|a/b/c}}" , "{{test}}" , "a/b/c/d/e");}
|
||||
@Test public void Slash_cur_mult() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/d/./e|a/b/c}}" , "{{test}}" , "a/b/c/d/e");}
|
||||
@Test public void Qry_ends_w_slash() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/d/|a/b/c}}" , "{{test}}" , "a/b/c/d");}
|
||||
@Test public void Qry_is_empty() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:|a/b/c}}" , "{{test}}" , "a/b/c");}
|
||||
@Test public void Qry_is_dot() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:.|a/b/c}}" , "{{test}}" , "a/b/c");}
|
||||
@Test public void DotDot_mult2() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/../..|a/b/c}}" , "{{test}}" , "a");}
|
||||
@Test public void DotDot_mult3() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/../../..|a/b/c}}" , "{{test}}" , "");}
|
||||
@Test public void Src_is_empty() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/d|}}" , "{{test}}" , "Test page/d");}
|
||||
@Test public void Err_owner() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:..}}" , "{{test}}" , "");} // PURPOSE.fix: should not fail
|
||||
@Test public void Err_owner_2() {fxt.Test_parse_tmpl_str_test("{{#rel2abs:/../../b|a}}" , "{{test}}" , "");} // PURPOSE.fix: should not fail
|
||||
@Test public void Ns_should_be_included_for_cur_page() {// PURPOSE.fix: current title was not returning ns; EX: de.wikipedia.org/wiki/Hilfe:Vorlagenprogrammierung#Funktion_rel2abs
|
||||
fxt.Page_ttl_("Help:A"); // set page to title with namespace
|
||||
fxt.Test_parse_tmpl_str_test("{{#rel2abs:.}}" , "{{test}}" , "Help:A");
|
||||
}
|
||||
@Test public void Owner_lvl0() {// PURPOSE.fix: old rel2abs was producing "/c"; EX: de.wikipedia.org/wiki/Hilfe:Vorlagenprogrammierung#Funktion_rel2abs
|
||||
fxt.Test_parse_tmpl_str_test("{{#rel2abs:../c|a}}" , "{{test}}" , "c");
|
||||
}
|
||||
@Test public void Rel2abs_slash() {
|
||||
fxt.Page_ttl_("Page_1");
|
||||
fxt.Init_defn_clear();
|
||||
fxt.Init_defn_add("test" , "{{/B}}");
|
||||
fxt.Init_page_create("Page_1/B" , "Page_1/B text");
|
||||
fxt.Test_parse_tmpl_str("{{test}}" , "Page_1/B text");
|
||||
fxt.Init_defn_clear();
|
||||
}
|
||||
@Test public void Rel2abs_dot() {
|
||||
fxt.Page_ttl_("Page_1/A");
|
||||
fxt.Init_defn_clear();
|
||||
fxt.Init_defn_add("test" , "{{../C}}");
|
||||
fxt.Init_page_create("Page_1/C" , "Page_1/C text");
|
||||
fxt.Test_parse_tmpl_str("{{test}}" , "Page_1/C text");
|
||||
fxt.Init_defn_clear();
|
||||
}
|
||||
@Test public void Rel2abs_ttl() {
|
||||
Tst_rel2abs_ttl("a../b", true);
|
||||
Tst_rel2abs_ttl("a../[b", false);
|
||||
}
|
||||
private void Tst_rel2abs_ttl(String raw, boolean expd) {Tfds.Eq(expd, Pf_xtn_rel2abs.Rel2abs_ttl(Bry_.new_ascii_(raw), 0, String_.Len(raw)));}
|
||||
}
|
||||
80
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_titleparts.java
Normal file
80
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_titleparts.java
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import gplx.core.ints.*; import gplx.xowa.xtns.pfuncs.times.*;
|
||||
class Pf_xtn_titleparts extends Pf_func_base {
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {// REF.MW:ParserFunctions_body.php
|
||||
// get argx
|
||||
int args_len = self.Args_len();
|
||||
byte[] argx = Eval_argx(ctx, src, caller, self); if (argx == null) return; // no argx; return empty
|
||||
Xoa_ttl argx_as_ttl = Xoa_ttl.new_(ctx.Wiki(), ctx.App().Msg_log_null(), argx, argx, 0, argx.length); // transform to title in order to upper first, replace _, etc..
|
||||
if (argx_as_ttl == null) {bb.Add(argx); return;} // NOTE: argx_as_ttl will be null if invalid, such as [[a|b]]; EX.WP:owl and {{taxobox/showtaxon|Dinosauria}}
|
||||
else argx = argx_as_ttl.Full_txt();
|
||||
|
||||
// get parts_len
|
||||
byte[] parts_len_ary = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, 0);
|
||||
int parts_len = parts_len_ary == Bry_.Empty ? Int_.MinValue : Bry_.X_to_int_or(parts_len_ary, Int_.MaxValue);
|
||||
if (parts_len == Int_.MaxValue) {// len is not an int; EX: "a";
|
||||
ctx.Msg_log().Add_itm_none(Pf_xtn_titleparts_log.Len_is_invalid, src, caller.Src_bgn(), caller.Src_end());
|
||||
bb.Add(argx);
|
||||
return;
|
||||
}
|
||||
|
||||
// get parts_bgn
|
||||
byte[] parts_bgn_arg = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, 1);
|
||||
int parts_bgn = parts_bgn_arg == Bry_.Empty ? 0 : Bry_.X_to_int_or(parts_bgn_arg, Int_.MinValue);
|
||||
if (parts_bgn == Int_.MinValue) {// parts_bgn is not an int; EX: "a"
|
||||
ctx.Msg_log().Add_itm_none(Pf_xtn_titleparts_log.Bgn_is_invalid, src, caller.Src_bgn(), caller.Src_end());
|
||||
parts_bgn = 0; // NOTE: do not return
|
||||
}
|
||||
else if (parts_bgn > 0) parts_bgn -= ListAdp_.Base1; // adjust for base1
|
||||
bb.Add(TitleParts(argx, parts_len, parts_bgn));
|
||||
}
|
||||
private byte[] TitleParts(byte[] src, int parts_len, int parts_bgn) {
|
||||
// find dlm positions; EX: ab/cde/f/ will have -1,2,6,8
|
||||
int src_len = src.length; int dlms_ary_len = 1; // 1 b/c dlms_ary[0] will always be -1
|
||||
for (int i = 0; i < src_len; i++) {
|
||||
if (src[i] == Byte_ascii.Slash) dlms_ary[dlms_ary_len++] = i;
|
||||
}
|
||||
dlms_ary[dlms_ary_len] = src_len; // put src_len into last dlms_ary; makes dlms_ary[] logic easier
|
||||
|
||||
// calc bgn_idx; must occur before adjust parts_len
|
||||
int bgn_idx = parts_bgn > -1 ? parts_bgn : parts_bgn + dlms_ary_len; // negative parts_bgn means calc from end of dlms_ary_len; EX a/b/c|1|-1 means start from 2
|
||||
if ( bgn_idx < 0 // bgn_idx can be negative when parts_len is negative and greater than array; EX: {{#titleparts:a/b|-1|-2}} results in dlms_ary_len of 1 and parts_bgn of -2 which will be parts_bgn of -1
|
||||
|| bgn_idx > dlms_ary_len) return Bry_.Empty; // if bgn > len, return ""; EX: {{#titleparts:a/b|1|3}} should return ""
|
||||
|
||||
// adjust parts_len for negative/null
|
||||
if (parts_len == Int_.MinValue) parts_len = dlms_ary_len; // no parts_len; default to dlms_ary_len
|
||||
else if (parts_len < 0) { // neg parts_len; shorten parts now and default to rest of String; EX: a/b/c|-1 -> makes String a/b/c and get 2 parts
|
||||
dlms_ary_len += parts_len;
|
||||
parts_len = dlms_ary_len;
|
||||
if (parts_len < 1) return Bry_.Empty; // NOTE: if zerod'd b/c of neg length, return empty; contrast with line below; EX: a/b/c|-4
|
||||
}
|
||||
if (parts_len == 0) return src; // if no dlms, return orig
|
||||
|
||||
// calc idxs for extraction
|
||||
int bgn_pos = dlms_ary[bgn_idx] + 1; // +1 to start after slash
|
||||
int end_idx = bgn_idx + parts_len;
|
||||
int end_pos = end_idx > dlms_ary_len ? dlms_ary[dlms_ary_len] : dlms_ary[end_idx];
|
||||
if (end_pos < bgn_pos) return Bry_.Empty;
|
||||
return Bry_.Mid(src, bgn_pos, end_pos);
|
||||
} static int[] dlms_ary = new Int_ary_bldr(255).Set(0, -1).Xto_int_ary(); // set pos0 to -1; makes +1 logic easier
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_titleparts;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_xtn_titleparts().Name_(name);}
|
||||
}
|
||||
81
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_titleparts_tst.java
Normal file
81
400_xowa/src_530_pf_str/gplx/xowa/Pf_xtn_titleparts_tst.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
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; import gplx.*;
|
||||
import org.junit.*;
|
||||
public class Pf_xtn_titleparts_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Len1() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|1}}" , "{{test}}", "A");}
|
||||
@Test public void Len2() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|2}}" , "{{test}}", "A/b");}
|
||||
@Test public void Len2_Bgn2() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|2|2}}" , "{{test}}", "b/c");}
|
||||
@Test public void LenNeg1() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|-1}}" , "{{test}}", "A/b/c");}
|
||||
@Test public void LenNeg1Bgn2() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|-1|2}}" , "{{test}}", "b/c");}
|
||||
|
||||
@Test public void Exc_len0() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|0}}" , "{{test}}", "A/b/c/d");}
|
||||
@Test public void Exc_lenNeg4() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|-4}}" , "{{test}}", "");}
|
||||
@Test public void Exc_lenNeg5() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|-5}}" , "{{test}}", "");}
|
||||
@Test public void Exc_no_dlm() {fxt.Test_parse_tmpl_str_test("{{#titleparts:abcd|1}}" , "{{test}}", "Abcd");}
|
||||
@Test public void Exc_parts0() {fxt.Test_parse_tmpl_str_test("{{#titleparts:abcd|0}}" , "{{test}}", "Abcd");}
|
||||
@Test public void Exc_many_segs() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b|1|4}}" , "{{test}}", "");} // PURPOSE: bgn=4, len=1 requested; only bgn=1,2 available
|
||||
|
||||
@Test public void Exc_bad_len() {fxt.Init_log_(Pf_xtn_titleparts_log.Len_is_invalid).Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|bad}}" , "{{test}}", "A/b/c/d");}
|
||||
@Test public void Exc_bad_bgn() {fxt.Init_log_(Pf_xtn_titleparts_log.Bgn_is_invalid).Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d|1|bad}}" , "{{test}}", "A");}
|
||||
@Test public void Exc_1() {fxt.Test_parse_tmpl_str_test("{{#titleparts:50|1|1}}" , "{{test}}", "50");}
|
||||
@Test public void Exc_2() {fxt.Test_parse_tmpl_str_test("{{#titleparts:50|1|2}}" , "{{test}}", "");}
|
||||
|
||||
@Test public void Lnki() {fxt.Test_parse_tmpl_str_test("{{#titleparts:[[a|b]]|1}}" , "{{test}}", "[[a|b]]");} // PURPOSE: invalid title was not being rendered
|
||||
@Test public void Invalid_table() {// PURPOSE: Template:Taxobox/showtaxon calls #titleparts on table fragments; do not remove new lines; EX.WP:Owl
|
||||
fxt.Init_defn_clear();
|
||||
fxt.Init_defn_add("!", "|");
|
||||
fxt.Init_defn_add("!!", "||");
|
||||
fxt.Test_parse_tmpl_str_test
|
||||
( String_.Concat_lines_nl_skip_last
|
||||
( "{|"
|
||||
, "|-"
|
||||
, "{{#titleparts:"
|
||||
, "{{!}} Order: {{!!}} '''Strigiformes'''"
|
||||
, "{{!}}-|1}}"
|
||||
, "|}"
|
||||
)
|
||||
, "{{test}}"
|
||||
, String_.Concat_lines_nl_skip_last
|
||||
( "" // NOTE: don't know why this new line is necessary, but hopefully it is benign
|
||||
, "{|"
|
||||
, "|-"
|
||||
, "| Order: || '''Strigiformes'''"
|
||||
, "|-"
|
||||
, "|}"
|
||||
)
|
||||
);
|
||||
}
|
||||
@Test public void Invalid_xml() {// PURPOSE: handle calls like {{#titleparts:a<span id='b'>c</span>d|1}}; EX.WP:Triceratops
|
||||
fxt.Test_parse_tmpl_str_test
|
||||
( "{{#titleparts:a<span id='b'>c</span>d/e|1}}"
|
||||
, "{{test}}"
|
||||
, "a<span id='b'>c</span>d/e"
|
||||
);
|
||||
}
|
||||
@Test public void Bgn_neg_1() {fxt.Test_parse_tmpl_str_test("{{#titleparts:a/b/c/d||-1}}" , "{{test}}", "d");}
|
||||
@Test public void Bgn_neg_2() { // PURPOSE: EX: Wikisource:Requests for comment/Annotations and derivative works; DATE:2013-12-19
|
||||
fxt.Test_parse_tmpl_str_test
|
||||
( "{{#titleparts:a/b|-1|-2}}"
|
||||
, "{{test}}"
|
||||
, "A"
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user