/* XOWA: the XOWA Offline Wiki Application Copyright (C) 2012-2017 gnosygnu@gmail.com XOWA is licensed under the terms of the General Public License (GPL) Version 3, or alternatively under the terms of the Apache License Version 2.0. You may use XOWA according to either of these licenses as is most appropriate for your project on a case-by-case basis. The terms of each license can be found in the source code repository: GPLv3 License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-GPLv3.txt Apache License: https://github.com/gnosygnu/xowa/blob/master/LICENSE-APACHE2.txt */ package gplx.xowa.parsers.tmpls; import gplx.*; import gplx.xowa.*; import gplx.xowa.parsers.*; import gplx.xowa.parsers.xndes.*; public class Xop_curly_wkr implements Xop_ctx_wkr { public void Ctor_ctx(Xop_ctx ctx) {} public void Page_bgn(Xop_ctx ctx, Xop_root_tkn root) {} public void Page_end(Xop_ctx ctx, Xop_root_tkn root, byte[] src, int src_len) {} public void AutoClose(Xop_ctx ctx, Xop_tkn_mkr tkn_mkr, Xop_root_tkn root, byte[] src, int src_len, int lxr_bgn_pos, int lxr_cur_pos, Xop_tkn_itm tkn) {} public int MakeTkn_bgn(Xop_ctx ctx, Xop_tkn_mkr tkn_mkr, Xop_root_tkn root, byte[] src, int src_len, int lxr_bgn_pos, int lxr_cur_pos) { int lxr_end_pos = Bry_find_.Find_fwd_while(src, lxr_cur_pos, src_len, Byte_ascii.Curly_bgn); // NOTE: can be many consecutive {; EX: {{{{{1}}}|a}} ctx.Subs_add_and_stack(root, tkn_mkr.Tmpl_curly_bgn(lxr_bgn_pos, lxr_end_pos)); return lxr_end_pos; } public int MakeTkn_end(Xop_ctx ctx, Xop_tkn_mkr tkn_mkr, Xop_root_tkn root, byte[] src, int src_len, int lxr_bgn_pos, int lxr_cur_pos) { if (ctx.Cur_tkn_tid() == Xop_tkn_itm_.Tid_brack_bgn) // WORKAROUND: ignore }} if inside lnki; EX.CM:Template:Protected; {{#switch:a|b=[[a|ja=}}]]}} return ctx.Lxr_make_txt_(lxr_cur_pos); int lxr_end_pos = Bry_find_.Find_fwd_while(src, lxr_cur_pos, src_len, Byte_ascii.Curly_end); // NOTE: can be many consecutive }; EX: {{a|{{{1}}}}} int end_tkn_len = lxr_end_pos - lxr_bgn_pos; boolean vnt_enabled = ctx.Wiki().Lang().Vnt_mgr().Enabled(); while (end_tkn_len > 0) { int acs_pos = -1, acs_len = ctx.Stack_len(); for (int i = acs_len - 1; i > -1; i--) { // find auto-close pos Xop_tkn_itm stack_tkn = ctx.Stack_get(i); switch (stack_tkn.Tkn_tid()) { case Xop_tkn_itm_.Tid_tmpl_curly_bgn: // found curly_bgn; mark and exit acs_pos = i; i = -1; break; case Xop_tkn_itm_.Tid_brack_bgn: // found no curly_bgn, but found brack_bgn; note that extra }} should not close any frames beyond lnki; EX:w:Template:Cite wikisource; w:John Fletcher (playwright) i = -1; break; case Xop_tkn_itm_.Tid_xnde: // found xnde; ignore; handle {{template|<poem>}}</poem>}} DATE:2014-03-03 Xop_xnde_tkn stack_xnde = (Xop_xnde_tkn)stack_tkn; if (stack_xnde.Tag().Xtn()) i = -1; break; } } if (acs_pos == -1) { // "}}+" found but no "{{+" found; warn and output literal tkn ctx.Msg_log().Add_itm_none(Xop_curly_log.Bgn_not_found, src, lxr_bgn_pos, lxr_end_pos); ctx.Subs_add(root, tkn_mkr.Txt(lxr_bgn_pos, lxr_end_pos)); return lxr_end_pos; } Xop_curly_bgn_tkn bgn_tkn = (Xop_curly_bgn_tkn)ctx.Stack_pop_til(root, src, acs_pos, true, lxr_bgn_pos, lxr_end_pos, Xop_tkn_itm_.Tid_tmpl_curly_bgn); // NOTE: in theory, an unclosed [[ can be on stack; for now, ignore int bgn_tkn_len = bgn_tkn.Src_end() - bgn_tkn.Src_bgn(); int bgn_tkn_pos_bgn = bgn_tkn.Src_bgn();// save original pos_bgn boolean vnt_dash_adjust = false; if (vnt_enabled ) { int curly_bgn_dash = bgn_tkn.Src_bgn() - 1; if (curly_bgn_dash > -1 && src[curly_bgn_dash] == Byte_ascii.Dash) { // "-" exists before curlies; EX: "-{{" int curly_end_dash = lxr_end_pos; if (curly_end_dash < src_len && src[curly_end_dash] == Byte_ascii.Dash) { // "-" exists after curlies; EX: "}}-" if (bgn_tkn_len > 2 && end_tkn_len > 2) { // more than 3 curlies at bgn / end with flanking dashes; EX: "-{{{ }}}-"; NOTE: 3 is needed b/c 2 will never be reduced; EX: "-{{" will always be "-" and "{{", not "-{" and "{" int numeric_val = Bry_.To_int_or(src, bgn_tkn.Src_end(), lxr_bgn_pos, -1); if ( numeric_val != -1 // do not apply if numeric val; EX:"-{{{0}}}-" vs "-{{{#expr:0}}}-" sr.w:Template:Link_FA && bgn_tkn_len == 3 && end_tkn_len == 3 // exactly 3 tokens; assume param token; "-{{{" -> "-" + "{{{" x> -> "-{" + "{{"; if unbalanced (3,4 or 4,3) fall into code below ) { } // noop; PAGE:sr.w:ДНК; EX:<span id="interwiki-{{{1}}}-fa"></span> DATE:2014-07-03 else { --bgn_tkn_len; // reduce bgn curlies by 1; EX: "{{{" -> "{{" ++bgn_tkn_pos_bgn; // add one to bgn tkn_pos; --end_tkn_len; // reduce end curlies by 1; EX: "}}}" -> "}}" --lxr_end_pos; // reduce end by 1; this will "reprocess" the final "}" as a text tkn; EX: "}}}-" -> "}}" and position before "}-" vnt_dash_adjust = true; } } } } } int new_tkn_len = 0; if (bgn_tkn_len == end_tkn_len) // exact match; should be majority of cases new_tkn_len = bgn_tkn_len; else if (bgn_tkn_len > end_tkn_len) // more bgn than end; use end, and deduct bgn; EX: {{{{{1}}}|a}} new_tkn_len = end_tkn_len; else /*bgn_tkn_len < end_tkn_len*/ // more end than bgn; use bgn, and deduct end; EX: {{a|{{{1}}}}} new_tkn_len = bgn_tkn_len; int keep_curly_bgn = 0; /* NOTE: this is a semi-hack; if bgn_tkn > new_tkn, then pretend bgn_tkn fits new_tkn, give to bldr, and then adjust back later EX: {{{{{1}}}|a}} -> bgn_tkn_len=5,new_tkn_len=3 -> change bgn(0, 5) to bgn(2, 5) The "correct" way is to insert a new_bgn_tkn after cur_bgn_tkn on root, but this would have performance implications: array would have to be resized, and all subs will have to be reindexed NOTE: bgn curlies should also be preserved if new_tkn_len > 3; EX: {{{{{{1}}}}}}; note that bgn = end, but len > 3 */ if (bgn_tkn_len > new_tkn_len || new_tkn_len > 3) { bgn_tkn.Tkn_ini_pos(false, bgn_tkn.Src_end() - new_tkn_len, bgn_tkn.Src_end()); keep_curly_bgn = 1; // preserves {{ } switch (new_tkn_len) { case 0: // EXC_CASE: should not happen; warn; ctx.Msg_log().Add_itm_none(Xop_curly_log.Bgn_len_0, src, bgn_tkn.Src_bgn(), lxr_end_pos); break; // case 1: // EXC_CASE: SEE:NOTE_1; // break; case 2: // USE_CASE: make invk_tkn ctx.Invk().Make_tkn(ctx, root, src, lxr_bgn_pos, lxr_bgn_pos + new_tkn_len, bgn_tkn, keep_curly_bgn); break; default: // USE_CASE: make prm_tkn; NOTE: 3 or more new_tkn_len = 3; // gobble 3 at a time; EX: 6 -> 3 -> 0; EX: 7 -> 4 -> 1; prm_wkr.Make_tkn(ctx, tkn_mkr, root, src, src_len, lxr_bgn_pos, lxr_bgn_pos + new_tkn_len, bgn_tkn, keep_curly_bgn); break; } switch (bgn_tkn_len - new_tkn_len) { // continuation of semi-hack above; some bgn still left over; adjust and throw back on stack case 1: // 1 tkn; convert curly to generic text tkn bgn_tkn.Src_end_(bgn_tkn.Src_end() - 1); // NOTE: shorten end of bgn_tkn by 1; TEST ctx.Stack_add(tkn_mkr.Txt(bgn_tkn_pos_bgn, bgn_tkn.Src_end() - new_tkn_len)); break; case 0: // noop break; default: bgn_tkn.Tkn_ini_pos(false, bgn_tkn_pos_bgn, bgn_tkn.Src_end() - new_tkn_len); // bgn(2, 5) -> bgn (0, 2) ctx.Stack_add(bgn_tkn); break; } if (vnt_dash_adjust) { Xop_tkn_itm text_tkn = root.Subs_get_or_null(root.Subs_len() - 2); // -2 to get tkn before newly-created tmpl / prm if (text_tkn == null || text_tkn.Tkn_tid() != Xop_tkn_itm_.Tid_txt) ctx.Wiki().Appe().Usr_dlg().Warn_many("", "", "token before curly_bgn was not text tkn; src=~{0}", String_.new_u8(src, lxr_bgn_pos, lxr_end_pos)); else text_tkn.Src_end_(text_tkn.Src_end() + 1); // +1 to extend txt_tkn with dash be 1 to include curly; EX: "-" "{{{" -> "-{" "{{" } end_tkn_len -= new_tkn_len; lxr_bgn_pos += new_tkn_len; // move lxr_bgn_pos along if (end_tkn_len == 1) { // SEE:NOTE_1: ctx.Subs_add(root, tkn_mkr.Txt(lxr_bgn_pos, lxr_bgn_pos + 1)); end_tkn_len = 0; ++lxr_bgn_pos; } } return lxr_end_pos; } private Xot_prm_wkr prm_wkr = Xot_prm_wkr.Instance; public static final byte[] Hook_prm_bgn = new byte[] {Byte_ascii.Curly_bgn, Byte_ascii.Curly_bgn, Byte_ascii.Curly_bgn} , Hook_prm_end = new byte[] {Byte_ascii.Curly_end, Byte_ascii.Curly_end, Byte_ascii.Curly_end}; } /* NOTE_1: . end_tkn_len = 1 can happen when 4 on either side, or other permutations; EX: {{{{leaf_1}}}}; . cannot put in switch(new_tkn_len) b/c the 1 } will pop any {{ or {{{ off stack; .. EX: "{{#switch:a|{{{1}}}}=y|n}}"; 4th } will pop {{ of #switch off stack .. make separate check near end */