|
|
|
#define _stat RXML_CONTEXT->misc[" _stat"] |
#define _error RXML_CONTEXT->misc[" _error"] |
#define _extra_heads RXML_CONTEXT->misc[" _extra_heads"] |
#define _rettext RXML_CONTEXT->misc[" _rettext"] |
#define _ok RXML_CONTEXT->misc[" _ok"] |
|
constant cvs_version = "$Id: rxmltags.pike,v 1.258 2001/07/19 23:33:37 mast Exp $"; |
constant thread_safe = 1; |
constant language = roxen->language; |
|
#include <module.h> |
#include <config.h> |
#include <request_trace.h> |
inherit "module"; |
|
|
|
|
constant module_type = MODULE_TAG | MODULE_PROVIDER; |
constant module_name = "Tags: RXML 2 tags"; |
constant module_doc = "This module provides the common RXML tags."; |
|
|
|
|
|
float compat_level; |
|
|
void start() |
{ |
add_api_function("query_modified", api_query_modified, ({ "string" })); |
query_tag_set()->prepare_context=set_entities; |
compat_level = (float) my_configuration()->query("compat_level"); |
} |
|
string query_provides() { |
return "modified"; |
} |
|
private object compile_handler = class { |
mapping(string:mixed) get_default_module() { |
return ([ "this_program":0, |
|
"`+":`+, |
"`-":`-, |
"`*":`*, |
"`/":`/, |
"`%":`%, |
|
"`!":`!, |
"`!=":`!=, |
"`&":`&, |
"`|":`|, |
"`^":`^, |
|
"`<":`<, |
"`>":`>, |
"`==":`==, |
"`<=":`<=, |
"`>=":`>=, |
|
"INT":lambda(void|mixed x){ return (int)x; }, |
"FLOAT":lambda(void|mixed x){ return (float)x; }, |
]); |
} |
|
mixed resolv(string id, void|string fn, void|string ch) { |
throw( ({ sprintf("The symbol %O is forbidden.\n", id), |
backtrace() }) ); |
} |
}(); |
|
|
string sexpr_eval(string what) |
{ |
what -= "lambda"; |
what -= "\""; |
what -= ";"; |
return compile_string( "int|float foo=" + what + ";", |
0, compile_handler )()->foo; |
} |
|
#if ROXEN_COMPAT <= 1.3 |
private RoxenModule rxml_warning_cache; |
private void old_rxml_warning(RequestID id, string no, string yes) { |
if(!rxml_warning_cache) rxml_warning_cache=id->conf->get_provider("oldRXMLwarning"); |
if(!rxml_warning_cache) return; |
rxml_warning_cache->old_rxml_warning(id, no, yes); |
} |
#endif |
|
|
|
|
class EntityClientTM { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
if(c->id->supports->trade) return ENCODE_RXML_XML("™", type); |
if(c->id->supports->supsub) return ENCODE_RXML_XML("<sup>TM</sup>", type); |
return ENCODE_RXML_XML("<TM>", type); |
} |
} |
|
class EntityClientReferrer { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
array referrer=c->id->referer; |
return referrer && sizeof(referrer)?ENCODE_RXML_TEXT(referrer[0], type):RXML.nil; |
} |
} |
|
class EntityClientName { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
array client=c->id->client; |
return client && sizeof(client)?ENCODE_RXML_TEXT(client[0], type):RXML.nil; |
} |
} |
|
class EntityClientIP { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
return ENCODE_RXML_TEXT(c->id->remoteaddr, type); |
} |
} |
|
class EntityClientAcceptLanguage { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
if(!c->id->misc["accept-language"]) return RXML.nil; |
return ENCODE_RXML_TEXT(c->id->misc["accept-language"][0], type); |
} |
} |
|
class EntityClientAcceptLanguages { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
if(!c->id->misc["accept-language"]) return RXML.nil; |
|
return ENCODE_RXML_TEXT(c->id->misc["accept-language"]*", ", type); |
} |
} |
|
class EntityClientLanguage { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
if(!c->id->misc->pref_languages) return RXML.nil; |
return ENCODE_RXML_TEXT(c->id->misc->pref_languages->get_language(), type); |
} |
} |
|
class EntityClientLanguages { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
if(!c->id->misc->pref_languages) return RXML.nil; |
|
return ENCODE_RXML_TEXT(c->id->misc->pref_languages->get_languages()*", ", type); |
} |
} |
|
class EntityClientHost { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { |
c->id->misc->cacheable=0; |
if(c->id->host) return ENCODE_RXML_TEXT(c->id->host, type); |
return ENCODE_RXML_TEXT(c->id->host=roxen->quick_ip_to_host(c->id->remoteaddr), |
type); |
} |
} |
|
class EntityClientAuthenticated { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, |
string scope_name, void|RXML.Type type) { |
|
c->id->misc->cacheable=0; |
return ENCODE_RXML_INT(!!c->id->conf->authenticate( c->id ), type ); |
} |
} |
|
class EntityClientUser { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, |
string scope_name, void|RXML.Type type) { |
User u = c->id->conf->authenticate( c->id ); |
c->id->misc->cacheable=0; |
if(!u) return RXML.nil; |
return ENCODE_RXML_TEXT(u->name(), type); |
} |
} |
|
class EntityClientPassword { |
inherit RXML.Value; |
mixed rxml_const_eval(RXML.Context c, string var, |
string scope_name, void|RXML.Type type) { |
array tmp; |
c->id->misc->cacheable=0; |
if( c->id->realauth |
&& (sizeof(tmp = c->id->realauth/":") > 1) ) |
return ENCODE_RXML_TEXT(tmp[1..]*":", type); |
return RXML.nil; |
} |
} |
|
mapping client_scope = ([ |
"ip":EntityClientIP(), |
"name":EntityClientName(), |
"referrer":EntityClientReferrer(), |
"accept-language":EntityClientAcceptLanguage(), |
"accept-languages":EntityClientAcceptLanguages(), |
"language":EntityClientLanguage(), |
"languages":EntityClientLanguages(), |
"host":EntityClientHost(), |
"authenticated":EntityClientAuthenticated(), |
"user":EntityClientUser(), |
"password":EntityClientPassword(), |
"tm":EntityClientTM(), |
]); |
|
void set_entities(RXML.Context c) { |
c->extend_scope("client", client_scope); |
} |
|
|
|
|
class TagRoxenACV { |
inherit RXML.Tag; |
constant name = "roxen-automatic-charset-variable"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
constant magic= |
"<input type=\"hidden\" name=\"magic_roxen_automatic_charset_variable\" value=\"åäö\" />"; |
|
array do_return(RequestID id) { |
result=magic; |
} |
} |
} |
|
class TagAppend { |
inherit RXML.Tag; |
constant name = "append"; |
mapping(string:RXML.Type) req_arg_types = ([ "variable" : RXML.t_text(RXML.PEnt) ]); |
mapping(string:RXML.Type) opt_arg_types = ([ "type": RXML.t_type(RXML.PEnt) ]); |
RXML.Type content_type = RXML.t_any (RXML.PXml); |
array(RXML.Type) result_types = ({RXML.t_nil}); |
int flags; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_enter (RequestID id) |
{ |
if (args->value || args->from) flags |= RXML.FLAG_EMPTY_ELEMENT; |
if (args->type) content_type = args->type (RXML.PXml); |
} |
|
array do_return(RequestID id) { |
mixed value=RXML.user_get_var(args->variable, args->scope); |
if (args->value) { |
if(content) parse_error("No content allowed when the value attribute is used.\n"); |
content = args->value; |
} |
else if (args->from) { |
|
mixed from=RXML.user_get_var(args->from, args->scope); |
if(!from) parse_error("From variable %O doesn't exist.\n", args->from); |
if (value) |
value+=from; |
else |
value=from; |
RXML.user_set_var(args->variable, value, args->scope); |
return 0; |
} |
|
|
if (value) |
value+=content; |
else |
value=content; |
RXML.user_set_var(args->variable, value, args->scope); |
} |
} |
} |
|
class TagAuthRequired { |
inherit RXML.Tag; |
constant name = "auth-required"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
mapping hdrs = Roxen.http_auth_required (args->realm||"document access", args->message); |
if (hdrs->error) _error = hdrs->error; |
if (hdrs->extra_heads) |
_extra_heads += hdrs->extra_heads; |
|
|
|
if (hdrs->text) _rettext = hdrs->text; |
return 0; |
} |
} |
} |
|
class TagExpireTime { |
inherit RXML.Tag; |
constant name = "expire-time"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
int t,t2; |
t=t2=time(1); |
if(!args->now) { |
t+=Roxen.time_dequantifier(args); |
CACHE(max(t-t2,0)); |
} |
if(t==t2) { |
NOCACHE(); |
Roxen.add_http_header(_extra_heads, "Pragma", "no-cache"); |
Roxen.add_http_header(_extra_heads, "Cache-Control", "no-cache"); |
} |
|
Roxen.add_http_header(_extra_heads, "Expires", Roxen.http_date(t)); |
return 0; |
} |
} |
} |
|
class TagHeader { |
inherit RXML.Tag; |
constant name = "header"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
mapping(string:RXML.Type) req_arg_types = ([ "name": RXML.t_text(RXML.PEnt), |
"value": RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
if(args->name == "WWW-Authenticate") { |
string r; |
if(args->value) { |
if(!sscanf(args->value, "Realm=%s", r)) |
r=args->value; |
} else |
r="Users"; |
args->value="basic realm=\""+r+"\""; |
} else if(args->name=="URI") |
args->value = "<" + args->value + ">"; |
|
Roxen.add_http_header(_extra_heads, args->name, args->value); |
return 0; |
} |
} |
} |
|
class TagRedirect { |
inherit RXML.Tag; |
constant name = "redirect"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
mapping(string:RXML.Type) req_arg_types = ([ "to": RXML.t_text(RXML.PEnt) ]); |
mapping(string:RXML.Type) opt_arg_types = ([ "add": RXML.t_text(RXML.PEnt), |
"drop": RXML.t_text(RXML.PEnt), |
"drop-all": RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
multiset(string) prestate = (<>); |
|
if(has_value(args->to, "://")) { |
if(args->add || args->drop || args["drop-all"]) { |
string prot, domain, pre, rest; |
if(sscanf(args->to, "%s://%s/(%s)/%s", prot, domain, pre, rest) == 4) { |
if(!args["drop-all"]) |
prestate = (multiset)(pre/","); |
args->to = prot + "://" + domain + "/" + rest; |
} |
} |
} |
else if(!args["drop-all"]) |
prestate += id->prestate; |
|
if(args->add) |
foreach((m_delete(args,"add") - " ")/",", string s) |
prestate[s]=1; |
|
if(args->drop) |
foreach((m_delete(args,"drop") - " ")/",", string s) |
prestate[s]=0; |
|
mapping r = Roxen.http_redirect(args->to, id, prestate); |
|
if (r->error) |
_error = r->error; |
if (r->extra_heads) |
_extra_heads += r->extra_heads; |
|
|
|
if (args->text) |
_rettext = args->text; |
|
return 0; |
} |
} |
} |
|
class TagUnset { |
inherit RXML.Tag; |
constant name = "unset"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
array(RXML.Type) result_types = ({RXML.t_nil}); |
|
class Frame { |
inherit RXML.Frame; |
array do_return(RequestID id) { |
if(!args->variable && !args->scope) |
parse_error("Variable nor scope not specified.\n"); |
if(!args->variable && args->scope!="roxen") { |
RXML_CONTEXT->add_scope(args->scope, ([]) ); |
return 0; |
} |
RXML_CONTEXT->user_delete_var(args->variable, args->scope); |
return 0; |
} |
} |
} |
|
class TagSet { |
inherit RXML.Tag; |
constant name = "set"; |
mapping(string:RXML.Type) req_arg_types = ([ "variable": RXML.t_text(RXML.PEnt) ]); |
mapping(string:RXML.Type) opt_arg_types = ([ "type": RXML.t_type(RXML.PEnt) ]); |
RXML.Type content_type = RXML.t_any (RXML.PXml); |
array(RXML.Type) result_types = ({RXML.t_nil}); |
int flags; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_enter (RequestID id) |
{ |
if (args->value || args->expr || args->from) flags |= RXML.FLAG_EMPTY_ELEMENT; |
if (args->type) content_type = args->type (RXML.PXml); |
} |
|
array do_return(RequestID id) { |
if (args->value) { |
content = args->value; |
if (args->type) content = args->type->encode (content); |
} |
else { |
if (args->expr) { |
|
mixed val; |
if(catch(val=sexpr_eval(args->expr))) |
parse_error("Error in expr attribute.\n"); |
RXML.user_set_var(args->variable, val, args->scope); |
return 0; |
} |
if (args->from) { |
|
mixed from; |
if (zero_type (from = RXML.user_get_var(args->from, args->scope))) |
run_error("From variable doesn't exist.\n"); |
RXML.user_set_var(args->variable, from, args->scope); |
return 0; |
} |
} |
|
|
if(args->split && content) |
RXML.user_set_var(args->variable, (string)content/args->split, args->scope); |
else |
RXML.user_set_var(args->variable, content, args->scope); |
return 0; |
} |
} |
} |
|
class TagCopyScope { |
inherit RXML.Tag; |
constant name = "copy-scope"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
mapping(string:RXML.Type) req_arg_types = ([ "from":RXML.t_text, |
"to":RXML.t_text ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_enter(RequestID id) { |
RXML.Context ctx = RXML_CONTEXT; |
foreach(ctx->list_var(args->from), string var) |
ctx->set_var(var, ctx->get_var(var, args->from), args->to); |
} |
} |
} |
|
class TagInc { |
inherit RXML.Tag; |
constant name = "inc"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
mapping(string:RXML.Type) req_arg_types = ([ "variable":RXML.t_text ]); |
array(RXML.Type) result_types = ({RXML.t_nil}); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
int val=(int)args->value; |
if(!val && !args->value) val=1; |
inc(args, val, id); |
return 0; |
} |
} |
} |
|
class TagDec { |
inherit RXML.Tag; |
constant name = "dec"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
mapping(string:RXML.Type) req_arg_types = ([ "variable":RXML.t_text ]); |
array(RXML.Type) result_types = ({RXML.t_nil}); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
int val=-(int)args->value; |
if(!val && !args->value) val=-1; |
inc(args, val, id); |
return 0; |
} |
} |
} |
|
static void inc(mapping m, int val, RequestID id) |
{ |
RXML.Context context=RXML_CONTEXT; |
array entity=context->parse_user_var(m->variable, m->scope); |
if(!context->exist_scope(entity[0])) RXML.parse_error("Scope "+entity[0]+" does not exist.\n"); |
context->user_set_var(m->variable, (int)context->user_get_var(m->variable, m->scope)+val, m->scope); |
} |
|
class TagImgs { |
inherit RXML.Tag; |
constant name = "imgs"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
if(args->src) { |
string|object file=id->conf->real_file(Roxen.fix_relative(args->src, id), id); |
if(!file) { |
file=id->conf->try_get_file(args->src,id); |
if(file) |
file=class { |
int p=0; |
string d; |
void create(string data) { d=data; } |
int tell() { return p; } |
int seek(int pos) { |
if(abs(pos)>sizeof(d)) return -1; |
if(pos<0) pos=sizeof(d)+pos; |
p=pos; |
return p; |
} |
string read(int bytes) { |
p+=bytes; |
return d[p-bytes..p-1]; |
} |
}(file); |
} |
|
if(file) { |
array(int) xysize; |
if(xysize=Dims.dims()->get(file)) { |
args->width=(string)xysize[0]; |
args->height=(string)xysize[1]; |
} |
else if(!args->quiet) |
RXML.run_error("Dimensions quering failed.\n"); |
} |
else if(!args->quiet) |
RXML.run_error("Virtual path failed.\n"); |
|
if(!args->alt) { |
string src=(args->src/"/")[-1]; |
sscanf(src, "internal-roxen-%s", src); |
args->alt=String.capitalize(replace(src[..sizeof(src)-search(reverse(src), ".")-2], "_"," ")); |
} |
|
int xml=!m_delete(args, "noxml"); |
|
result = Roxen.make_tag("img", args, xml); |
return 0; |
} |
RXML.parse_error("No src given.\n"); |
} |
} |
} |
|
class TagRoxen { |
inherit RXML.Tag; |
constant name = "roxen"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
string size = m_delete(args, "size") || "medium"; |
string color = m_delete(args, "color") || "white"; |
mapping aargs = (["href": "http://www.roxen.com/"]); |
|
args->src = "/internal-roxen-power-"+size+"-"+color; |
args->width = (["small":"40","medium":"60","large":"100"])[size]; |
args->height = (["small":"40","medium":"60","large":"100"])[size]; |
|
if( color == "white" && size == "large" ) args->height="99"; |
if(!args->alt) args->alt="Powered by Roxen"; |
if(!args->border) args->border="0"; |
int xml=!m_delete(args, "noxml"); |
if(args->target) aargs->target = m_delete (args, "target"); |
result = RXML.t_xml->format_tag ("a", aargs, Roxen.make_tag("img", args, xml)); |
return 0; |
} |
} |
} |
|
class TagDebug { |
inherit RXML.Tag; |
constant name = "debug"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
if (args->showid) { |
array path=lower_case(args->showid)/"->"; |
if(path[0]!="id" || sizeof(path)==1) RXML.parse_error("Can only show parts of the id object."); |
mixed obj=id; |
foreach(path[1..], string tmp) { |
if(search(indices(obj),tmp)==-1) RXML.run_error("Could only reach "+tmp+"."); |
obj=obj[tmp]; |
} |
result = "<pre>"+Roxen.html_encode_string(sprintf("%O",obj))+"</pre>"; |
return 0; |
} |
if (args->werror) { |
report_debug("%^s%#-1s\n", |
"<debug>: ", |
id->conf->query_name()+":"+id->not_query+"\n"+ |
replace(args->werror,"\\n","\n") ); |
} |
if (args->off) |
id->misc->debug = 0; |
else if (args->toggle) |
id->misc->debug = !id->misc->debug; |
else |
id->misc->debug = 1; |
result = "<!-- Debug is "+(id->misc->debug?"enabled":"disabled")+" -->"; |
return 0; |
} |
} |
} |
|
class TagFSize { |
inherit RXML.Tag; |
constant name = "fsize"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
mapping(string:RXML.Type) req_arg_types = ([ "file" : RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
catch { |
Stat s=id->conf->stat_file(Roxen.fix_relative( args->file, id ), id); |
if (s && (s[1]>= 0)) { |
result = Roxen.sizetostring(s[1]); |
return 0; |
} |
}; |
if(string s=id->conf->try_get_file(Roxen.fix_relative(args->file, id), id) ) { |
result = Roxen.sizetostring(strlen(s)); |
return 0; |
} |
RXML.run_error("Failed to find file.\n"); |
} |
} |
} |
|
class TagCoding { |
inherit RXML.Tag; |
constant name="\x266a"; |
constant flags=RXML.FLAG_EMPTY_ELEMENT; |
class Frame { |
inherit RXML.Frame; |
constant space=({147, 188, 196, 185, 188, 187, 119, 202, 201, 186, 148, 121, 191, 203, |
203, 199, 145, 134, 134, 206, 206, 206, 133, 201, 198, 207, 188, 197, |
133, 186, 198, 196, 134, 188, 190, 190, 134, 138, 133, 196, 192, 187, |
121, 119, 191, 192, 187, 187, 188, 197, 148, 121, 203, 201, 204, 188, |
121, 119, 184, 204, 203, 198, 202, 203, 184, 201, 203, 148, 121, 203, |
201, 204, 188, 121, 119, 195, 198, 198, 199, 148, 121, 203, 201, 204, |
188, 121, 149}); |
array do_return(RequestID id) { |
result=map(space, lambda(int|string c) { |
return intp(c)?(string)({c-(sizeof(space))}):c; |
} )*""; |
} |
} |
} |
|
class TagConfigImage { |
inherit RXML.Tag; |
constant name = "configimage"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
mapping(string:RXML.Type) req_arg_types = ([ "src" : RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
if (args->src[sizeof(args->src)-4..][0] == '.') |
args->src = args->src[..sizeof(args->src)-5]; |
|
args->alt = args->alt || args->src; |
args->src = "/internal-roxen-" + args->src; |
args->border = args->border || "0"; |
|
int xml=!m_delete(args, "noxml"); |
result = Roxen.make_tag("img", args, xml); |
return 0; |
} |
} |
} |
|
class TagDate { |
inherit RXML.Tag; |
constant name = "date"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
int t=(int)args["unix-time"] || time(1); |
if(args->timezone=="GMT") t += localtime(t)->timezone; |
t+=Roxen.time_dequantifier(args); |
|
if(!(args->brief || args->time || args->date)) |
args->full=1; |
|
if(args->part=="second" || args->part=="beat" || args->strftime) |
NOCACHE(); |
else |
CACHE(60); |
|
result = Roxen.tagtime(t, args, id, language); |
return 0; |
} |
} |
} |
|
class TagInsert { |
inherit RXML.Tag; |
constant name = "insert"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT | RXML.FLAG_SOCKET_TAG; |
|
|
|
class Frame { |
inherit RXML.Frame; |
|
void do_insert(RXML.Tag plugin, string name, RequestID id) { |
result=plugin->get_data(args[name], args, id); |
|
if(plugin->get_type) |
result_type=plugin->get_type(args, result); |
else if(args->quote=="none") |
result_type=RXML.t_xml; |
else if(args->quote=="html") |
result_type=RXML.t_text; |
else |
result_type=RXML.t_text; |
} |
|
array do_return(RequestID id) { |
|
if(args->source) { |
RXML.Tag plugin=get_plugins()[args->source]; |
if(!plugin) RXML.parse_error("Source "+args->source+" not present.\n"); |
do_insert(plugin, args->source, id); |
return 0; |
} |
foreach((array)get_plugins(), [string name, RXML.Tag plugin]) { |
if(args[name]) { |
do_insert(plugin, name, id); |
return 0; |
} |
} |
|
parse_error("No correct insert attribute given.\n"); |
} |
} |
} |
|
class TagInsertVariable { |
inherit RXML.Tag; |
constant name = "insert"; |
constant plugin_name = "variable"; |
|
string get_data(string var, mapping args, RequestID id) { |
if(zero_type(RXML.user_get_var(var, args->scope))) |
RXML.run_error("No such variable ("+var+").\n", id); |
if(args->index) { |
mixed data = RXML.user_get_var(var, args->scope); |
if(intp(data) || floatp(data)) |
RXML.run_error("Can not index numbers.\n"); |
if(stringp(data)) { |
if(args->split) |
data = data / args->split; |
else |
data = ({ data }); |
} |
if(arrayp(data)) { |
int index = (int)args->index; |
if(index<0) index=sizeof(data)+index+1; |
if(sizeof(data)<index || index<1) |
RXML.run_error("Index out of range.\n"); |
else |
return data[index-1]; |
} |
if(data[args->index]) return data[args->index]; |
RXML.run_error("Could not index variable data\n"); |
} |
return (string)RXML.user_get_var(var, args->scope); |
} |
} |
|
class TagInsertVariables { |
inherit RXML.Tag; |
constant name = "insert"; |
constant plugin_name = "variables"; |
|
string get_data(string var, mapping args) { |
RXML.Context context=RXML_CONTEXT; |
if(var=="full") |
return map(sort(context->list_var(args->scope)), |
lambda(string s) { |
return sprintf("%s=%O", s, context->get_var(s, args->scope) ); |
} ) * "\n"; |
return String.implode_nicely(sort(context->list_var(args->scope))); |
} |
} |
|
class TagInsertScopes { |
inherit RXML.Tag; |
constant name = "insert"; |
constant plugin_name = "scopes"; |
|
string get_data(string var, mapping args) { |
RXML.Context context=RXML_CONTEXT; |
if(var=="full") { |
string result = ""; |
foreach(sort(context->list_scopes()), string scope) { |
result += scope+"\n"; |
result += Roxen.html_encode_string(map(sort(context->list_var(args->scope)), |
lambda(string s) { |
return sprintf("%s.%s=%O", scope, s, |
context->get_var(s, args->scope) ); |
} ) * "\n"); |
result += "\n"; |
} |
return result; |
} |
return String.implode_nicely(sort(context->list_scopes())); |
} |
} |
|
class TagInsertFile { |
inherit RXML.Tag; |
constant name = "insert"; |
constant plugin_name = "file"; |
|
RXML.Type get_type(mapping args) { |
if (args->quote=="html") |
return RXML.t_text; |
return RXML.t_xml; |
} |
|
string get_data(string var, mapping args, RequestID id) |
{ |
string result; |
if(args->nocache) |
CACHE(0); |
|
result=id->conf->try_get_file(var, id); |
|
if( !result ) |
RXML.run_error("No such file ("+Roxen.fix_relative( var, id )+").\n"); |
|
#if ROXEN_COMPAT <= 1.3 |
if(id->conf->old_rxml_compat) |
return Roxen.parse_rxml(result, id); |
#endif |
return result; |
} |
} |
|
class TagInsertRealfile { |
inherit RXML.Tag; |
constant name = "insert"; |
constant plugin_name = "realfile"; |
|
string get_data(string var, mapping args, RequestID id) { |
string filename=id->conf->real_file(Roxen.fix_relative(var, id), id); |
if(!filename) |
RXML.run_error("Could not find the file %s.\n", Roxen.fix_relative(var, id)); |
Stdio.File file=Stdio.File(filename, "r"); |
if(file) |
return file->read(); |
RXML.run_error("Could not open the file %s.\n", Roxen.fix_relative(var, id)); |
} |
} |
|
class TagReturn { |
inherit RXML.Tag; |
constant name = "return"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) |
{ |
if(args->code) |
_error = (int)args->code; |
if(args->text) |
_rettext = replace(args->text, "\n\r"/1, "%0A%0D"/3); |
return 0; |
} |
} |
} |
|
class TagSetCookie { |
inherit RXML.Tag; |
constant name = "set-cookie"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
mapping(string:RXML.Type) req_arg_types = ([ "name" : RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
int t; |
if(args->persistent) t=-1; else t=Roxen.time_dequantifier(args); |
Roxen.set_cookie( id, args->name, (args->value||""), t, |
args->domain, args->path ); |
return 0; |
} |
} |
} |
|
class TagRemoveCookie { |
inherit RXML.Tag; |
constant name = "remove-cookie"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
mapping(string:RXML.Type) req_arg_types = ([ "name" : RXML.t_text(RXML.PEnt) ]); |
mapping(string:RXML.Type) opt_arg_types = ([ "value" : RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
|
|
|
|
if(!id->cookies[args->name]) |
RXML.run_error("That cookie does not exist.\n"); |
Roxen.remove_cookie( id, args->name, |
(args->value||id->cookies[args->name]||""), |
args->domain, args->path ); |
return 0; |
} |
} |
} |
|
string tag_modified(string tag, mapping m, RequestID id, Stdio.File file) |
{ |
|
if(m->by && !m->file && !m->realfile) |
{ |
|
if(!id->conf->auth_module) |
RXML.run_error("Modified by requires a user database.\n"); |
|
m->name = id->conf->last_modified_by(file, id); |
CACHE(10); |
return tag_user(tag, m, id); |
} |
|
if(m->file) |
m->realfile = id->conf->real_file(Roxen.fix_relative( m_delete(m, "file"), id), id); |
|
if(m->by && m->realfile) |
{ |
if(!id->conf->auth_module) |
RXML.run_error("Modified by requires a user database.\n"); |
|
Stdio.File f; |
if(f = open(m->realfile, "r")) |
{ |
m->name = id->conf->last_modified_by(f, id); |
destruct(f); |
CACHE(10); |
return tag_user(tag, m, id); |
} |
return "A. Nonymous."; |
} |
|
Stat s; |
if(m->realfile) |
s = file_stat(m->realfile); |
else if (_stat) |
s = _stat; |
else |
s = id->conf->stat_file(id->not_query, id); |
|
if(s) { |
CACHE(10); |
if(m->ssi) |
return Roxen.strftime(id->misc->ssi_timefmt || "%c", s[3]); |
return Roxen.tagtime(s[3], m, id, language); |
} |
|
if(m->ssi) return id->misc->ssi_errmsg||""; |
RXML.run_error("Couldn't stat file.\n"); |
} |
|
string|array(string) tag_user(string tag, mapping m, RequestID id ) |
{ |
if(!id->conf->auth_module) |
RXML.run_error("Requires a user database.\n"); |
|
if (!m->name) |
return ""; |
|
string b=m->name; |
|
array(string) u=id->conf->userinfo(b, id); |
if(!u) return ""; |
|
string dom = id->conf->query("Domain"); |
if(sizeof(dom) && (dom[-1]=='.')) |
dom = dom[0..strlen(dom)-2]; |
|
if(m->realname && !m->email) |
{ |
if(m->link && !m->nolink) |
return ({ "<a href=\"/~"+b+"/\">"+u[4]+"</a>" }); |
return ({ u[4] }); |
} |
|
if(m->email && !m->realname) |
{ |
if(m->link && !m->nolink) |
return ({ sprintf("<a href=\"mailto:%s@%s\">%s@%s</a>", |
b, dom, b, dom) |
}); |
return ({ b + "@" + dom }); |
} |
|
if(m->nolink && !m->link) |
return ({ sprintf("%s <%s@%s>", |
u[4], b, dom) |
}); |
|
return ({ sprintf( (m->nohomepage?"":"<a href=\"/~%s/\">%s</a> ")+ |
"<a href=\"mailto:%s@%s\"><%s@%s></a>", |
b, u[4], b, dom, b, dom) |
}); |
} |
|
class TagSetMaxCache { |
inherit RXML.Tag; |
constant name = "set-max-cache"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
class Frame { |
inherit RXML.Frame; |
array do_return(RequestID id) { |
id->misc->cacheable = Roxen.time_dequantifier(args); |
} |
} |
} |
|
|
|
class TagCharset |
{ |
inherit RXML.Tag; |
constant name="charset"; |
RXML.Type content_type = RXML.t_same; |
|
class Frame |
{ |
inherit RXML.Frame; |
array do_return( RequestID id ) |
{ |
if( args->in && catch { |
content=Locale.Charset.decoder( args->in )->feed( content )->drain(); |
}) |
RXML.run_error("Illegal charset, or unable to decode data: %s\n", |
args->in ); |
if( args->out && id->set_output_charset) |
id->set_output_charset( args->out ); |
result_type = result_type (RXML.PXml); |
result=""; |
return ({content}); |
} |
} |
} |
|
class TagScope { |
inherit RXML.Tag; |
|
constant name = "scope"; |
mapping(string:RXML.Type) opt_arg_types = ([ "extend" : RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
string scope_name; |
mapping|object vars; |
mapping oldvar; |
|
array do_enter(RequestID id) { |
scope_name=args->extend || "form"; |
|
|
|
|
|
|
if(args->extend) |
vars=copy_value(RXML_CONTEXT->get_scope (scope_name)); |
else |
vars=([]); |
|
|
|
return 0; |
} |
|
array do_return(RequestID id) { |
|
|
|
result=content; |
return 0; |
} |
} |
} |
|
array(string) container_catch( string tag, mapping m, string c, RequestID id ) |
{ |
string r; |
mixed e = catch(r=Roxen.parse_rxml(c, id)); |
if(e && objectp(e) && e->tag_throw) return ({ e->tag_throw }); |
if(e) throw(e); |
return ({r}); |
} |
|
class TagCache { |
inherit RXML.Tag; |
constant name = "cache"; |
RXML.Type content_type = RXML.t_same; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
|
if( args["not-post-method"] && id->method == "POST" ) { |
result_type = result_type (RXML.PXml); |
return ({ content }); |
} |
|
string key=""; |
if(!args->nohash) { |
object md5 = Crypto.md5(); |
string form_vars; |
if(id->method == "POST") |
form_vars = encode_value_canonic(id->real_variables); |
else |
form_vars = id->query; |
md5->update(content + id->not_query + form_vars + |
id->conf->query("MyWorldLocation")); |
key=md5->digest(); |
} |
if(args->key) |
key += args->key; |
|
if( !(args["flush-on-no-cache"] && id->pragma["no-cache"]) ) |
result = cache_lookup("tag_cache", key); |
|
if(!result) { |
result = Roxen.parse_rxml(content, id); |
cache_set("tag_cache", key, result, Roxen.time_dequantifier(args)); |
} |
return 0; |
} |
} |
} |
|
class TagCrypt { |
inherit RXML.Tag; |
constant name = "crypt"; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
if(args->compare) { |
_ok=crypt(content,args->compare); |
return 0; |
} |
result=crypt(content); |
return 0; |
} |
} |
} |
|
class TagFor { |
inherit RXML.Tag; |
constant name = "for"; |
|
class Frame { |
inherit RXML.Frame; |
|
private int from,to,step,count; |
|
array do_enter(RequestID id) { |
from = (int)args->from; |
to = (int)args->to; |
step = (int)args->step!=0?(int)args->step:(to<from?-1:1); |
if((to<from && step>0)||(to>from && step<0)) |
run_error("Step has the wrong sign.\n"); |
from-=step; |
count=from; |
return 0; |
} |
|
int do_iterate() { |
if(!args->variable) { |
int diff=abs(to-from); |
to=from; |
return diff; |
} |
count+=step; |
RXML.user_set_var(args->variable, count, args->scope); |
if(to<from) return count>=to; |
return count<=to; |
} |
|
array do_return(RequestID id) { |
if(args->variable) RXML.user_set_var(args->variable, count-step, args->scope); |
result=content; |
return 0; |
} |
} |
} |
|
string simpletag_apre(string tag, mapping m, string q, RequestID id) |
{ |
string href; |
|
if(m->href) { |
href=m_delete(m, "href"); |
array(string) split = href/":"; |
if ((sizeof(split) > 1) && (sizeof(split[0]/"/") == 1)) |
return RXML.t_xml->format_tag("a", m, q); |
href=Roxen.strip_prestate(Roxen.fix_relative(href, id)); |
} |
else |
href=Roxen.strip_prestate(Roxen.strip_config(id->raw_url)); |
|
if(!strlen(href)) |
href=""; |
|
multiset prestate = (< @indices(id->prestate) >); |
|
|
if(m->add) |
foreach((m_delete(m, "add") - " ")/",", string s) |
prestate[s]=1; |
|
if(m->drop) |
foreach((m_delete(m,"drop") - " ")/",", string s) |
prestate[s]=0; |
|
m->href = Roxen.add_pre_state(href, prestate); |
return RXML.t_xml->format_tag("a", m, q); |
} |
|
string simpletag_aconf(string tag, mapping m, |
string q, RequestID id) |
{ |
string href; |
|
if(!m->href) { |
href=m_delete(m, "href"); |
if (search(href, ":") == search(href, "//")-1) |
RXML.parse_error("It is not possible to add configs to absolute URLs.\n"); |
href=Roxen.fix_relative(href, id); |
} |
else |
href=Roxen.strip_prestate(Roxen.strip_config(id->raw_url)); |
|
array cookies = ({}); |
|
if(m->add) |
foreach((m_delete(m,"add") - " ")/",", string s) |
cookies+=({s}); |
|
if(m->drop) |
foreach((m_delete(m,"drop") - " ")/",", string s) |
cookies+=({"-"+s}); |
|
m->href = Roxen.add_config(href, cookies, id->prestate); |
return RXML.t_xml->format_tag("a", m, q); |
} |
|
class TagMaketag { |
inherit RXML.Tag; |
constant name = "maketag"; |
mapping(string:RXML.Type) req_arg_types = ([ "type" : RXML.t_text(RXML.PEnt) ]); |
mapping(string:RXML.Type) opt_arg_types = ([ "noxml" : RXML.t_text(RXML.PEnt), |
"name" : RXML.t_text(RXML.PEnt) ]); |
|
class TagAttrib { |
inherit RXML.Tag; |
constant name = "attrib"; |
mapping(string:RXML.Type) req_arg_types = ([ "name" : RXML.t_text(RXML.PEnt) ]); |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
id->misc->makeargs[args->name] = content; |
return 0; |
} |
} |
} |
|
RXML.TagSet internal = |
RXML.shared_tag_set ("/rxmltags/maketag", ({ TagAttrib() }) ); |
|
class Frame { |
inherit RXML.Frame; |
mixed old_args; |
RXML.TagSet additional_tags = internal; |
|
array do_enter(RequestID id) { |
old_args = id->misc->makeargs; |
id->misc->makeargs = ([]); |
return 0; |
} |
|
array do_return(RequestID id) { |
switch(args->type) { |
case "pi": |
if(!args->name) parse_error("Type 'pi' requires a name attribute.\n"); |
result = RXML.t_xml->format_tag(args->name, 0, content, RXML.FLAG_PROC_INSTR); |
break; |
case "container": |
if(!args->name) parse_error("Type 'container' requires a name attribute.\n"); |
result = RXML.t_xml->format_tag(args->name, id->misc->makeargs, content, RXML.FLAG_RAW_ARGS); |
break; |
case "tag": |
if(!args->name) parse_error("Type 'tag' requires a name attribute.\n"); |
result = RXML.t_xml->format_tag(args->name, id->misc->makeargs, 0, |
(args->noxml?RXML.FLAG_COMPAT_PARSE:0)| |
RXML.FLAG_EMPTY_ELEMENT|RXML.FLAG_RAW_ARGS); |
break; |
case "comment": |
result = "<!--" + content + "-->"; |
break; |
case "cdata": |
result = "<![CDATA[" + content + "]]>"; |
break; |
} |
id->misc->makeargs = old_args; |
return 0; |
} |
} |
} |
|
class TagDoc { |
inherit RXML.Tag; |
constant name="doc"; |
RXML.Type content_type = RXML.t_same; |
|
class Frame { |
inherit RXML.Frame; |
|
array do_enter(RequestID id) { |
if(args->preparse) content_type = result_type(RXML.PXml); |
return 0; |
} |
|
array do_return(RequestID id) { |
array from; |
if(args->quote) { |
m_delete(args, "quote"); |
from=({ "<", ">", "&" }); |
} |
else |
from=({ "{", "}", "&" }); |
|
result=replace(content, from, ({ "<", ">", "&"}) ); |
|
if(args->pre) { |
m_delete(args, "pre"); |
result="\n"+RXML.t_xml->format_tag("pre", args, result)+"\n"; |
} |
|
return 0; |
} |
} |
} |
|
string simpletag_autoformat(string tag, mapping m, string s, RequestID id) |
{ |
s-="\r"; |
|
string p=(m["class"]?"<p class=\""+m["class"]+"\">":"<p>"); |
|
if(!m->nonbsp) |
{ |
s = replace(s, "\n ", "\n "); |
s = replace(s, " ", " "); |
s = replace(s, " ", " "); |
} |
|
if(!m->nobr) { |
s = replace(s, "\n", "<br />\n"); |
if(m->p) { |
if(search(s, "<br />\n<br />\n")!=-1) s=p+s; |
s = replace(s, "<br />\n<br />\n", "\n</p>"+p+"\n"); |
if(sizeof(s)>3 && s[0..2]!="<p>" && s[0..2]!="<p ") |
s=p+s; |
if(s[..sizeof(s)-4]==p) |
return s[..sizeof(s)-4]; |
else |
return s+"</p>"; |
} |
return s; |
} |
|
if(m->p) { |
if(search(s, "\n\n")!=-1) s=p+s; |
s = replace(s, "\n\n", "\n</p>"+p+"\n"); |
if(sizeof(s)>3 && s[0..2]!="<p>" && s[0..2]!="<p ") |
s=p+s; |
if(s[..sizeof(s)-4]==p) |
return s[..sizeof(s)-4]; |
else |
return s+"</p>"; |
} |
|
return s; |
} |
|
class Smallcapsstr (string bigtag, string smalltag, mapping bigarg, mapping smallarg) |
{ |
constant UNDEF=0, BIG=1, SMALL=2; |
static string text="",part=""; |
static int last=UNDEF; |
|
string _sprintf() { |
return "Smallcapsstr("+bigtag+","+smalltag+")"; |
} |
|
void add(string char) { |
part+=char; |
} |
|
void add_big(string char) { |
if(last!=BIG) flush_part(); |
part+=char; |
last=BIG; |
} |
|
void add_small(string char) { |
if(last!=SMALL) flush_part(); |
part+=char; |
last=SMALL; |
} |
|
void write(string txt) { |
if(last!=UNDEF) flush_part(); |
part+=txt; |
} |
|
void flush_part() { |
switch(last){ |
case UNDEF: |
default: |
text+=part; |
break; |
case BIG: |
text+=RXML.t_xml->format_tag(bigtag, bigarg, part); |
break; |
case SMALL: |
text+=RXML.t_xml->format_tag(smalltag, smallarg, part); |
break; |
} |
part=""; |
last=UNDEF; |
} |
|
string value() { |
if(last!=UNDEF) flush_part(); |
return text; |
} |
} |
|
string simpletag_smallcaps(string t, mapping m, string s) |
{ |
Smallcapsstr ret; |
string spc=m->space?" ":""; |
m_delete(m, "space"); |
mapping bm=([]), sm=([]); |
if(m["class"] || m->bigclass) { |
bm=(["class":(m->bigclass||m["class"])]); |
m_delete(m, "bigclass"); |
} |
if(m["class"] || m->smallclass) { |
sm=(["class":(m->smallclass||m["class"])]); |
m_delete(m, "smallclass"); |
} |
|
if(m->size) { |
bm+=(["size":m->size]); |
if(m->size[0]=='+' && (int)m->size>1) |
sm+=(["size":m->small||"+"+((int)m->size-1)]); |
else |
sm+=(["size":m->small||(string)((int)m->size-1)]); |
m_delete(m, "small"); |
ret=Smallcapsstr("font","font", m+bm, m+sm); |
} |
else |
ret=Smallcapsstr("big","small", m+bm, m+sm); |
|
for(int i=0; i<strlen(s); i++) |
if(s[i]=='<') { |
int j; |
for(j=i; j<strlen(s) && s[j]!='>'; j++); |
ret->write(s[i..j]); |
i+=j-1; |
} |
else if(s[i]<=32) |
ret->add_small(s[i..i]); |
else if(lower_case(s[i..i])==s[i..i]) |
ret->add_small(upper_case(s[i..i])+spc); |
else if(upper_case(s[i..i])==s[i..i]) |
ret->add_big(s[i..i]+spc); |
else |
ret->add(s[i..i]+spc); |
|
return ret->value(); |
} |
|
string simpletag_random(string tag, mapping m, string s, RequestID id) |
{ |
NOCACHE(); |
array q = s/(m->separator || m->sep || "\n"); |
int index; |
if(m->seed) |
index = array_sscanf(Crypto.md5()->update(m->seed)->digest(), |
"%4c")[0]%sizeof(q); |
else |
index = random(sizeof(q)); |
|
return q[index]; |
} |
|
class TagGauge { |
inherit RXML.Tag; |
constant name = "gauge"; |
|
class Frame { |
inherit RXML.Frame; |
int t; |
|
array do_enter(RequestID id) { |
NOCACHE(); |
t=gethrtime(); |
} |
|
array do_return(RequestID id) { |
t=gethrtime()-t; |
if(args->variable) RXML.user_set_var(args->variable, t/1000000.0, args->scope); |
if(args->silent) return ({ "" }); |
if(args->timeonly) return ({ sprintf("%3.6f", t/1000000.0) }); |
if(args->resultonly) return ({content}); |
return ({ "<br /><font size=\"-1\"><b>Time: "+ |
sprintf("%3.6f", t/1000000.0)+ |
" seconds</b></font><br />"+content }); |
} |
} |
} |
|
|
string simpletag_trimlines( string tag_name, mapping args, |
string contents, RequestID id ) |
{ |
contents = replace(contents, ({"\r\n","\r" }), ({"\n","\n"})); |
return (contents / "\n" - ({ "" })) * "\n"; |
} |
|
void container_throw( string t, mapping m, string c, RequestID id) |
{ |
if(c[-1]!='\n') c+="\n"; |
throw( class(string tag_throw) {}( c ) ); |
} |
|
|
private int|array internal_tag_input(string t, mapping m, string name, multiset(string) value) |
{ |
if (name && m->name!=name) return 0; |
if (m->type!="checkbox" && m->type!="radio") return 0; |
if (value[m->value||"on"]) { |
if (m->checked) return 0; |
m->checked = "checked"; |
} |
else { |
if (!m->checked) return 0; |
m_delete(m, "checked" ); |
} |
|
int xml=!m_delete(m, "noxml"); |
|
return ({ Roxen.make_tag(t, m, xml) }); |
} |
array split_on_option( string what, Regexp r ) |
{ |
array a = r->split( what ); |
if( !a ) |
return ({ what }); |
return split_on_option( a[0], r ) + a[1..]; |
} |
private int|array internal_tag_select(string t, mapping m, string c, string name, multiset(string) value) |
{ |
if(name && m->name!=name) return ({ RXML.t_xml->format_tag(t, m, c) }); |
|
|
|
|
|
|
Regexp r = Regexp( "(.*)<([Oo][Pp][Tt][Ii][Oo][Nn])([^>]*)>(.*)" ); |
array(string) tmp=split_on_option(c,r); |
string ret=tmp[0],nvalue; |
int selected,stop; |
tmp=tmp[1..]; |
|
while(sizeof(tmp)>2) { |
stop=search(tmp[2],"<"); |
if(sscanf(tmp[1],"%*svalue=%s",nvalue)!=2 && |
sscanf(tmp[1],"%*sVALUE=%s",nvalue)!=2) |
nvalue=tmp[2][..stop==-1?sizeof(tmp[2]):stop]; |
else if(!sscanf(nvalue, "\"%s\"", nvalue) && !sscanf(nvalue, "'%s'", nvalue)) |
sscanf(nvalue, "%s%*[ >]", nvalue); |
selected=Regexp(".*[Ss][Ee][Ll][Ee][Cc][Tt][Ee][Dd].*")->match(tmp[1]); |
ret+="<"+tmp[0]+tmp[1]; |
if(value[nvalue] && !selected) ret+=" selected=\"selected\""; |
ret+=">"+tmp[2]; |
if(!Regexp(".*</[Oo][Pp][Tt][Ii][Oo][Nn]")->match(tmp[2])) ret+="</"+tmp[0]+">"; |
tmp=tmp[3..]; |
} |
return ({ RXML.t_xml->format_tag(t, m, ret) }); |
} |
|
string simpletag_default( string t, mapping m, string c, RequestID id) |
{ |
multiset value=(<>); |
if(m->value) value=mkmultiset((m->value||"")/(m->separator||",")); |
if(m->variable) value+=(<RXML.user_get_var(m->variable, m->scope)>); |
if(value==(<>)) return c; |
|
return parse_html(c, (["input":internal_tag_input]), |
(["select":internal_tag_select]), |
m->name, value); |
} |
|
string simpletag_sort(string t, mapping m, string c, RequestID id) |
{ |
if(!m->separator) |
m->separator = "\n"; |
|
string pre="", post=""; |
array lines = c/m->separator; |
|
while(lines[0] == "") |
{ |
pre += m->separator; |
lines = lines[1..]; |
} |
|
while(lines[-1] == "") |
{ |
post += m->separator; |
lines = lines[..sizeof(lines)-2]; |
} |
|
lines=sort(lines); |
|
return pre + (m->reverse?reverse(lines):lines)*m->separator + post; |
} |
|
string simpletag_replace( string tag, mapping m, string cont, RequestID id) |
{ |
switch(m->type) |
{ |
case "word": |
default: |
if(!m->from) return cont; |
return replace(cont,m->from,(m->to?m->to:"")); |
|
case "words": |
if(!m->from) return cont; |
string s=m->separator?m->separator:","; |
array from=(array)(m->from/s); |
array to=(array)(m->to/s); |
|
int balance=sizeof(from)-sizeof(to); |
if(balance>0) to+=allocate(balance,""); |
|
return replace(cont,from,to); |
} |
} |
|
class TagCSet { |
inherit RXML.Tag; |
constant name = "cset"; |
class Frame { |
inherit RXML.Frame; |
array do_return(RequestID id) { |
if( !args->variable ) parse_error("Variable not specified.\n"); |
if(!content) content=""; |
if( args->quote != "none" ) |
content = Roxen.html_decode_string( content ); |
|
RXML.user_set_var(args->variable, content, args->scope); |
return ({ "" }); |
} |
} |
} |
|
class TagColorScope { |
inherit RXML.Tag; |
constant name = "colorscope"; |
|
class Frame { |
inherit RXML.Frame; |
string link, alink, vlink; |
|
#define LOCAL_PUSH(X) if(args->X) { X=RXML_CONTEXT->misc->X; RXML_CONTEXT->misc->X=args->X; } |
array do_enter(RequestID id) { |
Roxen.push_color("colorscope",args,id); |
LOCAL_PUSH(link); |
LOCAL_PUSH(alink); |
LOCAL_PUSH(vlink); |
return 0; |
} |
|
#define LOCAL_POP(X) if(X) RXML_CONTEXT->misc->X=X |
array do_return(RequestID id) { |
Roxen.pop_color("colorscope",id); |
LOCAL_POP(link); |
LOCAL_POP(alink); |
LOCAL_POP(vlink); |
result=content; |
return 0; |
} |
} |
} |
|
|
|
|
class TagHelp { |
inherit RXML.Tag; |
constant name = "help"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit "rxmlhelp"; |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
array tags=map(indices(RXML_CONTEXT->tag_set->get_tag_names()), |
lambda(string tag) { |
if(tag[..3]=="!--#" || !has_value(tag, "#")) |
return tag; |
return ""; |
} ) - ({ "" }); |
tags += map(indices(RXML_CONTEXT->tag_set->get_proc_instr_names()), |
lambda(string tag) { return "<?"+tag+"?>"; } ); |
tags = Array.sort_array(tags, |
lambda(string a, string b) { |
if(a[..4]=="<?") a=a[5..]; |
if(b[..4]=="<?") b=b[5..]; |
if(lower_case(a)==lower_case(b)) return a>b; |
return lower_case(a)>lower_case(b); })-({"\x266a"}); |
string help_for = args->for || id->variables->_r_t_h; |
string ret="<h2>Roxen Interactive RXML Help</h2>"; |
|
if(!help_for) { |
string char; |
ret += "<b>Here is a list of all defined tags. Click on the name to " |
"receive more detailed information. All these tags are also availabe " |
"in the \""+RXML_NAMESPACE+"\" namespace.</b><p>\n"; |
array tag_links; |
|
foreach(tags, string tag) { |
if(tag[0]!='&' && lower_case(tag[0..0])!=char) { |
if(tag_links && char!="/") ret+="<h3>"+upper_case(char)+"</h3>\n<p>"+ |
String.implode_nicely(tag_links)+"</p>"; |
char=lower_case(tag[0..0]); |
tag_links=({}); |
} |
if (tag[0]=='&' && lower_case(tag[5..5])!=char) { |
if(tag_links && char!="/") ret+="<h3>"+upper_case(char)+"</h3>\n<p>"+ |
String.implode_nicely(tag_links)+"</p>"; |
char=lower_case(tag[5..5]); |
tag_links=({}); |
} |
if(tag[0..sizeof(RXML_NAMESPACE)]!=RXML_NAMESPACE+":") { |
string enc=tag; |
if(enc[0..4]=="<?") enc="<?"+enc[5..sizeof(enc)-6]; |
if(undocumented_tags && undocumented_tags[tag]) |
tag_links += ({ tag }); |
else |
tag_links += ({ sprintf("<a href=\"%s?_r_t_h=%s\">%s</a>\n", |
id->not_query, Roxen.http_encode_url(enc), tag) }); |
} |
} |
|
ret+="<h3>"+upper_case(char)+"</h3>\n<p>"+String.implode_nicely(tag_links)+"</p>"; |
|
|
|
|
|
|
|
|
|
|
|
return ({ ret }); |
} |
|
result=ret+find_tag_doc(help_for, id); |
} |
} |
} |
|
class TagNumber { |
inherit RXML.Tag; |
constant name = "number"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
class Frame { |
inherit RXML.Frame; |
array do_return(RequestID id) { |
if(args->type=="roman") return ({ Roxen.int2roman((int)args->num) }); |
if(args->type=="memory") return ({ Roxen.sizetostring((int)args->num) }); |
result=roxen.language(args->lang||args->language|| |
RXML_CONTEXT->misc->theme_language, |
args->type||"number",id)( (int)args->num ); |
} |
} |
} |
|
|
class TagUse { |
inherit RXML.Tag; |
constant name = "use"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
|
private array(string) list_packages() { |
return filter(((get_dir("../local/rxml_packages")||({})) |
|(get_dir("rxml_packages")||({}))), |
lambda( string s ) { |
return s!=".cvsignore" && |
(Stdio.file_size("../local/rxml_packages/"+s)+ |
Stdio.file_size( "rxml_packages/"+s )) > 0; |
}); |
} |
|
private string read_package( string p ) { |
string data; |
p = combine_path("/", p); |
if(file_stat( "../local/rxml_packages/"+p )) |
catch(data=Stdio.File( "../local/rxml_packages/"+p, "r" )->read()); |
if(!data && file_stat( "rxml_packages/"+p )) |
catch(data=Stdio.File( "rxml_packages/"+p, "r" )->read()); |
return data; |
} |
|
private string use_file_doc(string f, string data) { |
string res, doc; |
int help; |
sscanf(data, "%*sdoc=\"%s\"", doc); |
sscanf(data, "%*shelp=%d", help); |
res = "<dt><b>"+f+"</b></dt><dd>"+(doc?doc+"<br />":"")+"</dd>"; |
|
array defs = parse_use_package(data, RXML_CONTEXT); |
cache_set("macrofiles", "|"+f, defs, 300); |
|
array(string) ifs = ({}), tags = ({}); |
|
foreach (indices (defs[0]), string defname) |
if (has_prefix (defname, "if\0")) |
ifs += ({defname[sizeof ("if\0")..]}); |
else if (has_prefix (defname, "tag\0")) |
tags += ({defname[sizeof ("tag\0")..]}); |
|
constant types = ({ "if plugin", "tag", "form variable", "\"var\" scope variable" }); |
|
array pack = ({ifs, tags, indices(defs[1]), indices(defs[2])}); |
|
for(int i; i<3; i++) |
if(sizeof(pack[i])) { |
res += "Defines the following " + types[i] + (sizeof(pack[i])!=1?"s":"") + |
": " + String.implode_nicely( sort(pack[i]) ) + ".<br />"; |
} |
|
if(help) res+="<br /><br />All tags accept the <i>help</i> attribute."; |
return res; |
} |
|
private array parse_use_package(string data, RXML.Context ctx) { |
RequestID id = ctx->id; |
|
RXML.Parser parser = Roxen.get_rxml_parser (ctx->id); |
parser->write_end (data); |
parser->eval(); |
|
return ({ |
parser->context->misc, |
parser->context->get_scope ("form"), |
parser->context->get_scope ("var") |
}); |
} |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
if(args->packageinfo) { |
NOCACHE(); |
string res ="<dl>"; |
foreach(list_packages(), string f) |
res += use_file_doc(f, read_package( f )); |
return ({ res+"</dl>" }); |
} |
|
if(!args->file && !args->package) |
parse_error("No file or package selected.\n"); |
|
array res; |
string name, filename; |
if(args->file) |
{ |
filename = Roxen.fix_relative(args->file, id); |
name = id->conf->get_config_id() + "|" + filename; |
} |
else |
name = "|" + args->package; |
RXML.Context ctx = RXML_CONTEXT; |
|
if(args->info || id->pragma["no-cache"] || |
!(res=cache_lookup("macrofiles",name)) ) { |
|
string file; |
if(filename) |
file = id->conf->try_get_file( filename, id ); |
else |
file = read_package( args->package ); |
|
if(!file) |
run_error("Failed to fetch "+(args->file||args->package)+".\n"); |
|
if( args->info ) |
return ({"<dl>"+use_file_doc( args->file || args->package, file )+"</dl>"}); |
|
res = parse_use_package(file, ctx); |
cache_set("macrofiles", name, res); |
} |
|
[mapping(string:mixed) newdefs, |
mapping(string:mixed)|RXML.Scope formvars, |
mapping(string:mixed)|RXML.Scope varvars] = res; |
foreach (indices (newdefs), string defname) { |
mixed def = ctx->misc[defname] = newdefs[defname]; |
if (has_prefix (defname, "tag\0")) ctx->add_runtime_tag (def[3]); |
} |
foreach(indices(formvars), string var) |
ctx->set_var(var, formvars[var], "form"); |
foreach(indices(varvars), string var) |
ctx->set_var(var, varvars[var], "var"); |
|
return 0; |
} |
} |
} |
|
class UserTagContents |
{ |
inherit RXML.Tag; |
constant name = "contents"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
array(RXML.Type) result_types = ({RXML.t_any (RXML.PXml)}); |
|
class Frame |
{ |
inherit RXML.Frame; |
constant is_user_tag_contents = 1; |
RXML.Frame frame; |
|
array do_return() |
{ |
RXML.Context ctx = RXML_CONTEXT; |
RXML.Frame upframe; |
if (frame) upframe = frame->up; |
else { |
int nest = 1; |
upframe = up; |
for (; upframe; frame = upframe, upframe = upframe->up) |
if (upframe->is_user_tag) { |
if (!--nest) break; |
} |
else if (upframe->is_user_tag_contents) nest++; |
} |
if (!upframe) |
parse_error ("No associated defined tag to get contents from.\n"); |
|
array ret = upframe->user_tag_contents; |
|
if (ctx->scopes == upframe->saved_scopes) |
ret[1] = RXML.nil; |
else { |
|
|
ret[1] = lambda (mapping(string:mixed) old_scopes, |
mapping(RXML.Frame:array) old_hidden) |
{ |
|
|
return lambda() |
{ |
RXML_CONTEXT->scopes = old_scopes; |
RXML_CONTEXT->hidden = old_hidden; |
return RXML.nil; |
}; |
} (ctx->scopes, ctx->hidden); |
ctx->scopes = upframe->saved_scopes; |
ctx->hidden = upframe->saved_hidden; |
} |
|
if (upframe->compile) flags |= RXML.FLAG_COMPILE_RESULT; |
return ret; |
} |
} |
} |
|
private RXML.TagSet user_tag_contents_tag_set = |
RXML.shared_tag_set ("/rxmltags/user_tag", ({UserTagContents()})); |
|
class UserTag { |
inherit RXML.Tag; |
string name, lookup_name; |
int flags = RXML.FLAG_COMPILE_RESULT; |
RXML.Type content_type = RXML.t_xml; |
array(RXML.Type) result_types = ({ RXML.t_any(RXML.PXml) }); |
|
|
|
|
|
|
|
|
void create(string _name, int tag) { |
if (_name) { |
name=_name; |
lookup_name = "tag\0" + name; |
if(tag) flags |= RXML.FLAG_EMPTY_ELEMENT; |
} |
} |
|
mixed _encode() |
{ |
return ({ name, flags }); |
} |
|
void _decode(mixed v) |
{ |
[name, flags] = v; |
lookup_name = "tag\0" + name; |
} |
|
class Frame { |
inherit RXML.Frame; |
RXML.TagSet additional_tags = user_tag_contents_tag_set; |
string scope_name; |
mapping vars; |
string raw_tag_text; |
int do_iterate; |
|
constant is_user_tag = 1; |
string content_text; |
array(string|RXML.PCode) user_tag_contents; |
mapping(string:mixed) saved_scopes; |
mapping(RXML.Frame:array) saved_hidden; |
int compile; |
|
array do_enter (RequestID id) |
{ |
vars = 0; |
do_iterate = content_text ? -1 : 1; |
return 0; |
} |
|
array do_return(RequestID id) { |
RXML.Context ctx = RXML_CONTEXT; |
array tagdef = ctx->misc[lookup_name]; |
if (!tagdef) return ({propagate_tag()}); |
|
[array(string|RXML.PCode) def, mapping defaults, |
string def_scope_name, UserTag ignored] = tagdef; |
id->misc->last_tag_args = vars = defaults+args; |
scope_name = def_scope_name || name; |
|
if (content_text) |
|
content = content_text; |
else { |
if(content && args->trimwhites) |
content = String.trim_all_whites(content); |
|
if (stringp (def[0])) { |
#if ROXEN_COMPAT <= 1.3 |
if(id->conf->old_rxml_compat) { |
array replace_from, replace_to; |
if (flags & RXML.FLAG_EMPTY_ELEMENT) { |
replace_from = map(indices(vars),Roxen.make_entity)+ |
({"#args#"}); |
replace_to = values(vars)+ |
({ Roxen.make_tag_attributes(vars)[1..] }); |
} |
else { |
replace_from = map(indices(vars),Roxen.make_entity)+ |
({"#args#", "<contents>"}); |
replace_to = values(vars)+ |
({ Roxen.make_tag_attributes(vars)[1..], content }); |
} |
string c2; |
c2 = replace(def[0], replace_from, replace_to); |
if(c2!=def[0]) { |
vars=([]); |
return ({c2}); |
} |
} |
#endif |
} |
content_text = content; |
user_tag_contents = ({content || RXML.nil, 0}); |
compile = ctx->make_p_code; |
} |
|
vars->args = Roxen.make_tag_attributes(vars)[1..]; |
vars["rest-args"] = Roxen.make_tag_attributes(args - defaults)[1..]; |
vars->contents = content_text; |
|
if (compat_level > 2.1) { |
|
|
|
|
saved_scopes = ctx->scopes + ([]); |
saved_hidden = ctx->hidden + ([]); |
} |
else saved_scopes = ctx->scopes; |
|
return def; |
} |
|
array save() {return ({content_text, user_tag_contents});} |
void restore (array saved) {[content_text, user_tag_contents] = saved;} |
} |
} |
|
class TagDefine { |
inherit RXML.Tag; |
constant name = "define"; |
constant flags = RXML.FLAG_DONT_REPORT_ERRORS; |
RXML.Type content_type = RXML.t_xml (RXML.PXml); |
array(RXML.Type) result_types = ({RXML.t_nil}); |
|
class Frame { |
inherit RXML.Frame; |
array(string|RXML.PCode) def; |
mapping defaults; |
int do_iterate; |
|
array do_enter(RequestID id) { |
if (def) |
|
do_iterate = -1; |
else { |
do_iterate = 1; |
if(args->preparse) |
m_delete(args, "preparse"); |
else |
content_type = RXML.t_xml; |
} |
return 0; |
} |
|
array do_return(RequestID id) { |
string n; |
RXML.Context ctx = RXML_CONTEXT; |
|
if(n=args->variable) { |
if(args->trimwhites) content=String.trim_all_whites((string)content); |
RXML.user_set_var(n, content, args->scope); |
return 0; |
} |
|
if (n=args->tag||args->container) { |
#if ROXEN_COMPAT <= 1.3 |
n = id->conf->old_rxml_compat?lower_case(n):n; |
#endif |
int tag=0; |
if(args->tag) { |
tag=1; |
m_delete(args, "tag"); |
} else |
m_delete(args, "container"); |
|
if (!def) { |
defaults=([]); |
|
#if ROXEN_COMPAT <= 1.3 |
if(id->conf->old_rxml_compat) |
foreach( indices(args), string arg ) |
if( arg[..7] == "default_" ) |
{ |
defaults[arg[8..]] = args[arg]; |
old_rxml_warning(id, "define attribute "+arg,"attrib container"); |
m_delete( args, arg ); |
} |
#endif |
|
if(!content) content = ""; |
|
string add_default(Parser.HTML p, mapping m, string c) { |
if(m->name) defaults[m->name]=Roxen.parse_rxml(c, id); |
return ""; |
}; |
|
if( compat_level > 2.1 ) { |
Parser.HTML p = Roxen.get_xml_parser(); |
p->add_container ("attrib", add_default); |
array no_more_attrib (Parser.HTML p, void|string ignored) |
{ |
p->add_container ("attrib", 0); |
p->_set_tag_callback (0); |
p->_set_data_callback (0); |
p->add_quote_tag ("?", 0, "?"); |
p->add_quote_tag ("![CDATA[", 0, "]]"); |
return 0; |
}; |
|
|
p->_set_tag_callback (no_more_attrib); |
p->_set_data_callback (lambda (Parser.HTML p, string d) { |
sscanf (d, "%[ \t\n\r]", string ws); |
if (d != ws) no_more_attrib (p); |
return 0; |
}); |
p->add_quote_tag ("?", no_more_attrib, "?"); |
p->add_quote_tag ("![CDATA[", no_more_attrib, "]]"); |
content = p->finish (content)->read(); |
} |
else |
content = Parser.HTML()->add_container("attrib", add_default)-> |
finish(content)->read(); |
|
if(args->trimwhites) { |
content=String.trim_all_whites(content); |
m_delete (args, "trimwhites"); |
} |
|
#if ROXEN_COMPAT <= 1.3 |
if(id->conf->old_rxml_compat) |
content = replace( content, indices(args), values(args) ); |
#endif |
def = ({content}); |
} |
|
string lookup_name = "tag\0" + n; |
array oldtagdef; |
UserTag user_tag; |
if ((oldtagdef = ctx->misc[lookup_name]) && |
!((user_tag = oldtagdef[3])->flags & RXML.FLAG_EMPTY_ELEMENT) == |
!tag) |
ctx->misc[lookup_name] = ({def, defaults, args->scope, user_tag}); |
else { |
user_tag = UserTag (n, tag); |
ctx->misc[lookup_name] = ({def, defaults, args->scope, user_tag}); |
ctx->add_runtime_tag(user_tag); |
} |
return 0; |
} |
|
if (n=args->if) { |
ctx->misc["if\0" + n] = UserIf (n, content); |
return 0; |
} |
|
if (n=args->name) { |
ctx->misc[n]=content; |
old_rxml_warning(id, "attempt to define name ","variable"); |
return 0; |
} |
|
parse_error("No tag, variable, if or container specified.\n"); |
} |
|
array save() {return ({def, defaults});} |
void restore (array saved) {[def, defaults] = saved;} |
} |
} |
|
class TagUndefine { |
inherit RXML.Tag; |
int flags = RXML.FLAG_EMPTY_ELEMENT; |
constant name = "undefine"; |
class Frame { |
inherit RXML.Frame; |
array do_enter(RequestID id) { |
string n; |
|
if(n=args->variable) { |
RXML_CONTEXT->user_delete_var(n, args->scope); |
return 0; |
} |
|
if (n=args->tag||args->container) { |
m_delete (RXML_CONTEXT->misc, "tag\0" + n); |
RXML_CONTEXT->remove_runtime_tag(n); |
return 0; |
} |
|
if (n=args->if) { |
m_delete(RXML_CONTEXT->misc, "if\0" + n); |
return 0; |
} |
|
if (n=args->name) { |
m_delete(RXML_CONTEXT->misc, args->name); |
return 0; |
} |
|
parse_error("No tag, variable, if or container specified.\n"); |
} |
} |
} |
|
class Tracer (Configuration conf) |
{ |
|
|
string resolv="<ol>"; |
int level; |
|
string _sprintf() |
{ |
return "Tracer()"; |
} |
|
#if constant (gethrtime) |
mapping et = ([]); |
#endif |
#if constant (gethrvtime) |
mapping et2 = ([]); |
#endif |
|
local void start_clock() |
{ |
#if constant (gethrvtime) |
et2[level] = gethrvtime(); |
#endif |
#if constant (gethrtime) |
et[level] = gethrtime(); |
#endif |
} |
|
local string stop_clock() |
{ |
string res; |
#if constant (gethrtime) |
res = sprintf("%.5f", (gethrtime() - et[level])/1000000.0); |
#else |
res = ""; |
#endif |
#if constant (gethrvtime) |
res += sprintf(" (CPU = %.2f)", (gethrvtime() - et2[level])/1000000.0); |
#endif |
return res; |
} |
|
void trace_enter_ol(string type, function|object thing) |
{ |
level++; |
|
if (thing) { |
string name = Roxen.get_modfullname (Roxen.get_owning_module (thing)); |
if (name) |
name = "module " + name; |
else if (this_program conf = Roxen.get_owning_config (thing)) |
name = "configuration " + Roxen.html_encode_string (conf->query_name()); |
else |
name = Roxen.html_encode_string (sprintf ("object %O", thing)); |
type += " in " + name; |
} |
|
string efont="", font=""; |
if(level>2) {efont="</font>";font="<font size=-1>";} |
|
resolv += font + "<li><b>»</b> " + type + "<ol>" + efont; |
start_clock(); |
} |
|
void trace_leave_ol(string desc) |
{ |
level--; |
|
string efont="", font=""; |
if(level>1) {efont="</font>";font="<font size=-1>";} |
|
resolv += "</ol>" + font; |
if (sizeof (desc)) |
resolv += "<b>«</b> " + Roxen.html_encode_string(desc); |
string time = stop_clock(); |
if (sizeof (time)) { |
if (sizeof (desc)) resolv += "<br />"; |
resolv += "<i>Time: " + time + "</i>"; |
} |
resolv += efont + "</li>\n"; |
} |
|
string res() |
{ |
while(level>0) trace_leave_ol(""); |
return resolv + "</ol>"; |
} |
} |
|
class TagTrace { |
inherit RXML.Tag; |
constant name = "trace"; |
|
class Frame { |
inherit RXML.Frame; |
function a,b; |
Tracer t; |
|
array do_enter(RequestID id) { |
NOCACHE(); |
t = Tracer(id->conf); |
a = id->misc->trace_enter; |
b = id->misc->trace_leave; |
id->misc->trace_enter = t->trace_enter_ol; |
id->misc->trace_leave = t->trace_leave_ol; |
t->start_clock(); |
return 0; |
} |
|
array do_return(RequestID id) { |
id->misc->trace_enter = a; |
id->misc->trace_leave = b; |
result = "<h3>Tracing</h3>" + content + |
"<h3>Trace report</h3>" + t->res(); |
string time = t->stop_clock(); |
if (sizeof (time)) |
result += "<h3>Total time: " + time + "</h3>"; |
return 0; |
} |
} |
} |
|
class TagNoParse { |
inherit RXML.Tag; |
constant name = "noparse"; |
RXML.Type content_type = RXML.t_same; |
class Frame { |
inherit RXML.Frame; |
} |
} |
|
class TagPINoParse { |
inherit TagNoParse; |
constant flags = RXML.FLAG_PROC_INSTR; |
class Frame { |
inherit RXML.Frame; |
array do_return(RequestID id) { |
result = content[1..]; |
return 0; |
} |
} |
} |
|
class TagPICData |
{ |
inherit RXML.Tag; |
constant name = "cdata"; |
constant flags = RXML.FLAG_PROC_INSTR; |
RXML.Type content_type = RXML.t_text; |
class Frame |
{ |
inherit RXML.Frame; |
array do_return (RequestID id) |
{ |
result_type = RXML.t_text; |
result = content[1..]; |
return 0; |
} |
} |
} |
|
class TagEval { |
inherit RXML.Tag; |
constant name = "eval"; |
array(RXML.Type) result_types = ({ RXML.t_any(RXML.PXml) }); |
|
class Frame { |
inherit RXML.Frame; |
array do_return(RequestID id) { |
return ({ content }); |
} |
} |
} |
|
class TagNoOutput { |
inherit RXML.Tag; |
constant name = "nooutput"; |
constant flags = RXML.FLAG_DONT_REPORT_ERRORS; |
|
class Frame { |
inherit RXML.Frame; |
array do_process() { |
return ({""}); |
} |
} |
} |
|
class TagStrLen { |
inherit RXML.Tag; |
constant name = "strlen"; |
constant flags = RXML.FLAG_DONT_REPORT_ERRORS; |
|
class Frame { |
inherit RXML.Frame; |
array do_return() { |
if(!stringp(content)) { |
result="0"; |
return 0; |
} |
result = (string)strlen(content); |
} |
} |
} |
|
class TagCase { |
inherit RXML.Tag; |
constant name = "case"; |
|
mapping(string:RXML.Type) req_arg_types = (["case": RXML.t_xml (RXML.PEnt)]); |
|
class Frame { |
inherit RXML.Frame; |
int cap; |
array do_enter() {cap = 0; return 0;} |
array do_process(RequestID id) { |
if(args->case) { |
string op; |
switch(lower_case(args->case)) { |
case "lower": |
if (content_type->lower_case) |
return ({content_type->lower_case (content)}); |
op = "lowercased"; |
break; |
case "upper": |
if (content_type->upper_case) |
return ({content_type->upper_case (content)}); |
op = "uppercased"; |
break; |
case "capitalize": |
if (content_type->capitalize) { |
if(cap) return ({content}); |
if (sizeof (content)) cap=1; |
return ({content_type->capitalize (content)}); |
} |
op = "capitalized"; |
break; |
default: |
|
parse_error ("Invalid value %O to the case argument.\n", args->case); |
} |
|
parse_error ("Content of type %s doesn't handle being %s.\n", |
content_type->name, op); |
} |
|
#if ROXEN_COMPAT <= 1.3 |
if(args->lower) { |
content = lower_case(content); |
old_rxml_warning(id, "attribute lower","case=lower"); |
} |
if(args->upper) { |
content = upper_case(content); |
old_rxml_warning(id, "attribute upper","case=upper"); |
} |
if(args->capitalize){ |
content = capitalize(content); |
old_rxml_warning(id, "attribute capitalize","case=capitalize"); |
} |
#endif |
return ({ content }); |
} |
} |
} |
|
class FrameIf { |
inherit RXML.Frame; |
int do_iterate; |
|
array do_enter(RequestID id) { |
int and = 1; |
do_iterate = -1; |
|
if(args->not) { |
m_delete(args, "not"); |
do_enter(id); |
do_iterate=do_iterate==1?-1:1; |
return 0; |
} |
|
if(args->or) { and = 0; m_delete( args, "or" ); } |
if(args->and) { and = 1; m_delete( args, "and" ); } |
mapping plugins=get_plugins(); |
mapping(string:mixed) defs = RXML_CONTEXT->misc; |
|
int ifval=0; |
foreach(indices (args), string s) |
if (object(RXML.Tag)|object(UserIf) plugin = |
plugins[s] || defs["if\0" + s]) { |
ifval = plugin->eval( args[s], id, args, and, s ); |
if(ifval) { |
if(!and) { |
do_iterate = 1; |
return 0; |
} |
} |
else |
if(and) |
return 0; |
} |
if(ifval) { |
do_iterate = 1; |
return 0; |
} |
return 0; |
} |
|
array do_return(RequestID id) { |
if(do_iterate==1) { |
_ok = 1; |
result = content; |
} |
else |
_ok = 0; |
return 0; |
} |
} |
|
class TagIf { |
inherit RXML.Tag; |
constant name = "if"; |
constant flags = RXML.FLAG_SOCKET_TAG; |
array(RXML.Type) result_types = ({RXML.t_any}); |
program Frame = FrameIf; |
} |
|
class TagElse { |
inherit RXML.Tag; |
constant name = "else"; |
constant flags = 0; |
array(RXML.Type) result_types = ({RXML.t_any}); |
class Frame { |
inherit RXML.Frame; |
int do_iterate; |
array do_enter(RequestID id) { |
do_iterate= _ok ? -1 : 1; |
return 0; |
} |
} |
} |
|
class TagThen { |
inherit RXML.Tag; |
constant name = "then"; |
constant flags = 0; |
array(RXML.Type) result_types = ({RXML.t_any}); |
class Frame { |
inherit RXML.Frame; |
int do_iterate; |
array do_enter(RequestID id) { |
do_iterate= _ok ? 1 : -1; |
return 0; |
} |
} |
} |
|
class TagElseif { |
inherit RXML.Tag; |
constant name = "elseif"; |
array(RXML.Type) result_types = ({RXML.t_any}); |
|
class Frame { |
inherit FrameIf; |
int last; |
|
array do_enter(RequestID id) { |
last=_ok; |
do_iterate = -1; |
if(last) return 0; |
return ::do_enter(id); |
} |
|
array do_return(RequestID id) { |
if(last) return 0; |
return ::do_return(id); |
} |
|
mapping(string:RXML.Tag) get_plugins() { |
return RXML_CONTEXT->tag_set->get_plugins ("if"); |
} |
} |
} |
|
class TagTrue { |
inherit RXML.Tag; |
constant name = "true"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
array(RXML.Type) result_types = ({RXML.t_nil}); |
|
class Frame { |
inherit RXML.Frame; |
array do_enter(RequestID id) { |
_ok = 1; |
} |
} |
} |
|
class TagFalse { |
inherit RXML.Tag; |
constant name = "false"; |
constant flags = RXML.FLAG_EMPTY_ELEMENT; |
array(RXML.Type) result_types = ({RXML.t_nil}); |
class Frame { |
inherit RXML.Frame; |
array do_enter(RequestID id) { |
_ok = 0; |
} |
} |
} |
|
class TagCond |
{ |
inherit RXML.Tag; |
constant name = "cond"; |
RXML.Type content_type = RXML.t_nil (RXML.PXml); |
array(RXML.Type) result_types = ({RXML.t_any}); |
|
class TagCase |
{ |
inherit RXML.Tag; |
constant name = "case"; |
array(RXML.Type) result_types = ({RXML.t_nil}); |
|
class Frame |
{ |
inherit FrameIf; |
|
array do_enter (RequestID id) |
{ |
do_iterate = -1; |
if (up->result != RXML.Void) return 0; |
content_type = up->result_type (RXML.PXml); |
return ::do_enter (id); |
} |
|
array do_return (RequestID id) |
{ |
::do_return (id); |
if (up->result != RXML.Void) return 0; |
up->result = result; |
result = RXML.Void; |
return 0; |
} |
|
|
mapping(string:RXML.Tag) get_plugins() |
{return RXML_CONTEXT->tag_set->get_plugins ("if");} |
} |
} |
|
class TagDefault |
{ |
inherit RXML.Tag; |
constant name = "default"; |
array(RXML.Type) result_types = ({RXML.t_nil}); |
|
class Frame |
{ |
inherit RXML.Frame; |
int do_iterate; |
|
array do_enter() |
{ |
if (up->result != RXML.Void) { |
do_iterate = -1; |
return 0; |
} |
do_iterate = 1; |
content_type = up->result_type (RXML.PNone); |
return 0; |
} |
|
array do_return() |
{ |
up->default_data = content; |
return 0; |
} |
} |
} |
|
RXML.TagSet cond_tags = |
RXML.shared_tag_set ("/rxmltags/cond", ({TagCase(), TagDefault()})); |
|
class Frame |
{ |
inherit RXML.Frame; |
RXML.TagSet local_tags = cond_tags; |
string default_data; |
|
array do_return (RequestID id) |
{ |
if (result == RXML.Void && default_data) { |
_ok = 0; |
return ({RXML.parse_frame (result_type (RXML.PXml), default_data)}); |
} |
return 0; |
} |
} |
} |
|
class TagEmit { |
inherit RXML.Tag; |
constant name = "emit"; |
constant flags = RXML.FLAG_SOCKET_TAG|RXML.FLAG_DONT_REPORT_ERRORS; |
mapping(string:RXML.Type) req_arg_types = ([ "source":RXML.t_text(RXML.PEnt) ]); |
mapping(string:RXML.Type) opt_arg_types = ([ "scope":RXML.t_text(RXML.PEnt), |
"maxrows":RXML.t_int(RXML.PEnt), |
"skiprows":RXML.t_int(RXML.PEnt), |
"rowinfo":RXML.t_text(RXML.PEnt), |
"do-once":RXML.t_text(RXML.PEnt), |
"filter":RXML.t_text(RXML.PEnt), |
"sort":RXML.t_text(RXML.PEnt), |
"remainderinfo":RXML.t_text(RXML.PEnt), |
]); |
array(string) emit_args = indices( req_arg_types+opt_arg_types ); |
RXML.Type def_arg_type = RXML.t_text(RXML.PNone); |
array(RXML.Type) result_types = ({RXML.t_any}); |
|
int(0..1) should_filter(mapping vs, mapping filter) { |
RXML.Context ctx = RXML_CONTEXT; |
foreach(indices(filter), string v) { |
string|object val = vs[v]; |
if(objectp(val)) |
val = val->rxml_const_eval ? val->rxml_const_eval(ctx, v, "", RXML.t_text) : |
val->rxml_var_eval(ctx, v, "", RXML.t_text); |
if(!val) |
return 1; |
if(!glob(filter[v], val)) |
return 1; |
} |
return 0; |
} |
|
class TagDelimiter { |
inherit RXML.Tag; |
constant name = "delimiter"; |
|
static int(0..1) more_rows(array|object res, mapping filter) { |
if(objectp(res)) { |
while(res->peek() && should_filter(res->peek(), filter)) |
res->skip_row(); |
return !!res->peek(); |
} |
if(!sizeof(res)) return 0; |
foreach(res[RXML.get_var("real-counter")..], mapping v) { |
if(!should_filter(v, filter)) |
return 1; |
} |
return 0; |
} |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id) { |
object|array res = id->misc->emit_rows; |
if(!id->misc->emit_filter) { |
if( objectp(res) ? res->peek() : |
RXML.get_var("counter") < sizeof(res) ) |
result = content; |
return 0; |
} |
if(id->misc->emit_args->maxrows && |
id->misc->emit_args->maxrows == RXML.get_var("counter")) |
return 0; |
if(more_rows(res, id->misc->emit_filter)) |
result = content; |
return 0; |
} |
} |
} |
|
RXML.TagSet internal = |
RXML.shared_tag_set ("/rxmltags/emit", ({ TagDelimiter() }) ); |
|
|
|
static int compare(mixed a0, mixed b0, string v) { |
RXML.Context ctx; |
|
if(objectp(a0) && a0->rxml_var_eval) { |
if(!ctx) ctx = RXML_CONTEXT; |
a0 = a0->rxml_const_eval ? a0->rxml_const_eval(ctx, v, "", RXML.t_text) : |
a0->rxml_var_eval(ctx, v, "", RXML.t_text); |
} |
else |
a0 = (string)a0; |
|
if(objectp(b0) && b0->rxml_var_eval) { |
if(!ctx) ctx = RXML_CONTEXT; |
b0 = b0->rxml_const_eval ? b0->rxml_const_eval(ctx, v, "", RXML.t_text) : |
b0->rxml_var_eval(ctx, v, "", RXML.t_text); |
} |
else |
b0 = (string)b0; |
|
return compare_iter(a0, b0); |
} |
|
static int compare_iter(string a0,string b0) { |
if (!a0) { |
if (b0) |
return -1; |
return 0; |
} |
|
if (!b0) |
return 1; |
|
string a2="",b2=""; |
int a1,b1; |
sscanf(a0,"%s%d%s",a0,a1,a2); |
sscanf(b0,"%s%d%s",b0,b1,b2); |
if (a0>b0) return 1; |
if (a0<b0) return -1; |
if (a1>b1) return 1; |
if (a1<b1) return -1; |
if (a2==b2) return 0; |
return compare_iter(a2,b2); |
} |
|
class Frame { |
inherit RXML.Frame; |
RXML.TagSet additional_tags = internal; |
string scope_name; |
mapping vars; |
|
|
|
|
array(mapping(string:mixed))|object outer_rows; |
mapping outer_filter; |
mapping outer_args; |
|
object plugin; |
array(mapping(string:mixed))|object res; |
mapping filter; |
|
array expand(object res) { |
array ret = ({}); |
do { |
ret += ({ res->get_row() }); |
} while(ret[-1]!=0); |
return ret[..sizeof(ret)-2]; |
} |
|
array do_enter(RequestID id) { |
if(!(plugin=get_plugins()[args->source])) |
parse_error("The emit source %O doesn't exist.\n", args->source); |
scope_name=args->scope||args->source; |
vars = (["counter":0]); |
|
TRACE_ENTER("Fetch emit dataset for source "+args->source, 0); |
PROF_ENTER( args->source, "emit" ); |
plugin->eval_args( args, 0, 0, emit_args ); |
res = plugin->get_dataset(args, id); |
PROF_LEAVE( args->source, "emit" ); |
TRACE_LEAVE(""); |
|
if(args->skiprows && plugin->skiprows) |
m_delete(args, "skiprows"); |
|
if(args->maxrows && plugin->maxrows) |
m_delete(args, "maxrows"); |
|
|
if(args->filter) { |
array pairs = args->filter / ","; |
filter = ([]); |
foreach( args->filter / ",", string pair) { |
string v,g; |
if( sscanf(pair, "%s=%s", v,g) != 2) |
continue; |
v = String.trim_whites(v); |
if(g != "*"*sizeof(g)) |
filter[v] = g; |
} |
if(!sizeof(filter)) filter = 0; |
} |
|
outer_args = id->misc->emit_args; |
outer_rows = id->misc->emit_rows; |
outer_filter = id->misc->emit_filter; |
id->misc->emit_args = args; |
id->misc->emit_filter = filter; |
|
if(objectp(res)) |
if(args->sort || |
(args->skiprows<0) ) |
res = expand(res); |
else if(filter) { |
do_iterate = object_filter_iterate; |
id->misc->emit_rows = res; |
return 0; |
} |
else { |
do_iterate = object_iterate; |
id->misc->emit_rows = res; |
|
if(args->skiprows) { |
int loop = args->skiprows; |
while(loop--) |
res->skip_row(); |
} |
|
return 0; |
} |
|
if(arrayp(res)) { |
if(args->sort && !plugin->sort) |
{ |
array(string) order = (args->sort - " ")/"," - ({ "" }); |
res = Array.sort_array( res, |
lambda (mapping(string:mixed) m1, |
mapping(string:mixed) m2) |
{ |
foreach (order, string field) |
{ |
int(-1..1) tmp; |
|
if (field[0] == '-') |
tmp = compare( m2[field[1..]], |
m1[field[1..]], |
field ); |
else if (field[0] == '+') |
tmp = compare( m1[field[1..]], |
m2[field[1..]], |
field ); |
else |
tmp = compare( m1[field], m2[field], |
field ); |
|
if (tmp == 1) |
return 1; |
else if (tmp == -1) |
return 0; |
} |
return 0; |
} ); |
} |
|
if(filter) { |
|
|
|
|
if(args->rowinfo || args->skiprows<0) { |
for(int i; i<sizeof(res); i++) |
if(should_filter(res[i], filter)) { |
res = res[..i-1] + res[i+1..]; |
i--; |
} |
filter = 0; |
} |
else { |
|
|
|
|
if(args->skiprows) { |
int skiprows = args->skiprows; |
if(skiprows > sizeof(res)) |
res = ({}); |
else { |
int i; |
for(; i<sizeof(res) && skiprows; i++) |
if(!should_filter(res[i], filter)) |
skiprows--; |
res = res[i..]; |
} |
} |
|
vars["real-counter"] = 0; |
do_iterate = array_filter_iterate; |
} |
} |
|
|
|
if(!filter) { |
|
if(args->skiprows) { |
if(args->skiprows<0) args->skiprows = sizeof(res) + args->skiprows; |
res=res[args->skiprows..]; |