1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00
This commit is contained in:
gnosygnu
2015-07-12 21:10:02 -04:00
commit 794b5a232f
3099 changed files with 238212 additions and 0 deletions

View 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.xtns.pfuncs.strings; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
public class Pfunc_case extends Pf_func_base { // EX: {{lc:A}} -> a
private boolean first; private int case_type;
public Pfunc_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 Pfunc_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__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);
}
}

View File

@@ -0,0 +1,40 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.strings; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
import gplx.xowa.langs.cases.*;
public class Pfunc_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
fxt.Wiki().Lang().Case_mgr_utf8_();
fxt.Test_parse_tmpl_str_test("{{uc:ĉ}}" , "{{test}}", "Ĉ"); // upper all
}
@Test public void Multi_byte_asymmetric() {
fxt.Wiki().Lang().Case_mgr_utf8_();
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() {
fxt.Wiki().Lang().Case_mgr_utf8_();
fxt.Test_parse_tmpl_str_test("{{ucfirst:провинция}}" , "{{test}}", "Провинция"); // upper first; DATE:2014-02-04
}
}

View File

@@ -0,0 +1,61 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.strings; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.intl.*;
public class Pfunc_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 = Utf8_.Len_of_bry(val); // NOTE: length must be in chars, not bytes, else won't work for non-ASCII chars; EX:niǎo has length of 4, not 5; PAGE:zh.d:不 DATE:2014-08-27
byte[] pad_len = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
int pad_len_int = Bry_.Xto_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 it 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_a7("0");
public Pfunc_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 Pfunc_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
*/

View 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.xtns.pfuncs.strings; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pfunc_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_word_3_utf8() {fxt.Test_parse_tmpl_str_test("{{padleft: niǎo|5}}" , "{{test}}" , "0niǎo");} // PURPOSE:use length of String in chars, not bytes; PAGE:zh.d:不 DATE:2014-08-27
@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ā");}
}

View File

@@ -0,0 +1,128 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.strings; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import gplx.xowa.html.*;
public class Pfunc_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 Pfunc_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();
Xoae_app app = ctx.App();
Bry_bfr tmp = app.Utl__bfr_mkr().Get_b512();
try {
int tag_idx = ++tag__next_id;
Xop_xnde_tag tag = (Xop_xnde_tag)app.Xnde_tag_regy().XndeNames(ctx.Xnde_names_tid()).Match_exact(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); // NOTE: must evaluate arg; don't try to parse arg_tkn's key / val separately; EX:{{#tag:pre|a|{{#switch:a|a=id}}=c}}
if (arg.length == 0) continue; // skip empty atrs
tmp.Add_byte(Byte_ascii.Space);
Pfunc_tag_kv_bldr.Add_arg_as_html_atr(arg, tmp);
}
}
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();}
}
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_a7("<xtag_bgn id='")
, Xtag_end_lhs = Bry_.new_a7("<xtag_end id='")
, Xtag_rhs = Bry_.new_a7("'/>")
;
private static int tag__next_id = 0; // NOTE:must be app-level variable, not page-level, b/c pre-compiled templates can reserve tag #s; PAGE:de.s:Seite:NewtonPrincipien.djvu/465 DATE:2015-02-03
}
class Pfunc_tag_kv_bldr {
public int Key_bgn() {return key_bgn;} private int key_bgn;
public int KeyEnd() {return key_end;} private int key_end;
public Pfunc_tag_kv_bldr 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 Pfunc_tag_kv_bldr 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;
}
public static void Add_arg_as_html_atr(byte[] src, Bry_bfr tmp) {
synchronized (kv_bldr) {
ParseKeyVal(src, kv_bldr);
if (kv_bldr.Val_bgn() == -1) return; // ignore atrs with empty vals: EX:{{#tag:ref||group=}} PAGE:ru.w:Колчак,_Александр_Васильевич DATE:2014-07-03
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();
}
}
private static void ParseKeyVal(byte[] src, Pfunc_tag_kv_bldr kv_bldr) {
kv_bldr.Clear(); // do not forget to clear; DATE:2014-07-20
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.Nl:// 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);
}
private static Pfunc_tag_kv_bldr kv_bldr = new Pfunc_tag_kv_bldr();
}

View File

@@ -0,0 +1,40 @@
/*
XOWA: the XOWA Offline Wiki Application
Copyright (C) 2012 gnosygnu@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package gplx.xowa.xtns.pfuncs.strings; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
import org.junit.*;
public class Pfunc_tag_tst {
@Before public void init() {fxt.Reset();} private Xop_fxt fxt = new Xop_fxt();
@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 Val_empty() {fxt.Test_html_full_str("{{#tag:pre|a|id=}}" , "<pre>a</pre>");} // PURPOSE: ignore atrs with no val; EX:{{#ref||group=}} PAGE:ru.w:Колчак,_Александр_Васильевич; DATE:2014-07-03
@Test public void Tmpl() {fxt.Test_html_full_str("{{#tag:pre|a|{{#switch:a|a=id}}=c}}" , "<pre id=\"c\">a</pre>");} // PURPOSE: args must be evaluated
@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>");
}
}