mirror of
https://github.com/gnosygnu/xowa.git
synced 2026-03-02 03:49:30 +00:00
v2.7.2.1
This commit is contained in:
24
400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func.java
Normal file
24
400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public interface Pf_func extends Xot_defn {
|
||||
int Id();
|
||||
void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb);
|
||||
boolean Func_require_colon_arg();
|
||||
Pf_func New(int id, byte[] name);
|
||||
}
|
||||
423
400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func_.java
Normal file
423
400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func_.java
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
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; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
import gplx.xowa.xtns.pfuncs.ifs.*; import gplx.xowa.xtns.pfuncs.times.*; import gplx.xowa.xtns.pfuncs.numbers.*; import gplx.xowa.xtns.pfuncs.ttls.*; import gplx.xowa.xtns.pfuncs.langs.*; import gplx.xowa.xtns.pfuncs.strings.*; import gplx.xowa.xtns.pfuncs.stringutils.*; import gplx.xowa.xtns.pfuncs.pages.*; import gplx.xowa.xtns.pfuncs.wikis.*;
|
||||
public class Pf_func_ {
|
||||
public static byte[] Eval_arg_or_empty(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, int self_args_len, int i) {return Eval_arg_or(ctx, src, caller, self, self_args_len, i, Bry_.Empty);}
|
||||
public static final byte Name_dlm = Byte_ascii.Colon;
|
||||
public static byte[] Eval_arg_or(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, int self_args_len, int i, byte[] or) {
|
||||
if (i >= self_args_len) return or;
|
||||
Bry_bfr bfr = Bry_bfr.new_();
|
||||
Arg_nde_tkn nde = self.Args_get_by_idx(i);
|
||||
nde.Key_tkn().Tmpl_evaluate(ctx, src, caller, bfr); // NOTE: must add key b/c parser functions do not have keys and some usages pass in xml_tkns; EX: {{#if|<a href='{{{1}}}'|}}; "<a href" should not be interpreted as key
|
||||
if (nde.KeyTkn_exists()) bfr.Add_byte(Byte_ascii.Eq);
|
||||
nde.Val_tkn().Tmpl_evaluate(ctx, src, caller, bfr);
|
||||
return bfr.Xto_bry_and_clear_and_trim();
|
||||
}
|
||||
public static byte[] Eval_val_or(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, int self_args_len, int i, byte[] or) {
|
||||
if (i >= self_args_len) return or;
|
||||
Bry_bfr bfr = Bry_bfr.new_();
|
||||
Arg_nde_tkn nde = self.Args_get_by_idx(i);
|
||||
nde.Val_tkn().Tmpl_evaluate(ctx, src, caller, bfr);
|
||||
return bfr.Xto_bry_and_clear_and_trim();
|
||||
}
|
||||
public static byte[] Eval_tkn(Bry_bfr bfr, Xop_ctx ctx, byte[] src, Xot_invk caller, Xop_tkn_itm tkn) {
|
||||
tkn.Tmpl_evaluate(ctx, src, caller, bfr);
|
||||
return bfr.Xto_bry_and_clear();
|
||||
}
|
||||
private static final Number_parser lhs_parser = new Number_parser().Hex_enabled_(true), rhs_parser = new Number_parser().Hex_enabled_(true);
|
||||
public static boolean Eq_(byte[] lhs, byte[] rhs) { // PATCH.PHP: php allows "003" == "3.0"; ASSUME: numbers are either int or int-like decimal; long, float, decimal not supported
|
||||
int lhs_len = lhs.length, rhs_len = rhs.length;
|
||||
boolean rv = true;
|
||||
if (lhs_len == rhs_len) {
|
||||
for (int i = 0; i < lhs_len; i++) {
|
||||
if (lhs[i] != rhs[i]) {
|
||||
rv = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rv) return true;
|
||||
}
|
||||
else if (lhs_len == 0 || rhs_len == 0) // one side is empty String and the other side is String; return false;
|
||||
return false;
|
||||
lhs_parser.Parse(lhs, 0, lhs_len);
|
||||
if (lhs_parser.Has_err()) return false;
|
||||
rhs_parser.Parse(rhs, 0, rhs_len);
|
||||
if (rhs_parser.Has_err()) return false;
|
||||
return lhs_parser.Has_frac() || rhs_parser.Has_frac() ? lhs_parser.Rv_as_dec().Eq(rhs_parser.Rv_as_dec()) : lhs_parser.Rv_as_int() == rhs_parser.Rv_as_int();
|
||||
}
|
||||
public static void Reg(gplx.xowa.langs.Xol_func_name_regy func_regy, Xol_lang lang) {
|
||||
Xol_kwd_mgr kwd_mgr = lang.Kwd_mgr();
|
||||
int[] kwd_ary = Ary_get(!lang.Kwd_mgr__strx());
|
||||
int len = kwd_ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int id = kwd_ary[i];
|
||||
func_regy.Reg_defn(kwd_mgr, id, Get_prototype(id));
|
||||
}
|
||||
}
|
||||
public static int[] Ary_get(boolean wmf) {
|
||||
if (wmf) return Ary_wmf;
|
||||
if (Ary_nonwmf == null) {
|
||||
List_adp list = List_adp_.new_();
|
||||
int len = Ary_wmf.length;
|
||||
for (int i = 0; i < len; ++i) {
|
||||
list.Add(Ary_wmf[i]);
|
||||
}
|
||||
list.Add_many
|
||||
( Xol_kwd_grp_.Id_strx_len
|
||||
, Xol_kwd_grp_.Id_strx_pos
|
||||
, Xol_kwd_grp_.Id_strx_rpos
|
||||
, Xol_kwd_grp_.Id_strx_sub
|
||||
, Xol_kwd_grp_.Id_strx_count
|
||||
, Xol_kwd_grp_.Id_strx_replace
|
||||
, Xol_kwd_grp_.Id_strx_explode
|
||||
, Xol_kwd_grp_.Id_strx_urldecode
|
||||
);
|
||||
Ary_nonwmf = (int[])list.To_ary_and_clear(int.class);
|
||||
}
|
||||
return Ary_nonwmf;
|
||||
}
|
||||
private static int[] Ary_nonwmf = null;
|
||||
private static final int[] Ary_wmf = new int[]
|
||||
{ Xol_kwd_grp_.Id_utc_year
|
||||
, Xol_kwd_grp_.Id_utc_month_int_len2
|
||||
, Xol_kwd_grp_.Id_utc_month_int
|
||||
, Xol_kwd_grp_.Id_utc_day_int_len2
|
||||
, Xol_kwd_grp_.Id_utc_day_int
|
||||
, Xol_kwd_grp_.Id_utc_hour
|
||||
, Xol_kwd_grp_.Id_utc_time
|
||||
, Xol_kwd_grp_.Id_utc_timestamp
|
||||
, Xol_kwd_grp_.Id_utc_week
|
||||
, Xol_kwd_grp_.Id_utc_dow
|
||||
, Xol_kwd_grp_.Id_utc_month_abrv
|
||||
, Xol_kwd_grp_.Id_utc_month_name
|
||||
, Xol_kwd_grp_.Id_utc_month_gen
|
||||
, Xol_kwd_grp_.Id_utc_day_name
|
||||
, Xol_kwd_grp_.Id_lcl_year
|
||||
, Xol_kwd_grp_.Id_lcl_month_int_len2
|
||||
, Xol_kwd_grp_.Id_lcl_month_int
|
||||
, Xol_kwd_grp_.Id_lcl_day_int_len2
|
||||
, Xol_kwd_grp_.Id_lcl_day_int
|
||||
, Xol_kwd_grp_.Id_lcl_hour
|
||||
, Xol_kwd_grp_.Id_lcl_time
|
||||
, Xol_kwd_grp_.Id_lcl_timestamp
|
||||
, Xol_kwd_grp_.Id_lcl_week
|
||||
, Xol_kwd_grp_.Id_lcl_dow
|
||||
, Xol_kwd_grp_.Id_lcl_month_abrv
|
||||
, Xol_kwd_grp_.Id_lcl_month_name
|
||||
, Xol_kwd_grp_.Id_lcl_month_gen
|
||||
, Xol_kwd_grp_.Id_lcl_day_name
|
||||
, Xol_kwd_grp_.Id_rev_year
|
||||
, Xol_kwd_grp_.Id_rev_month_int_len2
|
||||
, Xol_kwd_grp_.Id_rev_month_int
|
||||
, Xol_kwd_grp_.Id_rev_day_int_len2
|
||||
, Xol_kwd_grp_.Id_rev_day_int
|
||||
, Xol_kwd_grp_.Id_rev_timestamp
|
||||
, Xol_kwd_grp_.Id_ns_txt
|
||||
, Xol_kwd_grp_.Id_ns_url
|
||||
, Xol_kwd_grp_.Id_ns_subj_txt
|
||||
, Xol_kwd_grp_.Id_ns_subj_url
|
||||
, Xol_kwd_grp_.Id_ns_talk_txt
|
||||
, Xol_kwd_grp_.Id_ns_talk_url
|
||||
, Xol_kwd_grp_.Id_ttl_full_txt
|
||||
, Xol_kwd_grp_.Id_ttl_full_url
|
||||
, Xol_kwd_grp_.Id_ttl_page_txt
|
||||
, Xol_kwd_grp_.Id_ttl_base_txt
|
||||
, Xol_kwd_grp_.Id_ttl_page_url
|
||||
, Xol_kwd_grp_.Id_ttl_base_url
|
||||
, Xol_kwd_grp_.Id_ttl_leaf_txt
|
||||
, Xol_kwd_grp_.Id_ttl_leaf_url
|
||||
, Xol_kwd_grp_.Id_ttl_subj_txt
|
||||
, Xol_kwd_grp_.Id_ttl_subj_url
|
||||
, Xol_kwd_grp_.Id_ttl_talk_txt
|
||||
, Xol_kwd_grp_.Id_ttl_talk_url
|
||||
, Xol_kwd_grp_.Id_site_sitename
|
||||
, Xol_kwd_grp_.Id_site_servername
|
||||
, Xol_kwd_grp_.Id_site_server
|
||||
, Xol_kwd_grp_.Id_site_articlepath
|
||||
, Xol_kwd_grp_.Id_site_scriptpath
|
||||
, Xol_kwd_grp_.Id_site_stylepath
|
||||
, Xol_kwd_grp_.Id_site_contentlanguage
|
||||
, Xol_kwd_grp_.Id_site_directionmark
|
||||
, Xol_kwd_grp_.Id_site_currentversion
|
||||
, Xol_kwd_grp_.Id_num_pages
|
||||
, Xol_kwd_grp_.Id_num_articles
|
||||
, Xol_kwd_grp_.Id_num_files
|
||||
, Xol_kwd_grp_.Id_num_edits
|
||||
, Xol_kwd_grp_.Id_num_views
|
||||
, Xol_kwd_grp_.Id_num_users
|
||||
, Xol_kwd_grp_.Id_num_users_active
|
||||
, Xol_kwd_grp_.Id_num_admins
|
||||
, Xol_kwd_grp_.Id_rev_id
|
||||
, Xol_kwd_grp_.Id_rev_pagesize
|
||||
, Xol_kwd_grp_.Id_rev_user
|
||||
, Xol_kwd_grp_.Id_rev_protectionlevel
|
||||
, Xol_kwd_grp_.Id_page_displaytitle
|
||||
, Xol_kwd_grp_.Id_page_defaultsort
|
||||
, Xol_kwd_grp_.Id_noeditsection
|
||||
, Xol_kwd_grp_.Id_site_pagesincategory
|
||||
, Xol_kwd_grp_.Id_url_ns
|
||||
, Xol_kwd_grp_.Id_url_nse
|
||||
, Xol_kwd_grp_.Id_url_urlencode
|
||||
, Xol_kwd_grp_.Id_str_lc
|
||||
, Xol_kwd_grp_.Id_str_lcfirst
|
||||
, Xol_kwd_grp_.Id_str_uc
|
||||
, Xol_kwd_grp_.Id_str_ucfirst
|
||||
, Xol_kwd_grp_.Id_str_padleft
|
||||
, Xol_kwd_grp_.Id_str_padright
|
||||
, Xol_kwd_grp_.Id_str_formatnum
|
||||
, Xol_kwd_grp_.Id_str_formatdate
|
||||
, Xol_kwd_grp_.Id_url_localurl
|
||||
, Xol_kwd_grp_.Id_url_localurle
|
||||
, Xol_kwd_grp_.Id_url_fullurl
|
||||
, Xol_kwd_grp_.Id_url_fullurle
|
||||
, Xol_kwd_grp_.Id_url_filepath
|
||||
, Xol_kwd_grp_.Id_url_anchorencode
|
||||
, Xol_kwd_grp_.Id_i18n_plural
|
||||
, Xol_kwd_grp_.Id_misc_tag
|
||||
, Xol_kwd_grp_.Id_i18n_language
|
||||
, Xol_kwd_grp_.Id_i18n_int
|
||||
, Xol_kwd_grp_.Id_i18n_grammar
|
||||
, Xol_kwd_grp_.Id_i18n_gender
|
||||
, Xol_kwd_grp_.Id_xtn_expr
|
||||
, Xol_kwd_grp_.Id_xtn_if
|
||||
, Xol_kwd_grp_.Id_xtn_ifeq
|
||||
, Xol_kwd_grp_.Id_xtn_iferror
|
||||
, Xol_kwd_grp_.Id_xtn_ifexpr
|
||||
, Xol_kwd_grp_.Id_xtn_ifexist
|
||||
, Xol_kwd_grp_.Id_xtn_rel2abs
|
||||
, Xol_kwd_grp_.Id_xtn_switch
|
||||
, Xol_kwd_grp_.Id_xtn_time
|
||||
, Xol_kwd_grp_.Id_xtn_timel
|
||||
, Xol_kwd_grp_.Id_xtn_titleparts
|
||||
, Xol_kwd_grp_.Id_subst
|
||||
, Xol_kwd_grp_.Id_safesubst
|
||||
, Xol_kwd_grp_.Id_raw
|
||||
, Xol_kwd_grp_.Id_msg
|
||||
, Xol_kwd_grp_.Id_msgnw
|
||||
, Xol_kwd_grp_.Id_xowa_dbg
|
||||
, Xol_kwd_grp_.Id_xtn_geodata_coordinates
|
||||
, Xol_kwd_grp_.Id_url_canonicalurl
|
||||
, Xol_kwd_grp_.Id_url_canonicalurle
|
||||
, Xol_kwd_grp_.Id_lst
|
||||
, Xol_kwd_grp_.Id_lstx
|
||||
, Xol_kwd_grp_.Id_invoke
|
||||
, Xol_kwd_grp_.Id_property
|
||||
, Xol_kwd_grp_.Id_noexternallanglinks
|
||||
, Xol_kwd_grp_.Id_wbreponame
|
||||
, Xol_kwd_grp_.Id_ns_num
|
||||
, Xol_kwd_grp_.Id_page_id
|
||||
, Xol_kwd_grp_.Id_xowa
|
||||
, Xol_kwd_grp_.Id_mapSources_deg2dd
|
||||
, Xol_kwd_grp_.Id_mapSources_dd2dms
|
||||
, Xol_kwd_grp_.Id_mapSources_geoLink
|
||||
, Xol_kwd_grp_.Id_geoCrumbs_isin
|
||||
, Xol_kwd_grp_.Id_relatedArticles
|
||||
, Xol_kwd_grp_.Id_insider
|
||||
, Xol_kwd_grp_.Id_massMessage_target
|
||||
, Xol_kwd_grp_.Id_cascadingSources
|
||||
, Xol_kwd_grp_.Id_pendingChangeLevel
|
||||
, Xol_kwd_grp_.Id_pagesUsingPendingChanges
|
||||
, Xol_kwd_grp_.Id_bang
|
||||
};
|
||||
public static Xot_defn Get_prototype(int id) {
|
||||
switch (id) {
|
||||
case Xol_kwd_grp_.Id_utc_year:
|
||||
case Xol_kwd_grp_.Id_utc_month_int_len2:
|
||||
case Xol_kwd_grp_.Id_utc_month_int:
|
||||
case Xol_kwd_grp_.Id_utc_day_int_len2:
|
||||
case Xol_kwd_grp_.Id_utc_day_int:
|
||||
case Xol_kwd_grp_.Id_utc_hour:
|
||||
case Xol_kwd_grp_.Id_utc_time:
|
||||
case Xol_kwd_grp_.Id_utc_timestamp:
|
||||
case Xol_kwd_grp_.Id_utc_week:
|
||||
case Xol_kwd_grp_.Id_utc_dow: return Pft_func_date_int.Utc;
|
||||
case Xol_kwd_grp_.Id_utc_month_abrv: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_utc, DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_abrv_jan - Int_.Base1);
|
||||
case Xol_kwd_grp_.Id_utc_month_name: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_utc, DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_name_january - Int_.Base1);
|
||||
case Xol_kwd_grp_.Id_utc_month_gen: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_utc, DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_gen_january - Int_.Base1);
|
||||
case Xol_kwd_grp_.Id_utc_day_name: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_utc, DateAdp_.SegIdx_dayOfWeek, Xol_msg_itm_.Id_dte_dow_name_sunday);
|
||||
|
||||
case Xol_kwd_grp_.Id_lcl_year:
|
||||
case Xol_kwd_grp_.Id_lcl_month_int_len2:
|
||||
case Xol_kwd_grp_.Id_lcl_month_int:
|
||||
case Xol_kwd_grp_.Id_lcl_day_int_len2:
|
||||
case Xol_kwd_grp_.Id_lcl_day_int:
|
||||
case Xol_kwd_grp_.Id_lcl_hour:
|
||||
case Xol_kwd_grp_.Id_lcl_time:
|
||||
case Xol_kwd_grp_.Id_lcl_timestamp:
|
||||
case Xol_kwd_grp_.Id_lcl_week:
|
||||
case Xol_kwd_grp_.Id_lcl_dow: return Pft_func_date_int.Lcl;
|
||||
case Xol_kwd_grp_.Id_lcl_month_abrv: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_lcl, DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_abrv_jan - Int_.Base1);
|
||||
case Xol_kwd_grp_.Id_lcl_month_name: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_lcl, DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_name_january - Int_.Base1);
|
||||
case Xol_kwd_grp_.Id_lcl_month_gen: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_lcl, DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_gen_january - Int_.Base1);
|
||||
case Xol_kwd_grp_.Id_lcl_day_name: return new Pft_func_date_name(-1, Pft_func_date_int.Date_tid_lcl, DateAdp_.SegIdx_dayOfWeek, Xol_msg_itm_.Id_dte_dow_name_sunday);
|
||||
|
||||
case Xol_kwd_grp_.Id_rev_year:
|
||||
case Xol_kwd_grp_.Id_rev_month_int_len2:
|
||||
case Xol_kwd_grp_.Id_rev_month_int:
|
||||
case Xol_kwd_grp_.Id_rev_day_int_len2:
|
||||
case Xol_kwd_grp_.Id_rev_day_int:
|
||||
case Xol_kwd_grp_.Id_rev_timestamp: return Pft_func_date_int.Rev;
|
||||
|
||||
case Xol_kwd_grp_.Id_ns_num:
|
||||
case Xol_kwd_grp_.Id_ns_txt:
|
||||
case Xol_kwd_grp_.Id_ns_url:
|
||||
case Xol_kwd_grp_.Id_ns_subj_txt:
|
||||
case Xol_kwd_grp_.Id_ns_subj_url:
|
||||
case Xol_kwd_grp_.Id_ns_talk_txt:
|
||||
case Xol_kwd_grp_.Id_ns_talk_url:
|
||||
case Xol_kwd_grp_.Id_ttl_full_txt:
|
||||
case Xol_kwd_grp_.Id_ttl_full_url:
|
||||
case Xol_kwd_grp_.Id_ttl_page_txt:
|
||||
case Xol_kwd_grp_.Id_ttl_base_txt:
|
||||
case Xol_kwd_grp_.Id_ttl_page_url:
|
||||
case Xol_kwd_grp_.Id_ttl_base_url:
|
||||
case Xol_kwd_grp_.Id_ttl_leaf_txt:
|
||||
case Xol_kwd_grp_.Id_ttl_leaf_url:
|
||||
case Xol_kwd_grp_.Id_ttl_subj_txt:
|
||||
case Xol_kwd_grp_.Id_ttl_subj_url:
|
||||
case Xol_kwd_grp_.Id_ttl_talk_txt:
|
||||
case Xol_kwd_grp_.Id_ttl_talk_url: return Pfunc_ttl._;
|
||||
|
||||
case Xol_kwd_grp_.Id_site_sitename:
|
||||
case Xol_kwd_grp_.Id_site_servername:
|
||||
case Xol_kwd_grp_.Id_site_server:
|
||||
case Xol_kwd_grp_.Id_site_articlepath:
|
||||
case Xol_kwd_grp_.Id_site_scriptpath:
|
||||
case Xol_kwd_grp_.Id_site_stylepath:
|
||||
case Xol_kwd_grp_.Id_site_contentlanguage:
|
||||
case Xol_kwd_grp_.Id_site_directionmark:
|
||||
case Xol_kwd_grp_.Id_site_currentversion: return Pfunc_wiki_props._;
|
||||
|
||||
case Xol_kwd_grp_.Id_num_pages:
|
||||
case Xol_kwd_grp_.Id_num_articles:
|
||||
case Xol_kwd_grp_.Id_num_files:
|
||||
case Xol_kwd_grp_.Id_num_edits:
|
||||
case Xol_kwd_grp_.Id_num_views:
|
||||
case Xol_kwd_grp_.Id_num_users:
|
||||
case Xol_kwd_grp_.Id_num_users_active:
|
||||
case Xol_kwd_grp_.Id_num_admins: return Pfunc_wiki_stats._;
|
||||
|
||||
case Xol_kwd_grp_.Id_page_id:
|
||||
case Xol_kwd_grp_.Id_rev_id:
|
||||
case Xol_kwd_grp_.Id_rev_pagesize:
|
||||
case Xol_kwd_grp_.Id_rev_user:
|
||||
case Xol_kwd_grp_.Id_rev_protectionlevel: return Pfunc_rev_props._;
|
||||
case Xol_kwd_grp_.Id_page_displaytitle: return Pfunc_displaytitle._;
|
||||
case Xol_kwd_grp_.Id_page_defaultsort: return Pfunc_defaultsort._;
|
||||
case Xol_kwd_grp_.Id_noeditsection: return Pfunc_noeditsection._;
|
||||
case Xol_kwd_grp_.Id_site_pagesincategory: return Pfunc_pagesincategory._;
|
||||
|
||||
case Xol_kwd_grp_.Id_url_ns: return new Pfunc_ns(false);
|
||||
case Xol_kwd_grp_.Id_url_nse: return new Pfunc_ns(true);
|
||||
case Xol_kwd_grp_.Id_url_urlencode: return new Pfunc_urlencode();
|
||||
case Xol_kwd_grp_.Id_str_lc: return new Pfunc_case(Xol_lang.Tid_lower, false);
|
||||
case Xol_kwd_grp_.Id_str_lcfirst: return new Pfunc_case(Xol_lang.Tid_lower, true);
|
||||
case Xol_kwd_grp_.Id_str_uc: return new Pfunc_case(Xol_lang.Tid_upper, false);
|
||||
case Xol_kwd_grp_.Id_str_ucfirst: return new Pfunc_case(Xol_lang.Tid_upper, true);
|
||||
case Xol_kwd_grp_.Id_str_padleft: return new Pfunc_pad(Xol_kwd_grp_.Id_str_padleft, false);
|
||||
case Xol_kwd_grp_.Id_str_padright: return new Pfunc_pad(Xol_kwd_grp_.Id_str_padright, true);
|
||||
case Xol_kwd_grp_.Id_str_formatnum: return new Pf_formatnum();
|
||||
case Xol_kwd_grp_.Id_str_formatdate: return new Pft_func_formatdate();
|
||||
case Xol_kwd_grp_.Id_url_localurl: return new Pfunc_urlfunc(Xol_kwd_grp_.Id_url_localurl, Pfunc_urlfunc.Tid_local, false);
|
||||
case Xol_kwd_grp_.Id_url_localurle: return new Pfunc_urlfunc(Xol_kwd_grp_.Id_url_localurle, Pfunc_urlfunc.Tid_local, true);
|
||||
case Xol_kwd_grp_.Id_url_fullurl: return new Pfunc_urlfunc(Xol_kwd_grp_.Id_url_fullurl, Pfunc_urlfunc.Tid_full, false);
|
||||
case Xol_kwd_grp_.Id_url_fullurle: return new Pfunc_urlfunc(Xol_kwd_grp_.Id_url_fullurle, Pfunc_urlfunc.Tid_full, true);
|
||||
case Xol_kwd_grp_.Id_url_canonicalurl: return new Pfunc_urlfunc(Xol_kwd_grp_.Id_url_canonicalurl, Pfunc_urlfunc.Tid_canonical, false);
|
||||
case Xol_kwd_grp_.Id_url_canonicalurle: return new Pfunc_urlfunc(Xol_kwd_grp_.Id_url_canonicalurle, Pfunc_urlfunc.Tid_canonical, false);
|
||||
case Xol_kwd_grp_.Id_url_filepath: return new Pfunc_filepath();
|
||||
case Xol_kwd_grp_.Id_url_anchorencode: return new Pfunc_anchorencode();
|
||||
case Xol_kwd_grp_.Id_strx_len: return new Pfunc_len();
|
||||
case Xol_kwd_grp_.Id_strx_pos: return new Pfunc_pos();
|
||||
case Xol_kwd_grp_.Id_strx_rpos: return new Pfunc_rpos();
|
||||
case Xol_kwd_grp_.Id_strx_sub: return new Pfunc_sub();
|
||||
case Xol_kwd_grp_.Id_strx_count: return new Pfunc_count();
|
||||
case Xol_kwd_grp_.Id_strx_replace: return new Pfunc_replace();
|
||||
case Xol_kwd_grp_.Id_strx_explode: return new Pfunc_explode();
|
||||
case Xol_kwd_grp_.Id_strx_urldecode: return new Pfunc_urldecode();
|
||||
|
||||
case Xol_kwd_grp_.Id_i18n_plural: return new Pfunc_plural();
|
||||
case Xol_kwd_grp_.Id_i18n_language: return new Pfunc_language();
|
||||
case Xol_kwd_grp_.Id_i18n_int: return new Pfunc_int();
|
||||
case Xol_kwd_grp_.Id_i18n_grammar: return new Pfunc_grammar();
|
||||
case Xol_kwd_grp_.Id_i18n_gender: return new Pfunc_gender();
|
||||
case Xol_kwd_grp_.Id_misc_tag: return new Pfunc_tag();
|
||||
|
||||
case Xol_kwd_grp_.Id_xtn_expr: return new gplx.xowa.xtns.pfuncs.exprs.Pfunc_expr();
|
||||
case Xol_kwd_grp_.Id_xtn_if: return new Pfunc_if();
|
||||
case Xol_kwd_grp_.Id_xtn_ifeq: return new Pfunc_ifeq();
|
||||
case Xol_kwd_grp_.Id_xtn_iferror: return new Pfunc_iferror();
|
||||
case Xol_kwd_grp_.Id_xtn_ifexpr: return new Pfunc_ifexpr();
|
||||
case Xol_kwd_grp_.Id_xtn_ifexist: return new Pfunc_ifexist();
|
||||
case Xol_kwd_grp_.Id_xtn_rel2abs: return new Pfunc_rel2abs();
|
||||
case Xol_kwd_grp_.Id_xtn_switch: return new Pfunc_switch();
|
||||
case Xol_kwd_grp_.Id_xtn_time: return Pft_func_time._Utc;
|
||||
case Xol_kwd_grp_.Id_xtn_timel: return Pft_func_time._Lcl;
|
||||
case Xol_kwd_grp_.Id_xtn_titleparts: return new Pfunc_titleparts();
|
||||
|
||||
case Xol_kwd_grp_.Id_subst:
|
||||
case Xol_kwd_grp_.Id_safesubst:
|
||||
case Xol_kwd_grp_.Id_msg:
|
||||
case Xol_kwd_grp_.Id_msgnw:
|
||||
case Xol_kwd_grp_.Id_raw: return new Xot_defn_subst((byte)id, Bry_.Empty);
|
||||
|
||||
case Xol_kwd_grp_.Id_xowa_dbg: return new Xop_xowa_dbg();
|
||||
case Xol_kwd_grp_.Id_xowa: return new gplx.xowa.xtns.xowa_cmds.Xop_xowa_func();
|
||||
case Xol_kwd_grp_.Id_xtn_geodata_coordinates: return gplx.xowa.xtns.geodata.Geo_coordinates_func._;
|
||||
case Xol_kwd_grp_.Id_lst: return gplx.xowa.xtns.lst.Lst_pfunc_lst._;
|
||||
case Xol_kwd_grp_.Id_lstx: return gplx.xowa.xtns.lst.Lst_pfunc_lstx._;
|
||||
case Xol_kwd_grp_.Id_invoke: return new gplx.xowa.xtns.scribunto.Scrib_invoke_func();
|
||||
|
||||
case Xol_kwd_grp_.Id_property: return new gplx.xowa.xtns.wdatas.pfuncs.Wdata_pf_property();
|
||||
case Xol_kwd_grp_.Id_noexternallanglinks: return new gplx.xowa.xtns.wdatas.pfuncs.Wdata_pf_noExternalLangLinks();
|
||||
case Xol_kwd_grp_.Id_wbreponame: return new gplx.xowa.xtns.wdatas.pfuncs.Wdata_pf_wbreponame();
|
||||
|
||||
case Xol_kwd_grp_.Id_mapSources_deg2dd: return gplx.xowa.xtns.mapSources.Map_deg2dd_func._;
|
||||
case Xol_kwd_grp_.Id_mapSources_dd2dms: return gplx.xowa.xtns.mapSources.Map_dd2dms_func._;
|
||||
case Xol_kwd_grp_.Id_mapSources_geoLink: return gplx.xowa.xtns.mapSources.Map_geolink_func._;
|
||||
|
||||
case Xol_kwd_grp_.Id_geoCrumbs_isin: return gplx.xowa.xtns.geoCrumbs.Geoc_isin_func._;
|
||||
|
||||
case Xol_kwd_grp_.Id_relatedArticles: return gplx.xowa.xtns.relatedArticles.Articles_func._;
|
||||
case Xol_kwd_grp_.Id_insider: return gplx.xowa.xtns.insiders.Insider_func._;
|
||||
|
||||
case Xol_kwd_grp_.Id_massMessage_target: return gplx.xowa.xtns.massMessage.Message_target_func._;
|
||||
|
||||
case Xol_kwd_grp_.Id_pendingChangeLevel: return gplx.xowa.xtns.flaggedRevs.Pending_change_level_func._;
|
||||
case Xol_kwd_grp_.Id_pagesUsingPendingChanges: return gplx.xowa.xtns.flaggedRevs.Pages_using_pending_changes_func._;
|
||||
|
||||
case Xol_kwd_grp_.Id_cascadingSources:
|
||||
return new Pf_func_noop(id);
|
||||
case Xol_kwd_grp_.Id_bang: return Pf_func_bang._;
|
||||
default: throw Exc_.new_unhandled(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
class Pf_func_noop extends Pf_func_base {
|
||||
public Pf_func_noop(int id) {this.id = id;} private int id;
|
||||
@Override public int Id() {return id;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_func_noop(id).Name_(name);}
|
||||
}
|
||||
class Pf_func_bang extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_bang;}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {bfr.Add_byte_pipe();}
|
||||
@Override public Pf_func New(int id, byte[] name) {return this;}
|
||||
public static final Pf_func_bang _ = new Pf_func_bang();
|
||||
Pf_func_bang() {this.Name_(Byte_ascii.Bang_bry);}
|
||||
}
|
||||
71
400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func_base.java
Normal file
71
400_xowa/src/gplx/xowa/xtns/pfuncs/Pf_func_base.java
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
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; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*;
|
||||
public abstract class Pf_func_base implements Pf_func {
|
||||
public byte Defn_tid() {return Xot_defn_.Tid_func;}
|
||||
public byte[] Name() {return name;} public Pf_func_base Name_(byte[] v) {name = v; name_len = v.length; return this;} private byte[] name = Bry_.Empty; int name_len = 0;
|
||||
@gplx.Virtual public boolean Func_require_colon_arg() {return false;}
|
||||
public boolean Defn_require_colon_arg() {return this.Func_require_colon_arg();}
|
||||
public int Cache_size() {return 1024;} // arbitrary size
|
||||
public abstract int Id();
|
||||
public void Rls() {name = null; argx_dat = null;}
|
||||
public abstract Pf_func New(int id, byte[] name);
|
||||
public Xot_defn Clone(int id, byte[] name) {return New(id, name);}
|
||||
public abstract void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr);
|
||||
public byte[] Argx_dat() {return argx_dat;} public void Argx_dat_(byte[] v) {argx_dat = v;} private byte[] argx_dat = Bry_.Empty;
|
||||
public byte[] Eval_argx(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self) {
|
||||
if (argx_dat == Bry_.Empty) {
|
||||
Arg_itm_tkn name_val_tkn = self.Name_tkn().Val_tkn();
|
||||
int subs_len = name_val_tkn.Subs_len();
|
||||
if (subs_len > 0) {
|
||||
Bry_bfr tmp = Bry_bfr.new_();
|
||||
for (int i = 0; i < subs_len; i++)
|
||||
name_val_tkn.Subs_get(i).Tmpl_evaluate(ctx, src, caller, tmp);
|
||||
argx_dat = tmp.Xto_bry_and_clear_and_trim();
|
||||
}
|
||||
}
|
||||
return argx_dat;
|
||||
}
|
||||
public byte[] Eval_argx_or_null(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, byte[] func_name) {
|
||||
if (argx_dat == Bry_.Empty) {
|
||||
Arg_nde_tkn name_tkn = self.Name_tkn();
|
||||
Arg_itm_tkn name_val_tkn = name_tkn.Val_tkn();
|
||||
int subs_len = name_val_tkn.Subs_len();
|
||||
if (subs_len == 0) { // no subs; either {{#func}} or {{#func:}}
|
||||
int src_bgn = name_tkn.Src_bgn();
|
||||
int colon_pos = Bry_finder.Find_bwd(src, Byte_ascii.Colon, self.Src_end(), src_bgn); // look for ":"; NOTE: used to be src_bgn - 1, but this would always search one character too many; DATE:2014-02-11
|
||||
if (colon_pos == Bry_.NotFound) // no colon; EX: {{#func}}
|
||||
return Eval_arg_or_null_is_null;
|
||||
else { // colon found; EX: {{#func:}}
|
||||
if (Bry_.Match_bwd_any(src, colon_pos - 1, src_bgn - 1, func_name)) // #func == func_name; EX: {{NAMESPACE:}}
|
||||
return Eval_arg_or_null_is_empty;
|
||||
else // #func != func_name; assume subst: or safesubst:; EX: {{safesubst:NAMESPACE}}; NOTE: can check subst / safesubs trie, but will be expensive; also, only Pfunc_ttl calls this function
|
||||
return Eval_arg_or_null_is_null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Bry_bfr tmp = Bry_bfr.new_();
|
||||
for (int i = 0; i < subs_len; i++)
|
||||
name_val_tkn.Subs_get(i).Tmpl_evaluate(ctx, src, caller, tmp);
|
||||
argx_dat = tmp.Xto_bry_and_clear_and_trim();
|
||||
}
|
||||
}
|
||||
return argx_dat;
|
||||
}
|
||||
public static final byte[] Eval_arg_or_null_is_null = null, Eval_arg_or_null_is_empty = Bry_.Empty;
|
||||
}
|
||||
44
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr.java
Normal file
44
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr.java
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.pfuncs.exprs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_expr 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) {
|
||||
byte[] val_dat_ary = Eval_argx(ctx, src, caller, self); if (val_dat_ary == Bry_.Empty) return;
|
||||
Evaluate(bfr, ctx, val_dat_ary);
|
||||
}
|
||||
public static boolean Evaluate(Bry_bfr bfr, Xop_ctx ctx, byte[] expr) {
|
||||
DecimalAdp rslt = shunter.Evaluate(ctx, expr); // NOTE: php uses "float" but really is a double; http://www.php.net/manual/en/language.types.float.php
|
||||
if (rslt == Pfunc_expr_shunter.Null_rslt) {
|
||||
bfr.Add_bfr_and_preserve(shunter.Err());
|
||||
shunter.Err().Clear();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
bfr.Add_str(rslt.Xto_str());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private static Pfunc_expr_shunter shunter = Pfunc_expr_shunter._;
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_expr;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_expr().Name_(name);}
|
||||
}
|
||||
class Pfunc_expr_msg {
|
||||
public static final Gfo_msg_grp Nde = Gfo_msg_grp_.new_(Xoa_app_.Nde, "expr");
|
||||
public static final Gfo_msg_itm Unknown = Gfo_msg_itm_.new_warn_(Nde, "unknown", "unknown");
|
||||
}
|
||||
545
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_ops.java
Normal file
545
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_ops.java
Normal file
@@ -0,0 +1,545 @@
|
||||
/*
|
||||
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.exprs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
interface Expr_tkn {
|
||||
int Tid();
|
||||
byte[] Val_ary();
|
||||
String Val_str();
|
||||
}
|
||||
class Expr_tkn_ {
|
||||
public static final int Tid_operator = 1, Tid_paren_lhs = 5, Tid_paren_rhs = 6, Tid_space = 7, Tid_number = 8;
|
||||
}
|
||||
interface Func_tkn extends Expr_tkn {
|
||||
boolean Func_is_const();
|
||||
int ArgCount();
|
||||
int Precedence();
|
||||
Func_tkn GetAlt();
|
||||
boolean Calc(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack);
|
||||
}
|
||||
class Ws_tkn implements Expr_tkn {
|
||||
public int Tid() {return Expr_tkn_.Tid_space;}
|
||||
public byte[] Val_ary() {return val_ary;} private byte[] val_ary;
|
||||
public String Val_str() {return val_str;} private String val_str;
|
||||
public Ws_tkn(byte b) {this.val_ary = new byte[] {b}; this.val_str = Char_.XtoStr(Char_.XbyInt(b));}
|
||||
}
|
||||
class Paren_bgn_tkn implements Expr_tkn, Func_tkn {
|
||||
public int Tid() {return Expr_tkn_.Tid_paren_lhs;}
|
||||
public boolean Func_is_const() {return false;}
|
||||
public byte[] Val_ary() {return val_ary;} private byte[] val_ary = Bry_.new_u8(val_str);
|
||||
public String Val_str() {return val_str;} static final String val_str = "(";
|
||||
public int ArgCount() {return 0;}
|
||||
public int Precedence() {return -1;}
|
||||
public Func_tkn GetAlt() {return this;}
|
||||
public boolean Calc(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {throw Exc_.new_unimplemented();}
|
||||
public static Paren_bgn_tkn _ = new Paren_bgn_tkn(); Paren_bgn_tkn() {}
|
||||
}
|
||||
class Paren_end_tkn implements Expr_tkn {
|
||||
public int Tid() {return Expr_tkn_.Tid_paren_rhs;}
|
||||
public byte[] Val_ary() {return val_ary;} private byte[] val_ary = Bry_.new_u8(val_str);
|
||||
public String Val_str() {return val_str;} static final String val_str = ")";
|
||||
public static Paren_end_tkn _ = new Paren_end_tkn(); Paren_end_tkn() {}
|
||||
}
|
||||
class Num_tkn implements Expr_tkn {
|
||||
public int Tid() {return Expr_tkn_.Tid_number;}
|
||||
public byte[] Val_ary() {return val_ary;} private byte[] val_ary;
|
||||
public String Val_str() {return String_.new_u8(val_ary);}
|
||||
public Num_tkn(int val_int) {
|
||||
this.val_int = val_int;
|
||||
this.val_ary = new byte[] {Byte_.By_int(val_int + Byte_ascii.Num_0)};
|
||||
} int val_int;
|
||||
}
|
||||
class Dot_tkn implements Expr_tkn {
|
||||
public int Tid() {return Expr_tkn_.Tid_number;}
|
||||
public byte[] Val_ary() {return Val_Ary;} static final byte[] Val_Ary = new byte[] {Byte_ascii.Dot};
|
||||
public String Val_str() {return String_.new_u8(Val_Ary);}
|
||||
public Dot_tkn() {}
|
||||
}
|
||||
class Val_stack {
|
||||
public void Clear() {stack_len = 0;}
|
||||
public int Len() {return stack_len;}
|
||||
public DecimalAdp Pop() {
|
||||
int stack_len_new = stack_len - 1;
|
||||
DecimalAdp rv = stack[stack_len_new];
|
||||
stack_len = stack_len_new;
|
||||
return rv;
|
||||
}
|
||||
public void Push(DecimalAdp v) {
|
||||
int stack_len_new = stack_len + 1;
|
||||
if (stack_len_new > stack_max) {
|
||||
stack_max = stack_len_new * 2;
|
||||
stack = (DecimalAdp[])Array_.Resize(stack, stack_max);
|
||||
}
|
||||
stack[stack_len] = v;
|
||||
stack_len = stack_len_new;
|
||||
}
|
||||
DecimalAdp[] stack = new DecimalAdp[0]; int stack_len = 0, stack_max = 0;
|
||||
}
|
||||
class Func_tkn_stack {
|
||||
public void Clear() {stack_len = 0;}
|
||||
public int Len() {return stack_len;}
|
||||
public Func_tkn GetLast() {return stack_len == 0 ? null : stack[stack_len - 1];}
|
||||
public Func_tkn Pop() {
|
||||
int stack_len_new = stack_len - 1;
|
||||
Func_tkn rv = stack[stack_len_new];
|
||||
stack_len = stack_len_new;
|
||||
return rv;
|
||||
}
|
||||
public void Push(Func_tkn v) {
|
||||
int stack_len_new = stack_len + 1;
|
||||
if (stack_len_new > stack_max) {
|
||||
stack_max = stack_len_new * 2;
|
||||
stack = (Func_tkn[])Array_.Resize(stack, stack_max);
|
||||
}
|
||||
stack[stack_len] = v;
|
||||
stack_len = stack_len_new;
|
||||
}
|
||||
Func_tkn[] stack = new Func_tkn[0]; int stack_len = 0, stack_max = 0;
|
||||
}
|
||||
abstract class Func_tkn_base implements Func_tkn {
|
||||
public int Tid() {return Expr_tkn_.Tid_operator;}
|
||||
public abstract int Precedence();
|
||||
public abstract int ArgCount();
|
||||
@gplx.Virtual public boolean Func_is_const() {return false;}
|
||||
public void Ctor(String v) {val_ary = Bry_.new_u8(v);}
|
||||
public byte[] Val_ary() {return val_ary;} private byte[] val_ary;
|
||||
public String Val_str() {return String_.new_u8(Val_ary());}
|
||||
@gplx.Virtual public Func_tkn GetAlt() {return this;}
|
||||
public boolean Calc(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
if (val_stack.Len() < this.ArgCount()) {shunter.Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_missing_operand, Val_ary()); return false;}
|
||||
return Calc_hook(ctx, shunter, val_stack);
|
||||
}
|
||||
public abstract boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack);
|
||||
}
|
||||
class Func_tkn_plus extends Func_tkn_base {
|
||||
public Func_tkn_plus(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 6;}
|
||||
@Override public Func_tkn GetAlt() {return Func_tkn_plus_positive._;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Op_add(rhs));
|
||||
return true;
|
||||
}
|
||||
public static final Func_tkn_plus _ = new Func_tkn_plus(); Func_tkn_plus() {}
|
||||
}
|
||||
class Func_tkn_plus_positive extends Func_tkn_base {
|
||||
Func_tkn_plus_positive(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 10;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {return true;}// effectively a noop
|
||||
public static final Func_tkn_plus_positive _ = new Func_tkn_plus_positive("+");
|
||||
}
|
||||
class Func_tkn_minus extends Func_tkn_base {
|
||||
public Func_tkn_minus(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 6;}
|
||||
@Override public Func_tkn GetAlt() {return Func_tkn_minus_negative._;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Op_subtract(rhs));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_minus_negative extends Func_tkn_base {
|
||||
public Func_tkn_minus_negative(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 10;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(val.Op_mult(DecimalAdp_.Neg1));
|
||||
return true;
|
||||
}
|
||||
public static final Func_tkn_minus_negative _ = new Func_tkn_minus_negative("-");
|
||||
}
|
||||
class Func_tkn_divide extends Func_tkn_base {
|
||||
public Func_tkn_divide(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 7;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
if (rhs.Eq(0)) {
|
||||
shunter.Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_division_by_zero);
|
||||
return false;
|
||||
}
|
||||
val_stack.Push(lhs.Op_divide(rhs));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_times extends Func_tkn_base {
|
||||
public Func_tkn_times(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 7;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Op_mult(rhs));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_pow extends Func_tkn_base {
|
||||
public Func_tkn_pow(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 8;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
int rhs_int = rhs.Xto_int();
|
||||
if ((double)rhs_int == rhs.Xto_double()) // exponent is integer; use decimal pow which does less casts to double
|
||||
val_stack.Push(lhs.Op_pow(rhs_int));
|
||||
else {
|
||||
double rslt = Math_.Pow(lhs.Xto_double(), rhs.Xto_double());
|
||||
if (Double_.IsNaN(rslt)) {
|
||||
shunter.Rslt_set(Double_.NaN_bry);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
val_stack.Push(DecimalAdp_.double_thru_str_(rslt));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_e_op extends Func_tkn_base {
|
||||
public Func_tkn_e_op(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 9;} // NOTE: needs to be < than - sign
|
||||
@Override public Func_tkn GetAlt() {return Func_tkn_e_const._;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
int rhs_int = rhs.Xto_int();
|
||||
if ( rhs_int > 308
|
||||
|| (lhs.Xto_double() >= 1.8f && rhs_int == 308)) { // PHP:"maximum of ~1.8e308"; verified with {{#expr:1.8e308}} on sandbox; REF:http://php.net/manual/en/language.types.float.php; PAGE:en.w:Factorial; en.w:Astatine; DATE:2015-04-08; DATE:2015-04-21
|
||||
shunter.Rslt_set(Double_.Inf_pos_bry);
|
||||
return false;
|
||||
}
|
||||
double rhs_double = rhs.Xto_double();
|
||||
if ((double)rhs_int == rhs_double) // exponent is integer; use pow_10 which does less casts to double
|
||||
val_stack.Push(lhs.Op_mult(DecimalAdp_.pow_10_(rhs_int)));
|
||||
else
|
||||
val_stack.Push(lhs.Op_mult(DecimalAdp_.double_thru_str_(Math_.Pow(10d, rhs_double))));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_mod extends Func_tkn_base {
|
||||
public Func_tkn_mod(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 7;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
// must convert to int else issues with {{#expr:0.00999999mod10}} and {{USCensusPop|1960=763956|1970=756510}}; REF: http://php.net/manual/en/language.operators.arithmetic.php: "Operands of modulus are converted to integers (by stripping the decimal part) before processing"
|
||||
// must convert to long else issues with (39052000900/1) mod 100 which should be 0, not 47; JAVA does not fail int conversion, and instead converts to Int_.MaxValue; EX: de.w:Quijano_(Pi<50>lagos)
|
||||
long rhs = ((DecimalAdp)val_stack.Pop()).Xto_long();
|
||||
long lhs = ((DecimalAdp)val_stack.Pop()).Xto_long();
|
||||
if (rhs == 0) {
|
||||
shunter.Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_division_by_zero);
|
||||
return false;
|
||||
}
|
||||
val_stack.Push(DecimalAdp_.long_(lhs % rhs));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_eq extends Func_tkn_base {
|
||||
public Func_tkn_eq(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 4;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Eq(rhs) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_neq extends Func_tkn_base {
|
||||
public Func_tkn_neq(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 4;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Eq(rhs) ? DecimalAdp_.Zero : DecimalAdp_.One);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_gt extends Func_tkn_base {
|
||||
public Func_tkn_gt(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 4;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Comp_gt(rhs) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_lt extends Func_tkn_base {
|
||||
public Func_tkn_lt(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 4;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Comp_lt(rhs) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_gte extends Func_tkn_base {
|
||||
public Func_tkn_gte(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 4;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Comp_gte(rhs) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_lte extends Func_tkn_base {
|
||||
public Func_tkn_lte(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 4;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(lhs.Comp_lte(rhs) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_and extends Func_tkn_base {
|
||||
public Func_tkn_and(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 3;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(!lhs.Eq(0) && !rhs.Eq(0) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_or extends Func_tkn_base {
|
||||
public Func_tkn_or(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 2;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
val_stack.Push(!lhs.Eq(0) || !rhs.Eq(0) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_not extends Func_tkn_base {
|
||||
public Func_tkn_not(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(val.Eq(0) ? DecimalAdp_.One : DecimalAdp_.Zero);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_e_const extends Func_tkn_base {
|
||||
public Func_tkn_e_const(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 0;}
|
||||
@Override public int Precedence() {return 0;}
|
||||
@Override public boolean Func_is_const() {return true;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
val_stack.Push(DecimalAdp_.Const_e);
|
||||
return true;
|
||||
}
|
||||
public static final Func_tkn_e_const _ = new Func_tkn_e_const("e");
|
||||
}
|
||||
class Func_tkn_pi extends Func_tkn_base {
|
||||
public Func_tkn_pi(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 0;}
|
||||
@Override public int Precedence() {return 0;}
|
||||
@Override public boolean Func_is_const() {return true;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
val_stack.Push(DecimalAdp_.Const_pi);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_ceil extends Func_tkn_base {
|
||||
public Func_tkn_ceil(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Ceil(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_trunc extends Func_tkn_base {
|
||||
public Func_tkn_trunc(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Trunc(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_floor extends Func_tkn_base {
|
||||
public Func_tkn_floor(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Floor(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_abs extends Func_tkn_base {
|
||||
public Func_tkn_abs(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(val.Op_abs());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_exp extends Func_tkn_base {
|
||||
public Func_tkn_exp(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Exp(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_ln extends Func_tkn_base {
|
||||
public Func_tkn_ln(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
if (val.Comp_lte(0)) {shunter.Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_invalid_argument_ln); return false;}
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Log(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_sin extends Func_tkn_base {
|
||||
public Func_tkn_sin(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Sin(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_cos extends Func_tkn_base {
|
||||
public Func_tkn_cos(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Cos(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_tan extends Func_tkn_base {
|
||||
public Func_tkn_tan(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Tan(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_asin extends Func_tkn_base {
|
||||
public Func_tkn_asin(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
if (val.Comp_lt(-1) || val.Comp_gt(1)) {shunter.Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_invalid_argument, this.Val_ary()); return false;}
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Asin(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_acos extends Func_tkn_base {
|
||||
public Func_tkn_acos(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
if (val.Comp_lt(-1) || val.Comp_gt(1)) {shunter.Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_invalid_argument, this.Val_ary()); return false;}
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Acos(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_atan extends Func_tkn_base {
|
||||
public Func_tkn_atan(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(DecimalAdp_.double_(Math_.Atan(val.Xto_double())));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_round extends Func_tkn_base {
|
||||
public Func_tkn_round(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 5;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = val_stack.Pop();
|
||||
DecimalAdp lhs = val_stack.Pop();
|
||||
if (rhs.Comp_gt(16)) {
|
||||
rhs = DecimalAdp_.int_(16);
|
||||
}
|
||||
else if (rhs.Comp_lt(-16)) {
|
||||
rhs = DecimalAdp_.int_(-16);
|
||||
}
|
||||
DecimalAdp val = lhs.Op_round(rhs.Xto_int());
|
||||
if (val.Xto_double() == 0) // NOTE: must explicitly check for zero, else "0.0" will be pushed onto stack; EXE: {{#expr: 0 round 1}}; DATE:2013-11-09
|
||||
val_stack.Push(DecimalAdp_.Zero);
|
||||
else
|
||||
val_stack.Push(val);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_fmod extends Func_tkn_base {
|
||||
public Func_tkn_fmod(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 2;}
|
||||
@Override public int Precedence() {return 7;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp rhs = (DecimalAdp)val_stack.Pop();
|
||||
DecimalAdp lhs = (DecimalAdp)val_stack.Pop();
|
||||
if (rhs.Xto_double() == 0) {
|
||||
shunter.Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_division_by_zero);
|
||||
return false;
|
||||
}
|
||||
val_stack.Push(lhs.Op_mod(rhs));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
class Func_tkn_sqrt extends Func_tkn_base {
|
||||
public Func_tkn_sqrt(String v) {this.Ctor(v);}
|
||||
@Override public int ArgCount() {return 1;}
|
||||
@Override public int Precedence() {return 9;}
|
||||
@Override public boolean Calc_hook(Xop_ctx ctx, Pfunc_expr_shunter shunter, Val_stack val_stack) {
|
||||
DecimalAdp val = val_stack.Pop();
|
||||
val_stack.Push(val.Op_sqrt());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
220
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_shunter.java
Normal file
220
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_shunter.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
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.exprs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.btries.*;
|
||||
public class Pfunc_expr_shunter {
|
||||
Btrie_fast_mgr trie = expression_();
|
||||
Val_stack val_stack = new Val_stack();
|
||||
Func_tkn_stack prc_stack = new Func_tkn_stack();
|
||||
public static final DecimalAdp Null_rslt = null;
|
||||
public Bry_bfr Err() {return err_bfr;} Bry_bfr err_bfr = Bry_bfr.new_();
|
||||
public DecimalAdp Err_set(Xop_ctx ctx, int msgId) {return Err_set(ctx, msgId, Bry_.Empty);}
|
||||
public DecimalAdp Err_set(Xop_ctx ctx, int msg_id, byte[] arg) {
|
||||
byte[] msg_val = ctx.Wiki().Msg_mgr().Val_by_id(msg_id);
|
||||
err_bfr.Clear().Add(Err_bgn_ary);
|
||||
tmp_fmtr.Fmt_(msg_val).Bld_bfr_one(err_bfr, arg);
|
||||
err_bfr.Add(Err_end_ary);
|
||||
return Null_rslt;
|
||||
} static final byte[] Err_bgn_ary = Bry_.new_a7("<strong class=\"error\">"), Err_end_ary = Bry_.new_a7("</strong>"); Bry_fmtr tmp_fmtr = Bry_fmtr.tmp_();
|
||||
public void Rslt_set(byte[] bry) {
|
||||
err_bfr.Add(bry);
|
||||
}
|
||||
public DecimalAdp Evaluate(Xop_ctx ctx, byte[] src) { // REF.MW: Expr.php
|
||||
int src_len = src.length; if (src_len == 0) return Null_rslt;
|
||||
int cur_pos = 0; byte cur_byt = src[0];
|
||||
boolean mode_expr = true; Func_tkn prv_prc = null;
|
||||
val_stack.Clear(); prc_stack.Clear();
|
||||
while (true) {
|
||||
// can't think of a way for this to happen; note that operators will automatically push values/operators off stack that are lower; can't get up to 100
|
||||
// if (val_stack.Len() > 100 || prc_stack.Len() > 100) return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_err__stack_exhausted);
|
||||
Object o = trie.Match_bgn_w_byte(cur_byt, src, cur_pos, src_len);
|
||||
int bgn_pos = cur_pos;
|
||||
if (o == null) { // letter or unknown symbol
|
||||
while (cur_pos < src_len) {
|
||||
byte b = src[cur_pos++];
|
||||
if (Byte_ascii.Is_ltr(b))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_unrecognised_word, Bry_.Mid(src, bgn_pos, cur_pos));
|
||||
}
|
||||
else {
|
||||
Expr_tkn t = (Expr_tkn)o;
|
||||
cur_pos = trie.Match_pos();
|
||||
switch (t.Tid()) {
|
||||
case Expr_tkn_.Tid_space: break;
|
||||
case Expr_tkn_.Tid_number:
|
||||
if (!mode_expr) return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_unexpected_number);
|
||||
int numBgn = cur_pos - 1;
|
||||
boolean loop = true;
|
||||
while (loop) {
|
||||
if (cur_pos == src_len) break;
|
||||
switch (src[cur_pos]) {
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
case Byte_ascii.Dot:
|
||||
++cur_pos;
|
||||
break;
|
||||
default: loop = false; break;
|
||||
}
|
||||
}
|
||||
DecimalAdp num = Null_rslt;
|
||||
try {num = Bry_.XtoDecimalByPos(src, numBgn, cur_pos);}
|
||||
catch (Exception exc) {
|
||||
// NOTE: PATCH.PHP: 65.5.5 can evaluate to 65.5; EX "{{Geological eras|-600|height=2|border=none}}" eventually does "|10-to={{#ifexpr:{{{1|-4567}}}<-65.5|-65.5|{{{1}}}}}.5" which is 65.5.5
|
||||
Exc_.Noop(exc);
|
||||
int dot_count = 0;
|
||||
for (int i = numBgn; i < cur_pos; i++) {
|
||||
if (src[i] == Byte_ascii.Dot) {
|
||||
switch (dot_count) {
|
||||
case 0: dot_count = 1; break;
|
||||
case 1:
|
||||
try {
|
||||
num = Bry_.XtoDecimalByPos(src, numBgn, i);
|
||||
}
|
||||
catch (Exception exc_inner) {Exc_.Noop(exc_inner);}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num == null) return Null_rslt;
|
||||
}
|
||||
val_stack.Push(num);
|
||||
mode_expr = false;
|
||||
break;
|
||||
case Expr_tkn_.Tid_paren_lhs:
|
||||
if (!mode_expr) return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_unexpected_operator, Bry_.new_a7("("));
|
||||
prc_stack.Push((Func_tkn)t);
|
||||
break;
|
||||
case Expr_tkn_.Tid_operator:
|
||||
Func_tkn cur_prc = (Func_tkn)t;
|
||||
if (Byte_ascii.Is_ltr(cur_byt)) {
|
||||
int nxt_pos = Bry_finder.Find_fwd_while_letter(src, cur_pos, src_len);
|
||||
if (nxt_pos > cur_pos)
|
||||
return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_unrecognised_word, Bry_.Mid(src, bgn_pos, nxt_pos));
|
||||
}
|
||||
if (cur_prc.Func_is_const()) { // func is "pi" or "e"; DATE:2014-03-01
|
||||
if (mode_expr) { // number expected; just call Calc (which will place value on stack)
|
||||
cur_prc.Calc(ctx, this, val_stack);
|
||||
break;
|
||||
}
|
||||
else // operator expected; fail b/c pi / e is not an operator;
|
||||
return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_unexpected_number);
|
||||
}
|
||||
if (mode_expr) { // NOTE: all the GetAlts have higher precedence; "break;" need to skip evaluation below else will fail for --1
|
||||
Func_tkn alt_prc = cur_prc.GetAlt();
|
||||
prc_stack.Push(alt_prc);
|
||||
break;
|
||||
}
|
||||
prv_prc = prc_stack.GetLast();
|
||||
while (prv_prc != null && (cur_prc.Precedence() <= prv_prc.Precedence())) {
|
||||
if (!prv_prc.Calc(ctx, this, val_stack)) return Null_rslt;
|
||||
prc_stack.Pop();
|
||||
prv_prc = prc_stack.GetLast();
|
||||
}
|
||||
prc_stack.Push(cur_prc);
|
||||
mode_expr = true;
|
||||
break;
|
||||
case Expr_tkn_.Tid_paren_rhs: {
|
||||
prv_prc = prc_stack.GetLast();
|
||||
while (prv_prc != null && prv_prc.Tid() != Expr_tkn_.Tid_paren_lhs) {
|
||||
if (!prv_prc.Calc(ctx, this, val_stack)) return Null_rslt;
|
||||
prc_stack.Pop();
|
||||
prv_prc = prc_stack.GetLast();
|
||||
}
|
||||
if (prv_prc == Paren_bgn_tkn._)
|
||||
prc_stack.Pop();
|
||||
else
|
||||
return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_unexpected_closing_bracket);
|
||||
mode_expr = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cur_pos == src_len) break;
|
||||
cur_byt = src[cur_pos];
|
||||
}
|
||||
while (prc_stack.Len() > 0) {
|
||||
Func_tkn cur_prc = prc_stack.Pop();
|
||||
if (cur_prc.Tid() == Expr_tkn_.Tid_paren_lhs) return Err_set(ctx, Xol_msg_itm_.Id_pfunc_expr_unclosed_bracket);
|
||||
if (!cur_prc.Calc(ctx, this, val_stack)) return Null_rslt;
|
||||
}
|
||||
return val_stack.Len() == 0 ? Null_rslt : val_stack.Pop(); // HACK: for [[List of Premiers of South Australia by time in office]] and {{#expr:\n{{age in days
|
||||
}
|
||||
private static Btrie_fast_mgr expression_() {
|
||||
Btrie_fast_mgr rv = Btrie_fast_mgr.ci_ascii_(); // NOTE:ci.ascii:MW_const.en; math and expressions
|
||||
Trie_add(rv, new Ws_tkn(Byte_ascii.Space));
|
||||
Trie_add(rv, new Ws_tkn(Byte_ascii.Tab));
|
||||
Trie_add(rv, new Ws_tkn(Byte_ascii.Nl));
|
||||
Trie_add(rv, Paren_bgn_tkn._);
|
||||
Trie_add(rv, Paren_end_tkn._);
|
||||
Trie_add(rv, new Func_tkn_plus("+"));
|
||||
Trie_add(rv, new Func_tkn_minus("-"));
|
||||
Trie_add(rv, new Func_tkn_minus(Char_.XtoStr((char)8722)));
|
||||
Trie_add(rv, new Func_tkn_times("*"));
|
||||
Trie_add(rv, new Func_tkn_divide("/"));
|
||||
Trie_add(rv, new Func_tkn_divide("div"));
|
||||
Trie_add(rv, new Func_tkn_pow("^"));
|
||||
Trie_add(rv, new Func_tkn_mod("mod"));
|
||||
Trie_add(rv, new Func_tkn_eq("="));
|
||||
Trie_add(rv, new Func_tkn_neq("<>"));
|
||||
Trie_add(rv, new Func_tkn_neq("!="));
|
||||
Trie_add(rv, new Func_tkn_gt(">"));
|
||||
Trie_add(rv, new Func_tkn_lt("<"));
|
||||
Trie_add(rv, new Func_tkn_gte(">="));
|
||||
Trie_add(rv, new Func_tkn_lte("<="));
|
||||
Trie_add(rv, new Func_tkn_and("and"));
|
||||
Trie_add(rv, new Func_tkn_or("or"));
|
||||
Trie_add(rv, new Func_tkn_not("not"));
|
||||
Trie_add(rv, new Func_tkn_e_op("e"));
|
||||
Trie_add(rv, new Func_tkn_pi("pi"));
|
||||
Trie_add(rv, new Func_tkn_ceil("ceil"));
|
||||
Trie_add(rv, new Func_tkn_trunc("trunc"));
|
||||
Trie_add(rv, new Func_tkn_floor("floor"));
|
||||
Trie_add(rv, new Func_tkn_abs("abs"));
|
||||
Trie_add(rv, new Func_tkn_exp("exp"));
|
||||
Trie_add(rv, new Func_tkn_ln("ln"));
|
||||
Trie_add(rv, new Func_tkn_sin("sin"));
|
||||
Trie_add(rv, new Func_tkn_cos("cos"));
|
||||
Trie_add(rv, new Func_tkn_tan("tan"));
|
||||
Trie_add(rv, new Func_tkn_asin("asin"));
|
||||
Trie_add(rv, new Func_tkn_acos("acos"));
|
||||
Trie_add(rv, new Func_tkn_atan("atan"));
|
||||
Trie_add(rv, new Func_tkn_round("round"));
|
||||
Trie_add(rv, new Func_tkn_fmod("fmod"));
|
||||
Trie_add(rv, new Func_tkn_sqrt("sqrt"));
|
||||
Trie_add(rv, new Num_tkn(0));
|
||||
Trie_add(rv, new Num_tkn(1));
|
||||
Trie_add(rv, new Num_tkn(2));
|
||||
Trie_add(rv, new Num_tkn(3));
|
||||
Trie_add(rv, new Num_tkn(4));
|
||||
Trie_add(rv, new Num_tkn(5));
|
||||
Trie_add(rv, new Num_tkn(6));
|
||||
Trie_add(rv, new Num_tkn(7));
|
||||
Trie_add(rv, new Num_tkn(8));
|
||||
Trie_add(rv, new Num_tkn(9));
|
||||
Trie_add(rv, new Dot_tkn());
|
||||
Trie_add(rv, new Func_tkn_gt(">"));
|
||||
Trie_add(rv, new Func_tkn_lt("<"));
|
||||
Trie_add(rv, new Func_tkn_minus("−"));
|
||||
return rv;
|
||||
}
|
||||
private static void Trie_add(Btrie_fast_mgr trie, Expr_tkn tkn) {trie.Add(tkn.Val_ary(), tkn);}
|
||||
public static final Pfunc_expr_shunter _ = new Pfunc_expr_shunter(); Pfunc_expr_shunter() {}
|
||||
}
|
||||
116
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_tst.java
Normal file
116
400_xowa/src/gplx/xowa/xtns/pfuncs/exprs/Pfunc_expr_tst.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
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.exprs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_expr_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Null() {fxt.Test_parse_tmpl_str_test("{{#expr:}}" , "{{test}}" , "");}
|
||||
@Test public void Num_len1() {fxt.Test_parse_tmpl_str_test("{{#expr:1}}" , "{{test}}" , "1");}
|
||||
@Test public void Num_len3() {fxt.Test_parse_tmpl_str_test("{{#expr:123}}" , "{{test}}" , "123");}
|
||||
@Test public void Num_decimal() {fxt.Test_parse_tmpl_str_test("{{#expr:1.2}}" , "{{test}}" , "1.2");}
|
||||
@Test public void Num_decimal_lead() {fxt.Test_parse_tmpl_str_test("{{#expr:.12}}" , "{{test}}" , "0.12");}
|
||||
@Test public void Num_decimal_lax() {fxt.Test_parse_tmpl_str_test("{{#expr:1.2.3}}" , "{{test}}" , "1.2");} // PURPOSE: PHP allows 1.2.3 to be 1.2
|
||||
@Test public void Num_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:-1}}" , "{{test}}" , "-1");}
|
||||
@Test public void Num_neg_double() {fxt.Test_parse_tmpl_str_test("{{#expr:--1}}" , "{{test}}" , "1");}
|
||||
@Test public void Ws() {fxt.Test_parse_tmpl_str_test("{{#expr: 123\t\n }}" , "{{test}}" , "123");}
|
||||
@Test public void Plus_op() {fxt.Test_parse_tmpl_str_test("{{#expr:1 + 2}}" , "{{test}}" , "3");}
|
||||
@Test public void Minus_op() {fxt.Test_parse_tmpl_str_test("{{#expr:3 - 2}}" , "{{test}}" , "1");}
|
||||
@Test public void Mult() {fxt.Test_parse_tmpl_str_test("{{#expr:3 * 2}}" , "{{test}}" , "6");}
|
||||
@Test public void Div_sym() {fxt.Test_parse_tmpl_str_test("{{#expr:6 / 3}}" , "{{test}}" , "2");}
|
||||
@Test public void Div_word() {fxt.Test_parse_tmpl_str_test("{{#expr:6 div 3}}" , "{{test}}" , "2");}
|
||||
@Test public void Plus_sign() {fxt.Test_parse_tmpl_str_test("{{#expr:1 + + 2}}" , "{{test}}" , "3");}
|
||||
@Test public void Minus_sign() {fxt.Test_parse_tmpl_str_test("{{#expr:3 + - 2}}" , "{{test}}" , "1");}
|
||||
@Test public void Paren_1() {fxt.Test_parse_tmpl_str_test("{{#expr:(1 + 2) * 3}}" , "{{test}}" , "9");}
|
||||
@Test public void Paren_2() {fxt.Test_parse_tmpl_str_test("{{#expr:((1 + 2) * 3) * 4}}" , "{{test}}" , "36");}
|
||||
@Test public void Pow() {fxt.Test_parse_tmpl_str_test("{{#expr:2 ^ 4}}" , "{{test}}" , "16");}
|
||||
@Test public void Eq_y() {fxt.Test_parse_tmpl_str_test("{{#expr:2 = 2}}" , "{{test}}" , "1");}
|
||||
@Test public void Eq_n() {fxt.Test_parse_tmpl_str_test("{{#expr:2 = 3}}" , "{{test}}" , "0");}
|
||||
@Test public void Neq_1() {fxt.Test_parse_tmpl_str_test("{{#expr:2 != 3}}" , "{{test}}" , "1");}
|
||||
@Test public void Neq_2() {fxt.Test_parse_tmpl_str_test("{{#expr:2 <> 3}}" , "{{test}}" , "1");}
|
||||
@Test public void Gt() {fxt.Test_parse_tmpl_str_test("{{#expr:3 > 2}}" , "{{test}}" , "1");}
|
||||
@Test public void Lt() {fxt.Test_parse_tmpl_str_test("{{#expr:2 < 3}}" , "{{test}}" , "1");}
|
||||
@Test public void Gte() {fxt.Test_parse_tmpl_str_test("{{#expr:2 >= 2}}" , "{{test}}" , "1");}
|
||||
@Test public void Lte() {fxt.Test_parse_tmpl_str_test("{{#expr:2 <= 2}}" , "{{test}}" , "1");}
|
||||
@Test public void Mod() {fxt.Test_parse_tmpl_str_test("{{#expr:3 mod 2}}" , "{{test}}" , "1");}
|
||||
@Test public void And_1() {fxt.Test_parse_tmpl_str_test("{{#expr:1 and -1}}" , "{{test}}" , "1");}
|
||||
@Test public void And_0() {fxt.Test_parse_tmpl_str_test("{{#expr:1 and 0}}" , "{{test}}" , "0");}
|
||||
@Test public void Or_0() {fxt.Test_parse_tmpl_str_test("{{#expr:1 or 0}}" , "{{test}}" , "1");}
|
||||
@Test public void Not_y() {fxt.Test_parse_tmpl_str_test("{{#expr:not 0}}" , "{{test}}" , "1");}
|
||||
@Test public void Not_n() {fxt.Test_parse_tmpl_str_test("{{#expr:not 1}}" , "{{test}}" , "0");}
|
||||
@Test public void Minus_op_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:2 - 3}}" , "{{test}}" , "-1");}
|
||||
@Test public void E_num() {fxt.Test_parse_tmpl_str_test("{{#expr:e}}" , "{{test}}" , "2.71828182845904");}
|
||||
@Test public void Pi_num() {fxt.Test_parse_tmpl_str_test("{{#expr:pi}}" , "{{test}}" , "3.14159265358979");}
|
||||
@Test public void Pi_mult() {fxt.Test_parse_tmpl_str_test("{{#expr:pi*1}}" , "{{test}}" , "3.14159265358979");}
|
||||
@Test public void E_op_pos() {fxt.Test_parse_tmpl_str_test("{{#expr:1.2 e 2}}" , "{{test}}" , "120");}
|
||||
@Test public void E_op_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:1.2 e -2}}" , "{{test}}" , "0.012");}
|
||||
@Test public void E_op_inf() {fxt.Test_parse_tmpl_str_test("{{#expr:1.2 e 309}}" , "{{test}}" , "INF");} // PURPOSE:constrain to PHP double (e308); PAGE:en.w:Factorial; en.w:Astatine; DATE:2015-04-09
|
||||
@Test public void E_op_inf_2() {fxt.Test_parse_tmpl_str_test("{{#expr:1.8 e 308}}" , "{{test}}" , "INF");} // PURPOSE:constrain to PHP double (1.8 e308); PAGE:en.w:Mathematics_of_Sudoku DATE:2015-04-21
|
||||
@Test public void E_op_large() {fxt.Test_parse_tmpl_str_test("{{#expr:1E28}}" , "{{test}}" , "1E+28");} // PURPOSE:number should print in exponent notation (1E307), not full literal String (10000000...); DATE:2015-04-09;
|
||||
@Test public void Ceil_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:ceil(-1.2)}}" , "{{test}}" , "-1");}
|
||||
@Test public void Trunc_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:trunc(-1.2)}}" , "{{test}}" , "-1");}
|
||||
@Test public void Floor_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:floor(-1.2)}}" , "{{test}}" , "-2");}
|
||||
@Test public void Ceil_pos() {fxt.Test_parse_tmpl_str_test("{{#expr:ceil(1.2)}}" , "{{test}}" , "2");}
|
||||
@Test public void Trunc_pos() {fxt.Test_parse_tmpl_str_test("{{#expr:trunc(1.2)}}" , "{{test}}" , "1");}
|
||||
@Test public void Floor_pos() {fxt.Test_parse_tmpl_str_test("{{#expr:floor(1.2)}}" , "{{test}}" , "1");}
|
||||
@Test public void Abs_pos() {fxt.Test_parse_tmpl_str_test("{{#expr:abs(1)}}" , "{{test}}" , "1");}
|
||||
@Test public void Abs_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:abs(-1)}}" , "{{test}}" , "1");}
|
||||
@Test public void Exp() {fxt.Test_parse_tmpl_str_test("{{#expr:exp(10)}}" , "{{test}}" , "22026.46579480671789");} // NOTE: MW returns 4807, not 480671789;
|
||||
@Test public void Ln() {fxt.Test_parse_tmpl_str_test("{{#expr:ln(22026.4657948067)}}" , "{{test}}" , "10");}
|
||||
@Test public void Ln_mult() {fxt.Test_parse_tmpl_str_test("{{#expr:ln4/ln2}}" , "{{test}}" , "2");} // PAGE:en.w:Fieldbus; DATE:2015-04-09
|
||||
@Test public void Sin() {fxt.Test_parse_tmpl_str_test("{{#expr:sin(1.5707963267949)}}" , "{{test}}" , "1");}
|
||||
@Test public void Cos() {fxt.Test_parse_tmpl_str_test("{{#expr:cos(0)}}" , "{{test}}" , "1");}
|
||||
@Test public void Tan() {fxt.Test_parse_tmpl_str_test("{{#expr:tan(45)}}" , "{{test}}" , "1.61977519054386");}
|
||||
@Test public void Asin() {fxt.Test_parse_tmpl_str_test("{{#expr:asin(0)}}" , "{{test}}" , "0");}
|
||||
@Test public void Acos() {fxt.Test_parse_tmpl_str_test("{{#expr:acos(0)}}" , "{{test}}" , "1.57079632679489");} // NOTE: MW (and C#) returns 49, not 489
|
||||
@Test public void Atan() {fxt.Test_parse_tmpl_str_test("{{#expr:atan(0)}}" , "{{test}}" , "0");}
|
||||
@Test public void Round() {fxt.Test_parse_tmpl_str_test("{{#expr:1.5 round 0}}" , "{{test}}" , "2");}
|
||||
@Test public void Round_0() {fxt.Test_parse_tmpl_str_test("{{#expr:0 round 1}}" , "{{test}}" , "0");} // PURPOSE: 0 round 1 should be 0, not 0.0; DATE:2013-11-09
|
||||
@Test public void Round_ex_1() {fxt.Test_parse_tmpl_str_test("{{#expr:(0.03937007874015)round(3)}}" , "{{test}}" , "0.039");} // PURPOSE: rounding results in excessive decimal places; PAGE:en.w:Milky Way (light year conversions)
|
||||
@Test public void Mod_frac() {fxt.Test_parse_tmpl_str_test("{{#expr:0.00999999mod10}}" , "{{test}}" , "0");}
|
||||
@Test public void Mod_large() {fxt.Test_parse_tmpl_str_test("{{#expr:39052000900mod100}}" , "{{test}}" , "0");} // PURPOSE: JAVA was failing in converting to int and converted to Int_.MaxValue instead; DATE:2013-01-26
|
||||
@Test public void Fmod() {fxt.Test_parse_tmpl_str_test("{{#expr:1.25 fmod .5}}" , "{{test}}" , "0.25");}
|
||||
@Test public void Sqrt() {fxt.Test_parse_tmpl_str_test("{{#expr:sqrt 4}}" , "{{test}}" , "2");}
|
||||
@Test public void Sqrt_frac() {fxt.Test_parse_tmpl_str_test("{{#expr:sqrt 2}}" , "{{test}}" , "1.41421356237309");} // NOTE: MW (and C#) returns 31, not 309
|
||||
@Test public void Esc_xml_entRef() {fxt.Test_parse_tmpl_str_test("{{#expr:−1 < 5}}" , "{{test}}" , "1");}
|
||||
@Test public void Ex_1() {fxt.Test_parse_tmpl_str_test("{{#expr:1e2round0}}" , "{{test}}" , "100");} // PURPOSE: used in Convert
|
||||
@Test public void Floating() {fxt.Test_parse_tmpl_str_test("{{#expr:27.321582}}" , "{{test}}" , "27.321582");}
|
||||
@Test public void Floating_2() {fxt.Test_parse_tmpl_str_test("{{#expr:0.1*41}}" , "{{test}}" , "4.1");} // PURPOSE: division results in expanded floating-point; PAGE:en.w:Wikipedia
|
||||
@Test public void Floating_3() {fxt.Test_parse_tmpl_str_test("{{#expr:111/10^(-1)}}" , "{{test}}" , "1110");} // PURPOSE: division by pow; PAGE:en.w:Wikipedia:Featured articles
|
||||
@Test public void Floating_4() {fxt.Test_parse_tmpl_str_test("{{#expr:abs(-73.9023)}}" , "{{test}}" , "73.9023");} // PURPOSE: Abs;
|
||||
@Test public void Unicode_8722() {fxt.Test_parse_tmpl_str_test("{{#expr:2−1}}" , "{{test}}" , "1");} // PURPOSE: handle alternate minus; PAGE:en.w:Australian krill
|
||||
@Test public void Exp_large_neg() {fxt.Test_parse_tmpl_str_test("{{#expr:418400000000000000000000E-23}}" , "{{test}}" , "4.184");} // PURPOSE: handle large neg; EX: w:Chicxulub_crater; {{convert|100|TtonTNT|J|lk=on}}
|
||||
@Test public void Exp_large_neg2() {fxt.Test_parse_tmpl_str_test("{{#expr:210000000000000000E-17}}" , "{{test}}" , "2.1");} // PURPOSE: handle large neg2; EX: w:Chicxulub_crater; {{convert|50|MtonTNT|J|lk=on}}
|
||||
@Test public void Fix_transclusion() {fxt.Test_parse_tmpl_str_test("{{#expr:{{#if:||1}}/.2}}" , "{{test}}" , "5");} // PURPOSE: /. was invoking transclusion; DATE:2013-04-26
|
||||
@Test public void Exc_unrecognised_word() {fxt.Test_parse_tmpl_str_test("{{#expr:abc}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unrecognised word \"abc\"</strong>");}
|
||||
@Test public void Exc_division_by_zero() {fxt.Test_parse_tmpl_str_test("{{#expr:1/0}}" , "{{test}}" , "<strong class=\"error\">Division by zero</strong>");}
|
||||
@Test public void Exc_division_by_zero_mod() {fxt.Test_parse_tmpl_str_test("{{#expr:1 mod 0}}" , "{{test}}" , "<strong class=\"error\">Division by zero</strong>");}
|
||||
@Test public void Exc_unexpected_number() {fxt.Test_parse_tmpl_str_test("{{#expr:0 1}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unexpected number</strong>");}
|
||||
@Test public void Exc_unexpected_closing_bracket() {fxt.Test_parse_tmpl_str_test("{{#expr:5 + 1)}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unexpected closing bracket</strong>");}
|
||||
@Test public void Exc_unclosed_bracket() {fxt.Test_parse_tmpl_str_test("{{#expr:(5 + 1}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unclosed bracket</strong>");}
|
||||
@Test public void Exc_unexpected_operator_paren_end() {fxt.Test_parse_tmpl_str_test("{{#expr:5 ( 1}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unexpected ( operator</strong>");}
|
||||
@Test public void Exc_unexpected_number_pi() {fxt.Test_parse_tmpl_str_test("{{#expr:5 pi}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unexpected number</strong>");}
|
||||
@Test public void Exc_missing_operand() {fxt.Test_parse_tmpl_str_test("{{#expr:5 *}}" , "{{test}}" , "<strong class=\"error\">Expression error: Missing operand for *</strong>");}
|
||||
@Test public void Exc_invalid_argument_asin() {fxt.Test_parse_tmpl_str_test("{{#expr:asin(2)}}" , "{{test}}" , "<strong class=\"error\">Invalid argument for asin: < -1 or > 1</strong>");}
|
||||
@Test public void Exc_invalid_argument_acos() {fxt.Test_parse_tmpl_str_test("{{#expr:acos(2)}}" , "{{test}}" , "<strong class=\"error\">Invalid argument for acos: < -1 or > 1</strong>");}
|
||||
@Test public void Exc_invalid_argument_ln() {fxt.Test_parse_tmpl_str_test("{{#expr:ln(-1)}}" , "{{test}}" , "<strong class=\"error\">Invalid argument for ln: <= 0</strong>");}
|
||||
@Test public void Exc_pow_nan() {fxt.Test_parse_tmpl_str_test("{{#expr:(-2)^1.2}}" , "{{test}}" , "NaN");} // PURPOSE: handle nan; EX: w:Help:Calculation
|
||||
@Test public void Exc_unrecognized_word_ornot() {fxt.Test_parse_tmpl_str_test("{{#expr:0ornot0}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unrecognised word \"ornot\"</strong>");} // PURPOSE: handle nan; EX: w:Help:Calculation
|
||||
@Test public void Exc_unrecognized_word_notnot() {fxt.Test_parse_tmpl_str_test("{{#expr:notnot0}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unrecognised word \"notnot\"</strong>");} // PURPOSE: handle nan; EX: w:Help:Calculation
|
||||
@Test public void Exc_unrecognized_word_sinln() {fxt.Test_parse_tmpl_str_test("{{#expr:sinln1.1}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unrecognised word \"sinln\"</strong>");} // PURPOSE: handle nan; EX: w:Help:Calculation
|
||||
}
|
||||
37
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_if.java
Normal file
37
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_if.java
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.pfuncs.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_if 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) {
|
||||
byte[] val = Eval_argx(ctx, src, caller, self);
|
||||
boolean val_is_empty = true; int val_len = val.length;
|
||||
for (int i = 0; i < val_len; i++) {
|
||||
switch (val[i]) {
|
||||
case Byte_ascii.Space: case Byte_ascii.Nl: case Byte_ascii.Tab: break; // ws; continue
|
||||
default: val_is_empty = false; i = val_len; break; // non-ws; break loop
|
||||
}
|
||||
}
|
||||
if (val_is_empty)
|
||||
bfr.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self.Args_len(), 1));
|
||||
else
|
||||
bfr.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self.Args_len(), 0));
|
||||
}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_if;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_if().Name_(name);}
|
||||
}
|
||||
45
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_if_tst.java
Normal file
45
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_if_tst.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_if_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void If_y() {fxt.Test_parse_tmpl_str_test("{{#if:1|a|b}}" , "{{test}}" , "a");}
|
||||
@Test public void If_n() {fxt.Test_parse_tmpl_str_test("{{#if:|a|b}}" , "{{test}}" , "b");}
|
||||
@Test public void If_n_ws() {fxt.Test_parse_tmpl_str_test("{{#if: |a|b}}" , "{{test}}" , "b");}
|
||||
@Test public void If_y_ws() {fxt.Test_parse_tmpl_str_test("{{#if: |a|b \n}}" , "{{test}}" , "b");}
|
||||
@Test public void If_y_ws1() {fxt.Test_parse_tmpl_str_test("{{#if: |a|{{#if: |a|b}}\n}}" , "{{test}}" , "b");}
|
||||
@Test public void If_prm_n() {fxt.Test_parse_tmpl_str_test("{{#if:{{{1|}}}|{{{1}}}|b}}" , "{{test}}" , "b");}
|
||||
@Test public void If_prm_y() {fxt.Test_parse_tmpl_str_test("{{#if:{{{1|}}}|{{{1}}}|b}}" , "{{test|a}}" , "a");}
|
||||
@Test public void If_prm_n_dflt_ws() {fxt.Test_parse_tmpl_str_test("{{#if:{{{1| }}}|a|b}}" , "{{test}}" , "b");}
|
||||
@Test public void If_prm_nest_0() {fxt.Test_parse_tmpl_str_test("{{#if:{{{1|}}}|{{#if:{{{2|}}}|a|b}}|c}}" , "{{test}}" , "c");}
|
||||
@Test public void If_prm_nest_1() {fxt.Test_parse_tmpl_str_test("{{#if:{{{1|}}}|{{#if:{{{2|}}}|a|b}}|c}}" , "{{test|1}}" , "b");}
|
||||
@Test public void If_prm_nest_2() {fxt.Test_parse_tmpl_str_test("{{#if:{{{1|}}}|{{#if:{{{2|}}}|a|b}}|c}}" , "{{test|1|2}}" , "a");}
|
||||
@Test public void If_ignore_key() {fxt.Test_parse_tmpl_str_test("{{#if:|<i id=1|<i id=2}}" , "{{test}}" , "<i id=2");}
|
||||
@Test public void If_newline() { // PURPOSE: new_line in comments; WP:[[redirect-distinguish|a|b]]
|
||||
fxt.Test_parse_tmpl_str_test(String_.Concat_lines_nl_skip_last
|
||||
( "{{#if:1<!--"
|
||||
, "-->|a<!--"
|
||||
, "-->|b<!--"
|
||||
, "-->}}"
|
||||
)
|
||||
, "{{test}}", "a");
|
||||
}
|
||||
@Test public void If_rel2abs() {fxt.Test_parse_tmpl_str_test("{{#if:{{{1}}}|y}}" , "{{test|http://a.org/c/}}" , "y");} // PURPOSE.fix: trailing slash should not trigger rel2abs code; DATE:2013-04-06
|
||||
}
|
||||
32
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifeq.java
Normal file
32
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifeq.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_ifeq 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) {
|
||||
int self_args_len = self.Args_len(); if (self_args_len < 2) return; // no equal/not_equal clauses defined; return; EX: {{#if:a}} {{#if:a|b}}
|
||||
byte[] lhs = Eval_argx(ctx, src, caller, self);
|
||||
byte[] rhs = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
|
||||
if (Pf_func_.Eq_(lhs, rhs))
|
||||
bfr.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 1));
|
||||
else
|
||||
bfr.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 2));
|
||||
}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_ifeq;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_ifeq().Name_(name);}
|
||||
}
|
||||
48
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifeq_tst.java
Normal file
48
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifeq_tst.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_ifeq_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
|
||||
@Test public void Ifeq_y() {fxt.Test_parse_tmpl_str_test("{{#ifeq:1|1|a|b}}" , "{{test}}" , "a");}
|
||||
@Test public void Ifeq_n() {fxt.Test_parse_tmpl_str_test("{{#ifeq:1|2|a|b}}" , "{{test}}" , "b");}
|
||||
@Test public void Ifeq_prm_arg() {fxt.Test_parse_tmpl_str_test("{{#ifeq:{{{1}}}|1|a|b}}" , "{{test|1}}" , "a");}
|
||||
@Test public void Ifeq_prm_arg_n() {fxt.Test_parse_tmpl_str_test("{{#ifeq:{{{1}}}|1|a|b}}" , "{{test|2}}" , "b");}
|
||||
@Test public void Ifeq_prm_blank_y() {fxt.Test_parse_tmpl_str_test("{{#ifeq:||a|b}}" , "{{test}}" , "a");}
|
||||
@Test public void Ifeq_prm_blank_n() {fxt.Test_parse_tmpl_str_test("{{#ifeq:|1|a|b}}" , "{{test}}" , "b");}
|
||||
@Test public void Ifeq_numeric() {fxt.Test_parse_tmpl_str_test("{{#ifeq:003|3.0|y|n}}" , "{{test}}" , "y");}
|
||||
@Test public void Ifeq_numeric_neg() {fxt.Test_parse_tmpl_str_test("{{#ifeq:-1.0|-1|y|n}}" , "{{test}}" , "y");}
|
||||
@Test public void Ifeq_prm_arg0() {fxt.Test_parse_tmpl_str_test("{{#ifeq:1|{{{1}}}|a|b}}" , "{{test|1}}" , "a");}
|
||||
@Test public void Ifeq_expr_err() {fxt.Test_parse_tmpl_str_test("{{#ifeq:{{#expr:a}}|0|y|n}}" , "{{test}}" , "n");}
|
||||
@Test public void Ifeq_blank() {fxt.Test_parse_tmpl_str_test("{{#ifeq:0||y|n}}" , "{{test}}" , "n");}
|
||||
|
||||
@Test public void Ifeq_exc_args_0() {fxt.Test_parse_tmpl_str_test("{{#ifeq:}}" , "{{test}}" , "");}
|
||||
@Test public void Ifeq_exc_args_1() {fxt.Test_parse_tmpl_str_test("{{#ifeq:1|1}}" , "{{test}}" , "");}
|
||||
@Test public void Ifeq_exc_args_2() {fxt.Test_parse_tmpl_str_test("{{#ifeq:1|1|a}}" , "{{test}}" , "a");}
|
||||
@Test public void Ifeq_exp() {fxt.Test_parse_tmpl_str_test("{{#ifeq:0.006|+6.0E-3|y|n}}" , "{{test}}" , "y");}
|
||||
@Test public void Ifeq_plus_minus() {fxt.Test_parse_tmpl_str_test("{{#ifeq:+|-|y}}" , "{{test}}" , "");} // PURPOSE: was evaluating to y; PAGE:en.w:Permian-Triassic extinction
|
||||
@Test public void Tab_ent() { // PURPOSE: hack; tabs are materialized as "	" which causes trimming problems; PAGE:en.w:Template:Cretaceous_graphical_timeline and "|period11= Campanian\s\t"
|
||||
fxt.Test_parse_page_all_str("{{#ifeq:a|a 	|y|n}}", "y"); // note that "|a\s\t" gets trimmed to "a"
|
||||
}
|
||||
@Test public void Ifeq_hex() {fxt.Test_parse_tmpl_str_test("{{#ifeq:44|0X002C|y|n}}" , "{{test}}" , "y");} // PURPOSE: hex compares to int; EX:w:Comma
|
||||
@Test public void Colon_2() { // PURPOSE: 2nd colon causes error b/c of bad whitespace evaluation; PAGE:en.w:de.wiktionary.org/wiki/glitschig; DATE:2013-12-10
|
||||
fxt.Test_parse_tmpl_str_test("{{#ifeq: :|a|b|c}}" , "{{test}}" , "c");
|
||||
}
|
||||
}
|
||||
123
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_iferror.java
Normal file
123
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_iferror.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.primitives.*; import gplx.core.btries.*;
|
||||
public class Pfunc_iferror 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) {
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] val_dat_ary = Eval_argx(ctx, src, caller, self);
|
||||
if (val_dat_ary == null) return;
|
||||
if (Error_exists(val_dat_ary))
|
||||
bb.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0));
|
||||
else {
|
||||
if (self_args_len < 2) // pass clause absent; add original
|
||||
bb.Add(val_dat_ary);
|
||||
else
|
||||
bb.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 1));
|
||||
}
|
||||
}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_iferror;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_iferror().Name_(name);}
|
||||
boolean Error_exists(byte[] src) {
|
||||
// NOTE: approximation of MW code. basically checking for <tag class=error; REF.MW: ParserFunctions_body.php|iferror
|
||||
// /<(?:strong|span|p|div)\s(?:[^\s>]*\s+)*?class="(?:[^"\s>]*\s+)*?error(?:\s[^">]*)?"/
|
||||
int src_len = src.length;
|
||||
byte state = State_null;
|
||||
int pos = 0;
|
||||
boolean valid = false;
|
||||
while (true) {
|
||||
if (pos == src_len) break;
|
||||
byte b = src[pos];
|
||||
Object o = trie.Match_bgn_w_byte(b, src, pos, src_len);
|
||||
if (o == null)
|
||||
++pos;
|
||||
else {
|
||||
Byte_obj_val bv = (Byte_obj_val)o;
|
||||
int pos_nxt = trie.Match_pos();
|
||||
if (pos_nxt == src_len) return false; // each of the three states requires at least one character afterwards
|
||||
switch (bv.Val()) {
|
||||
case State_close: // >: reset state
|
||||
state = State_null;
|
||||
break;
|
||||
case State_nde: // <(?:strong|span|p|div)\s
|
||||
switch (src[pos_nxt]) {
|
||||
case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl:
|
||||
state = State_nde;
|
||||
++pos_nxt;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case State_class:
|
||||
if (state == State_nde) {
|
||||
valid = true;
|
||||
switch (src[pos - 1]) {
|
||||
case Byte_ascii.Quote: case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl:
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (valid) {
|
||||
state = State_class;
|
||||
++pos_nxt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case State_error:
|
||||
if (state == State_class) {
|
||||
valid = true;
|
||||
switch (src[pos - 1]) {
|
||||
case Byte_ascii.Quote: case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl:
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
switch (src[pos_nxt]) {
|
||||
case Byte_ascii.Quote: case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl:
|
||||
break;
|
||||
default:
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
if (valid)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pos = pos_nxt;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static final Btrie_slim_mgr trie = trie_();
|
||||
static final byte State_null = 0, State_nde = 1, State_class = 2, State_error = 3, State_close = 4;
|
||||
private static Btrie_slim_mgr trie_() {
|
||||
Btrie_slim_mgr rv = Btrie_slim_mgr.ci_ascii_(); // NOTE:ci.ascii:MW_const.en
|
||||
trie_init(rv, State_nde , "<strong");
|
||||
trie_init(rv, State_nde , "<span");
|
||||
trie_init(rv, State_nde , "<p");
|
||||
trie_init(rv, State_nde , "<div");
|
||||
trie_init(rv, State_class, "class=");
|
||||
trie_init(rv, State_error, "error");
|
||||
trie_init(rv, State_close, ">");
|
||||
return rv;
|
||||
}
|
||||
private static void trie_init(Btrie_slim_mgr trie, byte b, String s) {trie.Add_obj(s, Byte_obj_val.new_(b));}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_iferror_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Basic_pass() {fxt.Test_parse_tmpl_str_test("{{#iferror: {{#expr: 1 + 2 }} | error | ok }}" , "{{test}}" , "ok");}
|
||||
@Test public void Basic_fail() {fxt.Test_parse_tmpl_str_test("{{#iferror: {{#expr: 1 + X }} | error | ok }}" , "{{test}}" , "error");}
|
||||
@Test public void Basic_omit() {fxt.Test_parse_tmpl_str_test("{{#iferror: ok | error}}" , "{{test}}" , "ok");}
|
||||
@Test public void NoMatch_0() {fxt.Test_parse_tmpl_str_test("{{#iferror: <strong>error</strong> | error | ok }}" , "{{test}}" , "ok");}
|
||||
@Test public void NoMatch_1() {fxt.Test_parse_tmpl_str_test("{{#iferror: <strong test=\"error\"></strong> | error | ok }}" , "{{test}}" , "ok");}
|
||||
@Test public void NoMatch_2() {fxt.Test_parse_tmpl_str_test("{{#iferror: <strong class=\"errora\"></strong> | error | ok }}" , "{{test}}" , "ok");}
|
||||
//@Test public void NoMatch_3() {fxt.Test_parse_tmpl_str_test("{{#iferror: <strong class=\"error a| error | ok }}" , "{{test}}" , "ok");} // FUTURE: match for ">
|
||||
}
|
||||
35
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexist.java
Normal file
35
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexist.java
Normal file
@@ -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.xtns.pfuncs.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_ifexist extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_iferror;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_ifexist().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 rslt_bfr) {
|
||||
int args_len = self.Args_len();
|
||||
byte[] val_bry = Eval_argx(ctx, src, caller, self);
|
||||
if (Exists(ctx.Wiki(), val_bry))
|
||||
rslt_bfr.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, 0));
|
||||
else
|
||||
rslt_bfr.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, args_len, 1));
|
||||
}
|
||||
public static boolean Exists(Xowe_wiki wiki, byte[] ttl_bry) {
|
||||
synchronized (Mgr) {return Mgr.Exists(wiki, ttl_bry);}
|
||||
}
|
||||
public static final Pfunc_ifexist_mgr Mgr = new Pfunc_ifexist_mgr();
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.wmfs.apis.*; import gplx.xowa.wikis.data.tbls.*;
|
||||
public class Pfunc_ifexist_mgr {
|
||||
private Xowd_page_itm db_page = Xowd_page_itm.new_tmp();
|
||||
private Hash_adp regy = Hash_adp_bry.cs_();
|
||||
public void Clear() {regy.Clear();}
|
||||
public boolean Exists(Xowe_wiki wiki, byte[] raw_bry) {
|
||||
if (Bry_.Len_eq_0(raw_bry)) return false; // return early; NOTE: {{autolink}} can pass in "" (see test)
|
||||
Xoa_ttl ttl = Xoa_ttl.parse_(wiki, raw_bry); if (ttl == null) return false;
|
||||
byte[] ttl_bry = ttl.Page_db(); // NOTE: must use Page_db; EX: {{#ifexist:File:Peter & Paul fortress in SPB 03.jpg|y|n}}
|
||||
Object exists_obj = regy.Get_by(ttl_bry);
|
||||
if (exists_obj != null) return ((Pfunc_ifexist_itm)exists_obj).Exists();
|
||||
Pfunc_ifexist_itm exists_itm = new Pfunc_ifexist_itm(ttl_bry);
|
||||
regy.Add(ttl_bry, exists_itm);
|
||||
db_page.Clear();
|
||||
Xow_ns ttl_ns = ttl.Ns();
|
||||
boolean rv = false;
|
||||
switch (ttl_ns.Id()) {
|
||||
case Xow_ns_.Id_special: rv = true; break; // NOTE: some pages call for [[Special]]; always return true for now; DATE:2014-07-17
|
||||
case Xow_ns_.Id_media: rv = Find_ttl_for_media_ns(exists_itm, wiki, ttl_ns, ttl_bry); break;
|
||||
default: rv = Find_ttl_in_db(exists_itm, wiki, ttl_ns, ttl_bry); break;
|
||||
}
|
||||
exists_itm.Exists_(rv);
|
||||
return rv;
|
||||
}
|
||||
private boolean Find_ttl_in_db(Pfunc_ifexist_itm itm, Xowe_wiki wiki, Xow_ns ns, byte[] ttl_bry) {
|
||||
boolean rv = wiki.Db_mgr().Load_mgr().Load_by_ttl(db_page, ns, ttl_bry);
|
||||
if ( !rv
|
||||
&& wiki.Lang().Vnt_mgr().Enabled()) {
|
||||
Xowd_page_itm page = wiki.Lang().Vnt_mgr().Convert_ttl(wiki, ns, ttl_bry);
|
||||
if (page != Xowd_page_itm.Null)
|
||||
rv = page.Exists();
|
||||
}
|
||||
itm.Exists_(rv);
|
||||
return rv;
|
||||
}
|
||||
private boolean Find_ttl_for_media_ns(Pfunc_ifexist_itm itm, Xowe_wiki wiki, Xow_ns ns, byte[] ttl_bry) {
|
||||
Xow_ns file_ns = wiki.Ns_mgr().Ns_file();
|
||||
boolean rv = Find_ttl_in_db(itm, wiki, file_ns, ttl_bry); if (rv) return true; // rarely true, but check local wiki's [[File:]] table anyway
|
||||
Xowe_wiki commons_wiki = wiki.Appe().Wiki_mgr().Wiki_commons();
|
||||
boolean env_is_testing = Env_.Mode_testing();
|
||||
if ( commons_wiki != null // null check
|
||||
&& ( commons_wiki.Init_assert().Db_mgr().Tid() == gplx.xowa.dbs.Xodb_mgr_sql.Tid_sql // make sure tid=sql; tid=txt automatically created for online images; DATE:2014-09-21
|
||||
|| env_is_testing
|
||||
)
|
||||
) {
|
||||
file_ns = commons_wiki.Ns_mgr().Ns_file();
|
||||
return Find_ttl_in_db(itm, commons_wiki, file_ns, ttl_bry); // accurate test using page table in commons wiki (provided commons is up to date)
|
||||
}
|
||||
else {
|
||||
if (!env_is_testing)
|
||||
wiki.File_mgr().Init_file_mgr_by_load(wiki); // NOTE: must init Fsdb_mgr (else conn == null), and with bin_wkrs (else no images will ever load); DATE:2014-09-21
|
||||
return wiki.File_mgr().Exists(ttl_bry); // less-accurate test using either (1) orig_wiki table in local wiki (v2) or (2) meta_db_mgr (v1)
|
||||
}
|
||||
}
|
||||
}
|
||||
class Pfunc_ifexist_itm {
|
||||
public Pfunc_ifexist_itm(byte[] ttl) {this.ttl = ttl;}
|
||||
public byte[] Ttl() {return ttl;} private byte[] ttl;
|
||||
public boolean Exists() {return exists;} public void Exists_(boolean v) {exists = v;} private boolean exists;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_ifexist_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Basic_pass() {fxt.Test_parse_tmpl_str_test("{{#ifexist: Abc | exists | doesn't exist }}" , "{{test}}" , "doesn't exist");}
|
||||
@Test public void Empty() {fxt.Test_parse_tmpl_str_test("{{#ifexist:|y|n}}" , "{{test}}" , "n");} // NOTE: {{autolink}} can pass in ""
|
||||
@Test public void Db_key() { // PURPOSE: test that (1) & is encoded; (2) " " becomes "_"; EX: {{#ifexist:File:Peter & Paul fortress in SPB 03.jpg|y|n}}
|
||||
fxt.Init_page_create("A_&_b", "");
|
||||
fxt.Test_parse_tmpl_str_test("{{#ifexist:A & b|y|n}}", "{{test}}", "y");
|
||||
}
|
||||
@Test public void Media_n() {// DATE:2014-07-04
|
||||
Pfunc_ifexist.Mgr.Clear();
|
||||
fxt.Test_parse_tmpl_str_test("{{#ifexist:Media:A.png|y|n}}", "{{test}}", "n");
|
||||
}
|
||||
@Test public void Media_y_wiki() {// DATE:2014-07-04
|
||||
Pfunc_ifexist.Mgr.Clear();
|
||||
fxt.Init_page_create("File:A.png", "");
|
||||
fxt.Test_parse_tmpl_str_test("{{#ifexist:Media:A.png|y|n}}", "{{test}}", "y");
|
||||
}
|
||||
@Test public void Media_y_commons() {// DATE:2014-07-04
|
||||
Pfunc_ifexist.Mgr.Clear();
|
||||
Xowe_wiki commons_wiki = fxt.App().Wiki_mgr().Get_by_key_or_make(gplx.xowa.wikis.Xow_domain_.Domain_bry_commons);
|
||||
fxt.Init_page_create(commons_wiki, "File:A.png", "");
|
||||
fxt.Test_parse_tmpl_str_test("{{#ifexist:Media:A.png|y|n}}", "{{test}}", "y");
|
||||
}
|
||||
@Test public void Media_y_file_v1() {// DATE:2014-07-04
|
||||
Pfunc_ifexist.Mgr.Clear();
|
||||
Xof_meta_itm meta_itm = fxt.Wiki().File_mgr().Meta_mgr().Get_itm_or_new(Bry_.new_a7("A.png"));
|
||||
meta_itm.Orig_exists_(Bool_.Y_byte);
|
||||
fxt.Test_parse_tmpl_str_test("{{#ifexist:Media:A.png|y|n}}", "{{test}}", "y");
|
||||
}
|
||||
}
|
||||
42
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexpr.java
Normal file
42
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexpr.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.xtns.pfuncs.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.xtns.pfuncs.exprs.*;
|
||||
public class Pfunc_ifexpr 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) {
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] val_dat_ary = Eval_argx(ctx, src, caller, self);
|
||||
if (val_dat_ary == null) return;
|
||||
DecimalAdp result = shunter.Evaluate(ctx, val_dat_ary);
|
||||
boolean is_nan = result == Pfunc_expr_shunter.Null_rslt;
|
||||
if (is_nan && shunter.Err().Len() > 0) {
|
||||
bb.Add_bfr_and_preserve(shunter.Err());
|
||||
shunter.Err().Clear();
|
||||
}
|
||||
else {
|
||||
if (is_nan || result.Xto_int() == 0)
|
||||
bb.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 1));
|
||||
else
|
||||
bb.Add(Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0));
|
||||
}
|
||||
}
|
||||
Pfunc_expr_shunter shunter = Pfunc_expr_shunter._;
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_ifexpr;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_ifexpr().Name_(name);}
|
||||
}
|
||||
31
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexpr_tst.java
Normal file
31
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_ifexpr_tst.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.xtns.pfuncs.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_ifexpr_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Basic_y() {fxt.Test_parse_tmpl_str_test("{{#ifexpr: 1 > 0 |y|n}}" , "{{test}}" , "y");}
|
||||
@Test public void Basic_n() {fxt.Test_parse_tmpl_str_test("{{#ifexpr: 1 < 0 |y|n}}" , "{{test}}" , "n");}
|
||||
@Test public void Blank_n() {fxt.Test_parse_tmpl_str_test("{{#ifexpr: |y|n}}" , "{{test}}" , "n");}
|
||||
@Test public void Args_0_n() {fxt.Test_parse_tmpl_str_test("{{#ifexpr: 1 > 0}}" , "{{test}}" , "");}
|
||||
@Test public void Args_0_y() {fxt.Test_parse_tmpl_str_test("{{#ifexpr: 0 > 1}}" , "{{test}}" , "");}
|
||||
@Test public void Err() {fxt.Test_parse_tmpl_str_test("{{#ifexpr:20abc >1|y|n}}" , "{{test}}" , "<strong class=\"error\">Expression error: Unrecognised word \"abc \"</strong>");} // HACK: shouldn't be "abc "
|
||||
}
|
||||
/*
|
||||
*/
|
||||
89
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_switch.java
Normal file
89
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_switch.java
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_switch extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_switch;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_switch().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) {// REF.MW:ParserFunctions_body.php
|
||||
int self_args_len = self.Args_len(); if (self_args_len == 0) return; // no cases; return; effectively "empty"
|
||||
byte[] argx = Eval_argx(ctx, src, caller, self);
|
||||
boolean fall_thru_found = false;
|
||||
byte[] match = null;
|
||||
Arg_itm_tkn dflt_val_tkn = null; byte[] dflt_val_bry = null;
|
||||
Arg_nde_tkn last_keyless_arg = null;
|
||||
Bry_bfr tmp = ctx.Wiki().Utl__bfr_mkr().Get_b512();
|
||||
Xol_kwd_mgr kwd_mgr = ctx.Lang().Kwd_mgr();
|
||||
for (int i = 0; i < self_args_len; i++) {
|
||||
Arg_nde_tkn arg = self.Args_get_by_idx(i);
|
||||
if (arg.KeyTkn_exists()) { // = exists; EX: "|a=1|"
|
||||
last_keyless_arg = null; // set last_keyless_arg to null
|
||||
byte[] case_key = Get_or_eval(ctx, src, caller, self, bfr, arg.Key_tkn(), tmp);
|
||||
if ( fall_thru_found // fall-thru found earlier; take cur value; EX: {{#switch:a|a|b=1|c=2}} -> 1
|
||||
|| Pf_func_.Eq_(case_key, argx) // case_key matches argx; EX: {{#switch:a|a=1}}
|
||||
) {
|
||||
match = Get_or_eval(ctx, src, caller, self, bfr, arg.Val_tkn(), tmp);
|
||||
break; // stop iterating; explicit match found;
|
||||
}
|
||||
else if (kwd_mgr.Kwd_default_match(case_key)){ // case_key is #default; EX: {{#switch:a|#default=1}}; note that "#defaultabc" is also allowed;
|
||||
dflt_val_tkn = arg.Val_tkn(); // set dflt_val_tkn; note that there is no "break" b/c multiple #defaults will use last one; EX: {{#switch:a|#default=1|#default=2}} -> 2
|
||||
dflt_val_bry = null; // set dflt_val_bry to null; EX:{{#switch:a|#defaultabc|#default=2}} -> 2
|
||||
}
|
||||
else {} // case_key != argx; continue
|
||||
}
|
||||
else { // = missing; EX: "|a|", "|#default|"
|
||||
last_keyless_arg = arg;
|
||||
byte[] case_val = Get_or_eval(ctx, src, caller, self, bfr, arg.Val_tkn(), tmp);
|
||||
if (Pf_func_.Eq_(case_val, argx)) // argx matches case_val; EX: case_val="|a|" and argx="a"
|
||||
fall_thru_found = true; // set as fall-thru; note that fall-thrus will have "val" in next keyed arg, so need to continue iterating; EX: {{#switch:a|a|b=1|c=2}} "a" is fall-thru, but "b" is next keyed arg with a val
|
||||
else if (kwd_mgr.Kwd_default_match(case_val)) { // case_val starts with #default; EX: "|#default|" or "|#defaultabc|"
|
||||
last_keyless_arg = null; // unflag last keyless arg else |#defaultabc| will be treated as last_keyless_arg and generate "#defaultabc"; DATE:2014-05-29
|
||||
dflt_val_tkn = null; // unflag dflt_val_tkn; EX: {{#switch:a|b|#default=1|#default}} -> "" x> "1"
|
||||
int case_val_len = case_val.length;
|
||||
dflt_val_bry
|
||||
= case_val_len == Dflt_keyword_len // PERF: check if case_val = "|#default|"
|
||||
? null // PERF: set to null; don't create Bry_.Empty
|
||||
: Bry_.Mid(case_val, Dflt_keyword_len, case_val_len) // chop off "#default"; EX: {{#switch:a|b|#defaultabc}} -> "abc"
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (match == null) { // no match; will either use last_keyless arg or #default
|
||||
if (last_keyless_arg != null) // always prefer last_keyless_arg; EX: {{#switch:a|#default=1|2}} -> 2
|
||||
match = Get_or_eval(ctx, src, caller, self, bfr, last_keyless_arg.Val_tkn(), tmp);
|
||||
else if (dflt_val_bry != null) // "|#defaultabc|" found; use it
|
||||
match = dflt_val_bry;
|
||||
else if (dflt_val_tkn != null) // "|#default=val|" found; use it
|
||||
match = Get_or_eval(ctx, src, caller, self, bfr, dflt_val_tkn, tmp);
|
||||
else {} // nothing found; noop; match will remain null
|
||||
}
|
||||
if (match != null)
|
||||
bfr.Add(match);
|
||||
tmp.Mkr_rls();
|
||||
}
|
||||
private byte[] Get_or_eval(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb, Arg_itm_tkn itm, Bry_bfr tmp) {
|
||||
if (itm.Itm_static() == Bool_.Y_byte)
|
||||
return Bry_.Trim(src, itm.Dat_bgn(), itm.Dat_end());
|
||||
else {
|
||||
itm.Tmpl_evaluate(ctx, src, caller, tmp);
|
||||
return tmp.Xto_bry_and_clear_and_trim();
|
||||
}
|
||||
}
|
||||
public static final byte[] Dflt_keyword = Bry_.new_u8("#default"); // NOTE: technically should pull from messages, but would need to cache Dflt_keyword on wiki level; checked all Messages files, and no one overrides it; DATE:2014-05-29
|
||||
private static int Dflt_keyword_len = Dflt_keyword.length;
|
||||
}
|
||||
91
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_switch_tst.java
Normal file
91
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Pfunc_switch_tst.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_switch_tst {
|
||||
@Before public void init() {fxt.Reset();} private Xop_fxt fxt = new Xop_fxt();
|
||||
@Test public void Basic_a() {fxt.Test_parse_tmpl_str_test("{{#switch:a|a=1|b=2|3}}" , "{{test}}" , "1");}
|
||||
@Test public void Basic_b() {fxt.Test_parse_tmpl_str_test("{{#switch:b|a=1|b=2|3}}" , "{{test}}" , "2");}
|
||||
@Test public void Basic_dflt() {fxt.Test_parse_tmpl_str_test("{{#switch:z|a=1|b=2|3}}" , "{{test}}" , "3");}
|
||||
@Test public void FallThru_a() {fxt.Test_parse_tmpl_str_test("{{#switch:a|a|b|c=1|d=2|3}}" , "{{test}}" , "1");}
|
||||
@Test public void FallThru_b() {fxt.Test_parse_tmpl_str_test("{{#switch:b|a|b|c=1|d=2|3}}" , "{{test}}" , "1");}
|
||||
@Test public void FallThru_c() {fxt.Test_parse_tmpl_str_test("{{#switch:c|a|b|c=1|d=2|3}}" , "{{test}}" , "1");}
|
||||
@Test public void FallThru_d() {fxt.Test_parse_tmpl_str_test("{{#switch:d|a|b|c=1|d=2|3}}" , "{{test}}" , "2");}
|
||||
@Test public void FallThru_dflt() {fxt.Test_parse_tmpl_str_test("{{#switch:z|a|b|c=1|d=2|3}}" , "{{test}}" , "3");}
|
||||
@Test public void Dflt_named() {fxt.Test_parse_tmpl_str_test("{{#switch:z|b=2|#default=3|a=1}}" , "{{test}}" , "3");}
|
||||
@Test public void Dflt_last_idx_wins() // even if there is a named default, if last arg is un-keyd, then use it as default
|
||||
{fxt.Test_parse_tmpl_str_test("{{#switch:z|#default=3|9}}" , "{{test}}" , "9");}
|
||||
@Test public void Dflt_last_named_wins() // last named default wins
|
||||
{fxt.Test_parse_tmpl_str_test("{{#switch:z|#default=3|#default=4}}" , "{{test}}" , "4");}
|
||||
@Test public void Numeric() {fxt.Test_parse_tmpl_str_test("{{#switch:003|3.0=y|n}}" , "{{test}}" , "y");} //{{#switch:{{CURRENTMONTH}}|03=y|n}}
|
||||
@Test public void NoKeys() {fxt.Test_parse_tmpl_str_test("{{#switch:a|a|b|c|d}}" , "{{test}}" , "d");}// d wins b/c it is default
|
||||
@Test public void Prm_val() {fxt.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|a=1|b=2|3}}" , "{{test|b}}" , "2");}
|
||||
@Test public void Prm_case1v() {fxt.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|a={{{1}}}|b=2|3}}" , "{{test|a}}" , "a");}
|
||||
@Test public void Prm_case1k() {fxt.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|{{{1}}}=1|b=2|3}}" , "{{test|a}}" , "1");}
|
||||
@Test public void Null_x() {fxt.Test_parse_tmpl_str_test("{{#switch:|a=1|b=2|3}}" , "{{test|b}}" , "3");}
|
||||
@Test public void Exc_no_cases() {fxt.Test_parse_tmpl_str_test("{{#switch:a}}" , "{{test}}" , "");}
|
||||
@Test public void Exc_brace() {fxt.Test_parse_tmpl_str_test("{{#switch:a|{{{1}}}}=y|n}}" , "{{test|a}}" , "n");}// NOTE: deliberate 4th } brace
|
||||
@Test public void Ex_1() {fxt.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|off=none|def=off|{{{1|off}}}}}", "{{test|b}}" , "b");}
|
||||
@Test public void Ex_2() {
|
||||
fxt.Test_parse_tmpl_str_test(String_.Concat_lines_nl_skip_last
|
||||
( "{{#switch:{{{{{|safesubst:}}}NAMESPACE:Category:Foo}}"
|
||||
, "|{{ns:0}}"
|
||||
, "|{{ns:Category}}=yes"
|
||||
, "|no"
|
||||
, "}}"
|
||||
)
|
||||
, "{{test}}"
|
||||
, "yes");
|
||||
}
|
||||
@Test public void Ws() {
|
||||
fxt.Test_parse_tmpl_str_test(String_.Concat_lines_nl_skip_last
|
||||
( "{{#switch: | {{ns:0}}"
|
||||
, "|{{ns:2}} = yes"
|
||||
, "|no"
|
||||
, "}}"
|
||||
)
|
||||
, "{{test}}"
|
||||
, "yes");
|
||||
}
|
||||
@Test public void Do_not_call_val_unless_needed() {
|
||||
fxt.Init_defn_clear();
|
||||
Xop_xowa_dbg.Argx_list.Clear();
|
||||
fxt.Init_defn_add("fail", "{{#xowa_dbg:Fail}}");
|
||||
fxt.Init_defn_add("pass", "{{#xowa_dbg:Pass}}");
|
||||
fxt.Init_defn_add("dflt", "{{#xowa_dbg:Dflt}}");
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:{{{1}}}|a={{fail}}|#default={{dflt}}|b={{pass}}}}", "{{test|b}}", "Pass");
|
||||
Tfds.Eq(1, Xop_xowa_dbg.Argx_list.Count());
|
||||
}
|
||||
@Test public void Dflt_empty() { // PURPOSE: empty default should return "" not "#default"; PAGE:de.v:M<>nchen/Sehensw<73>rdigkeiten; DATE:2014-05-29
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:z|b=1|#default}}" , "{{test}}" , "");
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:z|b=1|#defaultabc}}" , "{{test}}" , "abc"); // chop off "#default"
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:a|#default|#default=1}}" , "{{test}}" , "1"); // override "|#default|" with "|#default=2|"
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:b|#default|1}}" , "{{test}}" , "1"); // override "|#default|" with "|2|"
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:b|#defaultabc=1}}" , "{{test}}" , "1"); // this is also supported by MW
|
||||
}
|
||||
@Test public void Multiple() {
|
||||
fxt.Wiki().Lang().Kwd_mgr().Kwd_default_match_reset();
|
||||
Xol_kwd_grp kwd_grp = fxt.Wiki().Lang().Kwd_mgr().Get_or_new(Xol_kwd_grp_.Id_xtn_default);
|
||||
kwd_grp.Srl_load(Bool_.Y, new byte[][] {Bry_.new_a7("#default1"), Bry_.new_a7("#default2")});
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:|n=n|#default1=y}}" , "{{test}}" , "y");
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:|n=n|#default2=y}}" , "{{test}}" , "y");
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:a|n=n|#default=y}}" , "{{test}}" , ""); // #default is just a case
|
||||
fxt.Test_parse_tmpl_str_test("{{#switch:|n=n|#default=y}}" , "{{test}}" , ""); // make sure empty String doesn't throw out of bounds
|
||||
fxt.Wiki().Lang().Kwd_mgr().Kwd_default_match_reset();
|
||||
}
|
||||
}
|
||||
28
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Xop_xowa_dbg.java
Normal file
28
400_xowa/src/gplx/xowa/xtns/pfuncs/ifs/Xop_xowa_dbg.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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.ifs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Xop_xowa_dbg extends Pf_func_base {
|
||||
@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);
|
||||
bfr.Add(argx);
|
||||
Argx_list.Add(argx);
|
||||
}
|
||||
public static final List_adp Argx_list = List_adp_.new_();
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xowa_dbg;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Xop_xowa_dbg().Name_(name);}
|
||||
}
|
||||
59
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_gender.java
Normal file
59
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_gender.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
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.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.primitives.*; import gplx.xowa.users.*;
|
||||
import gplx.xowa.langs.genders.*;
|
||||
public class Pfunc_gender extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_i18n_gender;}
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_gender().Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
byte[] user_name = Eval_argx(ctx, src, caller, self);
|
||||
byte[] when_m = Bry_.Empty, when_f = Bry_.Empty, when_u = Bry_.Empty;
|
||||
int self_args_len = self.Args_len();
|
||||
if (self_args_len == 0) return; // per MW: EX: {{gender:name}} -> ""
|
||||
else {
|
||||
if (self_args_len > 0) {
|
||||
when_m = when_u = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0); // default when_u to when_m
|
||||
if (self_args_len > 1) {
|
||||
when_f = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 1);
|
||||
if (self_args_len > 2) {
|
||||
when_u = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self_args_len == 1) {bfr.Add(when_m); return;} // per MW: EX: {{gender:name|a}} -> "a"
|
||||
int gender = Get_gender(ctx.App().User(), user_name);
|
||||
Xol_lang lang = ctx.Cur_page().Lang();
|
||||
bfr.Add(lang.Gender().Gender_eval(gender, when_m, when_f, when_u));
|
||||
}
|
||||
private static int Get_gender(Xou_user user, byte[] user_name) {
|
||||
int user_name_len = user_name.length;
|
||||
switch (user_name_len) {
|
||||
case 0: return Xol_gender_.Tid_unknown; // EX: {{gender:|m|f}}
|
||||
case 1: if (user_name[0] == Byte_ascii.Dot) return Xol_gender_.Tid_unknown; break; // EX: {{gender:.|m|f}}; TODO: should define default gender for wiki
|
||||
}
|
||||
Object o = gender_cache.Get_by_bry(user_name);
|
||||
return o == null ? user.Gender() : ((Int_obj_val)o).Val();
|
||||
}
|
||||
private static final Hash_adp_bry gender_cache = Hash_adp_bry.cs_() // for tests
|
||||
.Add_str_int("xowa_male" , Xol_gender_.Tid_male)
|
||||
.Add_str_int("xowa_female" , Xol_gender_.Tid_female)
|
||||
;
|
||||
}
|
||||
@@ -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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*; import gplx.xowa.langs.*;
|
||||
public class Pfunc_gender_tst { // REF.MW:https://translatewiki.net/wiki/Gender
|
||||
private final Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void No_args() {fxt.Test_parse_template("{{gender:}}" , "");}
|
||||
@Test public void Username_m() {fxt.Test_parse_template("{{gender:xowa_male|m|f|?}}" , "m");}
|
||||
@Test public void Username_f() {fxt.Test_parse_template("{{gender:xowa_female|m|f|?}}" , "f");}
|
||||
@Test public void Username_unknown() {fxt.Test_parse_template("{{gender:wmf_user|m|f|?}}" , "?");} // should look up gender of "wmf_user", but since not avaliable, default to unknown
|
||||
@Test public void Username_unknown_m() {fxt.Test_parse_template("{{gender:wmf_user|m}}" , "m");} // if only m is provided, use it
|
||||
@Test public void Username_unknown_f() {fxt.Test_parse_template("{{gender:wmf_user|m|f}}" , "m");} // if only m is provided; same as above, but make sure "f" doesn't change anything
|
||||
@Test public void Default() {fxt.Test_parse_template("{{gender:.|m|f|?}}" , "?");} // "." means use wiki's default gender; default to unknown
|
||||
@Test public void Unknown() {fxt.Test_parse_template("{{gender:|m|f|?}}" , "?");} // "" always is unknown
|
||||
}
|
||||
32
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_grammar.java
Normal file
32
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_grammar.java
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
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.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_grammar extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_i18n_grammar;}
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_grammar().Name_(name);} // NOTE: odmiana used as magic-word / template in pl.d; EX:pl.d:hund; DATE:2014-08-14
|
||||
@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) {Exc_.Noop(e);}
|
||||
if (!pass) Xot_invk_tkn.Print_not_found(bfr, ctx.Wiki().Ns_mgr(), this.Name());
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*; import gplx.xowa.langs.*;
|
||||
public class Pfunc_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");
|
||||
}
|
||||
}
|
||||
56
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_i18n_tst.java
Normal file
56
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_i18n_tst {
|
||||
@Before public void init() {fxt.Clear();} private Pfunc_i18n_fxt fxt = new Pfunc_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 Pfunc_i18n_fxt {
|
||||
public void Clear() {}
|
||||
public Xop_fxt Fxt() {return fxt;}
|
||||
public Pfunc_i18n_fxt lang_(String v) {lang_key = v; return this;} private String lang_key;
|
||||
public Pfunc_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_a7(lang_key));
|
||||
wiki = Xoa_app_fxt.wiki_(app, lang_key + ".wikipedia.org", lang);
|
||||
fxt = new Xop_fxt(app, wiki);
|
||||
return this;
|
||||
} private Xoae_app app; private Xop_fxt fxt; Xol_lang lang; Xowe_wiki wiki;
|
||||
public Pfunc_i18n_fxt Reg_func(String name, boolean case_match, String word) {
|
||||
Io_url url = Io_url_.mem_fil_("mem/xowa/bin/any/xowa/cfg/lang/core/" + lang_key + ".gfs");
|
||||
String func = "keywords.load_text('" + name + "|" + (case_match ? "1" : "0") + "|" + name + "~" + word + "~');";
|
||||
Io_mgr.I.SaveFilStr(url, func);
|
||||
return this;
|
||||
}
|
||||
public Pfunc_i18n_fxt Reg_msg(String key, String val) {
|
||||
Io_url url = Io_url_.mem_fil_("mem/xowa/bin/any/xowa/cfg/lang/core/" + lang_key + ".gfs");
|
||||
String func = "messages.load_text('" + key + "|" + val + "');";
|
||||
Io_mgr.I.SaveFilStr(url, func);
|
||||
return this;
|
||||
}
|
||||
public Pfunc_i18n_fxt Load() {
|
||||
lang.Init_by_load();
|
||||
wiki.Fragment_mgr().Evt_lang_changed(lang);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
38
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_int.java
Normal file
38
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.php.*; import gplx.xowa.langs.msgs.*;
|
||||
public class Pfunc_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);
|
||||
Xowe_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 = Xol_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 Pfunc_int().Name_(name);}
|
||||
}
|
||||
116
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_int_tst.java
Normal file
116
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_int_tst.java
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
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.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_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 Tmpl_html_entity() { // PURPOSE: check that is swapped out correctly for (194,160); PAGE:fr.s:Main_Page DATE:2014-08-17
|
||||
fxt.Init_msg_gfs("tst_msg", "A B", false, true);
|
||||
fxt.Test_parse_en("{{int:tst_msg}}", "A B"); // NOTE:
|
||||
}
|
||||
@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_u8("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
|
||||
Xowe_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 Xowe_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_u8(key));
|
||||
msg_itm.Atrs_set(Bry_.new_u8(val), fmt, tmpl);
|
||||
}
|
||||
public void Init_msg_db(String ttl, String val) {Init_msg_db(en_wiki, ttl, val);}
|
||||
public void Init_msg_db(Xowe_wiki wiki, String ttl, String val) {
|
||||
fxt.Init_page_create(wiki, "MediaWiki:" + ttl, val);
|
||||
}
|
||||
public Xowe_wiki Make_wiki(String domain) {return fxt.App().Wiki_mgr().Get_by_key_or_make(Bry_.new_u8(domain));}
|
||||
public void Test_parse_en(String raw, String expd) {
|
||||
fxt.Test_parse_tmpl_str_test(raw, "{{test}}" , expd);
|
||||
}
|
||||
public void Test_parse_wiki(Xowe_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_a7(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
|
||||
}
|
||||
}
|
||||
|
||||
35
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_language.java
Normal file
35
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_language.java
Normal file
@@ -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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.langs.*;
|
||||
public class Pfunc_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 Pfunc_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 Match_exact
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_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/gplx/xowa/xtns/pfuncs/langs/Pfunc_plural.java
Normal file
31
400_xowa/src/gplx/xowa/xtns/pfuncs/langs/Pfunc_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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_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 Pfunc_plural().Name_(name);}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.langs; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_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");}
|
||||
}
|
||||
43
400_xowa/src/gplx/xowa/xtns/pfuncs/numbers/Pf_formatnum.java
Normal file
43
400_xowa/src/gplx/xowa/xtns/pfuncs/numbers/Pf_formatnum.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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.numbers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.btries.*; import gplx.intl.*; import gplx.xowa.langs.numbers.*;
|
||||
public class Pf_formatnum extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_str_formatnum;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pf_formatnum().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) {
|
||||
Xol_lang lang = ctx.Wiki().Lang();
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] argx = Eval_argx(ctx, src, caller, self);
|
||||
byte[] arg1 = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
|
||||
bfr.Add(Format_num(lang, argx, arg1));
|
||||
}
|
||||
public static byte[] Format_num(Xol_lang lang, byte[] num, byte[] arg1) {
|
||||
Btrie_slim_mgr trie_raw = lang.Kwd_mgr().Trie_raw();
|
||||
Btrie_slim_mgr trie_nosep = lang.Kwd_mgr().Trie_nosep();
|
||||
int arg1_len = arg1.length;
|
||||
if (Bry_.Len_gt_0(arg1)) { // argument specified
|
||||
if (trie_raw .Match_exact(arg1, 0, arg1_len) != null)
|
||||
return lang.Num_mgr().Raw(num);
|
||||
else if (trie_nosep .Match_exact(arg1, 0, arg1_len) != null)
|
||||
return lang.Num_mgr().Format_num_no_separators(num);
|
||||
}
|
||||
return lang.Num_mgr().Format_num(num);
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.numbers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
import gplx.intl.*; import gplx.xowa.langs.numbers.*;
|
||||
public class Pf_formatnum_de_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {
|
||||
fxt.Reset();
|
||||
fxt.Init_lang_numbers_separators(".", ",");
|
||||
}
|
||||
@After public void term() {
|
||||
fxt.Init_lang_numbers_separators_en();
|
||||
}
|
||||
@Test public void Fmt__plain() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234,56}}" , "{{test}}" , "1.234.56");} // NOTE: double "." looks strange, but matches MW; DATE:2013-10-24
|
||||
@Test public void Fmt__grp_dlm() {fxt.Test_parse_tmpl_str_test("{{formatnum:1.234,56}}" , "{{test}}" , "1,234.56");}
|
||||
@Test public void Fmt__dec_dlm() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234.56}}" , "{{test}}" , "1.234,56");} // NOTE: "." should be treated as decimal separator, but replaced with ","; DATE:2013-10-21
|
||||
@Test public void Raw__grp_dlm() {fxt.Test_parse_tmpl_str_test("{{formatnum:1.234,56|R}}" , "{{test}}" , "1234.56");}
|
||||
@Test public void Raw__plain() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234,56|R}}" , "{{test}}" , "1234.56");}
|
||||
@Test public void Raw__dec_dlm() {fxt.Test_parse_tmpl_str_test("{{formatnum:12,34|R}}" , "{{test}}" , "12.34");} // NOTE: dec_dlm is always ".
|
||||
@Test public void Nosep__plain() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234,56|NOSEP}}" , "{{test}}" , "1234,56");}
|
||||
@Test public void Nosep__grp_dlm() {fxt.Test_parse_tmpl_str_test("{{formatnum:1.234,56|NOSEP}}" , "{{test}}" , "1.234,56");}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
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.numbers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
import gplx.intl.*;
|
||||
public class Pf_formatnum_en_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Len_4() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234}}" , "{{test}}" , "1,234");}
|
||||
@Test public void Len_7() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234567}}" , "{{test}}" , "1,234,567");}
|
||||
@Test public void Len_2() {fxt.Test_parse_tmpl_str_test("{{formatnum:12}}" , "{{test}}" , "12");}
|
||||
@Test public void Len_10() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234567890}}" , "{{test}}" , "1,234,567,890");}
|
||||
@Test public void Neg() {fxt.Test_parse_tmpl_str_test("{{formatnum:-1234}}" , "{{test}}" , "-1,234");}
|
||||
@Test public void Decimal() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234.5678}}" , "{{test}}" , "1,234.5678");}
|
||||
@Test public void Mixed() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234abc5678}}" , "{{test}}" , "1,234abc5,678");}
|
||||
@Test public void Zeros() {fxt.Test_parse_tmpl_str_test("{{formatnum:0000000}}" , "{{test}}" , "0,000,000");}
|
||||
@Test public void Raw__grp_dlm() {fxt.Test_parse_tmpl_str_test("{{formatnum:1,234.56|R}}" , "{{test}}" , "1234.56");}
|
||||
@Test public void Raw__plain() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234.56|R}}" , "{{test}}" , "1234.56");}
|
||||
@Test public void Nosep__plain() {fxt.Test_parse_tmpl_str_test("{{formatnum:1234.56|NOSEP}}" , "{{test}}" , "1234.56");}
|
||||
@Test public void Nosep__grp_dlm() {fxt.Test_parse_tmpl_str_test("{{formatnum:1,234.56|NOSEP}}" , "{{test}}" , "1,234.56");}
|
||||
@Test public void Cs() {fxt.Test_parse_tmpl_str_test("{{FORMATNUM:1234}}" , "{{test}}" , "1,234");}
|
||||
@Test public void Exc_ws() { // PURPOSE: EX: {{rnd|122835.3|(-3)}}
|
||||
fxt.Test_parse_tmpl_str_test(String_.Concat_lines_nl_skip_last
|
||||
( "{{formatnum:"
|
||||
, " {{#expr:2}}"
|
||||
, "}}"
|
||||
)
|
||||
, "{{test}}"
|
||||
, "2"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.numbers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
import gplx.intl.*; import gplx.xowa.langs.numbers.*;
|
||||
public class Pf_formatnum_es_tst {
|
||||
private Xop_fxt fxt;
|
||||
@Before public void init() {
|
||||
Xoae_app app = Xoa_app_fxt.app_();
|
||||
Xol_lang lang = new Xol_lang(app.Lang_mgr(), Bry_.new_a7("es")).Init_by_load_assert();
|
||||
Xowe_wiki wiki = Xoa_app_fxt.wiki_(app, "es.wikipedia.org", lang);
|
||||
fxt = new Xop_fxt(app, wiki);
|
||||
}
|
||||
@Test public void Basic() {
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:1234.56}}" , "{{test}}", "1234.56"); // fmt.n;
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:1234}}" , "{{test}}", "1234"); // fmt.n; decimal
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:-1234.56}}" , "{{test}}", "-1234.56"); // fmt.n; neg
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:12345.90}}" , "{{test}}", "12,345.90"); // fmt.y; 5
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:123456.90}}" , "{{test}}", "123,456.90"); // fmt.y; 6
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:1234.}}" , "{{test}}", "1,234."); // stress; decimal at end
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:123456a}}" , "{{test}}", "123,456a"); // stress; letters
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
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.numbers; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
import gplx.intl.*; import gplx.xowa.langs.numbers.*;
|
||||
public class Pf_formatnum_fa_tst {
|
||||
private Xop_fxt fxt;
|
||||
@Before public void init() {
|
||||
Xoae_app app = Xoa_app_fxt.app_();
|
||||
Xol_lang lang = new Xol_lang(app.Lang_mgr(), Bry_.new_a7("fa")).Init_by_load_assert();
|
||||
String gfs = String_.Concat_lines_nl
|
||||
( "numbers {"
|
||||
, " digits {"
|
||||
, " clear;"
|
||||
, " set('0', '۰');"
|
||||
, " set('1', '۱');"
|
||||
, " set('2', '۲');"
|
||||
, " set('3', '۳');"
|
||||
, " set('4', '۴');"
|
||||
, " set('5', '۵');"
|
||||
, " set('6', '۶');"
|
||||
, " set('7', '۷');"
|
||||
, " set('8', '۸');"
|
||||
, " set('9', '۹');"
|
||||
, " set('%', '٪');"
|
||||
, " set('.', '٫');"
|
||||
, " set(',', '٬');"
|
||||
, " }"
|
||||
, "}"
|
||||
);
|
||||
app.Gfs_mgr().Run_str_for(lang, gfs);
|
||||
Xowe_wiki wiki = Xoa_app_fxt.wiki_(app, "fa.wikipedia.org", lang);
|
||||
fxt = new Xop_fxt(app, wiki);
|
||||
}
|
||||
@Test public void Basic() {
|
||||
fxt.Test_parse_tmpl_str_test("{{formatnum:۱۵۰|R}}" , "{{test}}", "150");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_defaultsort extends Pf_func_base {
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_page_defaultsort;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_defaultsort().Name_(name);}
|
||||
public static final Pfunc_defaultsort _ = new Pfunc_defaultsort(); Pfunc_defaultsort() {}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
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.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.html.*; import gplx.xowa.langs.cases.*;
|
||||
public class Pfunc_displaytitle extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_page_displaytitle;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_displaytitle().Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
byte[] val_dat_ary = Eval_argx(ctx, src, caller, self);
|
||||
Xowe_wiki wiki = ctx.Wiki(); Xop_parser parser = wiki.Parser();
|
||||
Xop_ctx display_ttl_ctx = Xop_ctx.new_sub_(wiki);
|
||||
Xop_root_tkn display_ttl_root = parser.Parse_text_to_wdom(display_ttl_ctx, val_dat_ary, false);
|
||||
Bry_bfr tmp_bfr = wiki.Utl__bfr_mkr().Get_b512();
|
||||
boolean restrict = wiki.Cfg_parser().Display_title_restrict();
|
||||
Xoh_wtr_ctx hctx = restrict ? Xoh_wtr_ctx.Display_title : Xoh_wtr_ctx.Basic; // restrict removes certain HTML (display:none)
|
||||
wiki.Html_mgr().Html_wtr().Write_tkn(tmp_bfr, display_ttl_ctx, hctx, display_ttl_root.Data_mid(), display_ttl_root, 0, display_ttl_root);
|
||||
byte[] val_html = tmp_bfr.Xto_bry_and_clear();
|
||||
if (restrict) { // restrict only allows displayTitles which have text similar to the pageTitle; PAGE:de.b:Kochbuch/_Druckversion; DATE:2014-08-18
|
||||
Xoae_page page = ctx.Cur_page();
|
||||
wiki.Html_mgr().Html_wtr().Write_tkn(tmp_bfr, display_ttl_ctx, Xoh_wtr_ctx.Alt, display_ttl_root.Data_mid(), display_ttl_root, 0, display_ttl_root);
|
||||
byte[] val_html_lc = tmp_bfr.Xto_bry_and_clear();
|
||||
Xol_case_mgr case_mgr = wiki.Lang().Case_mgr();
|
||||
val_html_lc = Standardize_displaytitle_text(case_mgr, val_html_lc);
|
||||
byte[] page_ttl_lc = Standardize_displaytitle_text(case_mgr, page.Ttl().Page_db());
|
||||
if (!Bry_.Eq(val_html_lc, page_ttl_lc))
|
||||
val_html = null;
|
||||
}
|
||||
ctx.Cur_page().Html_data().Display_ttl_(val_html);
|
||||
tmp_bfr.Mkr_rls();
|
||||
}
|
||||
private static byte[] Standardize_displaytitle_text(Xol_case_mgr case_mgr, byte[] val) {
|
||||
byte[] rv = case_mgr.Case_build_lower(val); // lower-case
|
||||
return Bry_.Replace(rv, Byte_ascii.Space, Byte_ascii.Underline); // force underline; PAGE:de.w:Mod_qos DATE:2014-11-06
|
||||
}
|
||||
public static final Pfunc_displaytitle _ = new Pfunc_displaytitle(); Pfunc_displaytitle() {}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_displaytitle_tst {
|
||||
@Before public void init() {fxt.Reset();} private Pfunc_displaytitle_fxt fxt = new Pfunc_displaytitle_fxt();
|
||||
@Test public void Basic() {fxt.Init_restrict(Bool_.N).Test("{{DISPLAYTITLE:B A}}" , "B A");}
|
||||
@Test public void Apos_italic() {fxt.Init_restrict(Bool_.N).Test("{{DISPLAYTITLE:''B A''}}" , "<i>B A</i>");}
|
||||
@Test public void Restrict_skip() {fxt.Init_restrict(Bool_.Y).Test("{{DISPLAYTITLE:B A}}" , null);} // PURPOSE: skip if text does not match title; PAGE:de.b:Kochbuch/_Druckversion; DATE:2014-08-18
|
||||
@Test public void Restrict_keep_ci() {fxt.Init_restrict(Bool_.Y).Test("{{DISPLAYTITLE:a B}}" , "a B");} // PURPOSE: keep b/c case-insensitive match; DATE:2014-08-18
|
||||
@Test public void Restrict_keep_underscore() {fxt.Init_restrict(Bool_.Y).Test("{{DISPLAYTITLE:a_b}}" , "a_b");} // PURPOSE: keep b/c underscores should match spaces; PAGE:de.w:Mod_qos DATE:2014-11-06
|
||||
@Test public void Restrict_keep_tags() {fxt.Init_restrict(Bool_.Y).Test("{{DISPLAYTITLE:<b>a</b> <i>B</i>}}" , "<b>a</b> <i>B</i>");}// PURPOSE: keep b/c text match (tags ignored); DATE:2014-08-18
|
||||
@Test public void Strip_display() {
|
||||
String expd_fail = "<span style='/* attempt to bypass $wgRestrictDisplayTitle */'>A b</span>";
|
||||
fxt.Init_restrict(Bool_.Y);
|
||||
fxt.Test("{{DISPLAYTITLE:<span style='display:none;'>A b</span>}}" , expd_fail);
|
||||
fxt.Test("{{DISPLAYTITLE:<span style='user-select:n;'>A b</span>}}" , expd_fail);
|
||||
fxt.Test("{{DISPLAYTITLE:<span style='visibility:n;'>A b</span>}}" , expd_fail);
|
||||
fxt.Test("{{DISPLAYTITLE:<span style=''>display:none</span>}}" , null);
|
||||
}
|
||||
}
|
||||
class Pfunc_displaytitle_fxt {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
public void Reset() {
|
||||
fxt.Reset();
|
||||
fxt.Page_ttl_("A b");
|
||||
}
|
||||
public Pfunc_displaytitle_fxt Init_restrict(boolean v) {fxt.Wiki().Cfg_parser().Display_title_restrict_(v); return this;}
|
||||
public void Test(String raw, String expd) {
|
||||
fxt.Page().Html_data().Display_ttl_(null); // TEST: always reset; needed for Strip_display which calls multiple times
|
||||
fxt.Test_parse_tmpl_str_test(raw, "{{test}}", "");
|
||||
Tfds.Eq(expd, String_.new_u8(fxt.Page().Html_data().Display_ttl()));
|
||||
}
|
||||
}
|
||||
24
400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_misc_tst.java
Normal file
24
400_xowa/src/gplx/xowa/xtns/pfuncs/pages/Pfunc_misc_tst.java
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_misc_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void CascadingSources() {fxt.Test_parse_page_all_str("{{CASCADINGSOURCES}}", "");} // PURPOSE: noop; DATE:2014-04-09
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_noeditsection extends Pf_func_base {
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bb) {}
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_noeditsection;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_noeditsection().Name_(name);}
|
||||
public static final Pfunc_noeditsection _ = new Pfunc_noeditsection(); Pfunc_noeditsection() {}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
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.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.pages.*;
|
||||
public class Pfunc_rev_props extends Pf_func_base {
|
||||
@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);
|
||||
Xopg_revision_data rev_data = ctx.Cur_page().Revision_data();
|
||||
switch (id) {
|
||||
case Xol_kwd_grp_.Id_page_id:
|
||||
case Xol_kwd_grp_.Id_rev_id: bfr.Add_int_variable(ctx.Cur_page().Revision_data().Id()); break; // NOTE: making rev_id and page_id interchangeable; XOWA does not store rev_id
|
||||
case Xol_kwd_grp_.Id_rev_user: bfr.Add(rev_data.User()); break;
|
||||
case Xol_kwd_grp_.Id_rev_pagesize:
|
||||
if (argx.length > 0) {
|
||||
Xoa_ttl argx_ttl = Xoa_ttl.parse_(ctx.Wiki(), argx);
|
||||
if (argx_ttl == null) { // invalid ttl; EX: {{PAGESIZE:{{{bad}}}}}
|
||||
bfr.Add_byte(Byte_ascii.Num_0);
|
||||
return;
|
||||
}
|
||||
Xoae_page argx_page = ctx.Wiki().Data_mgr().Get_page(argx_ttl, false);
|
||||
if (!argx_page.Missing()) {
|
||||
bfr.Add_int_variable(argx_page.Data_raw().length);
|
||||
return;
|
||||
}
|
||||
}
|
||||
bfr.Add_byte(Byte_ascii.Num_0);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_rev_protectionlevel: bfr.Add(rev_data.Protection_level()); break;
|
||||
default: throw Exc_.new_unhandled(id);
|
||||
}
|
||||
}
|
||||
public Pfunc_rev_props(int id) {this.id = id;}
|
||||
@Override public int Id() {return id;} private int id;
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_rev_props(id).Name_(name);}
|
||||
public static final Pfunc_rev_props _ = new Pfunc_rev_props(-1);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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.pages; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_rev_props_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void setup() {fxt.Reset(); fxt.Page().Revision_data().User_(Bry_.new_a7("user")).Protection_level_(Bry_.new_a7("normal"));}
|
||||
@After public void teardown() {}
|
||||
@Test public void RevisionID() {fxt.Page().Revision_data().Id_(1); fxt.Test_parse_tmpl_str_test("{{REVISIONID}}" , "{{test}}", "1");}
|
||||
@Test public void PageID() {fxt.Page().Revision_data().Id_(1); fxt.Test_parse_tmpl_str_test("{{PAGEID}}" , "{{test}}", "1");}
|
||||
@Test public void RevisionUser() {fxt.Test_parse_tmpl_str_test("{{REVISIONUSER}}" , "{{test}}", "user");}
|
||||
@Test public void PageSize() {fxt.Test_parse_tmpl_str_test("{{PAGESIZE:Test page}}" , "{{test}}", "0");}
|
||||
@Test public void ProtectionLevel() {fxt.Test_parse_tmpl_str_test("{{PROTECTIONLEVEL}}" , "{{test}}", "normal");}
|
||||
@Test public void PageSize_invalid_ttl() {
|
||||
fxt.Init_log_(Xop_ttl_log.Invalid_char);
|
||||
fxt.Test_parse_tmpl_str_test("{{PAGESIZE:{{{100}}}|R}}" , "{{test}}", "0");
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.libs.*;
|
||||
import gplx.xowa.xtns.pfuncs.exprs.*;
|
||||
public class Pfunc_scrib_lib implements Scrib_lib {
|
||||
private Scrib_core core;
|
||||
public Scrib_lua_mod Mod() {return mod;} private Scrib_lua_mod mod;
|
||||
public Scrib_lib Init() {procs.Init_by_lib(this, Proc_names); return this;}
|
||||
public void Core_(Scrib_core v) {this.core = v;} // TEST:
|
||||
public Scrib_lua_mod Register(Scrib_core core, Io_url script_dir) {
|
||||
this.core = core;
|
||||
Init();
|
||||
mod = core.RegisterInterface(this, core.App().Fsys_mgr().Bin_xtns_dir().GenSubFil_nest("ParserFunctions", "mw.ext.ParserFunctions.lua"));
|
||||
return mod;
|
||||
}
|
||||
public Scrib_proc_mgr Procs() {return procs;} private Scrib_proc_mgr procs = new Scrib_proc_mgr();
|
||||
public boolean Procs_exec(int key, Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
switch (key) {
|
||||
case Proc_expr: return Expr(args, rslt);
|
||||
default: throw Exc_.new_unhandled(key);
|
||||
}
|
||||
}
|
||||
private static final int Proc_expr = 0;
|
||||
public static final String Invk_expr = "expr";
|
||||
private static final String[] Proc_names = String_.Ary(Invk_expr);
|
||||
public boolean Expr(Scrib_proc_args args, Scrib_proc_rslt rslt) {
|
||||
byte[] expr_bry = args.Pull_bry(0);
|
||||
Bry_bfr tmp_bfr = core.Wiki().Utl__bfr_mkr().Get_b128();
|
||||
boolean pass = Pfunc_expr.Evaluate(tmp_bfr, core.Ctx(), expr_bry);
|
||||
String expr_rslt = tmp_bfr.To_str_and_rls();
|
||||
if (pass)
|
||||
return rslt.Init_obj(expr_rslt);
|
||||
else
|
||||
throw Exc_.new_(expr_rslt);
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
import gplx.xowa.xtns.scribunto.*; import gplx.xowa.xtns.scribunto.libs.*;
|
||||
public class Pfunc_scrib_lib_tst {
|
||||
@Before public void init() {
|
||||
fxt.Clear_for_lib();
|
||||
lib = new Pfunc_scrib_lib();
|
||||
lib.Init();
|
||||
lib.Core_(fxt.Core());
|
||||
} private Scrib_invoke_func_fxt fxt = new Scrib_invoke_func_fxt(); private Pfunc_scrib_lib lib;
|
||||
@Test public void Expr() {
|
||||
fxt.Test_scrib_proc_str(lib, Pfunc_scrib_lib.Invk_expr, Object_.Ary("1 + 2") , "3");
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.scribunto; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.xtns.scribunto.*;
|
||||
public class Pfunc_xtn_mgr extends Xox_mgr_base {
|
||||
@Override public byte[] Xtn_key() {return XTN_KEY;} public static final byte[] XTN_KEY = Bry_.new_a7("ParserFunctions");
|
||||
@Override public void Xtn_init_by_app(Xoae_app app) {
|
||||
Scrib_xtn_mgr scrib_xtn = (Scrib_xtn_mgr)app.Xtn_mgr().Get_or_fail(Scrib_xtn_mgr.XTN_KEY);
|
||||
scrib_xtn.Lib_mgr().Add(new Pfunc_scrib_lib());
|
||||
}
|
||||
@Override public Xox_mgr Clone_new() {return new Pfunc_xtn_mgr();}
|
||||
}
|
||||
39
400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_case.java
Normal file
39
400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_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.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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
61
400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_pad.java
Normal file
61
400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_pad.java
Normal 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
|
||||
*/
|
||||
@@ -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ā");}
|
||||
}
|
||||
128
400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_tag.java
Normal file
128
400_xowa/src/gplx/xowa/xtns/pfuncs/strings/Pfunc_tag.java
Normal 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();
|
||||
}
|
||||
@@ -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>");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_count extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_count;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_count().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[] str = Eval_argx(ctx, src, caller, self);
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] find = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 0, null); if (find == null) find = Byte_ascii.Space_bry;
|
||||
bfr.Add_int_variable(Count(str, find));
|
||||
}
|
||||
public static int Count(byte[] src, byte[] find) {
|
||||
int src_len = src.length; int find_len = find.length;
|
||||
int pos = 0;
|
||||
int rv = 0;
|
||||
while (true) {
|
||||
int find_pos = Bry_finder.Find_fwd(src, find, pos, src_len);
|
||||
if (find_pos == Bry_finder.Not_found) break;
|
||||
pos = find_pos + find_len;
|
||||
++rv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_count_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Basic() {fxt.Test_parse_template("{{#count:aaa|a}}" , "3");}
|
||||
@Test public void Not_found() {fxt.Test_parse_template("{{#count:aaa|b}}" , "0");}
|
||||
@Test public void Find_defaults_to_space() {fxt.Test_parse_template("{{#count:a b c}}" , "2");}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_explode extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_explode;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_explode().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) {
|
||||
// * {{#explode:String | delimiter | position | limit}}
|
||||
byte[] s = Eval_argx(ctx, src, caller, self);
|
||||
int args_len = self.Args_len();
|
||||
byte[] dlm = Byte_ascii.Space_bry; int idx = 0, limit = -1;
|
||||
if (args_len > 0) {
|
||||
dlm = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 0, null);
|
||||
if (Bry_.Len_eq_0(dlm)) dlm = Byte_ascii.Space_bry; // handle empty String; EX: {{#explode:a b||1}}
|
||||
if (args_len > 1) {
|
||||
byte[] pos_bry = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 1, null);
|
||||
if (pos_bry != null) idx = Bry_.Xto_int_or(pos_bry, 0);
|
||||
if (args_len > 2) {
|
||||
byte[] limit_bry = Pf_func_.Eval_arg_or(ctx, src, caller, self, args_len, 2, null);
|
||||
if (limit_bry != null) limit = Bry_.Xto_int_or(pos_bry, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (idx < 0) {
|
||||
int count = Pfunc_count.Count(s, dlm);
|
||||
idx = count + idx;
|
||||
}
|
||||
byte[] rv = Split_and_get_by_idx(s, dlm, idx, limit);
|
||||
bfr.Add(rv);
|
||||
}
|
||||
private static byte[] Split_and_get_by_idx(byte[] src, byte[] dlm, int idx, int limit) {
|
||||
int src_len = src.length; int dlm_len = dlm.length;
|
||||
int pos = 0; int found = 0;
|
||||
while (true) {
|
||||
int find_pos = Bry_finder.Find_fwd(src, dlm, pos);
|
||||
if (find_pos == Bry_finder.Not_found) break;
|
||||
if (found == idx) return Bry_.Mid(src, pos, find_pos);
|
||||
pos = find_pos + dlm_len;
|
||||
++found;
|
||||
}
|
||||
return found == idx ? Bry_.Mid(src, pos, src_len) : Bry_.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_explode_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Idx_1st() {fxt.Test_parse_template("{{#explode:a,b,c|,|0}}" , "a");}
|
||||
@Test public void Idx_mid() {fxt.Test_parse_template("{{#explode:a,b,c|,|1}}" , "b");}
|
||||
@Test public void Idx_nth() {fxt.Test_parse_template("{{#explode:a,b,c|,|2}}" , "c");}
|
||||
@Test public void Idx_missing() {fxt.Test_parse_template("{{#explode:a,b,c|,|3}}" , "");}
|
||||
@Test public void Idx_neg() {fxt.Test_parse_template("{{#explode:a,b,c|,|-1}}" , "b");}
|
||||
@Test public void Find_defaults_to_space() {fxt.Test_parse_template("{{#explode:a b c||0}}" , "a");}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_len extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_len;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_len().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[] str = Eval_argx(ctx, src, caller, self);
|
||||
int char_count = gplx.intl.Utf8_.Len_of_bry(str);
|
||||
trg.Add_int_variable(char_count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_len_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Basic() {fxt.Test_parse_template("{{#len:abc}}" , "3");}
|
||||
@Test public void Empty() {fxt.Test_parse_template("{{#len:}}" , "0");}
|
||||
@Test public void Utf8_2() {fxt.Test_parse_template("{{#len:Ĉ}}" , "1");}
|
||||
@Test public void Utf8_3() {fxt.Test_parse_template("{{#len:Ⱥ}}" , "1");}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_pos extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_pos;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_pos().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[] str = Eval_argx(ctx, src, caller, self);
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] find = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 0, Byte_ascii.Space_bry); // MW: use " " if find is missing
|
||||
byte[] offset_bry = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 1, null);
|
||||
int offset = offset_bry == null ? 0 : Bry_.Xto_int(offset_bry);
|
||||
int pos = Bry_finder.Find_fwd(str, find, offset);
|
||||
if (pos != Bry_finder.Not_found)
|
||||
trg.Add_int_variable(pos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_pos_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Basic() {fxt.Test_parse_template("{{#pos:abcabc|b}}" , "1");}
|
||||
@Test public void Index() {fxt.Test_parse_template("{{#pos:abcabc|b|3}}" , "4");}
|
||||
@Test public void Missing() {fxt.Test_parse_template("{{#pos:abcabc|z}}" , "");}
|
||||
@Test public void Find_missing() {fxt.Test_parse_template("{{#pos:abc def}}" , "3");}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_replace extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_replace;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_replace().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[] str = Eval_argx(ctx, src, caller, self);
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] find = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 0, null);
|
||||
if (Bry_.Len_eq_0(find)) find = Byte_ascii.Space_bry; // NOTE: MW defaults empty finds to space (" "); note that leaving it as "" would cause Replace to loop infinitely
|
||||
byte[] repl = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 1, Bry_.Empty);
|
||||
byte[] limit_bry = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 2, null);
|
||||
int limit = limit_bry == null ? Int_.MaxValue : Bry_.Xto_int(limit_bry);
|
||||
Bry_bfr tmp_bfr = Xoa_app_.Utl__bfr_mkr().Get_b128();
|
||||
byte[] rv = Bry_.Replace(tmp_bfr, str, find, repl, 0, str.length, limit);
|
||||
tmp_bfr.Mkr_rls();
|
||||
trg.Add(rv);
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_replace_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Basic() {fxt.Test_parse_template("{{#replace:abc|b|z}}" , "azc");}
|
||||
@Test public void Replace_all() {fxt.Test_parse_template("{{#replace:aaa|a|b}}" , "bbb");}
|
||||
@Test public void Limit() {fxt.Test_parse_template("{{#replace:aaa|a|b|2}}" , "bba");}
|
||||
@Test public void Find_defaults_to_space() {fxt.Test_parse_template("{{#replace:a b c||_}}" , "a_b_c");}
|
||||
@Test public void Not_found() {fxt.Test_parse_template("{{#replace:aaa|b|c}}" , "aaa");}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_rpos extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_rpos;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_rpos().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[] str = Eval_argx(ctx, src, caller, self);
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] find = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 0, Byte_ascii.Space_bry); // MW: use " " if find is missing
|
||||
byte[] offset_bry = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 1, null);
|
||||
int offset = offset_bry == null ? str.length : Bry_.Xto_int(offset_bry);
|
||||
int pos = Bry_finder.Find_bwd(str, find, offset);
|
||||
if (pos == Bry_finder.Not_found) pos = -1;
|
||||
trg.Add_int_variable(pos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_rpos_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Basic() {fxt.Test_parse_template("{{#rpos:abcabc|b}}" , "4");}
|
||||
@Test public void Index() {fxt.Test_parse_template("{{#rpos:abcabc|b|3}}" , "1");}
|
||||
@Test public void Missing() {fxt.Test_parse_template("{{#rpos:abcabc|z}}" , "-1");}
|
||||
@Test public void Find_missing() {fxt.Test_parse_template("{{#rpos:abc def}}" , "3");}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_sub extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_sub;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_sub().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[] s = Eval_argx(ctx, src, caller, self);
|
||||
int self_args_len = self.Args_len();
|
||||
int bgn = 0, len = Int_.MinValue;
|
||||
if (self_args_len > 0) {
|
||||
byte[] bgn_bry = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 0, null);
|
||||
if (bgn_bry != null) bgn = Bry_.Xto_int_or(bgn_bry, 0);
|
||||
if (self_args_len > 1) {
|
||||
byte[] len_bry = Pf_func_.Eval_arg_or(ctx, src, caller, self, self_args_len, 1, null);
|
||||
if (len_bry != null) len = Bry_.Xto_int_or(len_bry, Int_.MinValue);
|
||||
}
|
||||
}
|
||||
int s_len = s.length;
|
||||
if (bgn < 0) bgn = s_len + bgn;
|
||||
if (len == Int_.MinValue) len = s_len - bgn;
|
||||
if (len < 0) len = s_len - bgn + len; // neg len should remove letters from end; EX: {{#sub:abcde|2|-1}} -> "cd"
|
||||
if (bgn < 0 || len < 0) return; // if still negative, return blank; EX: {{#sub:abcde|2|-5}} -> ""
|
||||
byte[] mid = Bry_.Mid(s, bgn, bgn + len);
|
||||
bfr.Add(mid);
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_sub_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Basic() {fxt.Test_parse_template("{{#sub:abcde|2|2}}" , "cd");}
|
||||
@Test public void No_len() {fxt.Test_parse_template("{{#sub:abcde|2}}" , "cde");}
|
||||
@Test public void Neg_len() {fxt.Test_parse_template("{{#sub:abcde|2|-1}}" , "cd");}
|
||||
@Test public void Neg_len_too_much() {fxt.Test_parse_template("{{#sub:abcde|2|-9}}" , "");}
|
||||
@Test public void No_bgn() {fxt.Test_parse_template("{{#sub:abcde}}" , "abcde");}
|
||||
@Test public void Neg_bgn() {fxt.Test_parse_template("{{#sub:abcde|-2}}" , "de");}
|
||||
@Test public void Neg_bgn_too_much() {fxt.Test_parse_template("{{#sub:abcde|-9}}" , "");}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_urldecode extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_strx_urldecode;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pfunc_urldecode().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[] encoded = Eval_argx(ctx, src, caller, self);
|
||||
byte[] decoded = Xoa_app_.Utl__encoder_mgr().Http_url().Decode(encoded);
|
||||
bfr.Add(decoded);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
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.stringutils; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_urldecode_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = Xop_fxt.new_nonwmf();
|
||||
@Test public void Basic() {fxt.Test_parse_template("{{#urldecode:a%20b}}" , "a b");}
|
||||
}
|
||||
22
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm.java
Normal file
22
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm.java
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public interface Pft_fmt_itm {
|
||||
int TypeId();
|
||||
void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr);
|
||||
}
|
||||
189
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm_.java
Normal file
189
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_fmt_itm_.java
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.btries.*;
|
||||
public class Pft_fmt_itm_ {
|
||||
public static final int
|
||||
Tid_seg_int = 1
|
||||
, Tid_hour_base12 = 2
|
||||
, Tid_dow_base0 = 3
|
||||
, Tid_seg_str = 4
|
||||
, Tid_year_isLeap = 5
|
||||
, Tid_timestamp_unix = 6
|
||||
, Tid_raw_ary = 7
|
||||
, Tid_raw_byt = 8
|
||||
, Tid_dayOfYear = 9
|
||||
, Tid_daysInMonth = 10
|
||||
, Tid_AmPm = 11
|
||||
, Tid_roman = 12
|
||||
, Tid_iso_fmt = 13
|
||||
, Tid_rfc_5322 = 14
|
||||
, Tid_raw = 15
|
||||
, Tid_timezone_offset = 16
|
||||
, Tid_thai = 17
|
||||
, Tid_minguo = 18
|
||||
, Tid_hebrew_year_num = 21
|
||||
, Tid_hebrew_month_num = 20
|
||||
, Tid_hebrew_day_num = 19
|
||||
, Tid_hebrew_month_days_count = 22
|
||||
, Tid_hebrew_month_name_full = 23
|
||||
, Tid_hebrew_month_name_gen = 24
|
||||
, Tid_hebrew_numeral = 25
|
||||
;
|
||||
|
||||
public static final Pft_fmt_itm
|
||||
Year_len4 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_year , 4, Bool_.Y)
|
||||
, Year_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_year , 2, Bool_.Y)
|
||||
, Month_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_month , 2, Bool_.Y)
|
||||
, Month_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_month , 2, Bool_.N)
|
||||
, Day_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_day , 2, Bool_.Y)
|
||||
, Day_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_day , 2, Bool_.N)
|
||||
, Hour_base24_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_hour , 2, Bool_.Y)
|
||||
, Hour_base24 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_hour , 2, Bool_.N)
|
||||
, Hour_base12_len2 = new Pft_fmt_itm_hour_base12(Bool_.Y)
|
||||
, Hour_base12 = new Pft_fmt_itm_hour_base12(Bool_.N)
|
||||
, Minute_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_minute , 2, Bool_.Y)
|
||||
, Second_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_second , 2, Bool_.Y)
|
||||
, Dow_base1_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_dayOfWeek , 1, Bool_.Y)
|
||||
, Dow_base0_int = new Pft_fmt_itm_dow_base0()
|
||||
, WeekOfYear_int = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_weekOfYear , 2, Bool_.N)
|
||||
, WeekOfYear_int_len2 = new Pft_fmt_itm_seg_int(DateAdp_.SegIdx_weekOfYear , 2, Bool_.Y)
|
||||
, Month_abrv = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_abrv_jan - Int_.Base1) // Jan
|
||||
, Month_name = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_name_january - Int_.Base1) // January
|
||||
, Month_gen = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_month, Xol_msg_itm_.Id_dte_month_gen_january - Int_.Base1) // January
|
||||
, Dow_abrv = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_dayOfWeek, Xol_msg_itm_.Id_dte_dow_abrv_sun) // Sun
|
||||
, Dow_name = new Pft_fmt_itm_seg_str(DateAdp_.SegIdx_dayOfWeek, Xol_msg_itm_.Id_dte_dow_name_sunday) // Sunday
|
||||
, Year_isLeap = new Pft_fmt_itm_year_isLeap()
|
||||
, Timestamp_unix = new Pft_fmt_itm_timestamp_unix()
|
||||
, Byte_space = new Pft_fmt_itm_raw_byt(Byte_ascii.Space)
|
||||
, Byte_comma = new Pft_fmt_itm_raw_byt(Byte_ascii.Comma)
|
||||
, Byte_dash = new Pft_fmt_itm_raw_byt(Byte_ascii.Dash)
|
||||
, DayOfYear_int = new Pft_fmt_itm_dayOfYear()
|
||||
, DaysInMonth_int = new Pft_fmt_itm_daysInMonth()
|
||||
, AmPm_lower = new Pft_fmt_itm_am_pm(true)
|
||||
, AmPm_upper = new Pft_fmt_itm_am_pm(false)
|
||||
, Roman = new Pft_fmt_itm_roman()
|
||||
, Thai = new Pft_fmt_itm_thai()
|
||||
, Minguo = new Pft_fmt_itm_minguo()
|
||||
, Hebrew_year_num = new Pft_fmt_itm_hebrew_year_num()
|
||||
, Hebrew_month_num = new Pft_fmt_itm_hebrew_month_num()
|
||||
, Hebrew_day_num = new Pft_fmt_itm_hebrew_day_num()
|
||||
, Hebrew_month_days_count = new Pft_fmt_itm_hebrew_month_days_count()
|
||||
, Hebrew_month_name_full = new Pft_fmt_itm_hebrew_month_name_full()
|
||||
, Hebrew_month_name_gen = new Pft_fmt_itm_hebrew_month_name_gen()
|
||||
, Hebrew_numeral = new Pft_fmt_itm_hebrew_numeral()
|
||||
, Raw = new Pft_fmt_itm_raw()
|
||||
, Iso_fmt = new Pft_fmt_itm_iso_fmt()
|
||||
, Rfc_5322 = new Pft_fmt_itm_rfc_5322()
|
||||
, Timezone_offset = new Pft_fmt_itm_timezone_offset()
|
||||
;
|
||||
public static final Btrie_fast_mgr Regy = Btrie_fast_mgr.cs_()
|
||||
.Add(Byte_ascii.Ltr_Y , Pft_fmt_itm_.Year_len4) // 2012
|
||||
.Add(Byte_ascii.Ltr_y , Pft_fmt_itm_.Year_len2) // 12
|
||||
.Add(Byte_ascii.Ltr_L , Pft_fmt_itm_.Year_isLeap) // 1,0
|
||||
.Add(Byte_ascii.Ltr_o , Pft_fmt_itm_.Year_len4) // 2012: ISO-8601; don't know why it's different vs Ltr_Y
|
||||
.Add(Byte_ascii.Ltr_n , Pft_fmt_itm_.Month_int) // 1
|
||||
.Add(Byte_ascii.Ltr_m , Pft_fmt_itm_.Month_int_len2) // 01
|
||||
.Add(Byte_ascii.Ltr_M , Pft_fmt_itm_.Month_abrv) // Jan
|
||||
.Add(Byte_ascii.Ltr_F , Pft_fmt_itm_.Month_name) // January
|
||||
.Add("xg" , Pft_fmt_itm_.Month_gen) // January
|
||||
.Add(Byte_ascii.Ltr_W , Pft_fmt_itm_.WeekOfYear_int_len2) // 01
|
||||
.Add(Byte_ascii.Ltr_j , Pft_fmt_itm_.Day_int) // 1
|
||||
.Add(Byte_ascii.Ltr_d , Pft_fmt_itm_.Day_int_len2) // 01
|
||||
.Add(Byte_ascii.Ltr_z , Pft_fmt_itm_.DayOfYear_int) // 0
|
||||
.Add(Byte_ascii.Ltr_D , Pft_fmt_itm_.Dow_abrv) // Sun
|
||||
.Add(Byte_ascii.Ltr_l , Pft_fmt_itm_.Dow_name) // Sunday
|
||||
.Add(Byte_ascii.Ltr_N , Pft_fmt_itm_.Dow_base0_int) // 1; Sunday=7
|
||||
.Add(Byte_ascii.Ltr_w , Pft_fmt_itm_.Dow_base1_int) // 1; Sunday=0
|
||||
.Add(Byte_ascii.Ltr_a , Pft_fmt_itm_.AmPm_lower) // am/pm
|
||||
.Add(Byte_ascii.Ltr_A , Pft_fmt_itm_.AmPm_upper) // AM/PM
|
||||
.Add(Byte_ascii.Ltr_g , Pft_fmt_itm_.Hour_base12) // 1; Base12
|
||||
.Add(Byte_ascii.Ltr_h , Pft_fmt_itm_.Hour_base12_len2) // 01; Base12; pad2
|
||||
.Add(Byte_ascii.Ltr_G , Pft_fmt_itm_.Hour_base24) // 13; Base24;
|
||||
.Add(Byte_ascii.Ltr_H , Pft_fmt_itm_.Hour_base24_len2) // 13; Base24; pad2
|
||||
.Add(Byte_ascii.Ltr_i , Pft_fmt_itm_.Minute_int_len2) // 04
|
||||
.Add(Byte_ascii.Ltr_s , Pft_fmt_itm_.Second_int_len2) // 05
|
||||
.Add(Byte_ascii.Ltr_t , Pft_fmt_itm_.DaysInMonth_int) // 31
|
||||
.Add(Byte_ascii.Ltr_U , Pft_fmt_itm_.Timestamp_unix) // 1343865600
|
||||
.Add(Byte_ascii.Ltr_Z , Pft_fmt_itm_.Timezone_offset) // timezone offset in seconds
|
||||
.Add(Byte_ascii.Ltr_c , Pft_fmt_itm_.Iso_fmt) // 2012-01-02T03:04:05+00:00
|
||||
.Add(Byte_ascii.Ltr_r , Pft_fmt_itm_.Rfc_5322) // Mon 02 Jan 2012 08:04:05 +0000
|
||||
.Add("xr" , Pft_fmt_itm_.Roman) // MCXI
|
||||
.Add("xkY" , Pft_fmt_itm_.Thai) // Year += 543
|
||||
.Add("xoY" , Pft_fmt_itm_.Minguo) // Year -= 1911
|
||||
.Add("xn" , Pft_fmt_itm_.Raw) // NOTE: really does nothing; REF.MW: Language.php|sprintfdate does $s .= $num; DATE:2013-12-31
|
||||
.Add("xN" , Pft_fmt_itm_.Raw)
|
||||
.Add("xjj" , Pft_fmt_itm_.Hebrew_day_num)
|
||||
.Add("xjn" , Pft_fmt_itm_.Hebrew_month_num)
|
||||
.Add("xjt" , Pft_fmt_itm_.Hebrew_month_days_count)
|
||||
.Add("xjF" , Pft_fmt_itm_.Hebrew_month_name_full)
|
||||
.Add("xjx" , Pft_fmt_itm_.Hebrew_month_name_gen)
|
||||
.Add("xjY" , Pft_fmt_itm_.Hebrew_year_num)
|
||||
.Add("xh" , Pft_fmt_itm_.Hebrew_numeral)
|
||||
// TODO: foreign; space; "
|
||||
;
|
||||
public static Pft_fmt_itm[] Parse(Xop_ctx ctx, byte[] fmt) {
|
||||
Btrie_fast_mgr trie = Pft_fmt_itm_.Regy;
|
||||
int i = 0, fmt_len = fmt.length;
|
||||
fmt_itms.Clear(); int raw_bgn = String_.Pos_neg1; byte raw_byt = Byte_.Zero;
|
||||
while (i < fmt_len) {
|
||||
byte b = fmt[i];
|
||||
Object o = trie.Match_bgn_w_byte(b, fmt, i, fmt_len);
|
||||
if (o != null) {
|
||||
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(i - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(raw_byt) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i)); raw_bgn = String_.Pos_neg1;}
|
||||
fmt_itms.Add((Pft_fmt_itm)o);
|
||||
i = trie.Match_pos();
|
||||
}
|
||||
else {
|
||||
switch (b) {
|
||||
case Byte_ascii.Backslash:
|
||||
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(i - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(raw_byt) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i)); raw_bgn = String_.Pos_neg1;}
|
||||
++i; // peek next char
|
||||
if (i == fmt_len) // trailing backslash; add one; EX: "b\" -> "b\" not "b"
|
||||
fmt_itms.Add(new Pft_fmt_itm_raw_byt(Byte_ascii.Backslash));
|
||||
else
|
||||
fmt_itms.Add(new Pft_fmt_itm_raw_byt(fmt[i]));
|
||||
++i;
|
||||
break;
|
||||
case Byte_ascii.Quote:
|
||||
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(i - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(raw_byt) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i)); raw_bgn = String_.Pos_neg1;}
|
||||
++i; // skip quote_bgn
|
||||
raw_bgn = i;
|
||||
while (i < fmt_len) {
|
||||
b = fmt[i];
|
||||
if (b == Byte_ascii.Quote) {
|
||||
break;
|
||||
}
|
||||
else
|
||||
++i;
|
||||
}
|
||||
fmt_itms.Add(i - raw_bgn == 0 ? new Pft_fmt_itm_raw_byt(Byte_ascii.Quote) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, i));
|
||||
raw_bgn = String_.Pos_neg1;
|
||||
++i; // skip quote_end
|
||||
break;
|
||||
default:
|
||||
if (raw_bgn == String_.Pos_neg1) {raw_bgn = i; raw_byt = b;}
|
||||
i += gplx.intl.Utf8_.Len_of_char_by_1st_byte(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (raw_bgn != String_.Pos_neg1) {fmt_itms.Add(fmt_len - raw_bgn == 1 ? new Pft_fmt_itm_raw_byt(fmt[fmt_len - 1]) : (Pft_fmt_itm)new Pft_fmt_itm_raw_ary(fmt, raw_bgn, fmt_len)); raw_bgn = String_.Pos_neg1;}
|
||||
return (Pft_fmt_itm[])fmt_itms.To_ary(Pft_fmt_itm.class);
|
||||
} private static List_adp fmt_itms = List_adp_.new_();
|
||||
}
|
||||
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
class Pft_fmt_itm_roman implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_roman;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int nxt_idx = bldr.Idx_cur() + 1;
|
||||
Pft_fmt_itm[] ary = bldr.Fmt_itms();
|
||||
if (nxt_idx < ary.length) {
|
||||
Pft_fmt_itm itm = (Pft_fmt_itm)ary[nxt_idx];
|
||||
if (itm.TypeId() == Pft_fmt_itm_.Tid_seg_int) {
|
||||
Pft_fmt_itm_seg_int nxt_int = (Pft_fmt_itm_seg_int)ary[nxt_idx]; // FUTURE: should check tkn type
|
||||
int v = date.Segment(nxt_int.SegIdx());
|
||||
Pfxtp_roman.ToRoman(v, bfr);
|
||||
bldr.Idx_nxt_(nxt_idx + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
bfr.Add_str_a7("xf");
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_thai implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_thai;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
bfr.Add_int_variable(date.Year() + 543);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_minguo implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_minguo;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
bfr.Add_int_variable(date.Year() - 1911);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_year_num implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_year_num;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
|
||||
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_year_num]);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_month_num implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_num;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
|
||||
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_month_num]);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_day_num implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_day_num;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
|
||||
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_day_num]);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_month_days_count implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_days_count;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
|
||||
bfr.Add_int_variable(hebrew_date[Pft_fmt_itm_hebrew_.Rslt_month_days_count]);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_month_name_full implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_name_full;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
bfr.Add(Pft_fmt_itm_hebrew_.Get_hebrew_month_name_full(wiki, date));
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_month_name_gen implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_month_name_gen;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
bfr.Add(Pft_fmt_itm_hebrew_.Get_hebrew_month_name_gen(wiki, date));
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_numeral implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hebrew_numeral;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
bfr.Add_str(Pft_fmt_itm_hebrew_.Calc_hebrew_numeral(date.Year()));
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_hebrew_ {
|
||||
public static int Calc_hebrew_year_num_start(int year) {
|
||||
int year_minus_1 = year - 1;
|
||||
int a = (12 * year_minus_1 + 17) % 19;
|
||||
int b = year_minus_1 % 4;
|
||||
double m = 32.044093161144d + 1.5542417966212d * a + b / 4.0 - 0.0031777940220923d * year_minus_1;
|
||||
if (m < 0)
|
||||
m--;
|
||||
int mar = (int)m;
|
||||
if (m < 0)
|
||||
m++;
|
||||
m -= mar;
|
||||
int c = (mar + 3 * year_minus_1 + 5 * b + 5) % 7;
|
||||
if (c == 0 && a > 11 && m >= 0.89772376543210d)
|
||||
mar++;
|
||||
else if (c == 1 && a > 6 && m >= 0.63287037037037d)
|
||||
mar += 2;
|
||||
else if (c == 2 || c == 4 || c == 6)
|
||||
mar++;
|
||||
double year_minus_3761 = year - 3761;
|
||||
mar += (int)(year_minus_3761 / 100 ) - (int)(year_minus_3761 / 400) - 24;
|
||||
return mar;
|
||||
}
|
||||
private static final int[] Hebrew_date_rslt = new int[4];
|
||||
public static int[] Calc_hebrew_date(DateAdp date) {
|
||||
synchronized (Hebrew_date_rslt) {
|
||||
Calc_hebrew_date(Hebrew_date_rslt, date.Year(), date.Month(), date.Day());
|
||||
return Hebrew_date_rslt;
|
||||
}
|
||||
}
|
||||
public static boolean Calc_hebrew_date(int[] rv, int year, int month, int day) { // REF.MW:Language.php|tsToHebrew
|
||||
// Calculate Hebrew year
|
||||
int hebrewYear = year + 3760;
|
||||
|
||||
// Month number when September = 1, August = 12
|
||||
month += 4;
|
||||
if (month > 12) {
|
||||
// Next year
|
||||
month -= 12;
|
||||
year++;
|
||||
hebrewYear++;
|
||||
}
|
||||
|
||||
// Calculate day of year from 1 September
|
||||
int dayOfYear = day;
|
||||
for (int i = 1; i < month; i++) {
|
||||
if (i == 6) {
|
||||
// February
|
||||
dayOfYear += 28;
|
||||
// Check if the year is leap
|
||||
if (year % 400 == 0 || (year % 4 == 0 && year % 100 > 0)) {
|
||||
dayOfYear++;
|
||||
}
|
||||
} else if (i == 8 || i == 10 || i == 1 || i == 3) {
|
||||
dayOfYear += 30;
|
||||
} else {
|
||||
dayOfYear += 31;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the start of the Hebrew year
|
||||
int start = Calc_hebrew_year_num_start(hebrewYear);
|
||||
|
||||
// Calculate next year's start
|
||||
int nextStart = 0;
|
||||
if (dayOfYear <= start) {
|
||||
// Day is before the start of the year - it is the previous year
|
||||
// Next year's start
|
||||
nextStart = start;
|
||||
// Previous year
|
||||
year--;
|
||||
hebrewYear--;
|
||||
// Add days since previous year's 1 September
|
||||
dayOfYear += 365;
|
||||
if ((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0)) {
|
||||
// Leap year
|
||||
dayOfYear++;
|
||||
}
|
||||
// Start of the new (previous) year
|
||||
start = Calc_hebrew_year_num_start(hebrewYear);
|
||||
} else {
|
||||
// Next year's start
|
||||
nextStart = Calc_hebrew_year_num_start(hebrewYear + 1);
|
||||
}
|
||||
|
||||
// Calculate Hebrew day of year
|
||||
int hebrewDayOfYear = dayOfYear - start;
|
||||
|
||||
// Difference between year's days
|
||||
int diff = nextStart - start;
|
||||
// Add 12 (or 13 for leap years) days to ignore the difference between
|
||||
// Hebrew and Gregorian year (353 at least vs. 365/6) - now the
|
||||
// difference is only about the year type
|
||||
if ((year % 400 == 0) || (year % 100 != 0 && year % 4 == 0)) {
|
||||
diff += 13;
|
||||
} else {
|
||||
diff += 12;
|
||||
}
|
||||
|
||||
// Check the year pattern, and is leap year
|
||||
// 0 means an incomplete year, 1 means a regular year, 2 means a complete year
|
||||
// This is mod 30, to work on both leap years (which add 30 days of Adar I)
|
||||
// and non-leap years
|
||||
int yearPattern = diff % 30;
|
||||
// Check if leap year
|
||||
boolean isLeap = diff >= 30;
|
||||
|
||||
// Calculate day in the month from number of day in the Hebrew year
|
||||
// Don't check Adar - if the day is not in Adar, we will stop before;
|
||||
// if it is in Adar, we will use it to check if it is Adar I or Adar II
|
||||
int hebrewDay = hebrewDayOfYear;
|
||||
int hebrewMonth = 1;
|
||||
int days = 0;
|
||||
|
||||
while (hebrewMonth <= 12) {
|
||||
// Calculate days in this month
|
||||
if (isLeap && hebrewMonth == 6) {
|
||||
// Adar in a leap year
|
||||
if (isLeap) {
|
||||
// Leap year - has Adar I, with 30 days, and Adar II, with 29 days
|
||||
days = 30;
|
||||
if (hebrewDay <= days) {
|
||||
// Day in Adar I
|
||||
hebrewMonth = 13;
|
||||
} else {
|
||||
// Subtract the days of Adar I
|
||||
hebrewDay -= days;
|
||||
// Try Adar II
|
||||
days = 29;
|
||||
if (hebrewDay <= days) {
|
||||
// Day in Adar II
|
||||
hebrewMonth = 14;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (hebrewMonth == 2 && yearPattern == 2) {
|
||||
// Cheshvan in a complete year (otherwise as the rule below)
|
||||
days = 30;
|
||||
} else if (hebrewMonth == 3 && yearPattern == 0) {
|
||||
// Kislev in an incomplete year (otherwise as the rule below)
|
||||
days = 29;
|
||||
} else {
|
||||
// Odd months have 30 days, even have 29
|
||||
days = 30 - (hebrewMonth - 1) % 2;
|
||||
}
|
||||
if (hebrewDay <= days) {
|
||||
// In the current month
|
||||
break;
|
||||
} else {
|
||||
// Subtract the days of the current month
|
||||
hebrewDay -= days;
|
||||
// Try in the next month
|
||||
hebrewMonth++;
|
||||
}
|
||||
}
|
||||
rv[0] = hebrewYear;
|
||||
rv[1] = hebrewMonth;
|
||||
rv[2] = hebrewDay;
|
||||
rv[3] = days;
|
||||
return true;
|
||||
}
|
||||
public static byte[] Get_hebrew_month_name_full(Xowe_wiki wiki, DateAdp date) {return Get_hebrew_month_name(wiki, date, Month_name_full_ary);}
|
||||
public static byte[] Get_hebrew_month_name_gen(Xowe_wiki wiki, DateAdp date) {return Get_hebrew_month_name(wiki, date, Month_name_gen_ary);}
|
||||
private static byte[] Get_hebrew_month_name(Xowe_wiki wiki, DateAdp date, byte[][] name_ary) {
|
||||
int[] hebrew_date = Pft_fmt_itm_hebrew_.Calc_hebrew_date(date);
|
||||
int hebrew_month = hebrew_date[Pft_fmt_itm_hebrew_.Rslt_month_num] - List_adp_.Base1;
|
||||
byte[] msg_key = name_ary[hebrew_month];
|
||||
return wiki.Msg_mgr().Val_by_key_obj(msg_key);
|
||||
}
|
||||
private static final byte[][] Month_name_full_ary = new byte[][]
|
||||
{ Bry_.new_a7("hebrew-calendar-m1"), Bry_.new_a7("hebrew-calendar-m2"), Bry_.new_a7("hebrew-calendar-m3")
|
||||
, Bry_.new_a7("hebrew-calendar-m4"), Bry_.new_a7("hebrew-calendar-m5"), Bry_.new_a7("hebrew-calendar-m6")
|
||||
, Bry_.new_a7("hebrew-calendar-m7"), Bry_.new_a7("hebrew-calendar-m8"), Bry_.new_a7("hebrew-calendar-m9")
|
||||
, Bry_.new_a7("hebrew-calendar-m10"), Bry_.new_a7("hebrew-calendar-m11"), Bry_.new_a7("hebrew-calendar-m12")
|
||||
, Bry_.new_a7("hebrew-calendar-m6a"), Bry_.new_a7("hebrew-calendar-m6b")
|
||||
};
|
||||
private static final byte[][] Month_name_gen_ary = new byte[][]
|
||||
{ Bry_.new_a7("hebrew-calendar-m1-gen"), Bry_.new_a7("hebrew-calendar-m2-gen"), Bry_.new_a7("hebrew-calendar-m3-gen")
|
||||
, Bry_.new_a7("hebrew-calendar-m4-gen"), Bry_.new_a7("hebrew-calendar-m5-gen"), Bry_.new_a7("hebrew-calendar-m6-gen")
|
||||
, Bry_.new_a7("hebrew-calendar-m7-gen"), Bry_.new_a7("hebrew-calendar-m8-gen"), Bry_.new_a7("hebrew-calendar-m9-gen")
|
||||
, Bry_.new_a7("hebrew-calendar-m10-gen"), Bry_.new_a7("hebrew-calendar-m11-gen"), Bry_.new_a7("hebrew-calendar-m12-gen")
|
||||
, Bry_.new_a7("hebrew-calendar-m6a-gen"), Bry_.new_a7("hebrew-calendar-m6b-gen")
|
||||
};
|
||||
public static final int
|
||||
Rslt_year_num = 0
|
||||
, Rslt_month_num = 1
|
||||
, Rslt_day_num = 2
|
||||
, Rslt_month_days_count = 3
|
||||
;
|
||||
|
||||
private static final String[][] Numeral_tbls = new String[][]
|
||||
{ new String[] {"", "א", "ב", "ג", "ד", "ה", "ו", "ז", "ח", "ט", "י"}
|
||||
, new String[] {"", "י", "כ", "ל", "מ", "נ", "ס", "ע", "פ", "צ", "ק"}
|
||||
, new String[] {"", "ק", "ר", "ש", "ת", "תק", "תר", "תש", "תת", "תתק", "תתר"}
|
||||
, new String[] {"", "א", "ב", "ג", "ד", "ה", "ו", "ז", "ח", "ט", "י"}
|
||||
};
|
||||
public static String Calc_hebrew_numeral(int num) {
|
||||
if (num > 9999 || num <= 0)
|
||||
return Int_.Xto_str(num);
|
||||
|
||||
String tmp = "";
|
||||
int pow10 = 1000;
|
||||
for (int i = 3; i >= 0; pow10 /= 10, i--) {
|
||||
if (num >= pow10) {
|
||||
if (num == 15 || num == 16) {
|
||||
tmp += Numeral_tbls[0][9] + Numeral_tbls[0][num - 9];
|
||||
num = 0;
|
||||
} else {
|
||||
tmp += Numeral_tbls[i][(int)(num / pow10)];
|
||||
if (pow10 == 1000)
|
||||
tmp += "'";
|
||||
}
|
||||
}
|
||||
num = num % pow10;
|
||||
}
|
||||
String rv = "";
|
||||
int tmp_len = String_.Len(tmp);
|
||||
if (tmp_len == 2) {
|
||||
rv = tmp + "'";
|
||||
}
|
||||
else {
|
||||
rv = String_.Mid(tmp, 0, tmp_len - 1) + "\"";
|
||||
rv += String_.Mid(tmp, tmp_len - 1);
|
||||
}
|
||||
int rv_len = String_.Len(rv);
|
||||
String start = String_.Mid(rv, 0, rv_len - 1);
|
||||
String end = String_.Mid(rv, rv_len - 1);
|
||||
if (String_.Eq(end, "כ"))
|
||||
rv = start + "ך";
|
||||
else if (String_.Eq(end, "מ"))
|
||||
rv = start + "ם";
|
||||
else if (String_.Eq(end, "נ"))
|
||||
rv = start + "ן";
|
||||
else if (String_.Eq(end, "פ"))
|
||||
rv = start + "ף";
|
||||
else if (String_.Eq(end, "צ"))
|
||||
rv = start + "ץ";
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
class Pft_fmt_itm_seg_int implements Pft_fmt_itm {
|
||||
public Pft_fmt_itm_seg_int(int segIdx, int len, boolean fixed_len) {this.segIdx = segIdx; this.fixed_len = fixed_len; this.len = len;} private int segIdx, len; boolean fixed_len;
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_seg_int;}
|
||||
public int SegIdx() {return segIdx;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int val = date.Segment(segIdx);
|
||||
if (fixed_len) bfr.Add_int_fixed(val, len);
|
||||
else bfr.Add_int_variable(val);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_raw implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_raw;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
// TODO: should flag .Raw() on bldr to skip transliterating numerals in foreign languages; DATE:2013-12-31
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_seg_str implements Pft_fmt_itm {
|
||||
public Pft_fmt_itm_seg_str(int segIdx, int type) {this.segIdx = segIdx; this.type = type;} private int segIdx, type;
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_seg_str;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
DateAdpTranslator_xapp.Translate(wiki, lang, type, date.Segment(segIdx), bfr);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_year_isLeap implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_year_isLeap;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_int_fixed(DateAdp_.IsLeapYear(date.Year()) ? 1 : 0, 1);}
|
||||
}
|
||||
class Pft_fmt_itm_hour_base12 implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_hour_base12;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int val = date.Hour();
|
||||
switch (val) {
|
||||
case 0: val = 12; break;
|
||||
case 13: case 14: case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: val -= 12; break;
|
||||
default: break;
|
||||
}
|
||||
if (fixed_len) bfr.Add_int_fixed(val, 2);
|
||||
else bfr.Add_int_variable(val);
|
||||
}
|
||||
public Pft_fmt_itm_hour_base12(boolean fixed_len) {this.fixed_len = fixed_len;} private boolean fixed_len;
|
||||
}
|
||||
class Pft_fmt_itm_timestamp_unix implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_timestamp_unix;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_long_variable(date.Timestamp_unix());}
|
||||
}
|
||||
class Pft_fmt_itm_raw_ary implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_raw_ary;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_mid(src, bgn, end);}
|
||||
public Pft_fmt_itm_raw_ary(byte[] src, int bgn, int end) {this.src = src; this.bgn = bgn; this.end = end;} private byte[] src; int bgn; int end;
|
||||
}
|
||||
class Pft_fmt_itm_raw_byt implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_raw_byt;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_byte(b);}
|
||||
public Pft_fmt_itm_raw_byt(byte b) {this.b = b;} private byte b;
|
||||
}
|
||||
class Pft_fmt_itm_daysInMonth implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_daysInMonth;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_int_variable(DateAdp_.DaysInMonth(date));}
|
||||
}
|
||||
class Pft_fmt_itm_dayOfYear implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_dayOfYear;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {bfr.Add_int_variable(date.DayOfYear() - Int_.Base1);} // php is base1; .net/java is base0
|
||||
}
|
||||
class Pft_fmt_itm_am_pm implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_AmPm;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
boolean am = date.Hour() < 13;
|
||||
byte[] val = null;
|
||||
if ( am && lower) val = Ary_am_lower;
|
||||
else if ( am && !lower) val = Ary_am_upper;
|
||||
else if (!am && lower) val = Ary_pm_lower;
|
||||
else if (!am && !lower) val = Ary_pm_upper;
|
||||
bfr.Add(val);
|
||||
} static final byte[] Ary_am_upper = Bry_.new_a7("AM"), Ary_pm_upper = Bry_.new_a7("PM"), Ary_am_lower = Bry_.new_a7("am"), Ary_pm_lower = Bry_.new_a7("pm");
|
||||
public Pft_fmt_itm_am_pm(boolean lower) {this.lower = lower;} private boolean lower;
|
||||
}
|
||||
class Pft_fmt_itm_dow_base0 implements Pft_fmt_itm {
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_dow_base0;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
int dow = date.DayOfWeek();
|
||||
if (dow == 0) dow = 7;
|
||||
bfr.Add_int_fixed(dow, 1);
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_iso_fmt implements Pft_fmt_itm {
|
||||
public Pft_fmt_itm_iso_fmt() {}
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_iso_fmt;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
bfr.Add_str(date.XtoStr_fmt("yyyy-MM-dd"));
|
||||
bfr.Add_byte(Byte_ascii.Ltr_T);
|
||||
bfr.Add_str(date.XtoStr_fmt("HH:mm:ss"));
|
||||
bfr.Add_str(date.XtoStr_tz());
|
||||
}
|
||||
}
|
||||
class Pft_fmt_itm_rfc_5322 implements Pft_fmt_itm {
|
||||
public Pft_fmt_itm_rfc_5322() {}
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_rfc_5322;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {// Mon, 02 Jan 2012 10:15:01 +0000
|
||||
int dow = date.DayOfWeek();
|
||||
DateAdpTranslator_xapp.Translate(wiki, lang, DateAdp_.SegIdx_dayOfWeek, dow, bfr);
|
||||
bfr.Add_byte(Byte_ascii.Comma).Add_byte(Byte_ascii.Space);
|
||||
bfr.Add_str(date.XtoStr_fmt("dd MMM yyyy HH:mm:ss")); // NOTE: always UTC time
|
||||
bfr.Add(CONST_timezone); // NOTE: always UTC time zone
|
||||
} static final byte[] CONST_timezone = Bry_.new_a7(" +0000");
|
||||
}
|
||||
class Pft_fmt_itm_timezone_offset implements Pft_fmt_itm {
|
||||
public Pft_fmt_itm_timezone_offset() {}
|
||||
public int TypeId() {return Pft_fmt_itm_.Tid_timezone_offset;}
|
||||
public void Fmt(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_func_formatdate_bldr bldr) {
|
||||
bfr.Add_int_variable(date.Timezone_offset());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pft_func_date_int extends Pf_func_base {
|
||||
public Pft_func_date_int(int id, int date_tid) {this.id = id; this.date_tid = date_tid;} private int date_tid;
|
||||
@Override public int Id() {return id;} private int id;
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_date_int(id, date_tid).Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
DateAdp date = DateAdp_.MinValue;
|
||||
Xowe_wiki wiki = ctx.Wiki(); Xol_lang lang = ctx.Lang();
|
||||
switch (date_tid) {
|
||||
case Date_tid_lcl: date = DateAdp_.Now(); break;
|
||||
case Date_tid_utc: date = DateAdp_.Now().XtoUtc(); break;
|
||||
case Date_tid_rev: date = ctx.Cur_page().Revision_data().Modified_on(); break;
|
||||
default: throw Exc_.new_unhandled(date_tid);
|
||||
}
|
||||
switch (id) {
|
||||
case Xol_kwd_grp_.Id_utc_year:
|
||||
case Xol_kwd_grp_.Id_lcl_year:
|
||||
case Xol_kwd_grp_.Id_rev_year:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Year_len4);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_utc_month_int_len2:
|
||||
case Xol_kwd_grp_.Id_lcl_month_int_len2:
|
||||
case Xol_kwd_grp_.Id_rev_month_int_len2:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Month_int_len2);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_utc_month_int:
|
||||
case Xol_kwd_grp_.Id_lcl_month_int:
|
||||
case Xol_kwd_grp_.Id_rev_month_int:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Month_int);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_utc_day_int_len2:
|
||||
case Xol_kwd_grp_.Id_lcl_day_int_len2:
|
||||
case Xol_kwd_grp_.Id_rev_day_int_len2:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Day_int_len2);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_utc_day_int:
|
||||
case Xol_kwd_grp_.Id_lcl_day_int:
|
||||
case Xol_kwd_grp_.Id_rev_day_int:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Day_int);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_lcl_hour:
|
||||
case Xol_kwd_grp_.Id_utc_hour:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Hour_base24_len2);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_lcl_dow:
|
||||
case Xol_kwd_grp_.Id_utc_dow:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.Dow_base1_int);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_lcl_week:
|
||||
case Xol_kwd_grp_.Id_utc_week:
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, wiki, lang, date, Pft_fmt_itm_.WeekOfYear_int);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_lcl_time:
|
||||
case Xol_kwd_grp_.Id_utc_time: // 17:29
|
||||
bfr.Add_int_fixed(date.Hour(), 2).Add_byte(Byte_ascii.Colon).Add_int_fixed(date.Minute(), 2);
|
||||
break;
|
||||
case Xol_kwd_grp_.Id_lcl_timestamp:
|
||||
case Xol_kwd_grp_.Id_utc_timestamp:
|
||||
case Xol_kwd_grp_.Id_rev_timestamp: // 20120123172956
|
||||
bfr .Add_int_fixed(date.Year() , 4)
|
||||
.Add_int_fixed(date.Month() , 2)
|
||||
.Add_int_fixed(date.Day() , 2)
|
||||
.Add_int_fixed(date.Hour() , 2)
|
||||
.Add_int_fixed(date.Minute(), 2)
|
||||
.Add_int_fixed(date.Second(), 2);
|
||||
break;
|
||||
default: throw Exc_.new_unhandled(id);
|
||||
}
|
||||
}
|
||||
public static final int Date_tid_utc = 0, Date_tid_lcl = 1, Date_tid_rev = 2;
|
||||
public static final Pft_func_date_int
|
||||
Utc = new Pft_func_date_int(-1, Date_tid_utc)
|
||||
, Lcl = new Pft_func_date_int(-1, Date_tid_lcl)
|
||||
, Rev = new Pft_func_date_int(-1, Date_tid_rev);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
XOWA: the XOWA Offline Wiki Application
|
||||
Copyright (C) 2012 gnosygnu@gmail.com
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package gplx.xowa.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_date_lcl_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void setup() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));}
|
||||
@After public void teardown() {Tfds.Now_enabled_n_();}
|
||||
@Test public void Lcl_year() {fxt.Test_parse_tmpl_str_test("{{LOCALYEAR}}" , "{{test}}", "2012");}
|
||||
@Test public void Lcl_month_int() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTH1}}" , "{{test}}", "1");}
|
||||
@Test public void Lcl_month_int_len2() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTH}}" , "{{test}}", "01");}
|
||||
@Test public void Lcl_day_int() {fxt.Test_parse_tmpl_str_test("{{LOCALDAY}}" , "{{test}}", "2");}
|
||||
@Test public void Lcl_day_int_len2() {fxt.Test_parse_tmpl_str_test("{{LOCALDAY2}}" , "{{test}}", "02");}
|
||||
@Test public void Lcl_day_hour_len2() {fxt.Test_parse_tmpl_str_test("{{LOCALHOUR}}" , "{{test}}", "03");}
|
||||
@Test public void Lcl_dow_int() {fxt.Test_parse_tmpl_str_test("{{LOCALDOW}}" , "{{test}}", "1");}
|
||||
@Test public void Lcl_week_int() {fxt.Test_parse_tmpl_str_test("{{LOCALWEEK}}" , "{{test}}", "1");}
|
||||
@Test public void Lcl_month_name() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTHNAME}}" , "{{test}}", "January");}
|
||||
@Test public void Lcl_month_gen() {fxt.Test_parse_tmpl_str_test("{{LOCALMONTHNAMEGEN}}" , "{{test}}", "January");}
|
||||
@Test public void Lcl_day_name() {fxt.Test_parse_tmpl_str_test("{{LOCALDAYNAME}}" , "{{test}}", "Monday");}
|
||||
@Test public void Lcl_time() {fxt.Test_parse_tmpl_str_test("{{LOCALTIME}}" , "{{test}}", "03:04");}
|
||||
@Test public void Lcl_timestamp() {fxt.Test_parse_tmpl_str_test("{{LOCALTIMESTAMP}}" , "{{test}}", "20120102030405");}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pft_func_date_name extends Pf_func_base {
|
||||
public Pft_func_date_name(int id, int date_tid, int seg_idx, int base_idx) {this.id = id; this.date_tid = date_tid; this.seg_idx = seg_idx; this.base_idx = base_idx;} private int date_tid, seg_idx, base_idx;
|
||||
@Override public int Id() {return id;} private int id;
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_date_name(id, date_tid, seg_idx, base_idx).Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
DateAdp date = DateAdp_.MinValue;
|
||||
switch (date_tid) {
|
||||
case Pft_func_date_int.Date_tid_lcl: date = DateAdp_.Now(); break;
|
||||
case Pft_func_date_int.Date_tid_utc: date = DateAdp_.Now().XtoUtc(); break;
|
||||
case Pft_func_date_int.Date_tid_rev: date = ctx.Cur_page().Revision_data().Modified_on(); break;
|
||||
default: throw Exc_.new_unhandled(date_tid);
|
||||
}
|
||||
byte[] val = ctx.Wiki().Msg_mgr().Val_by_id(base_idx + date.Segment(seg_idx));
|
||||
bfr.Add(val);
|
||||
// translator.Translate(base_idx, date.Segment(seg_idx), bfr);
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_date_rev_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void setup() {fxt.Reset(); fxt.Page().Revision_data().Modified_on_(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));}
|
||||
@After public void teardown() {}
|
||||
@Test public void Rev_year() {fxt.Test_parse_tmpl_str_test("{{REVISIONYEAR}}" , "{{test}}", "2012");}
|
||||
@Test public void Rev_month_int() {fxt.Test_parse_tmpl_str_test("{{REVISIONMONTH1}}" , "{{test}}", "1");}
|
||||
@Test public void Rev_month_int_len2() {fxt.Test_parse_tmpl_str_test("{{REVISIONMONTH}}" , "{{test}}", "01");}
|
||||
@Test public void Rev_day_int() {fxt.Test_parse_tmpl_str_test("{{REVISIONDAY}}" , "{{test}}", "2");}
|
||||
@Test public void Rev_day_int_len2() {fxt.Test_parse_tmpl_str_test("{{REVISIONDAY2}}" , "{{test}}", "02");}
|
||||
@Test public void Rev_timestamp() {fxt.Test_parse_tmpl_str_test("{{REVISIONTIMESTAMP}}" , "{{test}}", "20120102030405");}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_date_utc_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void setup() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2011, 12, 31, 22, 4, 5, 6));} // ENV:Assumes Eastern Standard Time (-5)
|
||||
@After public void teardown() {Tfds.Now_enabled_n_();}
|
||||
@Test public void Utc_year() {fxt.Test_parse_tmpl_str_test("{{CURRENTYEAR}}" , "{{test}}", "2012");}
|
||||
@Test public void Utc_month_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTH1}}" , "{{test}}", "1");}
|
||||
@Test public void Utc_month_int_len2() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTH}}" , "{{test}}", "01");}
|
||||
@Test public void Utc_day_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTDAY}}" , "{{test}}", "1");}
|
||||
@Test public void Utc_day_int_len2() {fxt.Test_parse_tmpl_str_test("{{CURRENTDAY2}}" , "{{test}}", "01");}
|
||||
@Test public void Utc_day_hour_len2() {fxt.Test_parse_tmpl_str_test("{{CURRENTHOUR}}" , "{{test}}", "03");}
|
||||
@Test public void Utc_dow_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTDOW}}" , "{{test}}", "0");}
|
||||
@Test public void Utc_week_int() {fxt.Test_parse_tmpl_str_test("{{CURRENTWEEK}}" , "{{test}}", "1");}
|
||||
@Test public void Utc_month_abrv() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTHABBREV}}" , "{{test}}", "Jan");}
|
||||
@Test public void Utc_month_name() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTHNAME}}" , "{{test}}", "January");}
|
||||
@Test public void Utc_month_gen() {fxt.Test_parse_tmpl_str_test("{{CURRENTMONTHNAMEGEN}}" , "{{test}}", "January");}
|
||||
@Test public void Utc_day_name() {fxt.Test_parse_tmpl_str_test("{{CURRENTDAYNAME}}" , "{{test}}", "Sunday");}
|
||||
@Test public void Utc_time() {fxt.Test_parse_tmpl_str_test("{{CURRENTTIME}}" , "{{test}}", "03:04");}
|
||||
@Test public void Utc_timestamp() {fxt.Test_parse_tmpl_str_test("{{CURRENTTIMESTAMP}}" , "{{test}}", "20120101030405");}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.btries.*;
|
||||
public class Pft_func_formatdate extends Pf_func_base {
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_str_formatdate;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_formatdate().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) {
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] date_bry = Eval_argx(ctx, src, caller, self);
|
||||
byte[] fmt_bry = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
|
||||
if (fmt_bry == Bry_.Empty) {bfr.Add(date_bry); return;} // no format given; add self;
|
||||
int fmt_bry_len = fmt_bry.length;
|
||||
Object o = trie.Match_bgn(fmt_bry, 0, fmt_bry_len);
|
||||
if (o == null
|
||||
|| o == Fmt_itms_default) {// NOOP for default?
|
||||
bfr.Add(date_bry);
|
||||
return;
|
||||
}
|
||||
DateAdp date = Pft_func_time.ParseDate(date_bry, false, ctx.App().Utl__bfr_mkr().Get_b512().Mkr_rls());
|
||||
if (date == null) {bfr.Add(date_bry); return;} // date not parseable; return self; DATE:2014-04-13
|
||||
date_bldr.Format(bfr, ctx.Wiki(), ctx.Lang(), date, (Pft_fmt_itm[])o);
|
||||
}
|
||||
public static Pft_func_formatdate_bldr Date_bldr() {return date_bldr;} private static Pft_func_formatdate_bldr date_bldr = new Pft_func_formatdate_bldr();
|
||||
private static final Pft_fmt_itm[] Fmt_itms_default = new Pft_fmt_itm[0];
|
||||
private static final Btrie_fast_mgr trie = Btrie_fast_mgr.cs_()
|
||||
.Add("dmy" , new Pft_fmt_itm[] {Pft_fmt_itm_.Day_int, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Month_name, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Year_len4})
|
||||
.Add("mdy" , new Pft_fmt_itm[] {Pft_fmt_itm_.Month_name, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Day_int, Pft_fmt_itm_.Byte_comma, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Year_len4})
|
||||
.Add("ymd" , new Pft_fmt_itm[] {Pft_fmt_itm_.Year_len4, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Month_name, Pft_fmt_itm_.Byte_space, Pft_fmt_itm_.Day_int})
|
||||
.Add("ISO 8601" , new Pft_fmt_itm[] {Pft_fmt_itm_.Year_len4, Pft_fmt_itm_.Byte_dash, Pft_fmt_itm_.Month_int_len2, Pft_fmt_itm_.Byte_dash, Pft_fmt_itm_.Day_int_len2})
|
||||
.Add("default" , Fmt_itms_default)
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pft_func_formatdate_bldr {
|
||||
public int Idx_cur() {return idx_cur;} private int idx_cur;
|
||||
public Pft_func_formatdate_bldr Idx_nxt_(int v) {idx_nxt = v; return this;} private int idx_nxt;
|
||||
public Pft_fmt_itm[] Fmt_itms() {return fmt_itms;} Pft_fmt_itm[] fmt_itms;
|
||||
public void Format(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_fmt_itm fmt_itm) {
|
||||
fmt_itm.Fmt(bfr, wiki, lang, date, this);
|
||||
}
|
||||
public void Format(Bry_bfr bfr, Xowe_wiki wiki, Xol_lang lang, DateAdp date, Pft_fmt_itm[] fmt_itms) {
|
||||
this.fmt_itms = fmt_itms;
|
||||
int len = fmt_itms.length;
|
||||
idx_cur = 0; idx_nxt = -1;
|
||||
Pft_fmt_itm last = null;
|
||||
while (idx_cur < len) {
|
||||
Pft_fmt_itm fmt_itm = fmt_itms[idx_cur];
|
||||
if (fmt_itm.TypeId() == Pft_fmt_itm_.Tid_hebrew_numeral)
|
||||
last = fmt_itm;
|
||||
else {
|
||||
fmt_itm.Fmt(bfr, wiki, lang, date, this);
|
||||
}
|
||||
if (idx_nxt == -1)
|
||||
++idx_cur;
|
||||
else {
|
||||
idx_cur = idx_nxt;
|
||||
idx_nxt = -1;
|
||||
}
|
||||
}
|
||||
if (last != null) {
|
||||
int year_int = bfr.XtoIntAndClear(-1);
|
||||
if (year_int != -1) { // handle no format; EX:{{#time:xh}} DATE:2014-07-20
|
||||
date = DateAdp_.seg_(new int[] {year_int, date.Month(), date.Day(), date.Hour(), date.Minute(), date.Second(), date.Frac()});
|
||||
last.Fmt(bfr, wiki, lang, date, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_formatdate_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset();}
|
||||
@Test public void Fmt_dmy() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|dmy}}" , "{{test}}" , "2 January 2012");}
|
||||
@Test public void Fmt_mdy() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|mdy}}" , "{{test}}" , "January 2, 2012");}
|
||||
@Test public void Fmt_ymd() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|ymd}}" , "{{test}}" , "2012 January 2");}
|
||||
@Test public void Fmt_ISO_8601() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|ISO 8601}}" , "{{test}}" , "2012-01-02");}
|
||||
@Test public void Fmt_default() {fxt.Test_parse_tmpl_str_test("{{#formatdate:2012-01-02|default}}" , "{{test}}" , "2012-01-02");} // NOOP?
|
||||
@Test public void Fmt_none() {fxt.Test_parse_tmpl_str_test("{{#formatdate:10 April 2012}}" , "{{test}}" , "10 April 2012");}
|
||||
@Test public void Err_multiple_years() {fxt.Test_parse_tmpl_str_test("{{#formatdate:January 2, 1999, 2000|Y}}" , "{{test}}" , "January 2, 1999, 2000");} // PURPOSE: check that multiple years don't fail
|
||||
@Test public void Unknown() {fxt.Test_parse_tmpl_str_test("{{#formatdate:unknown|dmy}}" , "{{test}}" , "unknown");} // PURPOSE: unknown term should output self, not ""; EX:w:Wikipedia:Wikipedia_Signpost/Newsroom/Opinion_desk/AdminCom; DATE:2014-04-13
|
||||
}
|
||||
/*
|
||||
{{#formatdate:2012-01-02|dmy}}<br/>
|
||||
{{#formatdate:2012-01-02|mdy}}<br/>
|
||||
{{#formatdate:2012-01-02|ymd}}<br/>
|
||||
{{#formatdate:2012-01-02|ISO 8601}}<br/>
|
||||
{{#formatdate:2012-01-02|default}}<br/>
|
||||
*/
|
||||
95
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_time.java
Normal file
95
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pft_func_time.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.langs.*;
|
||||
public class Pft_func_time extends Pf_func_base {
|
||||
Pft_func_time(boolean utc) {this.utc = utc;} private boolean utc;
|
||||
@Override public int Id() {return Xol_kwd_grp_.Id_xtn_time;}
|
||||
@Override public Pf_func New(int id, byte[] name) {return new Pft_func_time(utc).Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {// REF.MW:ParserFunctions_body.php
|
||||
int self_args_len = self.Args_len();
|
||||
byte[] arg_fmt = Eval_argx(ctx, src, caller, self);
|
||||
Pft_fmt_itm[] fmt_ary = Pft_fmt_itm_.Parse(ctx, arg_fmt);
|
||||
byte[] arg_date = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 0);
|
||||
byte[] arg_lang = Pf_func_.Eval_arg_or_empty(ctx, src, caller, self, self_args_len, 1);
|
||||
Bry_bfr error_bfr = Bry_bfr.new_();
|
||||
DateAdp date = ParseDate(arg_date, utc, error_bfr);
|
||||
if (date == null || error_bfr.Len() > 0)
|
||||
bfr.Add_str_a7("<strong class=\"error\">").Add_bfr_and_clear(error_bfr).Add_str("</strong>");
|
||||
else {
|
||||
Xol_lang lang = ctx.Lang();
|
||||
if (Bry_.Len_gt_0(arg_lang)) {
|
||||
Xol_lang_itm specified_lang_itm = Xol_lang_itm_.Get_by_key(arg_lang);
|
||||
if (specified_lang_itm != null) { // NOTE: if lang_code is bad, then ignore (EX:bad_code)
|
||||
Xol_lang specified_lang = ctx.Wiki().Appe().Lang_mgr().Get_by_key_or_new(arg_lang);
|
||||
lang = specified_lang;
|
||||
}
|
||||
}
|
||||
Pft_func_formatdate.Date_bldr().Format(bfr, ctx.Wiki(), lang, date, fmt_ary);
|
||||
}
|
||||
}
|
||||
public static DateAdp ParseDate(byte[] date, boolean utc, Bry_bfr error_bfr) {
|
||||
if (date == Bry_.Empty) return utc ? DateAdp_.Now().XtoUtc() : DateAdp_.Now();
|
||||
try {
|
||||
DateAdp rv = new Pxd_parser().Parse(date, error_bfr);
|
||||
return rv;
|
||||
}
|
||||
catch (Exception exc) {
|
||||
Exc_.Noop(exc);
|
||||
error_bfr.Add_str_a7("Invalid time");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static final Pft_func_time _Lcl = new Pft_func_time(false), _Utc = new Pft_func_time(true);
|
||||
}
|
||||
class DateAdpTranslator_xapp {
|
||||
public static void Translate(Xowe_wiki wiki, Xol_lang lang, int type, int val, Bry_bfr bb) {
|
||||
lang.Init_by_load_assert();
|
||||
byte[] itm_val = lang.Msg_mgr().Val_by_id(type + val); if (itm_val == null) return;
|
||||
bb.Add(itm_val);
|
||||
}
|
||||
}
|
||||
class Pfxtp_roman {
|
||||
public static void ToRoman(int num, Bry_bfr bfr) {
|
||||
if (num > 3000 || num <= 0) {
|
||||
bfr.Add_int_variable(num);
|
||||
return;
|
||||
}
|
||||
int pow10 = 1000;
|
||||
for (int i = 3; i > -1; i--) {
|
||||
if (num >= pow10) {
|
||||
bfr.Add(Names[i][Math_.Trunc(num / pow10)]);
|
||||
}
|
||||
num %= pow10;
|
||||
pow10 /= 10;
|
||||
}
|
||||
}
|
||||
private static byte[][][] Names = new byte[][][]
|
||||
{ Bry_dim2_new_("", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X")
|
||||
, Bry_dim2_new_("", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", "C")
|
||||
, Bry_dim2_new_("", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", "M")
|
||||
, Bry_dim2_new_("", "M", "MM", "MMM")
|
||||
};
|
||||
private static byte[][] Bry_dim2_new_(String... names) {
|
||||
int len = names.length;
|
||||
byte[][] rv = new byte[len][];
|
||||
for (int i = 0; i < len; i++)
|
||||
rv[i] = Bry_.new_u8(names[i]);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_time_basic_tst {
|
||||
@Before public void init() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));} private Xop_fxt fxt = new Xop_fxt();
|
||||
@After public void term() {Tfds.Now_enabled_n_();}
|
||||
@Test public void Utc_date() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-01-02 03:04:05}}" , "2012-01-02");}
|
||||
@Test public void Utc_time() {fxt.Test_parse_tmpl_str("{{#time:h:i:s A|2012-01-02 03:04:05}}" , "03:04:05 AM");}
|
||||
@Test public void Utc_dayOfYear() {fxt.Test_parse_tmpl_str("{{#time:z|2012-01-01 03:04:05}}" , "0");}
|
||||
@Test public void Utc_escape_basic() {fxt.Test_parse_tmpl_str("{{#time:\\Y Y|2012-01-02 03:04:05}}" , "Y 2012");}
|
||||
@Test public void Utc_escape_double() {fxt.Test_parse_tmpl_str("{{#time:\\\\ Y|2012-01-02 03:04:05}}" , "\\ 2012");}
|
||||
@Test public void Utc_escape_eos() {fxt.Test_parse_tmpl_str("{{#time:b\\|2012-01-02 03:04:05}}" , "b\\");}
|
||||
@Test public void Utc_escape_newLine() {fxt.Test_parse_tmpl_str("{{#time:b\\\nb|2012-01-02 03:04:05}}" , "b\nb");}
|
||||
@Test public void Utc_quote_basic() {fxt.Test_parse_tmpl_str("{{#time:b \"Y m d\" b|2012-01-02 03:04:05}}" , "b Y m d b");}
|
||||
@Test public void Utc_quote_double() {fxt.Test_parse_tmpl_str("{{#time:b \"\" b|2012-01-02 03:04:05}}" , "b \" b");}
|
||||
@Test public void Utc_quote_eos() {fxt.Test_parse_tmpl_str("{{#time:b \"|2012-01-02 03:04:05}}" , "b \"");}
|
||||
@Test public void Utc_ws() {fxt.Test_parse_tmpl_str("{{#time: Y-m-d |2012-01-02 03:04:05}}" , "2012-01-02");}
|
||||
@Test public void Lcl_date() {fxt.Test_parse_tmpl_str("{{#timel:Y-m-d|2012-01-02 03:04:05}}" , "2012-01-02");}
|
||||
@Test public void Utc_dow_abrv() {fxt.Test_parse_tmpl_str("{{#time:D|20120301}}" , "Thu");}
|
||||
@Test public void Utc_ymd() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|20120102}}" , "2012-01-02");}
|
||||
@Test public void Utc_ym() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|201201}}" , "2012-01-01");}
|
||||
@Test public void Utc_md() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2-13}}" , "2012-02-13");} // PURPOSE.fix: m-d failed
|
||||
@Test public void Slashes() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2/13/12}}" , "2012-02-13");} // PURPOSE: assert slashes work
|
||||
@Test public void Utc_day() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|March 27}}" , "2012-03-27");}
|
||||
@Test public void Parse_day() {fxt.Test_parse_tmpl_str("{{#time:m d|March 27}}" , "03 27");}
|
||||
@Test public void Month_name() {fxt.Test_parse_tmpl_str("{{#time:M|May 1 2012}}" , "May");}
|
||||
@Test public void Time_before_date__dmy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|04:50, 17 December 2010}}" , "2010-12-17 04:50");} // PAGE:en.w:Talk:Battle of Fort Washington
|
||||
@Test public void Time_before_date__mdy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|04:50, December 11, 2010}}" , "2010-12-11 04:50");} // PAGE:en.w:Wikipedia:WikiProject_Maine/members; DATE:2014-06-25
|
||||
@Test public void Error() {fxt.Test_parse_tmpl_str("{{#time:M|2}}" , "<strong class=\"error\">Invalid year: 2</strong>");}
|
||||
@Test public void Error2() {fxt.Test_parse_tmpl_str("{{#time:Y|July 28 - August 1, 1975}}" , "<strong class=\"error\">Invalid time</strong>");}
|
||||
@Test public void Error3() {fxt.Test_parse_tmpl_str("{{#time:Y|106BC-43BC}}" , "<strong class=\"error\">Invalid time</strong>");}
|
||||
@Test public void Timestamp() {fxt.Test_parse_tmpl_str("{{#time:F j, Y|20060827072854}}" , "August 27, 2006");} // PAGE:en.w:Great Fire of London
|
||||
@Test public void Unixtime_read() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|@0}}" , "1970-01-01 12:00:00 AM");} // EX:w:Wikipedia:WikiProject_Articles_for_creation/BLD_Preload
|
||||
@Test public void Unixtime_read_neg() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|@-3600}}" , "1969-12-31 11:00:00 PM");} // EX:w:Wikipedia:WikiProject_Articles_for_creation/October_-_November_2012_Backlog_Elimination_Drive; DATE:2014-05-10
|
||||
@Test public void Unixtime_8_digit() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|@20120304}}" , "1970-08-21 08:58:24 PM");} // PURPOSE: make sure yyyy-MM-dd is gobbled by "@" and not evaluated again as date; EX:w:Wikipedia:WikiProject_Articles_for_creation/October_-_November_2012_Backlog_Elimination_Drive; DATE:2014-05-10
|
||||
@Test public void Unixtime_write() {fxt.Test_parse_tmpl_str("{{#time:U|2012-08-02}}" , "1343865600");} // PAGE:en.w:Opa (programming language)
|
||||
@Test public void Year_4_digit() {fxt.Test_parse_tmpl_str("{{#time:Y|June 20, 451}}" , "0451");} // PAGE:en.w:Battle of the Catalaunian Plains
|
||||
@Test public void Year_month() {fxt.Test_parse_tmpl_str("{{#time:F Y|November 2012}}" , "November 2012");} // PAGE:en.w:Project:Current events
|
||||
@Test public void Day_addition_with_dash(){fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2011-11-13 +1 day}}" , "2011-11-14");} // PURPOSE: +1 day was becoming -1 day b/c it was picking up - at -13; PAGE:en.w:Template:POTD/2012-10-09
|
||||
@Test public void Hour_zero() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|August 18 2006 00:14}}" , "2006-08-18 00:14");} // PURPOSE: fix; invalid hour; PAGE:en.w:Talk:Martin Luther
|
||||
@Test public void Iso() {fxt.Test_parse_tmpl_str("{{#time:c|2012-01-02 03:04:05}}" , "2012-01-02T03:04:05-05:00");}
|
||||
@Test public void Ymdh() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-01-02-99}}" , "2012-01-06");} // PURPOSE: "99" is treated as 99th hour; EX:w:LimeWire; DATE:2014-03-24
|
||||
@Test public void Ymdh_noop() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-01-02-100}}" , "2012-01-02");} // PURPOSE: "100" is ignored
|
||||
@Test public void Month_is_0() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-00-01}}" , "2011-12-01");} // PURPOSE: "0" for month is treated as -1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
|
||||
@Test public void Day_is_0() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|2012-12-00}}" , "2012-11-30");} // PURPOSE: "0" for day is treated as -1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
|
||||
@Test public void Day_suffix_y() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|11th Dec 2013}}" , "2013-12-11");} // PURPOSE: ignore suffix days; EX:11th; DATE:2014-03-25
|
||||
@Test public void Day_suffix_n() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|32nd Dec 2013}}" , "<strong class=\"error\">Invalid day: 32</strong>");}
|
||||
@Test public void Day_rel_today() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|today}}" , "2012-01-02");}
|
||||
@Test public void Day_rel_tomorrow() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|tomorrow}}" , "2012-01-03");}
|
||||
@Test public void Day_rel_yesterday() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|yesterday}}" , "2012-01-01");}
|
||||
@Test public void Unit_rel_year_next() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|next year}}" , "2013-01-02");} // DATE:2014-05-02
|
||||
@Test public void Unit_rel_year_last() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|last year}}" , "2011-01-02");}
|
||||
@Test public void Unit_rel_year_previous(){fxt.Test_parse_tmpl_str("{{#time:Y-m-d|previous year}}" , "2011-01-02");}
|
||||
@Test public void Unit_rel_year_this() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|this year}}" , "2012-01-02");}
|
||||
@Test public void Time_rel_now() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|now}}" , "2012-01-02 03:05:05 AM");} // NOTE: minute is 5, not 4, b/c each call to DateAdp_.Now() automatically increments by 1 minute; DATE:2014-04-13
|
||||
@Test public void Empty_is_today() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|}}" , "2012-01-02");} // tested on MW
|
||||
@Test public void Day_name_today() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|Monday}}" , "2012-01-02");} // 2012-01-02 is Monday, so return Monday; DATE:2014-05-02
|
||||
@Test public void Day_name_future_1() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|Saturday}}" , "2012-01-07");} // return next Sunday; DATE:2014-05-02
|
||||
@Test public void Day_name_future_2() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d|Sunday}}" , "2012-01-08");} // return next Saturday; DATE:2014-05-02
|
||||
@Test public void Day_name_dow() {fxt.Test_parse_tmpl_str("{{#time:w|Monday}}" , "1");}
|
||||
@Test public void Timezone_offset() {
|
||||
DateAdp.Timezone_offset_test = -18000;
|
||||
fxt.Test_parse_tmpl_str("{{#time:Z|}}" , "-18000");
|
||||
DateAdp.Timezone_offset_test = Int_.MinValue;
|
||||
} // Z=timezone offset in seconds; http://php.net/manual/en/function.date.php;
|
||||
@Test public void Timezone_plus() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i:s|2012-01-02 03:04:05+06:30}}" , "2012-01-02 09:34:05");} // PURPOSE: handle timezone plus ; EX: +01:30; DATE:2014-08-26
|
||||
@Test public void Timezone_minus() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i:s|2012-01-02 09:34:05-06:30}}" , "2012-01-02 03:04:05");} // PURPOSE: handle timezone minus; EX: -01:30; DATE:2014-08-26
|
||||
@Test public void Timezone_wrap() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i:s|2012-01-31 22:30:05+01:30}}" , "2012-02-01 00:00:05");} // PURPOSE: handle timezone wrap ; DATE:2014-08-26
|
||||
@Test public void Rfc5322() {fxt.Test_parse_tmpl_str("{{#time:r|}}" , "Mon, 02 Jan 2012 08:04:05 +0000");}
|
||||
@Test public void Lang() {
|
||||
Xol_lang fr_lang = fxt.App().Lang_mgr().Get_by_key_or_new(Bry_.new_a7("fr"));
|
||||
Xol_msg_itm msg_itm = fr_lang.Msg_mgr().Itm_by_key_or_new(Bry_.new_a7("January"));
|
||||
msg_itm.Atrs_set(Bry_.new_a7("Janvier"), false, false);
|
||||
fxt.Test_parse_tmpl_str("{{#time:F|2012-01|fr}}" , "Janvier");
|
||||
// fxt.Test_parse_tmpl_str("{{#time:F|2012-01|fr_bad}}" , "January"); // default to english // commented out; fails when running all at once
|
||||
}
|
||||
@Test public void Hour_with_dash() {fxt.Test_parse_tmpl_str("{{#time:c|January 2, 2001-06}}" , "2001-01-02T06:00:00-05:00");} // PURPOSE.fix: w:Vim_(text_editor) generates this during {{time ago|November 2, 1991-06-19|min_magnitude=days}}; DATE:2013-06-19
|
||||
@Test public void Multiple_dates_gt_12() {fxt.Test_parse_tmpl_str("{{#time:c|January 2, 2001-06-19}}" , "2001-01-02T06:00:00-05:00");} // PURPOSE.fix: w:Vim_(text_editor)
|
||||
@Test public void Multiple_dates_lt_12() {fxt.Test_parse_tmpl_str("{{#time:c|January 2, 2001-06-11}}" , "2001-01-02T06:00:00-05:00");} // PURPOSE.fix: w:Vim_(text_editor)
|
||||
@Test public void Raw_H() {fxt.Test_parse_tmpl_str("{{#time:xnH}}" , "08");} // PURPOSE: ignore "xn" for now; chk 0-padded number is generated; DATE:2013-12-31
|
||||
@Test public void Raw_h() {fxt.Test_parse_tmpl_str("{{#time:xnh}}" , "08");} // PURPOSE: ignore "xn" for now; chk 0-padded number is generated; DATE:2013-12-31
|
||||
@Test public void Iso8601_T() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|T1:23}}" , "2012-01-01 01:23:00 AM");} // handle "T" flag; PAGE:pl.w:StarCraft_II:_Wings_of_Liberty
|
||||
@Test public void Iso8601_T_ws() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|T 1:23}}" , "2012-01-01 01:23:00 AM");} // handle "T" flag and ws
|
||||
@Test public void Iso8601_T_fail() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d h:i:s A|T2012-01-02}}" , "<strong class=\"error\">Invalid hour: T</strong>");} // handle "T" flag and ws
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_time_foreign_tst {
|
||||
@Before public void init() {fxt.Clear();} private Pft_func_time_foreign_fxt fxt = new Pft_func_time_foreign_fxt();
|
||||
@After public void term() {fxt.Term();}
|
||||
@Test public void Roman() {fxt.Test_parse("{{#time:xrY|2012}}" , "MMXII");}
|
||||
@Test public void Thai() {fxt.Test_parse("{{#time:xkY|2012}}" , "2555");}
|
||||
@Test public void Minguo() {fxt.Test_parse("{{#time:xoY|2012}}" , "101");}
|
||||
@Test public void Hebrew_year_num() {fxt.Test_parse("{{#time:xjY|2012-01-02}}" , "5772");}
|
||||
@Test public void Hebrew_month_num() {fxt.Test_parse("{{#time:xjn|2012-01-02}}" , "4");}
|
||||
@Test public void Hebrew_day_num() {fxt.Test_parse("{{#time:xjj|2012-01-02}}" , "7");}
|
||||
@Test public void Hebrew_month_days_count() {fxt.Test_parse("{{#time:xjt|2012-01-02}}" , "29");}
|
||||
@Test public void Hebrew_month_name_full() {fxt.Init_msg("hebrew-calendar-m4" , "Tevet").Test_parse("{{#time:xjF|2012-01-02}}" , "Tevet");}
|
||||
@Test public void Hebrew_month_name_gen() {fxt.Init_msg("hebrew-calendar-m4-gen" , "Tevet").Test_parse("{{#time:xjx|2012-01-02}}" , "Tevet");}
|
||||
@Test public void Hebrew_numeral() {fxt.Test_parse("{{#time:xh}}" , "");}
|
||||
@Test public void Hebrew_numeral_2() {fxt.Test_parse("{{#time:xhxjY|2014}}" , "ה'תשע\"ד");}
|
||||
@Test public void Roman_various() {
|
||||
fxt.Test_Roman( 1, "I");
|
||||
fxt.Test_Roman( 2, "II");
|
||||
fxt.Test_Roman( 3, "III");
|
||||
fxt.Test_Roman( 4, "IV");
|
||||
fxt.Test_Roman( 5, "V");
|
||||
fxt.Test_Roman( 6, "VI");
|
||||
fxt.Test_Roman( 7, "VII");
|
||||
fxt.Test_Roman( 8, "VIII");
|
||||
fxt.Test_Roman( 9, "IX");
|
||||
fxt.Test_Roman( 10, "X");
|
||||
fxt.Test_Roman( 11, "XI");
|
||||
fxt.Test_Roman( 100, "C");
|
||||
fxt.Test_Roman( 101, "CI");
|
||||
fxt.Test_Roman( 111, "CXI");
|
||||
fxt.Test_Roman(1000, "M");
|
||||
fxt.Test_Roman(1001, "MI");
|
||||
fxt.Test_Roman(4000, "4000");
|
||||
}
|
||||
}
|
||||
class Pft_func_time_foreign_fxt {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
public void Clear() {
|
||||
fxt.Reset();
|
||||
Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));
|
||||
}
|
||||
public void Term() {
|
||||
Tfds.Now_enabled_n_();
|
||||
}
|
||||
public Pft_func_time_foreign_fxt Init_msg(String key, String val) {
|
||||
Xol_msg_itm msg = fxt.Wiki().Msg_mgr().Get_or_make(Bry_.new_u8(key));
|
||||
msg.Atrs_set(Bry_.new_u8(val), false, false);
|
||||
return this;
|
||||
}
|
||||
public void Test_parse(String raw, String expd) {
|
||||
fxt.Test_parse_tmpl_str_test(raw, "{{test}}", expd);
|
||||
}
|
||||
public void Test_Roman(int v, String expd) {
|
||||
Bry_bfr bfr = Bry_bfr.new_(16);
|
||||
Pfxtp_roman.ToRoman(v, bfr);
|
||||
String actl = bfr.Xto_str_and_clear();
|
||||
Tfds.Eq(expd, actl);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_time_int_tst {
|
||||
@Before public void init() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));} private Xop_fxt fxt = new Xop_fxt();
|
||||
@Test public void Time_before_date__dmy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|01:02 3.4.2005}}" , "2005-04-03 01:02");} // PAGE:sk.w:Dr._House; DATE:2014-09-23
|
||||
@Test public void Time_before_date__mdy() {fxt.Test_parse_tmpl_str("{{#time:Y-m-d H:i|01:02 3.14.2005}}" , "<strong class=\"error\">Invalid month: 14</strong>");} // mdy is invalid; DATE:2014-09-23
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pft_func_time_uncommon_tst {
|
||||
private Xop_fxt fxt = new Xop_fxt();
|
||||
@Before public void init() {fxt.Reset(); Tfds.Now_set(DateAdp_.new_(2012, 1, 2, 3, 4, 5, 6));}
|
||||
@After public void term() {Tfds.Now_enabled_n_();}
|
||||
@Test public void Year_5_digits() {fxt.Test_parse_tmpl_str_test("{{#time:Y-m-d|00123-4-5}}" , "{{test}}" , "2003-04-05");} // PURPOSE: emulate PHP's incorrect date parsing; EX:ca.w:Nicolau_de_Mira; DATE:2014-04-17
|
||||
}
|
||||
209
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_eval_seg.java
Normal file
209
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_eval_seg.java
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
class Pxd_eval_year {
|
||||
public static void Eval_at_pos_0(Pxd_parser tctx, Pxd_itm_int cur) {
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
if (tctx.Data_ary_len() < 2) return;
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_1 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
|
||||
}
|
||||
if (tctx.Data_ary_len() < 3) return;
|
||||
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
|
||||
if (itm_2 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_2)) return;
|
||||
}
|
||||
if (tctx.Data_ary_len() == 4) { // handle strange constructions like 2014-03-24-25;
|
||||
Pxd_itm_int itm_3 = Pxd_itm_int_.CastOrNull(data_ary[3]);
|
||||
if (itm_3 != null) { // treat 4th number as hour adjustment; EX: 2014-03-24-72 -> 2014-03-26; DATE:2014-03-24
|
||||
int itm_3_val = itm_3.Val();
|
||||
if (itm_3_val > 99) itm_3_val = 0; // only adjust if number is between 0 and 99;
|
||||
Pxd_itm_int_.Convert_to_rel(tctx, itm_3, Pxd_parser_.Unit_name_hour, DateAdp_.SegIdx_hour, itm_3_val);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void Eval_at_pos_2(Pxd_parser tctx, Pxd_itm_int cur) {
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_0 == null || itm_1 == null) return; // 0 or 1 is not an int;
|
||||
if (itm_1.Val() > 13) {
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_1)) return;
|
||||
}
|
||||
else {
|
||||
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
|
||||
}
|
||||
}
|
||||
public static void Eval_at_pos_n(Pxd_parser tctx, Pxd_itm_int cur) { // where n > 2; EX: 1:23 4.5.2010; PAGE:sk.w:Dr._House; DATE:2014-09-23
|
||||
Pxd_itm[] data_ary = tctx.Data_ary(); int data_ary_len = data_ary.length; int data_idx = cur.Data_idx();
|
||||
Pxd_itm_int lhs_1 = Pxd_itm_int_.Get_int_bwd(data_ary, data_ary_len, data_idx - 1);
|
||||
if (lhs_1 != null) { // lhs_1 is int; EX:05-2014
|
||||
Pxd_itm_int lhs_0 = Pxd_itm_int_.Get_int_bwd(data_ary, data_ary_len, data_idx - 2);
|
||||
if (lhs_0 != null) { // lhs_0 is int; EX:01-05-2014
|
||||
if (!Pxd_eval_seg.Eval_as_d(tctx, lhs_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, lhs_1)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_y(tctx, cur )) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static final int Month_max = 12;
|
||||
}
|
||||
class Pxd_eval_seg {
|
||||
public static boolean Eval_as_y(Pxd_parser tctx, Pxd_itm_int itm) {
|
||||
int val = itm.Val();
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
itm.Val_(val + (val > 69 ? 1900 : 2000)); // assume that 70 refers to 1970 and 69 refers to 2069
|
||||
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_year);
|
||||
return true;
|
||||
case 3: // NOTE: 3 digit numbers are valid years; MW relies on PHP time parse which always zero-pad numbers; PAGE:en.w:Battle of the Catalaunian Plains; {{#time:Y|June 20, 451}}
|
||||
case 4:
|
||||
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_year);
|
||||
return true;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_year, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static boolean Eval_as_m(Pxd_parser tctx, Pxd_itm_int itm) {
|
||||
int val = itm.Val();
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (val > 0 && val < 13) {
|
||||
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_month);
|
||||
return true;
|
||||
}
|
||||
else if (val == 0) {// 0 day means subtract 1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
|
||||
Pxd_itm_int_.Convert_to_rel(tctx, itm, Pxd_parser_.Unit_name_month, DateAdp_.SegIdx_month, -1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_month, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static boolean Eval_as_d(Pxd_parser tctx, Pxd_itm_int itm) {
|
||||
int val = itm.Val();
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (val > 0 && val < 32) {
|
||||
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_day);
|
||||
return true;
|
||||
}
|
||||
else if (val == 0) { // 0 day means subtract 1; EX:w:Mariyinsky_Palace; DATE:2014-03-25
|
||||
Pxd_itm_int_.Convert_to_rel(tctx, itm, Pxd_parser_.Unit_name_day, DateAdp_.SegIdx_day, -1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static boolean Eval_as_h(Pxd_parser tctx, Pxd_itm_int itm) {
|
||||
int val = itm.Val();
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (val > -1 && val < 25) {
|
||||
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_hour, val);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static boolean Eval_as_n(Pxd_parser tctx, Pxd_itm_int itm) {
|
||||
int val = itm.Val();
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (val > -1 && val < 60) {
|
||||
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_minute, val);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_minute, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static boolean Eval_as_s(Pxd_parser tctx, Pxd_itm_int itm) {
|
||||
int val = itm.Val();
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (val > -1 && val < 60) {
|
||||
tctx.Seg_idxs_(itm, DateAdp_.SegIdx_second);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_second, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static boolean Eval_as_tz_h(Pxd_parser tctx, Pxd_itm_int itm, boolean negative) {
|
||||
if (negative) itm.Val_(itm.Val() * -1);
|
||||
int val = itm.Val();
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (val > -12 && val < 12) {
|
||||
itm.Val_is_adj_(Bool_.Y);
|
||||
itm.Seg_idx_(DateAdp_.SegIdx_hour);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static boolean Eval_as_tz_m(Pxd_parser tctx, Pxd_itm_int itm, boolean negative) {
|
||||
int val = itm.Val();
|
||||
if (negative) val *= -1;
|
||||
switch (itm.Digits()) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (val > -60 && val < 60) {
|
||||
itm.Val_is_adj_(Bool_.Y);
|
||||
itm.Seg_idx_(DateAdp_.SegIdx_minute);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_minute, Bry_fmtr_arg_.int_(val));
|
||||
return false;
|
||||
}
|
||||
public static byte Eval_as_tz_sym(Pxd_parser tctx, Pxd_itm[] tkns, Pxd_itm_int hour_itm) {
|
||||
Pxd_itm sym = Pxd_itm_.Find_bwd__non_ws(tkns, hour_itm.Ary_idx());
|
||||
switch (sym.Tkn_tid()) {
|
||||
case Pxd_itm_.Tid_sym:
|
||||
Pxd_itm_sym sym_itm = (Pxd_itm_sym)sym;
|
||||
if (sym_itm.Sym_byte() == Byte_ascii.Plus)
|
||||
return Bool_.Y_byte;
|
||||
break;
|
||||
case Pxd_itm_.Tid_dash: return Bool_.N_byte;
|
||||
}
|
||||
tctx.Err_set(Pft_func_time_log.Invalid_timezone, Bry_fmtr_arg_.bry_("null"));
|
||||
return Bool_.__byte;
|
||||
}
|
||||
}
|
||||
122
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_.java
Normal file
122
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_.java
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
interface Pxd_itm {
|
||||
byte Tkn_tid();
|
||||
int Ary_idx();
|
||||
int Seg_idx();
|
||||
int Eval_idx();
|
||||
int Data_idx(); void Data_idx_(int v);
|
||||
void Eval(Pxd_parser state);
|
||||
void Time_ini(DateAdpBldr bldr);
|
||||
}
|
||||
class Pxd_itm_ {
|
||||
public static final int
|
||||
Tid_null = 0
|
||||
, Tid_int = 1
|
||||
, Tid_int_dmy_14 = 2
|
||||
, Tid_int_hms_6 = 3
|
||||
, Tid_month_name = 4
|
||||
, Tid_dow_name = 5
|
||||
, Tid_unit = 6
|
||||
, Tid_ago = 7
|
||||
, Tid_day_suffix = 8 // 1st, 2nd
|
||||
, Tid_day_relative = 9 // today, tomorrow, yesterday
|
||||
, Tid_time_relative = 10 // now
|
||||
, Tid_unit_relative = 11 // next, previous
|
||||
, Tid_unixtime = 12 // @123
|
||||
, Tid_iso8601_t = 13 // T
|
||||
, Tid_dash = Byte_ascii.Dash
|
||||
, Tid_dot = Byte_ascii.Dot
|
||||
, Tid_slash = Byte_ascii.Slash
|
||||
, Tid_colon = Byte_ascii.Colon
|
||||
, Tid_ws = 98
|
||||
, Tid_sym = 99
|
||||
;
|
||||
public static Pxd_itm Find_bwd__non_ws(Pxd_itm[] tkns, int bgn) {
|
||||
for (int i = bgn - 1; i > -1; --i) {
|
||||
Pxd_itm itm = tkns[i];
|
||||
if (itm.Tkn_tid() != Tid_ws) return itm;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static Pxd_itm Find_fwd_by_tid(Pxd_itm[] tkns, int bgn, int tid) {
|
||||
int len = tkns.length;
|
||||
for (int i = bgn; i < len; i++) {
|
||||
Pxd_itm itm = tkns[i];
|
||||
if (tid == itm.Tkn_tid()) return itm;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static boolean Eval_needed(Pxd_itm itm) {return itm.Seg_idx() == -1;}
|
||||
}
|
||||
abstract class Pxd_itm_base implements Pxd_itm {
|
||||
public abstract byte Tkn_tid();
|
||||
public int Ary_idx() {return ary_idx;} private int ary_idx;
|
||||
public int Seg_idx() {return seg_idx;} private int seg_idx = Seg_idx_null;
|
||||
public void Seg_idx_(int v) {seg_idx = v;}
|
||||
public int Data_idx() {return data_idx;} public void Data_idx_(int v) {data_idx = v;} private int data_idx;
|
||||
public abstract int Eval_idx();
|
||||
@gplx.Virtual public void Eval(Pxd_parser state) {}
|
||||
@gplx.Virtual public void Time_ini(DateAdpBldr bldr) {}
|
||||
public void Ctor(int ary_idx) {this.ary_idx = ary_idx;}
|
||||
public static final int Seg_idx_null = -1, Seg_idx_skip = -2;
|
||||
}
|
||||
interface Pxd_itm_prototype {
|
||||
Pxd_itm MakeNew(int ary_idx);
|
||||
}
|
||||
class DateAdpBldr {
|
||||
public DateAdp Date() {
|
||||
if (dirty) {
|
||||
if (date == null) date = DateAdp_.seg_(seg_ary); // date not set and seg_ary is dirty; make date = seg_ary;
|
||||
return date;
|
||||
}
|
||||
else
|
||||
return DateAdp_.Now(); // not dirtied; default to now;
|
||||
}
|
||||
public DateAdpBldr Date_(DateAdp v) {date = v; return this;} DateAdp date = null;
|
||||
public DateAdpBldr Seg_set(int idx, int val) {
|
||||
if (date == null) seg_ary[idx] = val;
|
||||
else {
|
||||
seg_ary = date.XtoSegAry();
|
||||
seg_ary[idx] = val;
|
||||
date = DateAdp_.seg_(seg_ary);
|
||||
}
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
public DateAdp Bld() {
|
||||
return date == null ? DateAdp_.seg_(seg_ary) : date;
|
||||
}
|
||||
public DateAdpBldr(int... seg_ary) {this.seg_ary = seg_ary;}
|
||||
int[] seg_ary = new int[DateAdp_.SegIdx__max]; boolean dirty = false;
|
||||
}
|
||||
class Pft_func_time_log {
|
||||
private static final Gfo_msg_grp owner = Gfo_msg_grp_.new_(Xoa_app_.Nde, "time_parser");
|
||||
public static final Gfo_msg_itm
|
||||
Invalid_day = Gfo_msg_itm_.new_warn_(owner, "Invalid day: ~{0}")
|
||||
, Invalid_month = Gfo_msg_itm_.new_warn_(owner, "Invalid month: ~{0}")
|
||||
, Invalid_year = Gfo_msg_itm_.new_warn_(owner, "Invalid year: ~{0}")
|
||||
, Invalid_year_mid = Gfo_msg_itm_.new_warn_(owner, "Invalid date: 4 digit year must be either yyyy-##-## or ##-##-yyyy")
|
||||
, Invalid_hour = Gfo_msg_itm_.new_warn_(owner, "Invalid hour: ~{0}")
|
||||
, Invalid_minute = Gfo_msg_itm_.new_warn_(owner, "Invalid minute: ~{0}")
|
||||
, Invalid_second = Gfo_msg_itm_.new_warn_(owner, "Invalid second: ~{0}")
|
||||
, Invalid_date = Gfo_msg_itm_.new_warn_(owner, "Invalid date: ~{0}")
|
||||
, Invalid_timezone = Gfo_msg_itm_.new_warn_(owner, "Invalid timezone: ~{0}")
|
||||
;
|
||||
}
|
||||
299
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_int.java
Normal file
299
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_int.java
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
interface Pxd_itm_int_interface extends Pxd_itm {
|
||||
int Xto_int_or(int or);
|
||||
}
|
||||
class Pxd_itm_int extends Pxd_itm_base implements Pxd_itm_int_interface {
|
||||
public Pxd_itm_int(int ary_idx, int digits, int val) {
|
||||
this.Ctor(ary_idx); this.digits = digits; this.val = val;
|
||||
switch (digits) {
|
||||
case 4: // assume year
|
||||
eval_idx = 50;
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
default:
|
||||
if (val > 12) // either day or year; not month
|
||||
eval_idx = 60;
|
||||
else
|
||||
eval_idx = 70; // day, year, or month
|
||||
break;
|
||||
}
|
||||
}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_int;}
|
||||
@Override public int Eval_idx() {return eval_idx;} private int eval_idx = 99;
|
||||
public int Val() {return val;} public Pxd_itm_int Val_(int v) {val = v; return this;} private int val;
|
||||
public boolean Val_is_adj() {return val_is_adj;} public void Val_is_adj_(boolean v) {val_is_adj = v;} private boolean val_is_adj;
|
||||
public int Xto_int_or(int or) {return val;}
|
||||
public int Digits() {return digits;} private int digits;
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
int seg_idx = this.Seg_idx();
|
||||
if (seg_idx == Pxd_itm_base.Seg_idx_skip) return;
|
||||
if (val_is_adj) {
|
||||
if (val == 0) return; // no adjustment to make
|
||||
DateAdp date = bldr.Date();
|
||||
switch (seg_idx) {
|
||||
case DateAdp_.SegIdx_hour: date = date.Add_hour(val); break;
|
||||
case DateAdp_.SegIdx_minute: date = date.Add_minute(val); break;
|
||||
default: return;
|
||||
}
|
||||
bldr.Date_(date);
|
||||
}
|
||||
else
|
||||
bldr.Seg_set(seg_idx, val);
|
||||
}
|
||||
@Override public void Eval(Pxd_parser tctx) {
|
||||
int data_idx = this.Data_idx();
|
||||
if (this.Seg_idx() != Pxd_itm_base.Seg_idx_null) return; // has seg_idx; already eval'd by something else
|
||||
switch (digits) {
|
||||
case 5: // 5 digits
|
||||
switch (data_idx) {
|
||||
case 0: Pxd_eval_year.Eval_at_pos_0(tctx, this); break; // year at pos 0; EX: 01234-02-03
|
||||
case 1: tctx.Err_set(Pft_func_time_log.Invalid_date); return; // year at pos 1; invalid; EX: 01-01234-02
|
||||
case 2: tctx.Err_set(Pft_func_time_log.Invalid_date); break; // year at pos 2; invalid; EX: 01-02-01234
|
||||
}
|
||||
val = 2000 + (val % 10); // NOTE: emulate PHP's incorrect behavior with 5 digit years; EX:ca.w:Nicolau_de_Mira; DATE:2014-04-18
|
||||
tctx.Seg_idxs_(this, DateAdp_.SegIdx_year);
|
||||
break;
|
||||
case 4: // 4 digits; assume year
|
||||
switch (data_idx) {
|
||||
case 0: Pxd_eval_year.Eval_at_pos_0(tctx, this); break; // year at pos 0; EX: 2001-02-03
|
||||
case 1: tctx.Err_set(Pft_func_time_log.Invalid_year_mid); return;// year at pos 1; invalid; EX: 02-2003-03
|
||||
case 2: Pxd_eval_year.Eval_at_pos_2(tctx, this); break; // year at pos 2; EX: 02-03-2001
|
||||
default: Pxd_eval_year.Eval_at_pos_n(tctx, this); break; // year at pos n; EX: 04:05 02-03-2001
|
||||
}
|
||||
tctx.Seg_idxs_(this, DateAdp_.SegIdx_year);
|
||||
break;
|
||||
default:
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
int data_ary_len = data_ary.length;
|
||||
Pxd_itm_int cur_itm = Pxd_itm_int_.CastOrNull(data_ary[data_idx]);
|
||||
Pxd_itm lhs_itm = data_idx == 0 ? null : data_ary[data_idx - 1];
|
||||
Pxd_itm rhs_itm = data_idx == data_ary_len - 1 ? null : data_ary[data_idx + 1];
|
||||
if ( lhs_itm != null && lhs_itm.Seg_idx() == DateAdp_.SegIdx_month // itm on left is month
|
||||
&& rhs_itm != null && rhs_itm.Seg_idx() == DateAdp_.SegIdx_year // itm on right is year
|
||||
&& tctx.Seg_idxs()[DateAdp_.SegIdx_day] == -1 // day not yet set; needed for {{#time:Y|July 28 - August 1, 1975}}
|
||||
)
|
||||
if (!Pxd_eval_seg.Eval_as_d(tctx, cur_itm)) return; // cur int should be day; EX:January 1, 2010; PAGE:en.w:Wikipedia:WikiProject_Maine/members; DATE:2014-06-25
|
||||
if (val > Month_max) { // value is not a month; assume day; DATE:2013-03-15
|
||||
switch (data_idx) {
|
||||
case 0: // > 12 in slot 0
|
||||
if (Match_sym(tctx, Bool_.Y, Pxd_itm_.Tid_dot)) // next sym is dot; assume m.d.y; EX: 22.5.70
|
||||
Eval_day_at_pos_0(tctx);
|
||||
else // next sym is not dot; assume y-m-d; EX: 70-5-22
|
||||
Eval_month_at_pos_0(tctx);
|
||||
break;
|
||||
case 1: Eval_month_at_pos_1(tctx); break; // > 12 in slot 1; assume m.d; EX: 5.22
|
||||
case 2: // > 12 in slot 2
|
||||
if (Match_sym(tctx, Bool_.N, Pxd_itm_.Tid_dot)) // prv sym is dot; assume d.m.y; EX: 22.5.70
|
||||
Eval_dmy_at_y(tctx);
|
||||
else // prv sym is not dot; assume m-d-y; EX: 22.5.70
|
||||
Eval_month_at_pos_2(tctx);
|
||||
break;
|
||||
case 4:
|
||||
Eval_unknown_at_pos_4(tctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { // value is either day or month;
|
||||
switch (data_idx) {
|
||||
case 0: Eval_unknown_at_pos_0(tctx); break;
|
||||
case 3: Eval_unknown_at_pos_3(tctx); break;
|
||||
case 4: Eval_unknown_at_pos_4(tctx); break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
public static final int Month_max = 12;
|
||||
private void Eval_unknown_at_pos_3(Pxd_parser tctx) { // int at pos 4
|
||||
if ( tctx.Seg_idxs_chk(DateAdp_.SegIdx_year, DateAdp_.SegIdx_month, DateAdp_.SegIdx_day) // check that ymd is set
|
||||
&& Match_sym(tctx, false, Pxd_itm_.Tid_dash)) // check that preceding symbol is "-"
|
||||
Pxd_eval_seg.Eval_as_h(tctx, this); // mark as hour; handles strange fmts like November 2, 1991-06; DATE:2013-06-19
|
||||
}
|
||||
private void Eval_unknown_at_pos_4(Pxd_parser tctx) {
|
||||
if ( tctx.Seg_idxs_chk(DateAdp_.SegIdx_year
|
||||
, DateAdp_.SegIdx_month, DateAdp_.SegIdx_day, DateAdp_.SegIdx_hour) // check that ymdh is set
|
||||
&& Match_sym(tctx, false, Pxd_itm_.Tid_dash)) // check that preceding symbol is "-"
|
||||
tctx.Seg_idxs_(this, Pxd_itm_base.Seg_idx_skip); // mark as ignore; handles strange fmts like November 2, 1991-06-19; DATE:2013-06-19
|
||||
}
|
||||
boolean Match_sym(Pxd_parser tctx, boolean fwd, int sym_tid) {
|
||||
int sym_idx = this.Ary_idx() + (fwd ? 1 : -1);
|
||||
Pxd_itm[] sym_tkns = tctx.Tkns();
|
||||
if (sym_idx < 0 || sym_idx > sym_tkns.length) return false; // NOTE: was Data_ary_len; DATE:2013-06-19
|
||||
return sym_tkns[sym_idx].Tkn_tid() == sym_tid;
|
||||
}
|
||||
private void Eval_month_at_pos_0(Pxd_parser tctx) {
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
if (tctx.Data_ary_len() < 2) return;
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_1 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
|
||||
}
|
||||
if (tctx.Data_ary_len() > 2) {
|
||||
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
|
||||
if (itm_2 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_2)) return;
|
||||
}
|
||||
}
|
||||
Pxd_eval_seg.Eval_as_y(tctx, this);
|
||||
}
|
||||
private void Eval_day_at_pos_0(Pxd_parser tctx) { // eval 1 as month; 2 as year, 0 as day
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
if (tctx.Data_ary_len() < 2) return;
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_1 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
|
||||
}
|
||||
if (tctx.Data_ary_len() > 2) {
|
||||
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
|
||||
if (itm_2 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_2)) return;
|
||||
}
|
||||
}
|
||||
Pxd_eval_seg.Eval_as_d(tctx, this);
|
||||
}
|
||||
private void Eval_dmy_at_y(Pxd_parser tctx) { // dmy format; cur is y (slot 2)
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
if (tctx.Data_ary_len() < 3) return; // since proc starts at y, assume at least d-m-y (not m-y)
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_1 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
|
||||
}
|
||||
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
|
||||
if (itm_0 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_0)) return;
|
||||
}
|
||||
Pxd_eval_seg.Eval_as_y(tctx, this);
|
||||
}
|
||||
private void Eval_month_at_pos_1(Pxd_parser tctx) {
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
|
||||
if (itm_0 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_0)) return;
|
||||
}
|
||||
if (tctx.Data_ary_len() > 2) {
|
||||
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
|
||||
if (itm_2 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_2)) return;
|
||||
}
|
||||
}
|
||||
Pxd_eval_seg.Eval_as_d(tctx, this);
|
||||
}
|
||||
private void Eval_month_at_pos_2(Pxd_parser tctx) {
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
|
||||
if (itm_0 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_0)) return;
|
||||
}
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_1 != null) {
|
||||
if (!Pxd_eval_seg.Eval_as_d(tctx, itm_1)) return;
|
||||
}
|
||||
Pxd_eval_seg.Eval_as_y(tctx, this);
|
||||
}
|
||||
private void Eval_unknown_at_pos_0(Pxd_parser tctx) { // NOTE: assumes dmy format
|
||||
Pxd_itm[] data_ary = tctx.Data_ary();
|
||||
if (tctx.Data_ary_len() < 2) {tctx.Err_set(Pft_func_time_log.Invalid_year, Bry_fmtr_arg_.int_(val)); return;}
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_1 != null) { // if 1st itm to right is number, parse it as month
|
||||
if (!Pxd_eval_seg.Eval_as_m(tctx, itm_1)) return;
|
||||
}
|
||||
if (tctx.Data_ary_len() > 2) {
|
||||
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
|
||||
if (itm_2 != null) { // if 2nd itm to right is number, assume it as year
|
||||
if (!Pxd_eval_seg.Eval_as_y(tctx, itm_2)) return;
|
||||
}
|
||||
}
|
||||
Pxd_eval_seg.Eval_as_d(tctx, this); // parse current as day (dmy format)
|
||||
}
|
||||
}
|
||||
class Pxd_itm_int_ {
|
||||
public static void Convert_to_rel(Pxd_parser tctx, Pxd_itm_int itm, byte[] unit_name, int seg_idx, int rel_val) {
|
||||
int tkn_idx = itm.Ary_idx();
|
||||
tctx.Tkns()[tkn_idx] = new Pxd_itm_unit(tkn_idx, unit_name, seg_idx, rel_val);
|
||||
}
|
||||
public static Pxd_itm_int CastOrNull(Pxd_itm itm) {return itm.Tkn_tid() == Pxd_itm_.Tid_int ? (Pxd_itm_int)itm : null; }
|
||||
public static Pxd_itm_int GetNearest(Pxd_itm[] tkns, int tkn_idx, boolean fwd) {
|
||||
int adj = 1, end = tkns.length;
|
||||
if (!fwd) {
|
||||
adj = -1;
|
||||
end = -1;
|
||||
}
|
||||
for (int i = tkn_idx + adj; i != end; i += adj) {
|
||||
Pxd_itm itm = tkns[i];
|
||||
if (itm.Tkn_tid() == Pxd_itm_.Tid_int) {
|
||||
Pxd_itm_int itm_int = (Pxd_itm_int)itm;
|
||||
return itm_int.Seg_idx() == -1 ? itm_int : null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static int Read_nearest_as_int_and_skip(Pxd_parser tctx, Pxd_itm[] tkns, int bgn, boolean fwd, int or) {
|
||||
int adj = 1, end = tkns.length;
|
||||
if (!fwd) {
|
||||
adj = -1;
|
||||
end = -1;
|
||||
}
|
||||
Pxd_itm dash_itm = null;
|
||||
for (int i = bgn + adj; i != end; i += adj) {
|
||||
Pxd_itm itm = tkns[i];
|
||||
switch (itm.Tkn_tid()) {
|
||||
case Pxd_itm_.Tid_dash:
|
||||
dash_itm = itm; // TODO: throw error if "--"; {{#time:U|@--1}}
|
||||
break;
|
||||
case Pxd_itm_.Tid_int:
|
||||
case Pxd_itm_.Tid_int_dmy_14:
|
||||
case Pxd_itm_.Tid_int_hms_6:
|
||||
Pxd_itm_int_interface itm_int = (Pxd_itm_int_interface)itm;
|
||||
int itm_int_seg_idx = itm_int.Seg_idx();
|
||||
if (itm_int_seg_idx == -1) { // not evaluated
|
||||
int factor = 1;
|
||||
if (dash_itm != null) {
|
||||
tctx.Seg_idxs_((Pxd_itm_base)dash_itm, Pxd_itm_base.Seg_idx_skip, -1);
|
||||
factor = -1;
|
||||
}
|
||||
tctx.Seg_idxs_((Pxd_itm_base)itm, Pxd_itm_base.Seg_idx_skip, -1);
|
||||
return itm_int.Xto_int_or(or) * factor;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return or;
|
||||
}
|
||||
public static Pxd_itm_int Get_int_bwd(Pxd_itm[] data_ary, int data_ary_len, int idx) {
|
||||
if (idx > -1) { // make sure idx is > 0
|
||||
Pxd_itm rv = data_ary[idx]; // assume caller not passing in anything > ary.len
|
||||
if ( rv.Tkn_tid() == Pxd_itm_.Tid_int // rv is int
|
||||
&& Pxd_itm_.Eval_needed(rv) // rv needs evaluation
|
||||
)
|
||||
return (Pxd_itm_int)rv; // return it
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static Pxd_itm Get_int_fwd(Pxd_itm[] data_ary, int data_ary_len, int idx) {
|
||||
if (idx < data_ary_len) {
|
||||
Pxd_itm rv = data_ary[idx];
|
||||
if ( rv.Tkn_tid() == Pxd_itm_.Tid_int
|
||||
&& rv.Seg_idx() == -1)
|
||||
return rv;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
134
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_misc.java
Normal file
134
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_misc.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.xtns.pfuncs.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
class Pxd_itm_colon extends Pxd_itm_base {
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_colon;}
|
||||
@Override public int Eval_idx() {return 20;}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
int colon_count = ++state.Colon_count;
|
||||
Pxd_itm[] tkns = state.Tkns();
|
||||
Pxd_itm_int itm_int = null;
|
||||
switch (colon_count) {
|
||||
case 1: // hh:mm
|
||||
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), Bool_.N);
|
||||
if (itm_int == null) {state.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.bry_("null")); return;}
|
||||
if (!Pxd_eval_seg.Eval_as_h(state, itm_int)) return;
|
||||
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), true);
|
||||
if (!Pxd_eval_seg.Eval_as_n(state, itm_int)) return;
|
||||
break;
|
||||
case 2: // :ss
|
||||
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), true);
|
||||
if (!Pxd_eval_seg.Eval_as_s(state, itm_int)) return;
|
||||
break;
|
||||
case 3: // +hh:mm; DATE:2014-08-26
|
||||
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), Bool_.N);
|
||||
if (itm_int == null) {state.Err_set(Pft_func_time_log.Invalid_timezone, Bry_fmtr_arg_.bry_("null")); return;}
|
||||
byte tz_positive_val = Pxd_eval_seg.Eval_as_tz_sym(state, tkns, itm_int);
|
||||
if (tz_positive_val == Bool_.__byte) return;
|
||||
boolean tz_negative = tz_positive_val == Bool_.N_byte;
|
||||
if (!Pxd_eval_seg.Eval_as_tz_h(state, itm_int, tz_negative)) return;
|
||||
itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), Bool_.Y);
|
||||
if (itm_int == null) {state.Err_set(Pft_func_time_log.Invalid_timezone, Bry_fmtr_arg_.bry_("null")); return;}
|
||||
if (tz_negative) itm_int.Val_(itm_int.Val() * -1);
|
||||
if (!Pxd_eval_seg.Eval_as_tz_m(state, itm_int, tz_negative)) return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
public Pxd_itm_colon(int ary_idx) {this.Ctor(ary_idx);}
|
||||
}
|
||||
class Pxd_itm_null extends Pxd_itm_base {
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_null;}
|
||||
@Override public int Eval_idx() {return 99;}
|
||||
public static final Pxd_itm_null _ = new Pxd_itm_null();
|
||||
}
|
||||
class Pxd_itm_dash extends Pxd_itm_base {
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_dash;}
|
||||
@Override public int Eval_idx() {return 99;}
|
||||
public Pxd_itm_dash(int ary_idx) {this.Ctor(ary_idx);}
|
||||
}
|
||||
class Pxd_itm_dot extends Pxd_itm_base {
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_dot;}
|
||||
@Override public int Eval_idx() {return 99;}
|
||||
public Pxd_itm_dot(int ary_idx) {this.Ctor(ary_idx);}
|
||||
}
|
||||
class Pxd_itm_ws extends Pxd_itm_base {
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_ws;}
|
||||
@Override public int Eval_idx() {return 99;}
|
||||
public Pxd_itm_ws(int ary_idx) {this.Ctor(ary_idx);}
|
||||
}
|
||||
class Pxd_itm_slash extends Pxd_itm_base {
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_slash;}
|
||||
@Override public int Eval_idx() {return 99;}
|
||||
public Pxd_itm_slash(int ary_idx) {this.Ctor(ary_idx);}
|
||||
}
|
||||
class Pxd_itm_sym extends Pxd_itm_base {
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_sym;}
|
||||
@Override public int Eval_idx() {return 99;}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {}
|
||||
public byte Sym_byte() {return sym_byte;} private byte sym_byte;
|
||||
public Pxd_itm_sym(int ary_idx, byte val) {this.Ctor(ary_idx); this.sym_byte = val;}
|
||||
}
|
||||
class Pxd_itm_int_dmy_14 extends Pxd_itm_base implements Pxd_itm_int_interface {
|
||||
public Pxd_itm_int_dmy_14(int ary_idx, byte[] src, int digits) {this.Ctor(ary_idx); this.src = src; this.digits = digits;} private byte[] src; int digits;
|
||||
public int Xto_int_or(int or) {return Bry_.Xto_int_or(src, or);}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_int_dmy_14;}
|
||||
@Override public int Eval_idx() {return eval_idx;} private int eval_idx = 20;
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
if (this.Seg_idx() != Pxd_itm_base.Seg_idx_null) return; // has seg_idx; already eval'd by something else
|
||||
bldr.Seg_set(DateAdp_.SegIdx_year , Bry_.Xto_int_or(src, 0, 4, 0));
|
||||
bldr.Seg_set(DateAdp_.SegIdx_month , Bry_.Xto_int_or(src, 4, 6, 0));
|
||||
if (digits > 6) {
|
||||
bldr.Seg_set(DateAdp_.SegIdx_day , Bry_.Xto_int_or(src, 6, 8, 0));
|
||||
if (digits > 8) {
|
||||
bldr.Seg_set(DateAdp_.SegIdx_hour , Bry_.Xto_int_or(src, 8, 10, 0));
|
||||
if (digits > 10) {
|
||||
bldr.Seg_set(DateAdp_.SegIdx_minute , Bry_.Xto_int_or(src, 10, 12, 0));
|
||||
if (digits > 12)
|
||||
bldr.Seg_set(DateAdp_.SegIdx_second , Bry_.Xto_int_or(src, 12, 14, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class Pxd_itm_int_mhs_6 extends Pxd_itm_base implements Pxd_itm_int_interface {
|
||||
public Pxd_itm_int_mhs_6(int ary_idx, byte[] src) {this.Ctor(ary_idx); this.src = src;} private byte[] src;
|
||||
public int Xto_int_or(int or) {return Bry_.Xto_int_or(src, or);}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_int_hms_6;}
|
||||
@Override public int Eval_idx() {return eval_idx;} private int eval_idx = 20;
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
if (this.Seg_idx() != Pxd_itm_base.Seg_idx_null) return; // has seg_idx; already eval'd by something else
|
||||
bldr.Seg_set(DateAdp_.SegIdx_hour , Bry_.Xto_int_or(src, 0, 2, 0));
|
||||
bldr.Seg_set(DateAdp_.SegIdx_minute , Bry_.Xto_int_or(src, 2, 4, 0));
|
||||
bldr.Seg_set(DateAdp_.SegIdx_second , Bry_.Xto_int_or(src, 4, 6, 0));
|
||||
}
|
||||
}
|
||||
class Pxd_itm_sorter implements gplx.lists.ComparerAble {
|
||||
public int compare(Object lhsObj, Object rhsObj) {
|
||||
Pxd_itm lhs = (Pxd_itm)lhsObj;
|
||||
Pxd_itm rhs = (Pxd_itm)rhsObj;
|
||||
return Int_.Compare(lhs.Eval_idx(), rhs.Eval_idx());
|
||||
}
|
||||
public static final Pxd_itm_sorter _ = new Pxd_itm_sorter();
|
||||
public static Pxd_itm[] XtoAryAndSort(Pxd_itm[] src, int src_len) {
|
||||
Pxd_itm[] rv = new Pxd_itm[src_len];
|
||||
for (int i = 0; i < src_len; i++)
|
||||
rv[i] = src[i];
|
||||
Array_.Sort(rv, Pxd_itm_sorter._);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
364
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_month_name.java
Normal file
364
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_itm_month_name.java
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
class Pxd_itm_month_name extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_month_name(int ary_idx, byte[] name, int seg_idx, int seg_val) {Ctor(ary_idx); this.name = name; Seg_idx_(seg_idx); this.seg_val = seg_val;} private byte[] name;
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_month_name;}
|
||||
@Override public int Eval_idx() {return 20;}
|
||||
int seg_val;
|
||||
public Pxd_itm MakeNew(int ary_idx) {
|
||||
Pxd_itm_month_name rv = new Pxd_itm_month_name(ary_idx, name, this.Seg_idx(), seg_val);
|
||||
return rv;
|
||||
}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
state.Seg_idxs_(this, this.Seg_idx(), seg_val);
|
||||
switch (this.Data_idx()) {
|
||||
case 0: Eval_month_0(state); break;
|
||||
case 1: Eval_month_1(state); break;
|
||||
case 2: Eval_month_2(state); break;
|
||||
default:
|
||||
Pxd_itm[] data_ary = state.Data_ary();
|
||||
int data_idx = this.Data_idx();
|
||||
if (data_idx + 1 < data_ary.length) {
|
||||
Pxd_itm_int itm_rhs = Pxd_itm_int_.CastOrNull(data_ary[data_idx + 1]);
|
||||
if (itm_rhs.Digits() == 4) { // handle fmts of 1 January 2010
|
||||
Eval_month_1(state);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Eval_month_2(state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
public void Eval_month_0(Pxd_parser state) {
|
||||
Pxd_itm[] data_ary = state.Data_ary();
|
||||
int data_ary_len = state.Data_ary_len();
|
||||
switch (data_ary_len) {
|
||||
case 1: break; // noop; nothing needs to be done
|
||||
case 2: {
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_1 == null) {return;} // trie: fail
|
||||
switch (itm_1.Digits()) {
|
||||
case 4: Pxd_eval_seg.Eval_as_y(state, itm_1); break;
|
||||
default: Pxd_eval_seg.Eval_as_d(state, itm_1); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: // NOTE: handle invalid dates like January 2, 1999, 2000; DATE:2013-05-06
|
||||
case 3: {
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
Pxd_itm_int itm_2 = Pxd_itm_int_.CastOrNull(data_ary[2]);
|
||||
if (itm_1 == null || itm_2 == null) {return;} // trie: fail
|
||||
if (itm_1.Digits() == 4) { // ASSUME: year since there are 4 digits; EX: May 2012
|
||||
if (Pxd_eval_seg.Eval_as_y(state, itm_1)) return; // no error; return; otherwise continue below;
|
||||
}
|
||||
if (!Pxd_eval_seg.Eval_as_d(state, itm_1)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_y(state, itm_2)) return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Eval_month_1(Pxd_parser state) {
|
||||
Pxd_itm[] data_ary = state.Data_ary();
|
||||
int data_ary_len = state.Data_ary_len();
|
||||
switch (data_ary_len) {
|
||||
case 2: {
|
||||
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
|
||||
if (itm_0 == null) {return;} // trie: fail
|
||||
switch (itm_0.Digits()) {
|
||||
case 4: Pxd_eval_seg.Eval_as_y(state, itm_0); break;
|
||||
default: Pxd_eval_seg.Eval_as_d(state, itm_0); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
case 3: {
|
||||
Pxd_itm_int itm_0 = Pxd_itm_int_.GetNearest(data_ary, this.Data_idx(), false);
|
||||
Pxd_itm_int itm_2 = Pxd_itm_int_.GetNearest(data_ary, this.Data_idx(), true);
|
||||
if (itm_0 == null || itm_2 == null) {return;} // trie: fail
|
||||
switch (itm_0.Digits()) {
|
||||
case 4:
|
||||
if (!Pxd_eval_seg.Eval_as_y(state, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_d(state, itm_2)) return;
|
||||
break;
|
||||
default:
|
||||
if (itm_2.Digits() == 4) {
|
||||
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_y(state, itm_2)) return;
|
||||
}
|
||||
else { // 2 digits on either side of month; assume dd mm yy; EX: 03 Feb 01 -> 2001-02-03
|
||||
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_y(state, itm_2)) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Eval_month_2(Pxd_parser state) {
|
||||
Pxd_itm[] data_ary = state.Data_ary();
|
||||
int data_ary_len = state.Data_ary_len();
|
||||
switch (data_ary_len) {
|
||||
case 3: {
|
||||
Pxd_itm_int itm_0 = Pxd_itm_int_.CastOrNull(data_ary[0]);
|
||||
Pxd_itm_int itm_1 = Pxd_itm_int_.CastOrNull(data_ary[1]);
|
||||
if (itm_0 == null || itm_1 == null) {return;} // trie: fail
|
||||
switch (itm_0.Digits()) {
|
||||
case 4:
|
||||
if (!Pxd_eval_seg.Eval_as_y(state, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_d(state, itm_1)) return;
|
||||
break;
|
||||
default:
|
||||
if (itm_1.Digits() == 4) {
|
||||
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_y(state, itm_1)) return;
|
||||
}
|
||||
else { // 2 digits on either side of month; assume dd mm yy; EX: 03 Feb 01 -> 2001-02-03
|
||||
if (!Pxd_eval_seg.Eval_as_d(state, itm_0)) return;
|
||||
if (!Pxd_eval_seg.Eval_as_y(state, itm_1)) return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
bldr.Seg_set(this.Seg_idx(), seg_val);
|
||||
}
|
||||
}
|
||||
class Pxd_itm_unit extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_unit(int ary_idx, byte[] name, int seg_idx, int seg_multiple) {Ctor(ary_idx); this.name = name; Seg_idx_(seg_idx); this.seg_multiple = seg_multiple;}
|
||||
public byte[] Name() {return name;} private byte[] name;
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_unit;}
|
||||
@Override public int Eval_idx() {return 10;}
|
||||
int seg_val = 1; int seg_multiple;
|
||||
public Pxd_itm MakeNew(int ary_idx) {
|
||||
return new Pxd_itm_unit(ary_idx, name, this.Seg_idx(), seg_val);
|
||||
}
|
||||
public void Unit_seg_val_(int v) { // handled by relative; EX: next year
|
||||
seg_val = v; seg_multiple = 1;
|
||||
eval_done_by_relative = true;
|
||||
} private boolean eval_done_by_relative;
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
if (eval_done_by_relative) return;
|
||||
state.Seg_idxs_(this, this.Seg_idx(), seg_val);
|
||||
Pxd_itm[] tkns = state.Tkns();
|
||||
Pxd_itm_int itm_int = Pxd_itm_int_.GetNearest(tkns, this.Ary_idx(), false);
|
||||
state.Seg_idxs_(itm_int, Pxd_itm_base.Seg_idx_skip);
|
||||
seg_val = itm_int.Val();
|
||||
for (int i = itm_int.Ary_idx(); i > -1; i--) {
|
||||
Pxd_itm itm = tkns[i];
|
||||
switch (itm.Tkn_tid()) {
|
||||
case Pxd_itm_.Tid_dash: // negative sign; stop;
|
||||
seg_val *= -1;
|
||||
i = -1;
|
||||
break;
|
||||
case Pxd_itm_.Tid_dot: case Pxd_itm_.Tid_int: case Pxd_itm_.Tid_ws: // ignore
|
||||
break;
|
||||
default: // word; stop;
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
DateAdp cur = bldr.Date();
|
||||
if (cur == null) cur = DateAdp_.Now();
|
||||
int val = seg_val * seg_multiple;
|
||||
switch (this.Seg_idx()) {
|
||||
case DateAdp_.SegIdx_second: cur = cur.Add_second(val); break;
|
||||
case DateAdp_.SegIdx_minute: cur = cur.Add_minute(val); break;
|
||||
case DateAdp_.SegIdx_hour : cur = cur.Add_hour (val); break;
|
||||
case DateAdp_.SegIdx_day : cur = cur.Add_day (val); break;
|
||||
case DateAdp_.SegIdx_month : cur = cur.Add_month (val); break;
|
||||
case DateAdp_.SegIdx_year : cur = cur.Add_year (val); break;
|
||||
default: throw Exc_.new_unhandled(this.Seg_idx());
|
||||
}
|
||||
bldr.Date_(cur);
|
||||
}
|
||||
}
|
||||
class Pxd_itm_ago extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_ago(int ary_idx, int seg_idx) {Ctor(ary_idx); Seg_idx_(seg_idx);}
|
||||
public byte[] Name() {return Name_ago;} public static final byte[] Name_ago = Bry_.new_a7("ago");
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_ago;}
|
||||
@Override public int Eval_idx() {return 5;} // set to high priority so it can evaluate before unit_name
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_ago(ary_idx, this.Seg_idx());}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
Pxd_itm[] tkns = state.Tkns();
|
||||
int end = this.Ary_idx();
|
||||
boolean unit_seen = false;
|
||||
for (int i = end - 1; i > -1; i--) { // loop over tokens, moving backward
|
||||
Pxd_itm itm = tkns[i];
|
||||
switch (itm.Tkn_tid()) {
|
||||
case Pxd_itm_.Tid_ws: break; // ignore ws
|
||||
case Pxd_itm_.Tid_unit: unit_seen = true; break; // unit seen; flag
|
||||
case Pxd_itm_.Tid_int:
|
||||
if (unit_seen) { // only if unit seen, reverse int; EX: "1 month ago" effectively becomes "-1 month"
|
||||
Pxd_itm_int itm_int = (Pxd_itm_int)itm;
|
||||
itm_int.Val_(-itm_int.Val());
|
||||
i = -1; // end loop
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
}
|
||||
}
|
||||
class Pxd_itm_day_suffix extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_day_suffix(int ary_idx) {Ctor(ary_idx);}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_day_suffix;}
|
||||
@Override public int Eval_idx() {return 99;} // set to low priority so it can evaluate after day
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_day_suffix(ary_idx);}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
Pxd_itm[] tkn_ary = state.Tkns();
|
||||
int tkn_idx = this.Ary_idx();
|
||||
if (tkn_idx == 0) state.Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.int_(Int_.MinValue));
|
||||
Pxd_itm day_itm = tkn_ary[tkn_idx - 1];
|
||||
if (day_itm.Seg_idx() != DateAdp_.SegIdx_day) {
|
||||
state.Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.int_(Int_.MinValue));
|
||||
}
|
||||
}
|
||||
public static final Pxd_itm_day_suffix _ = new Pxd_itm_day_suffix(); Pxd_itm_day_suffix() {}
|
||||
}
|
||||
class Pxd_itm_day_relative extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_day_relative(int adj, int ary_idx) {Ctor(ary_idx); this.adj = adj;}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_day_relative;}
|
||||
@Override public int Eval_idx() {return 5;}
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_day_relative(adj, ary_idx);}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
DateAdp date = DateAdp_.Now();
|
||||
if (adj != 0) date = date.Add_day(adj);
|
||||
bldr.Seg_set(DateAdp_.SegIdx_year , date.Year());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_month , date.Month());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_day , date.Day());
|
||||
}
|
||||
|
||||
public static final Pxd_itm_day_relative
|
||||
Today = new Pxd_itm_day_relative(0)
|
||||
, Tomorrow = new Pxd_itm_day_relative(1)
|
||||
, Yesterday = new Pxd_itm_day_relative(-1)
|
||||
;
|
||||
Pxd_itm_day_relative(int adj) {this.adj = adj;} private int adj;
|
||||
}
|
||||
class Pxd_itm_time_relative extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_time_relative(int ary_idx) {Ctor(ary_idx);}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_time_relative;}
|
||||
@Override public int Eval_idx() {return 5;}
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_time_relative(ary_idx);}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
DateAdp date = DateAdp_.Now();
|
||||
bldr.Seg_set(DateAdp_.SegIdx_year , date.Year());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_month , date.Month());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_day , date.Day());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_hour , date.Hour());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_minute , date.Minute());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_second , date.Second());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_frac , date.Frac());
|
||||
}
|
||||
public static final Pxd_itm_time_relative
|
||||
Now = new Pxd_itm_time_relative()
|
||||
;
|
||||
Pxd_itm_time_relative() {}
|
||||
}
|
||||
class Pxd_itm_unit_relative extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_unit_relative(int adj, int ary_idx) {Ctor(ary_idx); this.adj = adj;}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_unit_relative;}
|
||||
@Override public int Eval_idx() {return 5;}
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_unit_relative(adj, ary_idx);}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
Pxd_itm itm = Pxd_itm_.Find_fwd_by_tid(state.Tkns(), this.Ary_idx() + 1, Pxd_itm_.Tid_unit);
|
||||
if (itm == null) state.Err_set(Pft_func_time_log.Invalid_date, Bry_fmtr_arg_.int_(adj));
|
||||
Pxd_itm_unit unit_tkn = (Pxd_itm_unit)itm;
|
||||
unit_tkn.Unit_seg_val_(adj);
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
}
|
||||
public static final Pxd_itm_unit_relative
|
||||
Next = new Pxd_itm_unit_relative(1)
|
||||
, Prev = new Pxd_itm_unit_relative(-1)
|
||||
, This = new Pxd_itm_unit_relative(0)
|
||||
;
|
||||
Pxd_itm_unit_relative(int adj) {this.adj = adj;} private int adj;
|
||||
}
|
||||
class Pxd_itm_unixtime extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
private long unixtime;
|
||||
public Pxd_itm_unixtime(int ary_idx, int seg_idx) {Ctor(ary_idx); Seg_idx_(seg_idx);}
|
||||
public byte[] Name() {return Name_const;} public static final byte[] Name_const = Bry_.new_a7("@");
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_unixtime;}
|
||||
@Override public int Eval_idx() {return 5;} // set to high priority so it can evaluate number early
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_unixtime(ary_idx, this.Seg_idx());}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
Pxd_itm[] tkns = state.Tkns();
|
||||
unixtime = Pxd_itm_int_.Read_nearest_as_int_and_skip(state, tkns, this.Ary_idx(), true, Int_.MinValue);
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
DateAdp date = DateAdp_.unixtime_utc_seconds_(unixtime);
|
||||
bldr.Seg_set(DateAdp_.SegIdx_year , date.Year());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_month , date.Month());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_day , date.Day());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_hour , date.Hour());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_minute , date.Minute());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_second , date.Second());
|
||||
bldr.Seg_set(DateAdp_.SegIdx_frac , date.Frac());
|
||||
}
|
||||
}
|
||||
class Pxd_itm_dow_name extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
private int dow_idx;
|
||||
private byte[] dow_name;
|
||||
public Pxd_itm_dow_name(int ary_idx, byte[] dow_name, int dow_idx) {Ctor(ary_idx); this.dow_name = dow_name; this.Seg_idx_(DateAdp_.SegIdx_dayOfWeek); this.dow_idx = dow_idx;}
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_dow_name;}
|
||||
@Override public int Eval_idx() {return 20;}
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_dow_name(ary_idx, dow_name, dow_idx);}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {
|
||||
DateAdp now = DateAdp_.Now();
|
||||
int adj = dow_idx - now.DayOfWeek(); // adj = requested_dow - current_dow; EX: requesting Friday, and today is Wednesday; adj = 2 (4 - 2); DATE:2014-05-02
|
||||
if (adj < 0) adj += 7; // requested_down is before current_dow; add 7 to get the next day
|
||||
bldr.Date_(bldr.Date().Add_day(adj));
|
||||
}
|
||||
}
|
||||
class Pxd_itm_iso8601_t extends Pxd_itm_base implements Pxd_itm_prototype {
|
||||
public Pxd_itm_iso8601_t(int ary_idx, int seg_idx) {Ctor(ary_idx); Seg_idx_(seg_idx);}
|
||||
public byte[] Name() {return Name_const;} public static final byte[] Name_const = Bry_.new_a7("T");
|
||||
@Override public byte Tkn_tid() {return Pxd_itm_.Tid_iso8601_t;}
|
||||
@Override public int Eval_idx() {return 99;} // evaluate last
|
||||
public Pxd_itm MakeNew(int ary_idx) {return new Pxd_itm_iso8601_t(ary_idx, this.Seg_idx());}
|
||||
@Override public void Eval(Pxd_parser state) {
|
||||
Pxd_itm hour = Next_non_ws_tkn(state.Tkns(), this.Ary_idx() + 1);
|
||||
if (hour != null && hour.Seg_idx() == DateAdp_.SegIdx_hour) return; // next item is hour
|
||||
state.Err_set(Pft_func_time_log.Invalid_hour, Bry_fmtr_arg_.bry_("T"));
|
||||
}
|
||||
@Override public void Time_ini(DateAdpBldr bldr) {}
|
||||
private static Pxd_itm Next_non_ws_tkn(Pxd_itm[] tkns, int bgn) {
|
||||
int len = tkns.length;
|
||||
for (int i = bgn; i < len; i++) {
|
||||
Pxd_itm itm = tkns[i];
|
||||
if (itm.Tkn_tid() != Pxd_itm_.Tid_ws) return itm;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
262
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_parser.java
Normal file
262
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_parser.java
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.btries.*;
|
||||
class Pxd_parser {
|
||||
byte[] src; int cur_pos, tkn_bgn_pos, src_len, tkn_type;
|
||||
public Pxd_itm[] Tkns() {return tkns;} Pxd_itm[] tkns;
|
||||
public int Tkns_len() {return tkns_len;} private int tkns_len;
|
||||
public Pxd_itm[] Data_ary() {return data_ary;} Pxd_itm[] data_ary;
|
||||
public int Data_ary_len() {return data_ary_len;} private int data_ary_len;
|
||||
public int Colon_count;
|
||||
public int[] Seg_idxs() {return seg_idxs;} private int[] seg_idxs = new int[DateAdp_.SegIdx__max]; // temp ary for storing current state
|
||||
public boolean Seg_idxs_chk(int... ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
if (ary[i] == Pxd_itm_base.Seg_idx_null) return false;
|
||||
return true;
|
||||
}
|
||||
public void Seg_idxs_(Pxd_itm_int itm, int seg_idx) {Seg_idxs_(itm, seg_idx, itm.Val());}
|
||||
public void Seg_idxs_(Pxd_itm_base itm, int seg_idx, int val) {
|
||||
itm.Seg_idx_(seg_idx);
|
||||
if (seg_idx >= 0) // ignore Seg_idx_null and Seg_idx_skip
|
||||
seg_idxs[seg_idx] = val;
|
||||
}
|
||||
public void Err_set(Gfo_msg_itm itm, Bry_fmtr_arg... args) {
|
||||
if (itm == null) return;
|
||||
Bry_fmtr fmtr = itm.Fmtr();
|
||||
fmtr.Bld_bfr(error_bfr, args);
|
||||
} private Bry_bfr error_bfr = Bry_bfr.new_(32);
|
||||
public DateAdp Parse(byte[] src, Bry_bfr error_bfr) {
|
||||
Tokenize(src); // NOTE: should check if Tokenize failed, but want to be liberal as date parser is not fully implemented; this will always default to 1st day of year; DATE:2014-03-27
|
||||
return Evaluate(src, error_bfr);
|
||||
}
|
||||
private boolean Tokenize(byte[] src) {
|
||||
this.src = src; src_len = src.length;
|
||||
tkns = new Pxd_itm[src_len]; tkns_len = 0;
|
||||
tkn_type = Pxd_itm_.Tid_null; tkn_bgn_pos = -1;
|
||||
cur_pos = 0;
|
||||
Colon_count = 0;
|
||||
error_bfr.Clear();
|
||||
for (int i = 0; i < DateAdp_.SegIdx__max; i++)
|
||||
seg_idxs[i] = Pxd_itm_base.Seg_idx_null;
|
||||
while (cur_pos < src_len) {
|
||||
byte b = src[cur_pos];
|
||||
switch (b) {
|
||||
case Byte_ascii.Space: case Byte_ascii.Tab: case Byte_ascii.Nl:
|
||||
if (tkn_type != Pxd_itm_.Tid_ws) MakePrvTkn(cur_pos, Pxd_itm_.Tid_ws); break; // SEE:NOTE_1 for logic
|
||||
case Byte_ascii.Dash: case Byte_ascii.Dot: case Byte_ascii.Colon: case Byte_ascii.Slash:
|
||||
if (tkn_type != b) MakePrvTkn(cur_pos, b); break;
|
||||
case Byte_ascii.Num_0: case Byte_ascii.Num_1: case Byte_ascii.Num_2: case Byte_ascii.Num_3: case Byte_ascii.Num_4:
|
||||
case Byte_ascii.Num_5: case Byte_ascii.Num_6: case Byte_ascii.Num_7: case Byte_ascii.Num_8: case Byte_ascii.Num_9:
|
||||
if (tkn_type != Pxd_itm_.Tid_int) MakePrvTkn(cur_pos, Pxd_itm_.Tid_int); break;
|
||||
case Byte_ascii.Ltr_A: case Byte_ascii.Ltr_B: case Byte_ascii.Ltr_C: case Byte_ascii.Ltr_D: case Byte_ascii.Ltr_E:
|
||||
case Byte_ascii.Ltr_F: case Byte_ascii.Ltr_G: case Byte_ascii.Ltr_H: case Byte_ascii.Ltr_I: case Byte_ascii.Ltr_J:
|
||||
case Byte_ascii.Ltr_K: case Byte_ascii.Ltr_L: case Byte_ascii.Ltr_M: case Byte_ascii.Ltr_N: case Byte_ascii.Ltr_O:
|
||||
case Byte_ascii.Ltr_P: case Byte_ascii.Ltr_Q: case Byte_ascii.Ltr_R: case Byte_ascii.Ltr_S: case Byte_ascii.Ltr_T:
|
||||
case Byte_ascii.Ltr_U: case Byte_ascii.Ltr_V: case Byte_ascii.Ltr_W: case Byte_ascii.Ltr_X: case Byte_ascii.Ltr_Y: case Byte_ascii.Ltr_Z:
|
||||
case Byte_ascii.Ltr_a: case Byte_ascii.Ltr_b: case Byte_ascii.Ltr_c: case Byte_ascii.Ltr_d: case Byte_ascii.Ltr_e:
|
||||
case Byte_ascii.Ltr_f: case Byte_ascii.Ltr_g: case Byte_ascii.Ltr_h: case Byte_ascii.Ltr_i: case Byte_ascii.Ltr_j:
|
||||
case Byte_ascii.Ltr_k: case Byte_ascii.Ltr_l: case Byte_ascii.Ltr_m: case Byte_ascii.Ltr_n: case Byte_ascii.Ltr_o:
|
||||
case Byte_ascii.Ltr_p: case Byte_ascii.Ltr_q: case Byte_ascii.Ltr_r: case Byte_ascii.Ltr_s: case Byte_ascii.Ltr_t:
|
||||
case Byte_ascii.Ltr_u: case Byte_ascii.Ltr_v: case Byte_ascii.Ltr_w: case Byte_ascii.Ltr_x: case Byte_ascii.Ltr_y: case Byte_ascii.Ltr_z:
|
||||
case Byte_ascii.At:
|
||||
MakePrvTkn(cur_pos, Pxd_itm_.Tid_null); // first, make prv tkn
|
||||
Object o = trie.Match_bgn_w_byte(b, src, cur_pos, src_len); // now match String against tkn
|
||||
if (o == null) return false; // unknown letter / word; exit now;
|
||||
tkns[tkns_len] = ((Pxd_itm_prototype)o).MakeNew(tkns_len);
|
||||
++tkns_len;
|
||||
cur_pos = trie.Match_pos() - 1; // -1 b/c trie matches to next char, and ++ below
|
||||
break;
|
||||
case Byte_ascii.Comma: case Byte_ascii.Plus:
|
||||
MakePrvTkn(cur_pos, Pxd_itm_.Tid_null);
|
||||
tkns[tkns_len] = new Pxd_itm_sym(tkns_len, b);
|
||||
++tkns_len;
|
||||
break;
|
||||
}
|
||||
++cur_pos;
|
||||
}
|
||||
MakePrvTkn(cur_pos, Pxd_itm_.Tid_null);
|
||||
return true;
|
||||
}
|
||||
private void MakePrvTkn(int cur_pos, int nxt_type) {
|
||||
Pxd_itm itm = null;
|
||||
switch (tkn_type) {
|
||||
case Pxd_itm_.Tid_int:
|
||||
int int_val = Bry_.Xto_int_or(src, tkn_bgn_pos, cur_pos, Int_.MinValue);
|
||||
if (int_val == Int_.MinValue) {} // FUTURE: warn
|
||||
int digits = cur_pos - tkn_bgn_pos;
|
||||
switch (digits) {
|
||||
case 14:
|
||||
case 8:
|
||||
itm = new Pxd_itm_int_dmy_14(tkns_len, Bry_.Mid(src, tkn_bgn_pos, cur_pos), digits); break;
|
||||
case 6:
|
||||
itm = new Pxd_itm_int_mhs_6(tkns_len, Bry_.Mid(src, tkn_bgn_pos, cur_pos)); break;
|
||||
default:
|
||||
itm = new Pxd_itm_int(tkns_len, digits, int_val); break;
|
||||
}
|
||||
break;
|
||||
case Pxd_itm_.Tid_ws: itm = new Pxd_itm_ws(tkns_len); break;
|
||||
case Pxd_itm_.Tid_dash: itm = new Pxd_itm_dash(tkns_len); break;
|
||||
case Pxd_itm_.Tid_dot: itm = new Pxd_itm_dot(tkns_len); break;
|
||||
case Pxd_itm_.Tid_colon: itm = new Pxd_itm_colon(tkns_len); break;
|
||||
case Pxd_itm_.Tid_slash: itm = new Pxd_itm_slash(tkns_len); break;
|
||||
case Pxd_itm_.Tid_null: break; // NOOP
|
||||
}
|
||||
if (itm != null) {
|
||||
tkns[tkns_len] = itm;
|
||||
++tkns_len;
|
||||
}
|
||||
tkn_type = nxt_type;
|
||||
tkn_bgn_pos = cur_pos;
|
||||
}
|
||||
DateAdp Evaluate(byte[] src, Bry_bfr error) {
|
||||
if (tkns_len == 0) {
|
||||
Err_set(Pft_func_time_log.Invalid_day, Bry_fmtr_arg_.bry_(src));
|
||||
return null;
|
||||
}
|
||||
Pxd_itm[] eval_ary = Pxd_itm_sorter.XtoAryAndSort(tkns, tkns_len);
|
||||
MakeDataAry();
|
||||
for (int i = 0; i < tkns_len; i++) {
|
||||
eval_ary[i].Eval(this);
|
||||
if (error_bfr.Len() != 0) {
|
||||
error.Add_bfr_and_clear(error_bfr);
|
||||
return DateAdp_.MinValue;
|
||||
}
|
||||
}
|
||||
DateAdpBldr bldr = new DateAdpBldr(DateAdp_.Now().Year(), 1, 1, 0, 0, 0, 0);
|
||||
for (int i = 0; i < tkns_len; i++) {
|
||||
Pxd_itm itm = (Pxd_itm)tkns[i];
|
||||
itm.Time_ini(bldr);
|
||||
}
|
||||
return bldr.Bld();
|
||||
}
|
||||
private void MakeDataAry() {
|
||||
data_ary = new Pxd_itm[tkns_len]; data_ary_len = 0;
|
||||
for (int i = 0; i < tkns_len; i++) {
|
||||
Pxd_itm itm = tkns[i];
|
||||
switch (itm.Tkn_tid()) {
|
||||
case Pxd_itm_.Tid_month_name:
|
||||
case Pxd_itm_.Tid_int:
|
||||
itm.Data_idx_(data_ary_len);
|
||||
data_ary[data_ary_len++] = itm;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
private static Btrie_slim_mgr trie = Pxd_parser_.Trie();
|
||||
}
|
||||
class Pxd_parser_ {
|
||||
public static Btrie_slim_mgr Trie() {
|
||||
if (trie == null) {
|
||||
trie = Btrie_slim_mgr.ci_ascii_(); // NOTE:ci.ascii:MW_const.en
|
||||
Init();
|
||||
}
|
||||
return trie;
|
||||
} static Btrie_slim_mgr trie;
|
||||
private static final String[] Names_month_full = {"january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"};
|
||||
private static final String[] Names_month_abrv = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
|
||||
private static final String[] Names_month_roman = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"};
|
||||
private static final String[] Names_day_suffix = {"st", "nd", "rd", "th"};
|
||||
private static final String[] Names_day_full = {"sunday", "monday", "tuesday", "wednesday" , "thursday", "friday", "saturday"};
|
||||
private static final String[] Names_day_abrv = {"sun", "mon", "tue", "wed" , "thu", "fri", "sat"};
|
||||
//TODO:
|
||||
//private static final String[] Names_day_text = {"weekday", "weekdays"};
|
||||
//private static final String[] Names_ordinal_num = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth", "tenth", "eleventh", "twelfth"};
|
||||
|
||||
private static void Init_unit(int seg_idx, String... name_ary) {Init_unit(seg_idx, 1, name_ary);}
|
||||
private static void Init_unit(int seg_idx, int seg_val, String... name_ary) {
|
||||
int name_ary_len = name_ary.length;
|
||||
for (int i = 0; i < name_ary_len; i++) {
|
||||
byte[] name_bry = Bry_.new_u8(name_ary[i]);
|
||||
trie.Add_obj(name_bry, new Pxd_itm_unit(-1, name_bry, seg_idx, seg_val));
|
||||
}
|
||||
}
|
||||
public static final byte[]
|
||||
Unit_name_month = Bry_.new_a7("month")
|
||||
, Unit_name_day = Bry_.new_a7("day")
|
||||
, Unit_name_hour = Bry_.new_a7("hour")
|
||||
;
|
||||
private static void Init() {
|
||||
Init_reg_months(Names_month_full);
|
||||
Init_reg_months(Names_month_abrv);
|
||||
Init_reg_months(Names_month_roman);
|
||||
Init_reg_month("sept", 9);
|
||||
Init_reg_days_of_week(Names_day_full);
|
||||
Init_reg_days_of_week(Names_day_abrv);
|
||||
Init_unit(DateAdp_.SegIdx_second , "sec", "secs", "second", "seconds");
|
||||
Init_unit(DateAdp_.SegIdx_minute , "min", "mins", "minute", "minutes");
|
||||
Init_unit(DateAdp_.SegIdx_hour , "hour", "hours");
|
||||
Init_unit(DateAdp_.SegIdx_day , "day", "days");
|
||||
Init_unit(DateAdp_.SegIdx_day, 14 , "fortnight", "forthnight");
|
||||
Init_unit(DateAdp_.SegIdx_month , "month", "months");
|
||||
Init_unit(DateAdp_.SegIdx_year , "year", "years");
|
||||
Init_unit(DateAdp_.SegIdx_day, 7 , "week", "weeks");
|
||||
trie.Add_obj(Pxd_itm_ago.Name_ago, new Pxd_itm_ago(-1, -1));
|
||||
Init_suffix(Names_day_suffix);
|
||||
Init_relative();
|
||||
trie.Add_obj(Pxd_itm_unixtime.Name_const, new Pxd_itm_unixtime(-1, -1));
|
||||
trie.Add_obj(Pxd_itm_iso8601_t.Name_const, new Pxd_itm_iso8601_t(-1, -1));
|
||||
}
|
||||
private static void Init_reg_months(String[] names) {
|
||||
for (int i = 0; i < names.length; i++)
|
||||
Init_reg_month(names[i], i + Int_.Base1); // NOTE: Months are Base1: 1-12
|
||||
}
|
||||
private static void Init_reg_month(String name_str, int seg_val) {
|
||||
byte[] name_ary = Bry_.new_u8(name_str);
|
||||
trie.Add_obj(name_ary, new Pxd_itm_month_name(-1, name_ary, DateAdp_.SegIdx_month, seg_val));
|
||||
}
|
||||
private static void Init_reg_days_of_week(String[] ary) {
|
||||
int len = ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
byte[] itm_bry = Bry_.new_u8(ary[i]);
|
||||
trie.Add_obj(itm_bry, new Pxd_itm_dow_name(-1, itm_bry, i)); // NOTE: days are base0; 0-6
|
||||
}
|
||||
}
|
||||
private static void Init_suffix(String[] suffix_ary) {
|
||||
int len = suffix_ary.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
String suffix = suffix_ary[i];
|
||||
trie.Add_obj(suffix, Pxd_itm_day_suffix._);
|
||||
}
|
||||
}
|
||||
private static void Init_relative() {
|
||||
trie.Add_obj("today", Pxd_itm_day_relative.Today);
|
||||
trie.Add_obj("tomorrow", Pxd_itm_day_relative.Tomorrow);
|
||||
trie.Add_obj("yesterday", Pxd_itm_day_relative.Yesterday);
|
||||
trie.Add_obj("now", Pxd_itm_time_relative.Now);
|
||||
trie.Add_obj("next", Pxd_itm_unit_relative.Next);
|
||||
trie.Add_obj("last", Pxd_itm_unit_relative.Prev);
|
||||
trie.Add_obj("previous", Pxd_itm_unit_relative.Prev);
|
||||
trie.Add_obj("this", Pxd_itm_unit_relative.This);
|
||||
}
|
||||
}
|
||||
/*
|
||||
NOTE_1:parsing works by completing previous items and then setting current;
|
||||
EX: "123 456"
|
||||
1: tkn_type = null; b = number
|
||||
complete tkn (note that tkn is null)
|
||||
set tkn_type to number; set tkn_bgn to 0
|
||||
2: b == number == tkn_type; noop
|
||||
3: b == number == tkn_type; noop
|
||||
4: b == space != tkn_type;
|
||||
complete prv
|
||||
create tkn with bgn = tkn_bgn and end = cur_pos
|
||||
set tkn_type to space; set tkn_bgn to cur_pos
|
||||
etc..
|
||||
*/
|
||||
95
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_parser_tst.java
Normal file
95
400_xowa/src/gplx/xowa/xtns/pfuncs/times/Pxd_parser_tst.java
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
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.times; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pxd_parser_tst {
|
||||
Bry_bfr bfr = Bry_bfr.new_(16); Pxd_parser parser = new Pxd_parser();
|
||||
@Before public void init() {Tfds.Now_enabled_y_(); Tfds.Now_set(test_date);} DateAdp test_date = DateAdp_.parse_fmt("2012-02-27", "yyyy-MM-dd");
|
||||
@After public void teardown() {Tfds.Now_enabled_n_();}
|
||||
@Test public void Month_name_0__day__year() {tst_date_("Mar 2 2001" , "2001-03-02");} // y:Mar-02-2001;Mar.02.2001;Mar 02, 2001 n:Mar/02/2001;Feb,05,2011
|
||||
@Test public void Month_name_0__day__year__bad_day() {tst_date_("Mar 32 2001" , "Invalid day: 32");}
|
||||
@Test public void Month_name_0__day__year__bad_year() {tst_date_("Mar 3 999" , "0999-03-03");}
|
||||
@Test public void Month_name_0__day__year__bad_day_year() {tst_date_("Mar 32 999" , "Invalid day: 32");}
|
||||
@Test public void Month_name_0__year() {tst_date_("Mar 2001" , "2001-03-01");}
|
||||
@Test public void Month_name_0__day() {tst_date_("Mar 02" , "2012-03-02");}
|
||||
@Test public void Month_name_0__day_fail() {tst_date_("Mar 32" , "Invalid day: 32");}
|
||||
@Test public void Month_name_0() {tst_date_("Mar" , "2012-03-01");} // y: ,.,.. Feb; n: / Feb, - Feb
|
||||
@Test public void Month_name_1__day__year() {tst_date_("2 Mar 2001" , "2001-03-02");} // y: 3-Feb-2012; 3 Feb 2012;
|
||||
@Test public void Month_name_1__year__day() {tst_date_("2001 Mar 02" , "2001-03-02");} // y: 2012-Feb-3 n:2012.Feb.3;2012 Feb 3; 2012,Feb,3;2012/Feb/3
|
||||
@Test public void Month_name_1__day__year__guess() {tst_date_("02 Mar 01" , "2001-03-02");}
|
||||
@Test public void Month_name_1__day() {tst_date_("02 Mar" , "2012-03-02");}
|
||||
@Test public void Month_name_1__year() {tst_date_("2003 Mar" , "2003-03-01");}
|
||||
@Test public void Month_name_2__day__year() {tst_date_("2001.02.Mar" , "2001-03-02");} // y: 2012.5.Feb; 2012 5 Feb n: 2012-5-Feb; 2012/5/Feb
|
||||
@Test public void Year_0__month__day() {tst_date_("2001-03-31" , "2001-03-31");}
|
||||
@Test public void Year_0__day__month__fail() {tst_date_("2001-31-03" , "Invalid month: 31");} // n:2012.31.03; 2012/31/03
|
||||
@Test public void Year_0__month() {tst_date_("2001-03" , "2001-03-01");}
|
||||
@Test public void Year_0() {tst_date_("2001" , "2001-01-01");}
|
||||
@Test public void Year_1() {tst_date_("31-2001" , "Invalid date: 4 digit year must be either yyyy-##-## or ##-##-yyyy");} // n:31-2012; 31.2012; 31/2012; 03-2012; 03.2012; 03/2012
|
||||
@Test public void Year_2__month__day() {tst_date_("03/31/2001" , "2001-03-31");} // n: 03.31.2012;03-31-2012
|
||||
@Test public void Year_2__day__month() {tst_date_("31-03-2001" , "2001-03-31");} // y: 31.03.2012; n:31/03/2012
|
||||
@Test public void Day_0__month__day() {tst_date_("31-03-02" , "2031-03-02");}
|
||||
@Test public void Day_0__month__day_dot() {tst_date_("22.05.70" , "1970-05-22");} // PURPOSE: dmy when delimiter is dot
|
||||
@Test public void Day_1__month__year() {tst_date_("03-31-02" , "2002-03-31");}
|
||||
@Test public void Day_2__month__day() {tst_date_("03-02-31" , "2031-03-02");}
|
||||
@Test public void Dmy_is_default() {tst_date_("03-04-05" , "2005-04-03");}
|
||||
@Test public void Dmy_is_default_y4() {tst_date_("2-5-2000" , "2000-05-02");}
|
||||
@Test public void Colon_hour_min() {tst_time_("01:02" , "01:02:00.000");}
|
||||
@Test public void Colon_hour_min_second() {tst_time_("01:02:03" , "01:02:03.000");}
|
||||
@Test public void Time_all() {tst_both_("04-03-05 06:07:08" , "2005-03-04 06:07:08.000");}
|
||||
@Test public void Unit_day_pos() {tst_date_("+ 3 days" , "2012-03-01");}
|
||||
@Test public void Unit_day_neg() {tst_date_("- 3 days" , "2012-02-24");}
|
||||
@Test public void Unit_day_neg_w_day() {tst_date_("30 May 2012 -1 days" , "2012-05-29");} // PAGE:en.w:Main Page
|
||||
@Test public void Unit_week() {tst_date_("- 1 week" , "2012-02-26");} // PURPOSE.FIX: "week" was not being handled; error on main Page; EX:da.wikipedia.org/Main_Page
|
||||
@Test public void Time_len_6() {tst_time_("041526" , "04:15:26.000");}
|
||||
@Test public void Err_one_num() {tst_time_("2" , "Invalid year: 2");} // occurs on some templates; PAGE:en.w:Voyager 1 and {{date}}
|
||||
@Test public void Dmy_at_y_dot() {tst_date_("1.2.70" , "1970-02-01");} // PURPOSE: dmy when delimiter is dot
|
||||
@Test public void Mdy_at_y_slash() {tst_date_("1/2/70" , "1970-01-02");} // PURPOSE: mdy when delimiter is slash
|
||||
@Test public void Ago() {tst_date_("1 month ago" , "2012-01-27");}
|
||||
|
||||
private void tst_date_(String raw, String expd) {
|
||||
byte[] raw_ary = Bry_.new_u8(raw);
|
||||
DateAdp date = parser.Parse(raw_ary, bfr);
|
||||
if (date == DateAdp_.MinValue)
|
||||
Tfds.Eq(expd, bfr.Xto_str_and_clear(), raw);
|
||||
else
|
||||
Tfds.Eq(expd, date.XtoStr_fmt_yyyy_MM_dd());
|
||||
}
|
||||
private void tst_time_(String raw, String expd) {
|
||||
byte[] raw_ary = Bry_.new_u8(raw);
|
||||
DateAdp date = parser.Parse(raw_ary, bfr);
|
||||
if (date == DateAdp_.MinValue)
|
||||
Tfds.Eq(expd, bfr.Xto_str_and_clear(), raw);
|
||||
else
|
||||
Tfds.Eq(expd, date.XtoStr_fmt("HH:mm:ss.fff"));
|
||||
}
|
||||
private void tst_both_(String raw, String expd) {
|
||||
byte[] raw_ary = Bry_.new_u8(raw);
|
||||
DateAdp date = parser.Parse(raw_ary, bfr);
|
||||
if (date == DateAdp_.MinValue)
|
||||
Tfds.Eq(expd, bfr.Xto_str_and_clear(), raw);
|
||||
else
|
||||
Tfds.Eq(expd, date.XtoStr_fmt("yyyy-MM-dd HH:mm:ss.fff"));
|
||||
}
|
||||
}
|
||||
/*
|
||||
12:12 2012 5 Feb: pass
|
||||
2012 5 Feb 12:12: fail
|
||||
2012-Feb-5 12:12: pass (but 2012-02-01)
|
||||
2012-Feb-05 12:12: pass (and 2012-02-05)
|
||||
{{#time:Y-m-d H:i:s A|.....2012.-.-.Feb-09....}}
|
||||
*/
|
||||
104
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_anchorencode.java
Normal file
104
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_anchorencode.java
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
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.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.btries.*;
|
||||
import gplx.xowa.parsers.amps.*; import gplx.xowa.parsers.lnkes.*;
|
||||
public class Pfunc_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 Pfunc_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__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.Xto_bry_and_clear();
|
||||
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_u8_int(((Xop_amp_tkn_num)sub).Val()); break;
|
||||
case Xop_tkn_itm_.Tid_html_ref: tmp_bfr.Add_u8_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 Btrie_fast_mgr encode_trie = Btrie_fast_mgr.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.xtns.pfuncs.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_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");}
|
||||
}
|
||||
58
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_filepath.java
Normal file
58
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_filepath.java
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
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.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.xowa.files.*; import gplx.xowa.files.repos.*;
|
||||
import gplx.xowa.files.origs.*;
|
||||
public class Pfunc_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 Pfunc_filepath().Name_(name);}
|
||||
@Override public void Func_evaluate(Xop_ctx ctx, byte[] src, Xot_invk caller, Xot_invk self, Bry_bfr bfr) {
|
||||
byte[] val_ary = Eval_argx(ctx, src, caller, self); if (val_ary == Bry_.Empty) return;
|
||||
Xowe_wiki wiki = ctx.Wiki();
|
||||
Xoa_ttl ttl = wiki.Ttl_parse(Xow_ns_.Id_file, val_ary); if (ttl == null) return; // text is not valid ttl; exit;
|
||||
Xoae_page page = Load_page(wiki, ttl); if (page.Missing()) return; // page not found in wiki or commons; exit;
|
||||
byte[] ttl_bry = page.Ttl().Page_url();
|
||||
|
||||
// Xof_orig_itm orig_itm = wiki.File_mgr().Orig_mgr().Find_by_ttl_or_null(ttl_bry);
|
||||
// if (orig_itm == Xof_orig_itm.Null) return;
|
||||
// Xof_repo_itm repo = wiki.File_mgr().Repo_mgr().Get_trg_by_id_or_null(orig_itm.Repo()).Trg();
|
||||
// url_bldr.Init_for_trg_html(Xof_repo_itm_.Mode_orig, repo, orig_itm.Ttl(), Xof_file_wkr_.Md5_fast(orig_itm.Ttl()), orig_itm.Ext(), -1, -1, -1);
|
||||
// bfr.Add(url_bldr.Xto_bry());
|
||||
|
||||
Xofw_file_finder_rslt tmp_rslt = wiki.File_mgr().Repo_mgr().Page_finder_locate(ttl_bry);
|
||||
if (tmp_rslt.Repo_idx() == Byte_.Max_value_127) return;
|
||||
Xof_repo_itm trg_repo = wiki.File_mgr().Repo_mgr().Repos_get_at(tmp_rslt.Repo_idx()).Trg();
|
||||
xfer_itm.Orig_ttl_and_redirect_(ttl_bry, Bry_.Empty); // redirect is empty b/c Get_page does all redirect lookups
|
||||
byte[] url = url_bldr.Init_for_trg_html(Xof_repo_itm_.Mode_orig, trg_repo, ttl_bry, xfer_itm.Orig_ttl_md5(), xfer_itm.Orig_ext(), Xof_img_size.Size_null_deprecated, Xof_lnki_time.Null, Xof_lnki_page.Null).Xto_bry();
|
||||
bfr.Add(url);
|
||||
}
|
||||
private static final Xof_xfer_itm xfer_itm = new Xof_xfer_itm();
|
||||
private static final Xof_url_bldr url_bldr = new Xof_url_bldr();
|
||||
private static Xoae_page Load_page(Xowe_wiki wiki, Xoa_ttl ttl) {
|
||||
Xoae_page page = wiki.Data_mgr().Get_page(ttl, false);
|
||||
if (page.Missing()) { // file not found in current wiki; try commons;
|
||||
Xowe_wiki commons_wiki = wiki.Appe().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; DATE:2013-03-10
|
||||
page = commons_wiki.Data_mgr().Get_page(ttl, false);
|
||||
}
|
||||
}
|
||||
return page;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
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.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*; import gplx.dbs.*;
|
||||
import gplx.xowa.tdbs.*;
|
||||
import gplx.xowa.files.*; import gplx.xowa.files.exts.*; import gplx.xowa.files.origs.*;
|
||||
import gplx.xowa.wikis.*;
|
||||
public class Pfunc_filepath_tst {
|
||||
private final Xop_fxt fxt = new Xop_fxt();
|
||||
private final Xofw_wiki_wkr_mock mock_wkr = new Xofw_wiki_wkr_mock();
|
||||
private Xowe_wiki en_wiki, commons_wiki;
|
||||
@Before public void init() {
|
||||
fxt.Reset();
|
||||
Io_mgr.I.InitEngine_mem();
|
||||
Db_conn_bldr.I.Reg_default_mem();
|
||||
Xoae_app app = fxt.App();
|
||||
en_wiki = fxt.Wiki();
|
||||
// Init_orig_mgr(en_wiki);
|
||||
commons_wiki = Xoa_app_fxt.wiki_(app, Xow_domain_.Domain_str_commons);
|
||||
mock_wkr.Clear_commons(); // assume all files are in repo 0
|
||||
en_wiki.File_mgr().Repo_mgr().Page_finder_(mock_wkr);
|
||||
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());
|
||||
app.File_mgr().Repo_mgr().Set("trg_commons", "mem/xowa/file/commons/trg/", commons_wiki.Domain_str());
|
||||
en_wiki.File_mgr().Repo_mgr().Add_repo(Bry_.new_u8("src_commons"), Bry_.new_u8("trg_commons"));
|
||||
Io_mgr.I.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
|
||||
}
|
||||
@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.Tdb_fsys_mgr().Tdb_dir_regy()[Xotdb_dir_info_.Tid_page].Ext_tid_(gplx.ios.Io_stream_.Tid_raw);
|
||||
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.Init_log_(Xop_ttl_log.Invalid_char);
|
||||
fxt.Test_parse_tmpl_str_test("{{filepath:{{{ImageFile}}}}}", "{{test}}", "");
|
||||
}
|
||||
// private static void Init_orig_mgr(Xow_wiki wiki) {
|
||||
// Xof_orig_tbl orig_tbl = null;
|
||||
// wiki.File__orig_mgr().Init_by_wiki(wiki, Xof_fsdb_mode.new_v2_gui(), new Xof_orig_tbl[] {orig_tbl}, Xof_url_bldr.new_v2());
|
||||
// }
|
||||
}
|
||||
57
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_ns.java
Normal file
57
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_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.xtns.pfuncs.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
public class Pfunc_ns extends Pf_func_base { // EX: {{ns:6}} -> File
|
||||
private boolean encode;
|
||||
public Pfunc_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 Pfunc_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 bfr) {
|
||||
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_.Xto_int_or(val_dat_ary, 0, val_dat_ary_len, Int_.MinValue);
|
||||
if (ns_id == Int_.MinValue) {
|
||||
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"
|
||||
bfr.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}}"
|
||||
bfr.Add(encode ? itm.Name_enc() : itm.Name_txt());
|
||||
}
|
||||
}
|
||||
private static Hash_adp_bry canonical;
|
||||
private static void canonical_() {
|
||||
canonical = Hash_adp_bry.ci_ascii_(); // ASCII:canonical English names
|
||||
for (Xow_ns ns : Xow_ns_.Canonical)
|
||||
canonical_add(ns.Id(), ns.Name_bry());
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
37
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_ns_tst.java
Normal file
37
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_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.xtns.pfuncs.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import org.junit.*;
|
||||
public class Pfunc_ns_tst {
|
||||
@Before public void init() {fxt.Reset();} private final Xop_fxt fxt = new Xop_fxt();
|
||||
@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().Clear().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");
|
||||
}
|
||||
@Test public void Ns_neg1() {fxt.Test_parse_tmpl_str_test("{{ns:-1}}" , "{{test}}", "Special");} // PURPOSE.FIX:handle special; DATE:2015-05-18
|
||||
}
|
||||
183
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_rel2abs.java
Normal file
183
400_xowa/src/gplx/xowa/xtns/pfuncs/ttls/Pfunc_rel2abs.java
Normal file
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
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.ttls; import gplx.*; import gplx.xowa.*; import gplx.xowa.xtns.*; import gplx.xowa.xtns.pfuncs.*;
|
||||
import gplx.core.primitives.*; import gplx.core.btries.*;
|
||||
public class Pfunc_rel2abs extends Pf_func_base {
|
||||
@Override public boolean Func_require_colon_arg() {return true;}
|
||||
private static final byte[] Ary_dot_slash = Bry_.new_a7("./"), Ary_dot_dot = Bry_.new_a7(".."), Ary_dot_dot_slash = Bry_.new_a7("../");
|
||||
private static void qry_bgns_with_init() {
|
||||
qry_bgns_with = Btrie_fast_mgr.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 Btrie_fast_mgr 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__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.Match_bgn(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.Xto_bry_and_clear();
|
||||
}
|
||||
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 Pfunc_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
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user