6d754f2001-06-18Martin Stjernholm // This is a roxen module. Copyright © 1996 - 2001, Roxen IS.
4817401999-08-13Martin Nilsson //
6d754f2001-06-18Martin Stjernholm #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"]
4817401999-08-13Martin Nilsson 
e04d4c2001-08-23Per Hedbor constant cvs_version = "$Id: rxmltags.pike,v 1.279 2001/08/23 16:42:47 per Exp $";
0023a62000-08-22Martin Nilsson constant thread_safe = 1;
bfd5fb1999-10-08Martin Nilsson constant language = roxen->language;
4817401999-08-13Martin Nilsson  #include <module.h>
b156c62001-04-23Martin Nilsson #include <config.h> #include <request_trace.h>
4817401999-08-13Martin Nilsson inherit "module";
6743432000-03-19Martin Nilsson 
4817401999-08-13Martin Nilsson  // ---------------- Module registration stuff ----------------
b3281f2000-09-10Martin Nilsson constant module_type = MODULE_TAG | MODULE_PROVIDER;
bc0fa02001-03-08Per Hedbor constant module_name = "Tags: RXML 2 tags";
59ae152000-04-06Mattias Wingstedt constant module_doc = "This module provides the common RXML tags.";
0be6412000-01-18Martin Nilsson 
def33f2001-06-15Jonas Wallden  // Cached copy of conf->query("compat_level"). This setting is defined // to require a module reload to take effect so we only query it when // start() is called.
4fe73e2001-07-11Martin Stjernholm float compat_level;
def33f2001-06-15Jonas Wallden 
16509b1999-12-14Martin Nilsson void start()
659d4b1999-10-18Martin Nilsson {
ecab8b2000-01-23Martin Nilsson  add_api_function("query_modified", api_query_modified, ({ "string" }));
0be6412000-01-18Martin Nilsson  query_tag_set()->prepare_context=set_entities;
4fe73e2001-07-11Martin Stjernholm  compat_level = (float) my_configuration()->query("compat_level");
4817401999-08-13Martin Nilsson }
b7e95b1999-12-14Martin Nilsson string query_provides() { return "modified"; }
1d181a2001-06-08Martin Nilsson private object compile_handler = class { mapping(string:mixed) get_default_module() { return ([ "this_program":0, "`+":`+, "`-":`-, "`*":`*, "`/":`/, "`%":`%,
c1d6b02001-06-25Martin Nilsson  "`!":`!,
1edcd62001-06-25Martin Nilsson  "`!=":`!=,
1d181a2001-06-08Martin Nilsson  "`&":`&, "`|":`|, "`^":`^, "`<":`<, "`>":`>, "`==":`==, "`<=":`<=, "`>=":`>=, "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() }) ); } }();
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson string sexpr_eval(string what) {
1d181a2001-06-08Martin Nilsson  what -= "lambda"; what -= "\""; what -= ";";
c1d6b02001-06-25Martin Nilsson  return compile_string( "int|float foo=" + what + ";",
1d181a2001-06-08Martin Nilsson  0, compile_handler )()->foo;
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson #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
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson // ----------------- Entities ----------------------
e272382000-01-23Kenneth Johansson 
5d10522000-12-15Martin Nilsson class EntityClientTM { inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
da534e2001-03-13Martin Nilsson  c->id->misc->cacheable=0;
9a7cea2001-03-13Martin Nilsson  if(c->id->supports->trade) return ENCODE_RXML_XML("&trade;", type); if(c->id->supports->supsub) return ENCODE_RXML_XML("<sup>TM</sup>", type); return ENCODE_RXML_XML("&lt;TM&gt;", type);
5d10522000-12-15Martin Nilsson  } }
6d7a702000-02-07Martin Nilsson class EntityClientReferrer {
c8164c2000-02-08Martin Nilsson  inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
592ed72000-02-06Martin Nilsson  c->id->misc->cacheable=0; array referrer=c->id->referer;
f55a012001-03-14Martin Stjernholm  return referrer && sizeof(referrer)?ENCODE_RXML_TEXT(referrer[0], type):RXML.nil;
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
6d7a702000-02-07Martin Nilsson class EntityClientName {
c8164c2000-02-08Martin Nilsson  inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
592ed72000-02-06Martin Nilsson  c->id->misc->cacheable=0; array client=c->id->client;
f55a012001-03-14Martin Stjernholm  return client && sizeof(client)?ENCODE_RXML_TEXT(client[0], type):RXML.nil;
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
6d7a702000-02-07Martin Nilsson class EntityClientIP {
c8164c2000-02-08Martin Nilsson  inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
592ed72000-02-06Martin Nilsson  c->id->misc->cacheable=0;
f55a012001-03-14Martin Stjernholm  return ENCODE_RXML_TEXT(c->id->remoteaddr, type);
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
6d7a702000-02-07Martin Nilsson class EntityClientAcceptLanguage {
c8164c2000-02-08Martin Nilsson  inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
592ed72000-02-06Martin Nilsson  c->id->misc->cacheable=0;
9a7cea2001-03-13Martin Nilsson  if(!c->id->misc["accept-language"]) return RXML.nil;
f55a012001-03-14Martin Stjernholm  return ENCODE_RXML_TEXT(c->id->misc["accept-language"][0], type);
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
6d7a702000-02-07Martin Nilsson class EntityClientAcceptLanguages {
c8164c2000-02-08Martin Nilsson  inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
592ed72000-02-06Martin Nilsson  c->id->misc->cacheable=0;
9a7cea2001-03-13Martin Nilsson  if(!c->id->misc["accept-language"]) return RXML.nil; // FIXME: Should this be an array instead?
f55a012001-03-14Martin Stjernholm  return ENCODE_RXML_TEXT(c->id->misc["accept-language"]*", ", type);
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
6d7a702000-02-07Martin Nilsson class EntityClientLanguage {
c8164c2000-02-08Martin Nilsson  inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
592ed72000-02-06Martin Nilsson  c->id->misc->cacheable=0;
9a7cea2001-03-13Martin Nilsson  if(!c->id->misc->pref_languages) return RXML.nil;
f55a012001-03-14Martin Stjernholm  return ENCODE_RXML_TEXT(c->id->misc->pref_languages->get_language(), type);
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
6d7a702000-02-07Martin Nilsson class EntityClientLanguages {
c8164c2000-02-08Martin Nilsson  inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
592ed72000-02-06Martin Nilsson  c->id->misc->cacheable=0;
9a7cea2001-03-13Martin Nilsson  if(!c->id->misc->pref_languages) return RXML.nil; // FIXME: Should this be an array instead?
f55a012001-03-14Martin Stjernholm  return ENCODE_RXML_TEXT(c->id->misc->pref_languages->get_languages()*", ", type);
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
5b04132000-07-02Martin Nilsson class EntityClientHost { inherit RXML.Value;
9a7cea2001-03-13Martin Nilsson  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
5b04132000-07-02Martin Nilsson  c->id->misc->cacheable=0;
f55a012001-03-14Martin Stjernholm  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),
9a7cea2001-03-13Martin Nilsson  type);
5b04132000-07-02Martin Nilsson  } }
0628f32000-08-23Martin Nilsson class EntityClientAuthenticated { inherit RXML.Value;
0764862001-03-16Per Hedbor  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { // Actually, it is cacheable, but _only_ if there is no authentication.
f0e7ee2000-08-23Martin Nilsson  c->id->misc->cacheable=0;
0764862001-03-16Per Hedbor  return ENCODE_RXML_INT(!!c->id->conf->authenticate( c->id ), type );
0628f32000-08-23Martin Nilsson  } } class EntityClientUser { inherit RXML.Value;
0764862001-03-16Per Hedbor  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) { User u = c->id->conf->authenticate( c->id );
f0e7ee2000-08-23Martin Nilsson  c->id->misc->cacheable=0;
0764862001-03-16Per Hedbor  if(!u) return RXML.nil; return ENCODE_RXML_TEXT(u->name(), type);
0628f32000-08-23Martin Nilsson  } } class EntityClientPassword { inherit RXML.Value;
0764862001-03-16Per Hedbor  mixed rxml_const_eval(RXML.Context c, string var, string scope_name, void|RXML.Type type) {
0628f32000-08-23Martin Nilsson  array tmp;
f0e7ee2000-08-23Martin Nilsson  c->id->misc->cacheable=0;
0764862001-03-16Per Hedbor  if( c->id->realauth
6bfea42001-02-11Martin Nilsson  && (sizeof(tmp = c->id->realauth/":") > 1) )
f55a012001-03-14Martin Stjernholm  return ENCODE_RXML_TEXT(tmp[1..]*":", type);
9a7cea2001-03-13Martin Nilsson  return RXML.nil;
0628f32000-08-23Martin Nilsson  } }
dcc11b2001-05-30Martin Nilsson mapping client_scope = ([
916f4e2000-03-13Martin Nilsson  "ip":EntityClientIP(), "name":EntityClientName(), "referrer":EntityClientReferrer(), "accept-language":EntityClientAcceptLanguage(), "accept-languages":EntityClientAcceptLanguages(), "language":EntityClientLanguage(), "languages":EntityClientLanguages(),
5b04132000-07-02Martin Nilsson  "host":EntityClientHost(),
0628f32000-08-23Martin Nilsson  "authenticated":EntityClientAuthenticated(), "user":EntityClientUser(), "password":EntityClientPassword(),
5d10522000-12-15Martin Nilsson  "tm":EntityClientTM(),
916f4e2000-03-13Martin Nilsson ]);
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson void set_entities(RXML.Context c) { c->extend_scope("client", client_scope);
d0aab92001-08-22Martin Stjernholm  if (!c->id->misc->cache_tag_miss)
4063572001-08-22Martin Stjernholm  c->id->cache_status["cachetag"] = 1;
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson // ------------------- Tags ------------------------
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson class TagRoxenACV { inherit RXML.Tag; constant name = "roxen-automatic-charset-variable";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  class Frame { inherit RXML.Frame; constant magic=
0f31032000-12-12Martin Nilsson  "<input type=\"hidden\" name=\"magic_roxen_automatic_charset_variable\" value=\"åäö\" />";
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  array do_return(RequestID id) { result=magic; } } }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson class TagAppend { inherit RXML.Tag; constant name = "append";
89034d2000-07-17Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "variable" : RXML.t_text(RXML.PEnt) ]);
5952fd2001-04-25Martin Nilsson  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}); // No result. int flags;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
5952fd2001-04-25Martin Nilsson  array do_enter (RequestID id) {
806aaf2001-06-28Martin Stjernholm  if (args->value || args->from) flags |= RXML.FLAG_EMPTY_ELEMENT;
5952fd2001-04-25Martin Nilsson  if (args->type) content_type = args->type (RXML.PXml); }
592ed72000-02-06Martin Nilsson  array do_return(RequestID id) {
6444372000-03-10Martin Nilsson  mixed value=RXML.user_get_var(args->variable, args->scope);
592ed72000-02-06Martin Nilsson  if (args->value) {
5952fd2001-04-25Martin Nilsson  content = args->value;
4704942001-07-20Martin Stjernholm  if (args->type) content = args->type->encode (content);
592ed72000-02-06Martin Nilsson  }
5952fd2001-04-25Martin Nilsson  else if (args->from) {
592ed72000-02-06Martin Nilsson  // Append the value of another entity variable.
6444372000-03-10Martin Nilsson  mixed from=RXML.user_get_var(args->from, args->scope);
d2e6022001-04-18Martin Stjernholm  if(!from) parse_error("From variable %O doesn't exist.\n", args->from);
592ed72000-02-06Martin Nilsson  if (value) value+=from; else value=from;
6444372000-03-10Martin Nilsson  RXML.user_set_var(args->variable, value, args->scope);
592ed72000-02-06Martin Nilsson  return 0; }
5952fd2001-04-25Martin Nilsson  // Append a value to an entity variable. if (value) value+=content; else value=content; RXML.user_set_var(args->variable, value, args->scope);
592ed72000-02-06Martin Nilsson  } } }
e272382000-01-23Kenneth Johansson 
2e777e2000-06-09Martin Nilsson 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) {
dcc11b2001-05-30Martin Nilsson  mapping hdrs = Roxen.http_auth_required (args->realm||"document access", args->message);
2e777e2000-06-09Martin Nilsson  if (hdrs->error) _error = hdrs->error; if (hdrs->extra_heads) _extra_heads += hdrs->extra_heads; // We do not need this as long as hdrs only contains strings and numbers // foreach(indices(hdrs->extra_heads), string tmp) // Roxen.add_http_header(_extra_heads, tmp, hdrs->extra_heads[tmp]); if (hdrs->text) _rettext = hdrs->text; return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagExpireTime { inherit RXML.Tag; constant name = "expire-time"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  array do_return(RequestID id) { int t,t2;
7f6e242000-11-15Stefan Wallström  t=t2=time(1);
7222a22000-06-12Martin Nilsson  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; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagHeader { inherit RXML.Tag; constant name = "header"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
7078eb2001-05-18Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "name": RXML.t_text(RXML.PEnt), "value": RXML.t_text(RXML.PEnt) ]);
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  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; }
592ed72000-02-06Martin Nilsson  }
7222a22000-06-12Martin Nilsson } class TagRedirect { inherit RXML.Tag; constant name = "redirect"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
7078eb2001-05-18Martin Nilsson  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) ]);
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) {
7078eb2001-05-18Martin Nilsson  multiset(string) prestate = (<>);
21eeb02001-05-22Martin Nilsson  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"])
7078eb2001-05-18Martin Nilsson  prestate += id->prestate;
7222a22000-06-12Martin Nilsson 
cc3a942000-09-24Martin Nilsson  if(args->add) foreach((m_delete(args,"add") - " ")/",", string s)
7222a22000-06-12Martin Nilsson  prestate[s]=1;
cc3a942000-09-24Martin Nilsson  if(args->drop) foreach((m_delete(args,"drop") - " ")/",", string s)
7222a22000-06-12Martin Nilsson  prestate[s]=0;
d0f4f92001-05-16Martin Nilsson  mapping r = Roxen.http_redirect(args->to, id, prestate);
7222a22000-06-12Martin Nilsson  if (r->error) _error = r->error; if (r->extra_heads) _extra_heads += r->extra_heads; // We do not need this as long as r only contains strings and numbers // foreach(indices(r->extra_heads), string tmp) // Roxen.add_http_header(_extra_heads, tmp, r->extra_heads[tmp]); if (args->text) _rettext = args->text; return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson class TagUnset { inherit RXML.Tag; constant name = "unset";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
6660b42001-03-13Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) { if(!args->variable && !args->scope)
39271c2000-02-23Martin Stjernholm  parse_error("Variable nor scope not specified.\n");
592ed72000-02-06Martin Nilsson  if(!args->variable && args->scope!="roxen") {
6d754f2001-06-18Martin Stjernholm  RXML_CONTEXT->add_scope(args->scope, ([]) );
592ed72000-02-06Martin Nilsson  return 0; }
6d754f2001-06-18Martin Stjernholm  RXML_CONTEXT->user_delete_var(args->variable, args->scope);
592ed72000-02-06Martin Nilsson  return 0; } } }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson class TagSet { inherit RXML.Tag; constant name = "set";
89034d2000-07-17Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "variable": RXML.t_text(RXML.PEnt) ]);
d2e6022001-04-18Martin Stjernholm  mapping(string:RXML.Type) opt_arg_types = ([ "type": RXML.t_type(RXML.PEnt) ]);
4769122001-03-12Martin Stjernholm  RXML.Type content_type = RXML.t_any (RXML.PXml);
6660b42001-03-13Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
5952fd2001-04-25Martin Nilsson  int flags;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  class Frame { inherit RXML.Frame;
d2e6022001-04-18Martin Stjernholm  array do_enter (RequestID id) {
806aaf2001-06-28Martin Stjernholm  if (args->value || args->expr || args->from) flags |= RXML.FLAG_EMPTY_ELEMENT;
d2e6022001-04-18Martin Stjernholm  if (args->type) content_type = args->type (RXML.PXml); }
592ed72000-02-06Martin Nilsson  array do_return(RequestID id) {
5952fd2001-04-25Martin Nilsson  if (args->value) { content = args->value;
89cf122001-07-20Martin Stjernholm  if (args->type) content = args->type->encode (content);
5952fd2001-04-25Martin Nilsson  }
d2e6022001-04-18Martin Stjernholm  else { if (args->expr) { // Set an entity variable to an evaluated expression. 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) { // Copy a value from another entity variable. 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; }
592ed72000-02-06Martin Nilsson  }
e272382000-01-23Kenneth Johansson 
d2e6022001-04-18Martin Stjernholm  // Set an entity variable to a value.
8d5b812001-07-10Martin Nilsson  if(args->split && content) RXML.user_set_var(args->variable, (string)content/args->split, args->scope);
9a7cea2001-03-13Martin Nilsson  else
d2e6022001-04-18Martin Stjernholm  RXML.user_set_var(args->variable, content, args->scope);
9a7cea2001-03-13Martin Nilsson  return 0;
592ed72000-02-06Martin Nilsson  } } }
e272382000-01-23Kenneth Johansson 
e6227e2001-03-24Martin Nilsson 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) {
6d754f2001-06-18Martin Stjernholm  RXML.Context ctx = RXML_CONTEXT;
e6227e2001-03-24Martin Nilsson  foreach(ctx->list_var(args->from), string var) ctx->set_var(var, ctx->get_var(var, args->from), args->to); } } }
592ed72000-02-06Martin Nilsson class TagInc { inherit RXML.Tag; constant name = "inc";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
1c32782000-08-14Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "variable":RXML.t_text ]);
6660b42001-03-13Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  array do_return(RequestID id) {
1c32782000-08-14Martin Nilsson  int val=(int)args->value; if(!val && !args->value) val=1; inc(args, val, id);
592ed72000-02-06Martin Nilsson  return 0; } } }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson class TagDec { inherit RXML.Tag; constant name = "dec";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
1c32782000-08-14Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "variable":RXML.t_text ]);
6660b42001-03-13Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  array do_return(RequestID id) {
1c32782000-08-14Martin Nilsson  int val=-(int)args->value; if(!val && !args->value) val=-1; inc(args, val, id);
592ed72000-02-06Martin Nilsson  return 0; } } }
e272382000-01-23Kenneth Johansson 
1c32782000-08-14Martin Nilsson static void inc(mapping m, int val, RequestID id)
592ed72000-02-06Martin Nilsson {
6d754f2001-06-18Martin Stjernholm  RXML.Context context=RXML_CONTEXT;
592ed72000-02-06Martin Nilsson  array entity=context->parse_user_var(m->variable, m->scope);
1c32782000-08-14Martin Nilsson  if(!context->exist_scope(entity[0])) RXML.parse_error("Scope "+entity[0]+" does not exist.\n");
592ed72000-02-06Martin Nilsson  context->user_set_var(m->variable, (int)context->user_get_var(m->variable, m->scope)+val, m->scope); }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagImgs { inherit RXML.Tag; constant name = "imgs"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
a4ae902000-05-25Martin Nilsson 
7222a22000-06-12Martin Nilsson  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) {
9c5b0d2000-06-23Martin Stjernholm  file=id->conf->try_get_file(args->src,id);
7222a22000-06-12Martin Nilsson  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) {
01dcee2000-09-05Per Hedbor  string src=(args->src/"/")[-1];
7222a22000-06-12Martin Nilsson  sscanf(src, "internal-roxen-%s", src);
da534e2001-03-13Martin Nilsson  args->alt=String.capitalize(replace(src[..sizeof(src)-search(reverse(src), ".")-2], "_"," "));
7222a22000-06-12Martin Nilsson  }
cc3a942000-09-24Martin Nilsson  int xml=!m_delete(args, "noxml");
0023a62000-08-22Martin Nilsson  result = Roxen.make_tag("img", args, xml);
7222a22000-06-12Martin Nilsson  return 0;
592ed72000-02-06Martin Nilsson  }
7222a22000-06-12Martin Nilsson  RXML.parse_error("No src given.\n");
592ed72000-02-06Martin Nilsson  } } }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagRoxen { inherit RXML.Tag; constant name = "roxen"; constant flags = RXML.FLAG_EMPTY_ELEMENT; class Frame { inherit RXML.Frame; array do_return(RequestID id) {
cc3a942000-09-24Martin Nilsson  string size = m_delete(args, "size") || "medium"; string color = m_delete(args, "color") || "white";
7222a22000-06-12Martin Nilsson  mapping aargs = (["href": "http://www.roxen.com/"]);
cc3a942000-09-24Martin Nilsson 
7222a22000-06-12Martin Nilsson  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";
cc3a942000-09-24Martin Nilsson  int xml=!m_delete(args, "noxml"); if(args->target) aargs->target = m_delete (args, "target");
0023a62000-08-22Martin Nilsson  result = RXML.t_xml->format_tag ("a", aargs, Roxen.make_tag("img", args, xml));
7222a22000-06-12Martin Nilsson  return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson 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; }
403a402000-08-04Martin Stjernholm  if (args->werror) {
004da72001-01-29Per Hedbor  report_debug("%^s%#-1s\n", "<debug>: ", id->conf->query_name()+":"+id->not_query+"\n"+ replace(args->werror,"\\n","\n") );
403a402000-08-04Martin Stjernholm  }
7222a22000-06-12Martin Nilsson  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;
592ed72000-02-06Martin Nilsson  } } }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagFSize { inherit RXML.Tag; constant name = "fsize"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
89034d2000-07-17Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "file" : RXML.t_text(RXML.PEnt) ]);
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) { catch {
1f4a6c2000-08-28Per Hedbor  Stat s=id->conf->stat_file(Roxen.fix_relative( args->file, id ), id);
7222a22000-06-12Martin Nilsson  if (s && (s[1]>= 0)) {
81ba582000-07-25Per Hedbor  result = Roxen.sizetostring(s[1]);
7222a22000-06-12Martin Nilsson  return 0; } };
81ba582000-07-25Per Hedbor  if(string s=id->conf->try_get_file(Roxen.fix_relative(args->file, id), id) ) { result = Roxen.sizetostring(strlen(s));
7222a22000-06-12Martin Nilsson  return 0; } RXML.run_error("Failed to find file.\n"); }
592ed72000-02-06Martin Nilsson  } }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson class TagCoding { inherit RXML.Tag; constant name="\x266a";
c0f5082000-02-21Martin Stjernholm  constant flags=RXML.FLAG_EMPTY_ELEMENT;
592ed72000-02-06Martin Nilsson  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) {
30ce102000-09-16Martin Nilsson  result=map(space, lambda(int|string c) { return intp(c)?(string)({c-(sizeof(space))}):c; } )*"";
592ed72000-02-06Martin Nilsson  } } }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagConfigImage { inherit RXML.Tag; constant name = "configimage"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
89034d2000-07-17Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "src" : RXML.t_text(RXML.PEnt) ]);
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  array do_return(RequestID id) { if (args->src[sizeof(args->src)-4..][0] == '.') args->src = args->src[..sizeof(args->src)-5];
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  args->alt = args->alt || args->src; args->src = "/internal-roxen-" + args->src; args->border = args->border || "0";
cc3a942000-09-24Martin Nilsson  int xml=!m_delete(args, "noxml");
0023a62000-08-22Martin Nilsson  result = Roxen.make_tag("img", args, xml);
7222a22000-06-12Martin Nilsson  return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagDate { inherit RXML.Tag; constant name = "date"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  array do_return(RequestID id) { int t=(int)args["unix-time"] || time(1);
5b04132000-07-02Martin Nilsson  if(args->timezone=="GMT") t += localtime(t)->timezone;
7222a22000-06-12Martin Nilsson  t+=Roxen.time_dequantifier(args);
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  if(!(args->brief || args->time || args->date)) args->full=1;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  if(args->part=="second" || args->part=="beat" || args->strftime) NOCACHE(); else CACHE(60);
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  result = Roxen.tagtime(t, args, id, language); return 0; }
592ed72000-02-06Martin Nilsson  }
7222a22000-06-12Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagInsert { inherit RXML.Tag; constant name = "insert";
8b46c02000-07-25Martin Nilsson  constant flags = RXML.FLAG_EMPTY_ELEMENT | RXML.FLAG_SOCKET_TAG;
4953832000-08-07Martin Nilsson  // FIXME: result_types needs to be updated with all possible outputs // from the plugins.
f155c32000-03-01Martin Nilsson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
8b46c02000-07-25Martin Nilsson  void do_insert(RXML.Tag plugin, string name, RequestID id) { result=plugin->get_data(args[name], args, id);
7222a22000-06-12Martin Nilsson 
4953832000-08-07Martin Nilsson  if(plugin->get_type) result_type=plugin->get_type(args, result);
36274a2000-07-25Martin Nilsson  else if(args->quote=="none")
4953832000-08-07Martin Nilsson  result_type=RXML.t_xml; else if(args->quote=="html") result_type=RXML.t_text;
8b46c02000-07-25Martin Nilsson  else
4953832000-08-07Martin Nilsson  result_type=RXML.t_text;
8b46c02000-07-25Martin Nilsson  }
7222a22000-06-12Martin Nilsson 
8b46c02000-07-25Martin Nilsson  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);
7222a22000-06-12Martin Nilsson  return 0; }
8b46c02000-07-25Martin Nilsson  foreach((array)get_plugins(), [string name, RXML.Tag plugin]) { if(args[name]) { do_insert(plugin, name, id);
7222a22000-06-12Martin Nilsson  return 0; } }
880b6e2000-08-12Martin Nilsson  parse_error("No correct insert attribute given.\n");
8b46c02000-07-25Martin Nilsson  } } } 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);
880b6e2000-08-12Martin Nilsson  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"); }
8b46c02000-07-25Martin Nilsson  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) {
6d754f2001-06-18Martin Stjernholm  RXML.Context context=RXML_CONTEXT;
8b46c02000-07-25Martin Nilsson  if(var=="full")
30ce102000-09-16Martin Nilsson  return map(sort(context->list_var(args->scope)), lambda(string s) {
13b2ac2000-11-24Martin Nilsson  return sprintf("%s=%O", s, context->get_var(s, args->scope) );
30ce102000-09-16Martin Nilsson  } ) * "\n";
8b46c02000-07-25Martin Nilsson  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) {
6d754f2001-06-18Martin Stjernholm  RXML.Context context=RXML_CONTEXT;
8b46c02000-07-25Martin Nilsson  if(var=="full") { string result = ""; foreach(sort(context->list_scopes()), string scope) { result += scope+"\n";
30ce102000-09-16Martin Nilsson  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");
8b46c02000-07-25Martin Nilsson  result += "\n"; } return result; } return String.implode_nicely(sort(context->list_scopes())); } }
e04d4c2001-08-23Per Hedbor class TagInsertLocate { inherit RXML.Tag; constant name= "insert"; constant plugin_name = "locate"; 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) { array(string) result; result = VFS.find_above_read( id->not_query, var, id ); if( !result ) RXML.run_error("Cannot locate any file named "+var+".\n"); return result[1]; } }
8b46c02000-07-25Martin Nilsson class TagInsertFile { inherit RXML.Tag; constant name = "insert"; constant plugin_name = "file";
36274a2000-07-25Martin Nilsson  RXML.Type get_type(mapping args) { if (args->quote=="html") return RXML.t_text; return RXML.t_xml; }
f0d6942001-01-29Per Hedbor  string get_data(string var, mapping args, RequestID id) {
b9bc792000-08-14Martin Stjernholm  string result;
f0d6942001-01-29Per Hedbor  if(args->nocache) // try_get_file never uses the cache any more. CACHE(0); // Should we really enforce CACHE(0) here? result=id->conf->try_get_file(var, id); if( !result ) RXML.run_error("No such file ("+Roxen.fix_relative( var, id )+").\n");
b9bc792000-08-14Martin Stjernholm 
7f64e32001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
4953832000-08-07Martin Nilsson  if(id->conf->old_rxml_compat)
b9bc792000-08-14Martin Stjernholm  return Roxen.parse_rxml(result, id);
c886ad2000-06-13Martin Nilsson #endif
b9bc792000-08-14Martin Stjernholm  return result;
8b46c02000-07-25Martin Nilsson  } }
c886ad2000-06-13Martin Nilsson 
36274a2000-07-25Martin Nilsson class TagInsertRealfile {
8b46c02000-07-25Martin Nilsson  inherit RXML.Tag; constant name = "insert";
36274a2000-07-25Martin Nilsson  constant plugin_name = "realfile";
7222a22000-06-12Martin Nilsson 
8b46c02000-07-25Martin Nilsson  string get_data(string var, mapping args, RequestID id) {
36274a2000-07-25Martin Nilsson  string filename=id->conf->real_file(Roxen.fix_relative(var, id), id);
5ea81a2000-12-04Martin Nilsson  if(!filename) RXML.run_error("Could not find the file %s.\n", Roxen.fix_relative(var, id));
36274a2000-07-25Martin Nilsson  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));
592ed72000-02-06Martin Nilsson  }
7222a22000-06-12Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagReturn { inherit RXML.Tag; constant name = "return"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
e7bf332000-09-05Johan Sundström  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);
7222a22000-06-12Martin Nilsson  return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagSetCookie { inherit RXML.Tag; constant name = "set-cookie"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
e272382000-01-23Kenneth Johansson 
89034d2000-07-17Martin Nilsson  mapping(string:RXML.Type) req_arg_types = ([ "name" : RXML.t_text(RXML.PEnt) ]);
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson  array do_return(RequestID id) { int t;
99ec252000-09-03Per Hedbor  if(args->persistent) t=-1; else t=Roxen.time_dequantifier(args); Roxen.set_cookie( id, args->name, (args->value||""), t, args->domain, args->path );
7222a22000-06-12Martin Nilsson  return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
7222a22000-06-12Martin Nilsson class TagRemoveCookie { inherit RXML.Tag; constant name = "remove-cookie"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
89034d2000-07-17Martin Nilsson  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) ]);
7222a22000-06-12Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) {
99ec252000-09-03Per Hedbor // really... is this error a good idea? I don't think so, it makes // it harder to make pages that use cookies. But I'll let it be for now. // /Per
e272382000-01-23Kenneth Johansson 
99ec252000-09-03Per Hedbor  if(!id->cookies[args->name])
79f7e82000-10-21Martin Nilsson  RXML.run_error("That cookie does not exist.\n");
99ec252000-09-03Per Hedbor  Roxen.remove_cookie( id, args->name, (args->value||id->cookies[args->name]||""), args->domain, args->path );
7222a22000-06-12Martin Nilsson  return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson string tag_modified(string tag, mapping m, RequestID id, Stdio.File file) {
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  if(m->by && !m->file && !m->realfile) { // FIXME: The auth module should probably not be used in this case. if(!id->conf->auth_module)
39271c2000-02-23Martin Stjernholm  RXML.run_error("Modified by requires a user database.\n");
79f7e82000-10-21Martin Nilsson  // FIXME: The next row is defunct. last_modified_by does not exist.
592ed72000-02-06Martin Nilsson  m->name = id->conf->last_modified_by(file, id); CACHE(10);
01dcee2000-09-05Per Hedbor  return tag_user(tag, m, id);
592ed72000-02-06Martin Nilsson  }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  if(m->file)
cc3a942000-09-24Martin Nilsson  m->realfile = id->conf->real_file(Roxen.fix_relative( m_delete(m, "file"), id), id);
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  if(m->by && m->realfile) { if(!id->conf->auth_module)
39271c2000-02-23Martin Stjernholm  RXML.run_error("Modified by requires a user database.\n");
e272382000-01-23Kenneth Johansson 
8b46c02000-07-25Martin Nilsson  Stdio.File f;
592ed72000-02-06Martin Nilsson  if(f = open(m->realfile, "r")) { m->name = id->conf->last_modified_by(f, id); destruct(f); CACHE(10);
01dcee2000-09-05Per Hedbor  return tag_user(tag, m, id);
592ed72000-02-06Martin Nilsson  } return "A. Nonymous."; }
e272382000-01-23Kenneth Johansson 
1f4a6c2000-08-28Per Hedbor  Stat s;
592ed72000-02-06Martin Nilsson  if(m->realfile) s = file_stat(m->realfile);
8b46c02000-07-25Martin Nilsson  else if (_stat) s = _stat; else
6889d32000-10-12Martin Nilsson  s = id->conf->stat_file(id->not_query, id);
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  if(s) {
8b46c02000-07-25Martin Nilsson  CACHE(10);
592ed72000-02-06Martin Nilsson  if(m->ssi)
6743432000-03-19Martin Nilsson  return Roxen.strftime(id->misc->ssi_timefmt || "%c", s[3]); return Roxen.tagtime(s[3], m, id, language);
592ed72000-02-06Martin Nilsson  }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  if(m->ssi) return id->misc->ssi_errmsg||"";
39271c2000-02-23Martin Stjernholm  RXML.run_error("Couldn't stat file.\n");
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
01dcee2000-09-05Per Hedbor string|array(string) tag_user(string tag, mapping m, RequestID id )
592ed72000-02-06Martin Nilsson { if(!id->conf->auth_module)
39271c2000-02-23Martin Stjernholm  RXML.run_error("Requires a user database.\n");
e272382000-01-23Kenneth Johansson 
8b46c02000-07-25Martin Nilsson  if (!m->name) return "";
f1c9f02000-01-26Kenneth Johansson 
8b46c02000-07-25Martin Nilsson  string b=m->name; array(string) u=id->conf->userinfo(b, id); if(!u) return "";
f1c9f02000-01-26Kenneth Johansson 
8b46c02000-07-25Martin Nilsson  string dom = id->conf->query("Domain");
9f50812000-06-18Henrik Grubbström (Grubba)  if(sizeof(dom) && (dom[-1]=='.')) dom = dom[0..strlen(dom)-2];
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  if(m->realname && !m->email) { if(m->link && !m->nolink) return ({ "<a href=\"/~"+b+"/\">"+u[4]+"</a>" }); return ({ u[4] }); }
8b46c02000-07-25Martin Nilsson 
592ed72000-02-06Martin Nilsson  if(m->email && !m->realname) { if(m->link && !m->nolink)
d8e1ac2000-02-29Martin Nilsson  return ({ sprintf("<a href=\"mailto:%s@%s\">%s@%s</a>",
592ed72000-02-06Martin Nilsson  b, dom, b, dom) }); return ({ b + "@" + dom }); }
8b46c02000-07-25Martin Nilsson 
592ed72000-02-06Martin Nilsson  if(m->nolink && !m->link) return ({ sprintf("%s &lt;%s@%s&gt;", u[4], b, dom) });
8b46c02000-07-25Martin Nilsson 
bb1f632000-03-01Martin Nilsson  return ({ sprintf( (m->nohomepage?"":"<a href=\"/~%s/\">%s</a> ")+
592ed72000-02-06Martin Nilsson  "<a href=\"mailto:%s@%s\">&lt;%s@%s&gt;</a>", b, u[4], b, dom, b, dom) }); }
e272382000-01-23Kenneth Johansson 
8c96aa2000-02-24Martin Nilsson 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) {
6743432000-03-19Martin Nilsson  id->misc->cacheable = Roxen.time_dequantifier(args);
8c96aa2000-02-24Martin Nilsson  } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
5b3ff22000-02-10Martin Nilsson 
592ed72000-02-06Martin Nilsson // ------------------- Containers ----------------
cabde62000-12-09Per Hedbor class TagCharset
9aee392000-02-15Martin Nilsson {
cabde62000-12-09Per Hedbor  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}); } }
9aee392000-02-15Martin Nilsson }
e272382000-01-23Kenneth Johansson 
9aee392000-02-15Martin Nilsson class TagScope {
592ed72000-02-06Martin Nilsson  inherit RXML.Tag;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  constant name = "scope";
89034d2000-07-17Martin Nilsson  mapping(string:RXML.Type) opt_arg_types = ([ "extend" : RXML.t_text(RXML.PEnt) ]);
e272382000-01-23Kenneth Johansson 
9aee392000-02-15Martin Nilsson  class Frame {
592ed72000-02-06Martin Nilsson  inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
85d5af2000-09-15Martin Nilsson  string scope_name; mapping|object vars;
592ed72000-02-06Martin Nilsson  mapping oldvar;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  array do_enter(RequestID id) {
40b47b2001-08-17Martin Nilsson  scope_name = args->scope || args->extend || "form";
d5af942001-02-05Per Hedbor  // FIXME: Should probably work like this, but it's anything but // simple to do that now, since variables is a class that simply // fakes the old variable structure using real_variables // #if ROXEN_COMPAT <= 1.3 // if(scope_name=="form") oldvar=id->variables; // #endif
592ed72000-02-06Martin Nilsson  if(args->extend)
6d754f2001-06-18Martin Stjernholm  vars=copy_value(RXML_CONTEXT->get_scope (scope_name));
592ed72000-02-06Martin Nilsson  else vars=([]);
d5af942001-02-05Per Hedbor // #if ROXEN_COMPAT <= 1.3 // if(oldvar) id->variables=vars; // #endif
592ed72000-02-06Martin Nilsson  return 0; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  array do_return(RequestID id) {
d5af942001-02-05Per Hedbor // #if ROXEN_COMPAT <= 1.3 // if(oldvar) id->variables=oldvar; // #endif
592ed72000-02-06Martin Nilsson  result=content; return 0; } } }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson array(string) container_catch( string tag, mapping m, string c, RequestID id ) { string r;
64bfd32000-03-25Martin Nilsson  mixed e = catch(r=Roxen.parse_rxml(c, id)); if(e && objectp(e) && e->tag_throw) return ({ e->tag_throw }); if(e) throw(e);
592ed72000-02-06Martin Nilsson  return ({r}); }
e272382000-01-23Kenneth Johansson 
4c38642001-02-10Martin Nilsson class TagCache { inherit RXML.Tag; constant name = "cache";
226fbd2001-07-21Martin Stjernholm  constant flags = (RXML.FLAG_GET_RAW_CONTENT | RXML.FLAG_GET_EVALED_CONTENT |
93bb682001-08-22Martin Stjernholm  RXML.FLAG_DONT_CACHE_RESULT | RXML.FLAG_CUSTOM_TRACE);
4c38642001-02-10Martin Nilsson 
41a4da2001-07-26Martin Stjernholm  static class TimeOutEntry (TimeOutEntry next, mapping(string:RXML.PCode) alternatives, mapping(string:int) timeouts) {} static TimeOutEntry timeout_list; static void do_timeouts() { int now = time (1); for (TimeOutEntry t = timeout_list; t; t = t->next) foreach (indices (t->timeouts), string key) if (t->timeouts[key] < now) { m_delete (t->alternatives, key); m_delete (t->timeouts, key); } roxen.background_run (roxen.query("mem_cache_gc"), do_timeouts); } static void add_timeouts (mapping(string:RXML.PCode) alternatives, mapping(string:int) timeouts) { if (!timeout_list) roxen.background_run (roxen.query("mem_cache_gc"), do_timeouts); else for (TimeOutEntry t = timeout_list; t; t = t->next) if (t->timeouts == timeouts) return; timeout_list = TimeOutEntry (timeout_list, alternatives, timeouts); }
4c38642001-02-10Martin Nilsson  class Frame { inherit RXML.Frame;
77a8ac2001-06-26Martin Nilsson 
4704942001-07-20Martin Stjernholm  int do_iterate;
41a4da2001-07-26Martin Stjernholm  mapping(string|int:mixed) keymap; string key;
4704942001-07-20Martin Stjernholm  RXML.PCode evaled_content;
41a4da2001-07-26Martin Stjernholm  int timeout; // The following are retained for frame reuse. string content_hash; array(string|int) subvariables; mapping(string:RXML.PCode) alternatives; mapping(string:int) timeouts;
77a8ac2001-06-26Martin Nilsson 
4704942001-07-20Martin Stjernholm  array do_enter (RequestID id) {
41a4da2001-07-26Martin Stjernholm  if( args->nocache || args["not-post-method"] && id->method == "POST" ) {
4704942001-07-20Martin Stjernholm  do_iterate = 1; key = 0;
93bb682001-08-22Martin Stjernholm  TRACE_ENTER("tag &lt;cache&gt; no cache" + (args->nocache ? "" : " due to POST method"), tag);
4704942001-07-20Martin Stjernholm  return 0;
89cf122001-07-20Martin Stjernholm  }
77a8ac2001-06-26Martin Nilsson 
41a4da2001-07-26Martin Stjernholm  RXML.Context ctx = RXML_CONTEXT;
0e798d2001-08-22Martin Stjernholm  int default_key = compat_level < 2.2;
4704942001-07-20Martin Stjernholm 
41a4da2001-07-26Martin Stjernholm  if (args->propagate) { if (!(keymap = ctx->misc->cache_key)) m_delete (args, "propagate");
4c38642001-02-10Martin Nilsson  }
41a4da2001-07-26Martin Stjernholm  else keymap = ctx->misc->cache_key = ([]); if(args->key) keymap[0] += ({args->key});
93bb682001-08-22Martin Stjernholm  if (args->variable) { if (args->variable != "") foreach (args->variable / ",", string var) { var = String.trim_all_whites (var); array splitted = ctx->parse_user_var (var, 1); if (intp (splitted[0])) { // Depend on the whole scope. mapping|RXML.Scope scope = ctx->get_scope (var); if (mappingp (scope)) keymap[var] = scope + ([]); else if (var == "form") // Special case to optimize this scope. keymap->form = id->real_variables + ([]); else if (scope) { array indices = scope->_indices (ctx, var); keymap[var] = mkmapping (indices, rows (scope, indices)); } else parse_error ("Unknown scope %O.\n", var);
41a4da2001-07-26Martin Stjernholm  }
93bb682001-08-22Martin Stjernholm  else keymap[var] = ctx->get_var (splitted[1..], splitted[0]);
4704942001-07-20Martin Stjernholm  }
93bb682001-08-22Martin Stjernholm  default_key = 0;
41a4da2001-07-26Martin Stjernholm  }
93bb682001-08-22Martin Stjernholm  if (args->profile) {
a64efe2001-07-26Martin Stjernholm  if (mapping avail_profiles = id->misc->rxml_cache_cur_profile) foreach (args->profile / ",", string profile) { profile = String.trim_all_whites (profile); mixed profile_val = avail_profiles[profile]; if (zero_type (profile_val)) parse_error ("Unknown cache profile %O.\n", profile); keymap[" " + profile] = profile_val; } else parse_error ("There are no cache profiles.\n");
93bb682001-08-22Martin Stjernholm  default_key = 0; }
a64efe2001-07-26Martin Stjernholm 
41a4da2001-07-26Martin Stjernholm  if (args->propagate) { // Updated the key, so we're done. The surrounding cache tag // should do the caching. do_iterate = 1; key = keymap = 0; flags &= ~RXML.FLAG_DONT_CACHE_RESULT;
93bb682001-08-22Martin Stjernholm  TRACE_ENTER("tag &lt;cache&gt; propagating key", tag);
41a4da2001-07-26Martin Stjernholm  return 0; }
93bb682001-08-22Martin Stjernholm  if (default_key) { // Include the form variables and the page path by default. keymap->form = id->real_variables + ([]); keymap["page.path"] = id->not_query; }
41a4da2001-07-26Martin Stjernholm  if (subvariables) foreach (subvariables, string var) { array splitted = ctx->parse_user_var (var, 1); if (intp (splitted[0])) { // Depend on the whole scope. mapping|RXML.Scope scope = ctx->get_scope (var); if (mappingp (scope)) keymap[var] = scope + ([]); else if (var == "form") // Special case to optimize this scope. keymap->form = id->real_variables + ([]); else { array indices = scope->_indices (ctx, var); keymap[var] = mkmapping (indices, rows (scope, indices)); }
4704942001-07-20Martin Stjernholm  }
41a4da2001-07-26Martin Stjernholm  else keymap[var] = ctx->get_var (splitted[1..], splitted[0]); } timeout = Roxen.time_dequantifier (args); if (args->shared) { if(args->nohash) // Always use the configuration in the key; noone really // wants cache tainting between servers. keymap[1] = id->conf->name; else { if (!content_hash) // Include the content type in the hash since we cache the // p-code which has static type inference. content_hash = Crypto.md5()->update (content) ->update (content_type->name) ->digest(); keymap[1] = ({id->conf->name, content_hash}); } key = encode_value_canonic (keymap); if (!args["disable-key-hash"]) key = Crypto.md5()->update (key)->digest(); if (id->pragma["no-cache"] && args["flush-on-no-cache"]) cache_remove ("tag_cache", key); else if ((evaled_content = cache_lookup("tag_cache", key))) if (evaled_content->is_stale()) { cache_remove ("tag_cache", key); evaled_content = 0; } else { do_iterate = -1; key = keymap = 0;
93bb682001-08-22Martin Stjernholm  TRACE_ENTER("tag &lt;cache&gt; cache hit", tag);
41a4da2001-07-26Martin Stjernholm  return ({evaled_content}); } } else { key = encode_value_canonic (keymap); if (!args["disable-key-hash"]) key = Crypto.md5()->update (key)->digest(); if (alternatives) { if ((evaled_content = alternatives[key])) if (evaled_content->is_stale()) { m_delete (alternatives, key); evaled_content = 0; } else { if (timeout) timeouts[key] = time() + timeout; do_iterate = -1; key = keymap = 0;
93bb682001-08-22Martin Stjernholm  TRACE_ENTER("tag &lt;cache&gt; cache hit", tag);
41a4da2001-07-26Martin Stjernholm  return ({evaled_content}); } } else alternatives = ([]);
4c38642001-02-10Martin Nilsson  }
4704942001-07-20Martin Stjernholm 
41a4da2001-07-26Martin Stjernholm  keymap += ([]);
4704942001-07-20Martin Stjernholm  do_iterate = 1;
93bb682001-08-22Martin Stjernholm  TRACE_ENTER("tag &lt;cache&gt; cache miss" + (default_key ? " (using default dependencies)" : ""), tag);
4026102001-08-22Martin Stjernholm  id->cache_status["cachetag"] = 0;
4063572001-08-22Martin Stjernholm  id->misc->cache_tag_miss = 1;
4c38642001-02-10Martin Nilsson  return 0; }
4704942001-07-20Martin Stjernholm 
93bb682001-08-22Martin Stjernholm  array do_return (RequestID id)
4704942001-07-20Martin Stjernholm  {
41a4da2001-07-26Martin Stjernholm  if (key) { mapping(string|int:mixed) subkeymap = RXML_CONTEXT->misc->cache_key; if (sizeof (subkeymap) > sizeof (keymap)) { // The test above assumes that no subtag remove entries in // RXML_CONTEXT->misc->cache_key. subvariables = indices (subkeymap - keymap); RXML_CONTEXT->state_update(); }
93bb682001-08-22Martin Stjernholm  if (args->shared) {
41a4da2001-07-26Martin Stjernholm  cache_set("tag_cache", key, evaled_content, timeout);
93bb682001-08-22Martin Stjernholm  TRACE_LEAVE ("added shared cache entry"); }
41a4da2001-07-26Martin Stjernholm  else { alternatives[key] = evaled_content; if (timeout) { if (!timeouts) { timeouts = ([]); add_timeouts (alternatives, timeouts); } timeouts[key] = time() + timeout;
93bb682001-08-22Martin Stjernholm  TRACE_LEAVE ("added time limited cache entry");
41a4da2001-07-26Martin Stjernholm  }
93bb682001-08-22Martin Stjernholm  else {
41a4da2001-07-26Martin Stjernholm  // Only caches without timeouts is worth saving. RXML_CONTEXT->state_update();
93bb682001-08-22Martin Stjernholm  TRACE_LEAVE ("added (possibly persistent) cache entry"); }
41a4da2001-07-26Martin Stjernholm  } }
93bb682001-08-22Martin Stjernholm  else TRACE_LEAVE ("");
4704942001-07-20Martin Stjernholm  result += content; return 0; }
41a4da2001-07-26Martin Stjernholm  array save() { return ({content_hash, subvariables, alternatives, timeouts}); } void restore (array saved) { [content_hash, subvariables, alternatives, timeouts] = saved; if (timeouts) add_timeouts (alternatives, timeouts); }
4c38642001-02-10Martin Nilsson  }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
3a3a692001-08-07Martin Stjernholm class TagNocache { inherit RXML.Tag; constant name = "nocache"; constant flags = RXML.FLAG_DONT_CACHE_RESULT; class Frame { inherit RXML.Frame; } }
cde9a02000-03-10Martin Nilsson 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; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
6444372000-03-10Martin Nilsson class TagFor { inherit RXML.Tag; constant name = "for";
e272382000-01-23Kenneth Johansson 
6444372000-03-10Martin Nilsson  class Frame { inherit RXML.Frame;
e272382000-01-23Kenneth Johansson 
6444372000-03-10Martin Nilsson  private int from,to,step,count;
e272382000-01-23Kenneth Johansson 
6444372000-03-10Martin Nilsson  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);
916f4e2000-03-13Martin Nilsson  if((to<from && step>0)||(to>from && step<0)) run_error("Step has the wrong sign.\n");
6444372000-03-10Martin Nilsson  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) {
7efc1d2000-03-13Martin Nilsson  if(args->variable) RXML.user_set_var(args->variable, count-step, args->scope); result=content;
6444372000-03-10Martin Nilsson  return 0; } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
82f7132000-03-10Martin Nilsson string simpletag_apre(string tag, mapping m, string q, RequestID id)
592ed72000-02-06Martin Nilsson {
0023a62000-08-22Martin Nilsson  string href;
e272382000-01-23Kenneth Johansson 
cc3a942000-09-24Martin Nilsson  if(m->href) { href=m_delete(m, "href");
0023a62000-08-22Martin Nilsson  array(string) split = href/":"; if ((sizeof(split) > 1) && (sizeof(split[0]/"/") == 1)) return RXML.t_xml->format_tag("a", m, q);
6743432000-03-19Martin Nilsson  href=Roxen.strip_prestate(Roxen.fix_relative(href, id));
592ed72000-02-06Martin Nilsson  }
cc3a942000-09-24Martin Nilsson  else href=Roxen.strip_prestate(Roxen.strip_config(id->raw_url));
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  if(!strlen(href)) href="";
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  multiset prestate = (< @indices(id->prestate) >);
e272382000-01-23Kenneth Johansson 
0023a62000-08-22Martin Nilsson  // FIXME: add and drop should handle t_array
cc3a942000-09-24Martin Nilsson  if(m->add) foreach((m_delete(m, "add") - " ")/",", string s)
592ed72000-02-06Martin Nilsson  prestate[s]=1;
cc3a942000-09-24Martin Nilsson  if(m->drop) foreach((m_delete(m,"drop") - " ")/",", string s)
592ed72000-02-06Martin Nilsson  prestate[s]=0;
cc3a942000-09-24Martin Nilsson 
6743432000-03-19Martin Nilsson  m->href = Roxen.add_pre_state(href, prestate);
0023a62000-08-22Martin Nilsson  return RXML.t_xml->format_tag("a", m, q);
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
82f7132000-03-10Martin Nilsson string simpletag_aconf(string tag, mapping m, string q, RequestID id)
592ed72000-02-06Martin Nilsson {
0023a62000-08-22Martin Nilsson  string href;
e272382000-01-23Kenneth Johansson 
cc3a942000-09-24Martin Nilsson  if(!m->href) { href=m_delete(m, "href");
592ed72000-02-06Martin Nilsson  if (search(href, ":") == search(href, "//")-1)
39271c2000-02-23Martin Stjernholm  RXML.parse_error("It is not possible to add configs to absolute URLs.\n");
cc3a942000-09-24Martin Nilsson  href=Roxen.fix_relative(href, id);
592ed72000-02-06Martin Nilsson  }
cc3a942000-09-24Martin Nilsson  else href=Roxen.strip_prestate(Roxen.strip_config(id->raw_url));
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  array cookies = ({});
0023a62000-08-22Martin Nilsson  // FIXME: add and drop should handle t_array
cc3a942000-09-24Martin Nilsson  if(m->add) foreach((m_delete(m,"add") - " ")/",", string s)
592ed72000-02-06Martin Nilsson  cookies+=({s});
cc3a942000-09-24Martin Nilsson  if(m->drop) foreach((m_delete(m,"drop") - " ")/",", string s)
592ed72000-02-06Martin Nilsson  cookies+=({"-"+s});
f1c9f02000-01-26Kenneth Johansson 
6743432000-03-19Martin Nilsson  m->href = Roxen.add_config(href, cookies, id->prestate);
0023a62000-08-22Martin Nilsson  return RXML.t_xml->format_tag("a", m, q);
592ed72000-02-06Martin Nilsson }
f1c9f02000-01-26Kenneth Johansson 
7078eb2001-05-18Martin Nilsson 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;
0023a62000-08-22Martin Nilsson 
7078eb2001-05-18Martin Nilsson  array do_return(RequestID id) { id->misc->makeargs[args->name] = content; return 0; } } }
6534642001-06-28Martin Stjernholm  RXML.TagSet internal =
8061442001-07-09Martin Stjernholm  RXML.shared_tag_set ("/rxmltags/maketag", ({ TagAttrib() }) );
7078eb2001-05-18Martin Nilsson  class Frame { inherit RXML.Frame; mixed old_args; RXML.TagSet additional_tags = internal;
0023a62000-08-22Martin Nilsson 
7078eb2001-05-18Martin Nilsson  array do_enter(RequestID id) { old_args = id->misc->makeargs; id->misc->makeargs = ([]); return 0; }
0023a62000-08-22Martin Nilsson 
7078eb2001-05-18Martin Nilsson  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");
8fad902001-05-22Martin Nilsson  result = RXML.t_xml->format_tag(args->name, id->misc->makeargs, content, RXML.FLAG_RAW_ARGS);
7078eb2001-05-18Martin Nilsson  break; case "tag": if(!args->name) parse_error("Type 'tag' requires a name attribute.\n");
8fad902001-05-22Martin Nilsson  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);
7078eb2001-05-18Martin Nilsson  break; case "comment": result = "<!--" + content + "-->"; break; case "cdata": result = "<![CDATA[" + content + "]]>"; break; } id->misc->makeargs = old_args; return 0; } }
592ed72000-02-06Martin Nilsson }
f1c9f02000-01-26Kenneth Johansson 
a7a5432000-04-15Per Hedbor 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) {
7222a22000-06-12Martin Nilsson  if(args->preparse) content_type = result_type(RXML.PXml);
a7a5432000-04-15Per Hedbor  return 0;
592ed72000-02-06Martin Nilsson  }
a7a5432000-04-15Per Hedbor  array do_return(RequestID id) { array from; if(args->quote) { m_delete(args, "quote"); from=({ "<", ">", "&" }); } else from=({ "{", "}", "&" }); result=replace(content, from, ({ "&lt;", "&gt;", "&amp;"}) ); if(args->pre) { m_delete(args, "pre");
0023a62000-08-22Martin Nilsson  result="\n"+RXML.t_xml->format_tag("pre", args, result)+"\n";
a7a5432000-04-15Per Hedbor  } return 0;
592ed72000-02-06Martin Nilsson  }
a7a5432000-04-15Per Hedbor  }
592ed72000-02-06Martin Nilsson }
f1c9f02000-01-26Kenneth Johansson 
82f7132000-03-10Martin Nilsson string simpletag_autoformat(string tag, mapping m, string s, RequestID id)
592ed72000-02-06Martin Nilsson { s-="\r";
f1c9f02000-01-26Kenneth Johansson 
592ed72000-02-06Martin Nilsson  string p=(m["class"]?"<p class=\""+m["class"]+"\">":"<p>");
e272382000-01-23Kenneth Johansson 
8614702000-10-11Johan Sundström  if(!m->nonbsp) { s = replace(s, "\n ", "\n&nbsp;"); // "|\n |" => "|\n&nbsp;|" s = replace(s, " ", "&nbsp; "); // "| |" => "|&nbsp; |" s = replace(s, " ", " &nbsp;"); // "|&nbsp; |" => "|&nbsp; &nbsp;|" }
592ed72000-02-06Martin Nilsson  if(!m->nobr) {
5b0e5d2000-03-25Martin Nilsson  s = replace(s, "\n", "<br />\n");
592ed72000-02-06Martin Nilsson  if(m->p) {
5b0e5d2000-03-25Martin Nilsson  if(search(s, "<br />\n<br />\n")!=-1) s=p+s; s = replace(s, "<br />\n<br />\n", "\n</p>"+p+"\n");
592ed72000-02-06Martin Nilsson  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; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  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>"; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  return s; }
e272382000-01-23Kenneth Johansson 
cc3a942000-09-24Martin Nilsson class Smallcapsstr (string bigtag, string smalltag, mapping bigarg, mapping smallarg) {
592ed72000-02-06Martin Nilsson  constant UNDEF=0, BIG=1, SMALL=2;
cc3a942000-09-24Martin Nilsson  static string text="",part="";
592ed72000-02-06Martin Nilsson  static int last=UNDEF;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  string _sprintf() {
cc3a942000-09-24Martin Nilsson  return "Smallcapsstr("+bigtag+","+smalltag+")";
592ed72000-02-06Martin Nilsson  }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  void add(string char) { part+=char; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  void add_big(string char) { if(last!=BIG) flush_part(); part+=char; last=BIG; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  void add_small(string char) { if(last!=SMALL) flush_part(); part+=char; last=SMALL; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  void write(string txt) { if(last!=UNDEF) flush_part(); part+=txt; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  void flush_part() { switch(last){ case UNDEF: default: text+=part; break; case BIG:
0023a62000-08-22Martin Nilsson  text+=RXML.t_xml->format_tag(bigtag, bigarg, part);
592ed72000-02-06Martin Nilsson  break; case SMALL:
0023a62000-08-22Martin Nilsson  text+=RXML.t_xml->format_tag(smalltag, smallarg, part);
592ed72000-02-06Martin Nilsson  break; } part=""; last=UNDEF; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  string value() { if(last!=UNDEF) flush_part(); return text; } }
e272382000-01-23Kenneth Johansson 
82f7132000-03-10Martin Nilsson string simpletag_smallcaps(string t, mapping m, string s)
592ed72000-02-06Martin Nilsson { Smallcapsstr ret; string spc=m->space?"&nbsp;":""; 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"); }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  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);
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  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);
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  return ret->value(); }
e272382000-01-23Kenneth Johansson 
fe9f932000-09-12Johan Sundström string simpletag_random(string tag, mapping m, string s, RequestID id)
592ed72000-02-06Martin Nilsson {
fe9f932000-09-12Johan Sundström  NOCACHE();
b50d882001-02-11Martin Nilsson  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];
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
916f4e2000-03-13Martin Nilsson 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 }); } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson // Removes empty lines
82f7132000-03-10Martin Nilsson string simpletag_trimlines( string tag_name, mapping args,
592ed72000-02-06Martin Nilsson  string contents, RequestID id ) {
82f7132000-03-10Martin Nilsson  contents = replace(contents, ({"\r\n","\r" }), ({"\n","\n"})); return (contents / "\n" - ({ "" })) * "\n";
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson void container_throw( string t, mapping m, string c, RequestID id) {
64bfd32000-03-25Martin Nilsson  if(c[-1]!='\n') c+="\n";
9ceb8b2000-09-25Per Hedbor  throw( class(string tag_throw) {}( c ) );
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson // Internal methods for the default tag 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" ); }
e272382000-01-23Kenneth Johansson 
cc3a942000-09-24Martin Nilsson  int xml=!m_delete(m, "noxml");
0023a62000-08-22Martin Nilsson  return ({ Roxen.make_tag(t, m, xml) });
592ed72000-02-06Martin Nilsson } 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) {
0023a62000-08-22Martin Nilsson  if(name && m->name!=name) return ({ RXML.t_xml->format_tag(t, m, c) });
c4de052000-05-05Martin Nilsson  // Split indata into an array with the layout // ({ "option", option_args, stuff_before_next_option })*n // e.g. "fox<OPtioN foo='bar'>gazink</option>" will yield // tmp=({ "OPtioN", " foo='bar'", "gazink</option>" }) and // ret="fox"
592ed72000-02-06Martin Nilsson  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..];
c4de052000-05-05Martin Nilsson 
592ed72000-02-06Martin Nilsson  while(sizeof(tmp)>2) { stop=search(tmp[2],"<");
aa11102000-11-08Martin Nilsson  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);
592ed72000-02-06Martin Nilsson  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..]; }
0023a62000-08-22Martin Nilsson  return ({ RXML.t_xml->format_tag(t, m, ret) });
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
82f7132000-03-10Martin Nilsson string simpletag_default( string t, mapping m, string c, RequestID id)
592ed72000-02-06Martin Nilsson { multiset value=(<>); if(m->value) value=mkmultiset((m->value||"")/(m->separator||","));
cde9a02000-03-10Martin Nilsson  if(m->variable) value+=(<RXML.user_get_var(m->variable, m->scope)>);
82f7132000-03-10Martin Nilsson  if(value==(<>)) return c;
e272382000-01-23Kenneth Johansson 
82f7132000-03-10Martin Nilsson  return parse_html(c, (["input":internal_tag_input]), (["select":internal_tag_select]), m->name, value);
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
82f7132000-03-10Martin Nilsson string simpletag_sort(string t, mapping m, string c, RequestID id)
592ed72000-02-06Martin Nilsson { if(!m->separator) m->separator = "\n";
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  string pre="", post=""; array lines = c/m->separator;
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  while(lines[0] == "") { pre += m->separator; lines = lines[1..]; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  while(lines[-1] == "") { post += m->separator; lines = lines[..sizeof(lines)-2]; }
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  lines=sort(lines);
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  return pre + (m->reverse?reverse(lines):lines)*m->separator + post; }
e272382000-01-23Kenneth Johansson 
82f7132000-03-10Martin Nilsson string simpletag_replace( string tag, mapping m, string cont, RequestID id)
592ed72000-02-06Martin Nilsson { switch(m->type) { case "word": default: if(!m->from) return cont; return replace(cont,m->from,(m->to?m->to:""));
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  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);
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  int balance=sizeof(from)-sizeof(to); if(balance>0) to+=allocate(balance,"");
e272382000-01-23Kenneth Johansson 
592ed72000-02-06Martin Nilsson  return replace(cont,from,to); } }
e272382000-01-23Kenneth Johansson 
30d6a52000-02-16Martin Nilsson class TagCSet { inherit RXML.Tag; constant name = "cset"; class Frame { inherit RXML.Frame; array do_return(RequestID id) {
5b0e5d2000-03-25Martin Nilsson  if( !args->variable ) parse_error("Variable not specified.\n");
ea31c52000-02-16Martin Nilsson  if(!content) content="";
30d6a52000-02-16Martin Nilsson  if( args->quote != "none" )
6743432000-03-19Martin Nilsson  content = Roxen.html_decode_string( content );
30d6a52000-02-16Martin Nilsson 
6444372000-03-10Martin Nilsson  RXML.user_set_var(args->variable, content, args->scope);
30d6a52000-02-16Martin Nilsson  return ({ "" }); } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
43ff412001-02-06Martin Nilsson class TagColorScope { inherit RXML.Tag; constant name = "colorscope"; class Frame { inherit RXML.Frame; string link, alink, vlink;
6d754f2001-06-18Martin Stjernholm #define LOCAL_PUSH(X) if(args->X) { X=RXML_CONTEXT->misc->X; RXML_CONTEXT->misc->X=args->X; }
43ff412001-02-06Martin Nilsson  array do_enter(RequestID id) { Roxen.push_color("colorscope",args,id); LOCAL_PUSH(link); LOCAL_PUSH(alink); LOCAL_PUSH(vlink); return 0; }
6d754f2001-06-18Martin Stjernholm #define LOCAL_POP(X) if(X) RXML_CONTEXT->misc->X=X
43ff412001-02-06Martin Nilsson  array do_return(RequestID id) { Roxen.pop_color("colorscope",id); LOCAL_POP(link); LOCAL_POP(alink); LOCAL_POP(vlink); result=content; return 0; } } }
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson // ------------------------- RXML Core tags --------------------------
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson class TagHelp {
592ed72000-02-06Martin Nilsson  inherit RXML.Tag;
b156c62001-04-23Martin Nilsson  constant name = "help"; constant flags = RXML.FLAG_EMPTY_ELEMENT; class Frame { inherit "rxmlhelp"; inherit RXML.Frame; array do_return(RequestID id) {
6d754f2001-06-18Martin Stjernholm  array tags=map(indices(RXML_CONTEXT->tag_set->get_tag_names()),
b156c62001-04-23Martin Nilsson  lambda(string tag) { if(tag[..3]=="!--#" || !has_value(tag, "#")) return tag; return ""; } ) - ({ "" });
6d754f2001-06-18Martin Stjernholm  tags += map(indices(RXML_CONTEXT->tag_set->get_proc_instr_names()),
b156c62001-04-23Martin Nilsson  lambda(string tag) { return "&lt;?"+tag+"?&gt;"; } ); tags = Array.sort_array(tags, lambda(string a, string b) { if(a[..4]=="&lt;?") a=a[5..]; if(b[..4]=="&lt;?") 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]=="&lt;?") 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) }); } }
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson  ret+="<h3>"+upper_case(char)+"</h3>\n<p>"+String.implode_nicely(tag_links)+"</p>"; /* ret+="<p><b>This is a list of all currently defined RXML scopes and their entities</b></p>";
e272382000-01-23Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  RXML.Context context=RXML_CONTEXT;
b156c62001-04-23Martin Nilsson  foreach(sort(context->list_scopes()), string scope) { ret+=sprintf("<h3><a href=\"%s?_r_t_h=%s\">%s</a></h3>\n", id->not_query, Roxen.http_encode_url("&"+scope+";"), scope); ret+="<p>"+String.implode_nicely(Array.map(sort(context->list_var(scope)), lambda(string ent) { return ent; }) )+"</p>"; } */ return ({ ret }); }
df3c452000-07-26Johan Sundström 
b156c62001-04-23Martin Nilsson  result=ret+find_tag_doc(help_for, id); }
df3c452000-07-26Johan Sundström  } }
b156c62001-04-23Martin Nilsson class TagNumber { inherit RXML.Tag; constant name = "number"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
df3c452000-07-26Johan Sundström 
b156c62001-04-23Martin Nilsson  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||
6d754f2001-06-18Martin Stjernholm  RXML_CONTEXT->misc->theme_language,
b156c62001-04-23Martin Nilsson  args->type||"number",id)( (int)args->num ); } }
592ed72000-02-06Martin Nilsson }
e272382000-01-23Kenneth Johansson 
cde9a02000-03-10Martin Nilsson 
b156c62001-04-23Martin Nilsson class TagUse { inherit RXML.Tag; constant name = "use"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  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; }); }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  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; }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  private string use_file_doc(string f, string data) { string res, doc; int help; // If true, all tags support the 'help' argument. sscanf(data, "%*sdoc=\"%s\"", doc); sscanf(data, "%*shelp=%d", help); res = "<dt><b>"+f+"</b></dt><dd>"+(doc?doc+"<br />":"")+"</dd>";
9b03652001-03-07Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  array defs = parse_use_package(data, RXML_CONTEXT); cache_set("macrofiles", "|"+f, defs, 300);
9b03652001-03-07Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  array(string) ifs = ({}), tags = ({});
9b03652001-03-07Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  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])});
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  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 />"; }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  if(help) res+="<br /><br />All tags accept the <i>help</i> attribute."; return res; }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  private array parse_use_package(string data, RXML.Context ctx) {
6d754f2001-06-18Martin Stjernholm  RequestID id = ctx->id;
9b03652001-03-07Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  RXML.Parser parser = Roxen.get_rxml_parser (ctx->id); parser->write_end (data); parser->eval();
9b03652001-03-07Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  return ({ parser->context->misc, parser->context->get_scope ("form"), parser->context->get_scope ("var") });
b156c62001-04-23Martin Nilsson  }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame;
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  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>" }); }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  if(!args->file && !args->package) parse_error("No file or package selected.\n");
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  array res; string name, filename; if(args->file) { filename = Roxen.fix_relative(args->file, id); name = id->conf->get_config_id() + "|" + filename; }
e04d4c2001-08-23Per Hedbor  else if( args->locate ) { filename = VFS.find_above( id->not_query, args->locate, id, "locate" ); name = id->conf->get_config_id() + "|" + filename; }
b156c62001-04-23Martin Nilsson  else
e04d4c2001-08-23Per Hedbor  {
b156c62001-04-23Martin Nilsson  name = "|" + args->package;
e04d4c2001-08-23Per Hedbor  }
6d754f2001-06-18Martin Stjernholm  RXML.Context ctx = RXML_CONTEXT;
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  if(args->info || id->pragma["no-cache"] || !(res=cache_lookup("macrofiles",name)) ) {
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  string file; if(filename) file = id->conf->try_get_file( filename, id ); else file = read_package( args->package );
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  if(!file) run_error("Failed to fetch "+(args->file||args->package)+".\n");
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  if( args->info ) return ({"<dl>"+use_file_doc( args->file || args->package, file )+"</dl>"});
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  res = parse_use_package(file, ctx); cache_set("macrofiles", name, res); }
9b03652001-03-07Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  [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");
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  return 0; } } }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson class UserTagContents { inherit RXML.Tag; constant name = "contents"; constant flags = RXML.FLAG_EMPTY_ELEMENT; array(RXML.Type) result_types = ({RXML.t_any (RXML.PXml)});
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame; constant is_user_tag_contents = 1;
2e9f8e2001-08-11Martin Stjernholm  array exec;
8061442001-07-09Martin Stjernholm 
2e9f8e2001-08-11Martin Stjernholm  local RXML.Frame get_upframe()
b156c62001-04-23Martin Nilsson  {
40b7be2001-08-13Martin Stjernholm  RXML.Frame upframe = up; int nest = 1; for (; upframe; upframe = upframe->up) if (upframe->is_user_tag) { if (!--nest) return upframe; } else if (upframe->is_user_tag_contents) nest++; parse_error ("No associated defined tag to get contents from.\n");
2e9f8e2001-08-11Martin Stjernholm  }
8061442001-07-09Martin Stjernholm 
2e9f8e2001-08-11Martin Stjernholm  array do_return() { RXML.Frame upframe = get_upframe(); RXML.Context ctx = RXML_CONTEXT; array ret;
b835722001-07-10Martin Stjernholm  if (ctx->scopes == upframe->saved_scopes)
2e9f8e2001-08-11Martin Stjernholm  ret = ({upframe->user_tag_contents});
b835722001-07-10Martin Stjernholm  else { // This is poking in the internals; there ought to be some // sort of interface here.
2e9f8e2001-08-11Martin Stjernholm  ret = ({upframe->user_tag_contents, lambda (mapping(string:mixed) old_scopes, mapping(RXML.Frame:array) old_hidden) { // Wrap this in a lambda to avoid getting all the // locals in do_return in the dynamic frame. return lambda() { RXML_CONTEXT->scopes = old_scopes; RXML_CONTEXT->hidden = old_hidden; return RXML.nil; }; } (ctx->scopes, ctx->hidden)});
b835722001-07-10Martin Stjernholm  ctx->scopes = upframe->saved_scopes; ctx->hidden = upframe->saved_hidden; }
2e9f8e2001-08-11Martin Stjernholm  if (upframe->compile) { flags |= RXML.FLAG_COMPILE_RESULT; exec = stringp (ret[0]) && ret; }
b835722001-07-10Martin Stjernholm  return ret;
b156c62001-04-23Martin Nilsson  }
2e9f8e2001-08-11Martin Stjernholm  int save() { if (exec) { RXML.Frame upframe = get_upframe(); upframe->user_tag_contents = exec[0]; } return 0; }
b156c62001-04-23Martin Nilsson  } }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson private RXML.TagSet user_tag_contents_tag_set =
8061442001-07-09Martin Stjernholm  RXML.shared_tag_set ("/rxmltags/user_tag", ({UserTagContents()}));
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson class UserTag { inherit RXML.Tag;
6d754f2001-06-18Martin Stjernholm  string name, lookup_name;
8061442001-07-09Martin Stjernholm  int flags = RXML.FLAG_COMPILE_RESULT;
b156c62001-04-23Martin Nilsson  RXML.Type content_type = RXML.t_xml; array(RXML.Type) result_types = ({ RXML.t_any(RXML.PXml) });
6d754f2001-06-18Martin Stjernholm  // Note: We can't store the actual user tag definition directly in // this object; it won't work correctly in p-code since we don't // reparse the source and thus don't create a frame with the current // runtime tag definition. By looking up the definition in // RXML.Context.misc we can get the current definition even if it // changes in loops etc.
b156c62001-04-23Martin Nilsson 
6d754f2001-06-18Martin Stjernholm  void create(string _name, int tag) {
8061442001-07-09Martin Stjernholm  if (_name) { name=_name; lookup_name = "tag\0" + name; if(tag) flags |= RXML.FLAG_EMPTY_ELEMENT; }
b156c62001-04-23Martin Nilsson  }
9b03652001-03-07Kenneth Johansson 
224a972001-06-22Marcus Comstedt  mixed _encode() {
8061442001-07-09Martin Stjernholm  return ({ name, flags });
224a972001-06-22Marcus Comstedt  } void _decode(mixed v) {
8061442001-07-09Martin Stjernholm  [name, flags] = v; lookup_name = "tag\0" + name;
224a972001-06-22Marcus Comstedt  }
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame; RXML.TagSet additional_tags = user_tag_contents_tag_set;
b835722001-07-10Martin Stjernholm  string scope_name;
b156c62001-04-23Martin Nilsson  mapping vars;
8061442001-07-09Martin Stjernholm  string raw_tag_text;
b835722001-07-10Martin Stjernholm  int do_iterate;
b156c62001-04-23Martin Nilsson  constant is_user_tag = 1;
b835722001-07-10Martin Stjernholm  string content_text;
2e9f8e2001-08-11Martin Stjernholm  string|RXML.PCode user_tag_contents;
b835722001-07-10Martin Stjernholm  mapping(string:mixed) saved_scopes; mapping(RXML.Frame:array) saved_hidden;
8061442001-07-09Martin Stjernholm  int compile;
9b03652001-03-07Kenneth Johansson 
6d754f2001-06-18Martin Stjernholm  array do_enter (RequestID id) {
b835722001-07-10Martin Stjernholm  vars = 0; do_iterate = content_text ? -1 : 1; return 0;
6d754f2001-06-18Martin Stjernholm  }
b156c62001-04-23Martin Nilsson  array do_return(RequestID id) {
b835722001-07-10Martin Stjernholm  RXML.Context ctx = RXML_CONTEXT; array tagdef = ctx->misc[lookup_name];
97e5d62001-07-11Martin Stjernholm  if (!tagdef) return ({propagate_tag()});
b835722001-07-10Martin Stjernholm 
8061442001-07-09Martin Stjernholm  [array(string|RXML.PCode) def, mapping defaults, string def_scope_name, UserTag ignored] = tagdef; id->misc->last_tag_args = vars = defaults+args;
6d754f2001-06-18Martin Stjernholm  scope_name = def_scope_name || name;
9b03652001-03-07Kenneth Johansson 
8061442001-07-09Martin Stjernholm  if (content_text) // A previously evaluated tag was restored. content = content_text; else { if(content && args->trimwhites) content = String.trim_all_whites(content);
e272382000-01-23Kenneth Johansson 
8061442001-07-09Martin Stjernholm  if (stringp (def[0])) {
b156c62001-04-23Martin Nilsson #if ROXEN_COMPAT <= 1.3
8061442001-07-09Martin Stjernholm  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
b156c62001-04-23Martin Nilsson  }
8061442001-07-09Martin Stjernholm  content_text = content;
2e9f8e2001-08-11Martin Stjernholm  user_tag_contents = content || RXML.nil;
b835722001-07-10Martin Stjernholm  compile = ctx->make_p_code;
b156c62001-04-23Martin Nilsson  }
9b03652001-03-07Kenneth Johansson 
8061442001-07-09Martin Stjernholm  vars->args = Roxen.make_tag_attributes(vars)[1..];
b156c62001-04-23Martin Nilsson  vars["rest-args"] = Roxen.make_tag_attributes(args - defaults)[1..];
8061442001-07-09Martin Stjernholm  vars->contents = content_text;
b835722001-07-10Martin Stjernholm 
4fe73e2001-07-11Martin Stjernholm  if (compat_level > 2.1) {
b835722001-07-10Martin Stjernholm  // Save the scope state so that we can switch back in // <contents/>, thereby achieving static variable binding in // the content. This is poking in the internals; there ought // to be some sort of interface here. saved_scopes = ctx->scopes + ([]); saved_hidden = ctx->hidden + ([]); } else saved_scopes = ctx->scopes; // Makes the test in UserTagContents always true.
8061442001-07-09Martin Stjernholm  return def;
b156c62001-04-23Martin Nilsson  }
8061442001-07-09Martin Stjernholm  array save() {return ({content_text, user_tag_contents});} void restore (array saved) {[content_text, user_tag_contents] = saved;}
b156c62001-04-23Martin Nilsson  } }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson 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}); // No result.
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame;
8061442001-07-09Martin Stjernholm  array(string|RXML.PCode) def; mapping defaults; int do_iterate;
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  array do_enter(RequestID id) {
8061442001-07-09Martin Stjernholm  if (def) // A previously evaluated tag was restored. do_iterate = -1; else { do_iterate = 1; if(args->preparse) m_delete(args, "preparse"); else content_type = RXML.t_xml; }
b156c62001-04-23Martin Nilsson  return 0; }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  array do_return(RequestID id) { string n;
6d754f2001-06-18Martin Stjernholm  RXML.Context ctx = RXML_CONTEXT;
8e7db32001-04-21Martin Nilsson 
b156c62001-04-23Martin Nilsson  if(n=args->variable) {
21eeb02001-05-22Martin Nilsson  if(args->trimwhites) content=String.trim_all_whites((string)content);
b156c62001-04-23Martin Nilsson  RXML.user_set_var(n, content, args->scope); return 0; }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  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");
9b03652001-03-07Kenneth Johansson 
8061442001-07-09Martin Stjernholm  if (!def) { defaults=([]);
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson #if ROXEN_COMPAT <= 1.3
8061442001-07-09Martin Stjernholm  if(id->conf->old_rxml_compat) foreach( indices(args), string arg ) if( arg[..7] == "default_" )
b156c62001-04-23Martin Nilsson  { defaults[arg[8..]] = args[arg]; old_rxml_warning(id, "define attribute "+arg,"attrib container"); m_delete( args, arg ); } #endif
21eeb02001-05-22Martin Nilsson 
8061442001-07-09Martin Stjernholm  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 "";
6d754f2001-06-18Martin Stjernholm  };
b156c62001-04-23Martin Nilsson 
4fe73e2001-07-11Martin Stjernholm  if( compat_level > 2.1 ) {
8061442001-07-09Martin Stjernholm  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; }; // Stop parsing for attrib tags when we reach something else // than whitespace and comments. 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"); }
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson #if ROXEN_COMPAT <= 1.3
8061442001-07-09Martin Stjernholm  if(id->conf->old_rxml_compat) content = replace( content, indices(args), values(args) );
b156c62001-04-23Martin Nilsson #endif
8061442001-07-09Martin Stjernholm  def = ({content}); }
b156c62001-04-23Martin Nilsson 
97e5d62001-07-11Martin Stjernholm  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) // Redefine. 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); }
b156c62001-04-23Martin Nilsson  return 0; } if (n=args->if) {
6d754f2001-06-18Martin Stjernholm  ctx->misc["if\0" + n] = UserIf (n, content);
b156c62001-04-23Martin Nilsson  return 0; }
c8c6332001-04-24Martin Nilsson  if (n=args->name) {
6d754f2001-06-18Martin Stjernholm  ctx->misc[n]=content;
b156c62001-04-23Martin Nilsson  old_rxml_warning(id, "attempt to define name ","variable"); return 0; } parse_error("No tag, variable, if or container specified.\n"); }
8061442001-07-09Martin Stjernholm  array save() {return ({def, defaults});} void restore (array saved) {[def, defaults] = saved;}
b156c62001-04-23Martin Nilsson  } } 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) {
6d754f2001-06-18Martin Stjernholm  RXML_CONTEXT->user_delete_var(n, args->scope);
b156c62001-04-23Martin Nilsson  return 0; } if (n=args->tag||args->container) {
6d754f2001-06-18Martin Stjernholm  m_delete (RXML_CONTEXT->misc, "tag\0" + n); RXML_CONTEXT->remove_runtime_tag(n);
b156c62001-04-23Martin Nilsson  return 0; } if (n=args->if) {
6d754f2001-06-18Martin Stjernholm  m_delete(RXML_CONTEXT->misc, "if\0" + n);
b156c62001-04-23Martin Nilsson  return 0; } if (n=args->name) {
6d754f2001-06-18Martin Stjernholm  m_delete(RXML_CONTEXT->misc, args->name);
b156c62001-04-23Martin Nilsson  return 0; } parse_error("No tag, variable, if or container specified.\n"); } } } class Tracer (Configuration conf) { // Note: \n is used sparingly in output to make it look nice even // inside <pre>. 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";
6d754f2001-06-18Martin Stjernholm  // FIXME: 2.1 compat: Not mandatory. mapping(string:RXML.Type) req_arg_types = (["case": RXML.t_xml (RXML.PEnt)]);
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame;
6d754f2001-06-18Martin Stjernholm  int cap; array do_enter() {cap = 0; return 0;}
b156c62001-04-23Martin Nilsson  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: // FIXME: 2.1 compat: Not an error. parse_error ("Invalid value %O to the case argument.\n", args->case); } // FIXME: 2.1 compat: Not an error. 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;
141ada2001-06-11Martin Stjernholm  int do_iterate;
b156c62001-04-23Martin Nilsson  array do_enter(RequestID id) { int and = 1;
141ada2001-06-11Martin Stjernholm  do_iterate = -1;
b156c62001-04-23Martin Nilsson  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();
6d754f2001-06-18Martin Stjernholm  mapping(string:mixed) defs = RXML_CONTEXT->misc;
b156c62001-04-23Martin Nilsson  int ifval=0;
6d754f2001-06-18Martin Stjernholm  foreach(indices (args), string s)
3c29d52001-06-25Martin Stjernholm  if (object(RXML.Tag)|object(UserIf) plugin = plugins[s] || defs["if\0" + s]) {
6d754f2001-06-18Martin Stjernholm  ifval = plugin->eval( args[s], id, args, and, s ); if(ifval) { if(!and) { do_iterate = 1; return 0; }
b156c62001-04-23Martin Nilsson  }
6d754f2001-06-18Martin Stjernholm  else if(and) return 0;
b156c62001-04-23Martin Nilsson  } 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;
6d754f2001-06-18Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_any});
b156c62001-04-23Martin Nilsson  program Frame = FrameIf; } class TagElse { inherit RXML.Tag; constant name = "else"; constant flags = 0;
6d754f2001-06-18Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_any});
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame;
6d754f2001-06-18Martin Stjernholm  int do_iterate;
b156c62001-04-23Martin Nilsson  array do_enter(RequestID id) {
6d754f2001-06-18Martin Stjernholm  do_iterate= _ok ? -1 : 1;
b156c62001-04-23Martin Nilsson  return 0; } } } class TagThen { inherit RXML.Tag; constant name = "then"; constant flags = 0;
6d754f2001-06-18Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_any});
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame;
6d754f2001-06-18Martin Stjernholm  int do_iterate;
b156c62001-04-23Martin Nilsson  array do_enter(RequestID id) {
6d754f2001-06-18Martin Stjernholm  do_iterate= _ok ? 1 : -1;
b156c62001-04-23Martin Nilsson  return 0; } } } class TagElseif { inherit RXML.Tag; constant name = "elseif";
6d754f2001-06-18Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_any});
b156c62001-04-23Martin Nilsson  class Frame { inherit FrameIf; int last;
46c3252001-06-25Martin Nilsson 
b156c62001-04-23Martin Nilsson  array do_enter(RequestID id) { last=_ok;
46c3252001-06-25Martin Nilsson  do_iterate = -1;
b156c62001-04-23Martin Nilsson  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() {
6d754f2001-06-18Martin Stjernholm  return RXML_CONTEXT->tag_set->get_plugins ("if");
b156c62001-04-23Martin Nilsson  } } } class TagTrue { inherit RXML.Tag; constant name = "true"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
6d754f2001-06-18Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
b156c62001-04-23Martin Nilsson  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;
6d754f2001-06-18Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
b156c62001-04-23Martin Nilsson  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) {
46c3252001-06-25Martin Nilsson  do_iterate = -1;
b156c62001-04-23Martin Nilsson  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; } // Must override this since it's used by FrameIf. mapping(string:RXML.Tag) get_plugins()
6d754f2001-06-18Martin Stjernholm  {return RXML_CONTEXT->tag_set->get_plugins ("if");}
b156c62001-04-23Martin Nilsson  } } class TagDefault { inherit RXML.Tag; constant name = "default"; array(RXML.Type) result_types = ({RXML.t_nil}); class Frame { inherit RXML.Frame;
8061442001-07-09Martin Stjernholm  int do_iterate;
b156c62001-04-23Martin Nilsson  array do_enter() { if (up->result != RXML.Void) { do_iterate = -1; return 0; }
8061442001-07-09Martin Stjernholm  do_iterate = 1;
b156c62001-04-23Martin Nilsson  content_type = up->result_type (RXML.PNone); return 0; } array do_return() { up->default_data = content; return 0; } } } RXML.TagSet cond_tags =
8061442001-07-09Martin Stjernholm  RXML.shared_tag_set ("/rxmltags/cond", ({TagCase(), TagDefault()}));
b156c62001-04-23Martin Nilsson  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;
12fe642001-06-09Martin Nilsson  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), // t_var "do-once":RXML.t_text(RXML.PEnt), // t_bool "filter":RXML.t_text(RXML.PEnt), // t_list "sort":RXML.t_text(RXML.PEnt), // t_list
c09ff22001-06-09Martin Nilsson  "remainderinfo":RXML.t_text(RXML.PEnt), // t_var
12fe642001-06-09Martin Nilsson  ]);
c09ff22001-06-09Martin Nilsson  array(string) emit_args = indices( req_arg_types+opt_arg_types );
12fe642001-06-09Martin Nilsson  RXML.Type def_arg_type = RXML.t_text(RXML.PNone);
6d754f2001-06-18Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_any});
b156c62001-04-23Martin Nilsson  int(0..1) should_filter(mapping vs, mapping filter) {
6d754f2001-06-18Martin Stjernholm  RXML.Context ctx = RXML_CONTEXT;
b156c62001-04-23Martin Nilsson  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 &&
12fe642001-06-09Martin Nilsson  id->misc->emit_args->maxrows == RXML.get_var("counter"))
b156c62001-04-23Martin Nilsson  return 0; if(more_rows(res, id->misc->emit_filter)) result = content; return 0; } } }
6534642001-06-28Martin Stjernholm  RXML.TagSet internal =
8061442001-07-09Martin Stjernholm  RXML.shared_tag_set ("/rxmltags/emit", ({ TagDelimiter() }) );
b156c62001-04-23Martin Nilsson  // A slightly modified Array.dwim_sort_func // used as emits sort function.
3202d32001-06-11Martin Nilsson  static int compare(mixed a0, mixed b0, string v) {
b156c62001-04-23Martin Nilsson  RXML.Context ctx;
3202d32001-06-11Martin Nilsson  if(objectp(a0) && a0->rxml_var_eval) {
6d754f2001-06-18Martin Stjernholm  if(!ctx) ctx = RXML_CONTEXT;
b156c62001-04-23Martin Nilsson  a0 = a0->rxml_const_eval ? a0->rxml_const_eval(ctx, v, "", RXML.t_text) : a0->rxml_var_eval(ctx, v, "", RXML.t_text); }
3202d32001-06-11Martin Nilsson  else a0 = (string)a0; if(objectp(b0) && b0->rxml_var_eval) {
6d754f2001-06-18Martin Stjernholm  if(!ctx) ctx = RXML_CONTEXT;
b156c62001-04-23Martin Nilsson  b0 = b0->rxml_const_eval ? b0->rxml_const_eval(ctx, v, "", RXML.t_text) : b0->rxml_var_eval(ctx, v, "", RXML.t_text); }
3202d32001-06-11Martin Nilsson  else b0 = (string)b0; return compare_iter(a0, b0); }
b156c62001-04-23Martin Nilsson 
3202d32001-06-11Martin Nilsson  static int compare_iter(string a0,string b0) {
b156c62001-04-23Martin Nilsson  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;
3202d32001-06-11Martin Nilsson  return compare_iter(a2,b2);
b156c62001-04-23Martin Nilsson  } class Frame { inherit RXML.Frame; RXML.TagSet additional_tags = internal; string scope_name; mapping vars; // These variables are used to store id->misc-variables // that otherwise would be overwritten when emits are // nested. 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);
b989392001-05-16Per Hedbor  PROF_ENTER( args->source, "emit" );
c09ff22001-06-09Martin Nilsson  plugin->eval_args( args, 0, 0, emit_args );
12fe642001-06-09Martin Nilsson  res = plugin->get_dataset(args, id);
b989392001-05-16Per Hedbor  PROF_LEAVE( args->source, "emit" );
b156c62001-04-23Martin Nilsson  TRACE_LEAVE("");
c09ff22001-06-09Martin Nilsson  if(args->skiprows && plugin->skiprows)
b156c62001-04-23Martin Nilsson  m_delete(args, "skiprows");
5ac7892001-06-04Martin Nilsson 
12fe642001-06-09Martin Nilsson  if(args->maxrows && plugin->maxrows)
b156c62001-04-23Martin Nilsson  m_delete(args, "maxrows"); // Parse the filter argument 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 ||
12fe642001-06-09Martin Nilsson  (args->skiprows<0) )
b156c62001-04-23Martin Nilsson  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) {
12fe642001-06-09Martin Nilsson  int loop = args->skiprows;
b156c62001-04-23Martin Nilsson  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,
3202d32001-06-11Martin Nilsson  lambda (mapping(string:mixed) m1, mapping(string:mixed) m2)
b156c62001-04-23Martin Nilsson  { 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 rowinfo or negative skiprows are used we have // to do filtering in a loop of its own, instead of // doing it during the emit loop.
12fe642001-06-09Martin Nilsson  if(args->rowinfo || args->skiprows<0) {
b156c62001-04-23Martin Nilsson  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 skiprows is to be used we must only count // the rows that wouldn't be filtered in the // emit loop. if(args->skiprows) {
12fe642001-06-09Martin Nilsson  int skiprows = args->skiprows;
b156c62001-04-23Martin Nilsson  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; } } // We have to check the filter again, since it // could have been zeroed in the last if statement. if(!filter) { if(args->skiprows) {
12fe642001-06-09Martin Nilsson  if(args->skiprows<0) args->skiprows = sizeof(res) + args->skiprows; res=res[args->skiprows..];
b156c62001-04-23Martin Nilsson  }
5ac7892001-06-04Martin Nilsson  if(args->remainderinfo)
b156c62001-04-23Martin Nilsson  RXML.user_set_var(args->remainderinfo, args->maxrows? max(sizeof(res)-args->maxrows, 0): 0); if(args->maxrows) res=res[..args->maxrows-1]; if(args["do-once"] && sizeof(res)==0) res=({ ([]) }); do_iterate = array_iterate; } id->misc->emit_rows = res; return 0; } parse_error("Wrong return type from emit source plugin.\n"); } int(0..1) do_once_more() { if(vars->counter || !args["do-once"]) return 0; vars = (["counter":1]); return 1; } function do_iterate; int(0..1) object_iterate(RequestID id) { int counter = vars->counter; if(args->maxrows && counter == args->maxrows) return do_once_more(); if(mappingp(vars=res->get_row())) { vars->counter = ++counter; return 1; } vars = (["counter":counter]); return do_once_more(); } int(0..1) object_filter_iterate(RequestID id) { int counter = vars->counter; if(args->maxrows && counter == args->maxrows) return do_once_more(); if(args->skiprows>0) while(args->skiprows-->-1) while((vars=res->get_row()) && should_filter(vars, filter)); else while((vars=res->get_row()) && should_filter(vars, filter)); if(mappingp(vars)) { vars->counter = ++counter; return 1; } vars = (["counter":counter]); return do_once_more(); } int(0..1) array_iterate(RequestID id) { int counter=vars->counter; if(counter>=sizeof(res)) return 0; vars=res[counter++]; vars->counter=counter; return 1; } int(0..1) array_filter_iterate(RequestID id) { int real_counter = vars["real-counter"]; int counter = vars->counter; if(real_counter>=sizeof(res)) return do_once_more(); if(args->maxrows && counter == args->maxrows) return do_once_more(); while(should_filter(res[real_counter++], filter)) if(real_counter>=sizeof(res)) return do_once_more(); vars=res[real_counter-1]; vars["real-counter"] = real_counter; vars->counter = counter+1; return 1; } array do_return(RequestID id) { result = content; id->misc->emit_rows = outer_rows; id->misc->emit_filter = outer_filter; id->misc->emit_args = outer_args; int rounds = vars->counter - !!args["do-once"]; if(args->rowinfo) RXML.user_set_var(args->rowinfo, rounds); _ok = !!rounds; if(args->remainderinfo) { if(args->filter) { int rem; if(arrayp(res)) { foreach(res[vars["real-counter"]+1..], mapping v) if(!should_filter(v, filter)) rem++; } else { mapping v; while( v=res->get_row() ) if(!should_filter(v, filter)) rem++; } RXML.user_set_var(args->remainderinfo, rem); } else if( do_iterate == object_iterate ) RXML.user_set_var(args->remainderinfo, res->num_rows_left()); } return 0; } } } class TagComment { inherit RXML.Tag; constant name = "comment"; constant flags = RXML.FLAG_DONT_REPORT_ERRORS;
6d754f2001-06-18Martin Stjernholm  RXML.Type content_type = RXML.t_any (RXML.PXml); array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
b156c62001-04-23Martin Nilsson  class Frame { inherit RXML.Frame;
6d754f2001-06-18Martin Stjernholm  int do_iterate;
b156c62001-04-23Martin Nilsson  array do_enter() {
6d754f2001-06-18Martin Stjernholm  do_iterate = args && args->preparse ? 1 : -1;
b156c62001-04-23Martin Nilsson  return 0; } array do_return = ({}); } } class TagPIComment { inherit TagComment; constant flags = RXML.FLAG_PROC_INSTR;
6d754f2001-06-18Martin Stjernholm  RXML.Type content_type = RXML.t_any (RXML.PXml); array(RXML.Type) result_types = ({RXML.t_nil}); // No result.
b156c62001-04-23Martin Nilsson } // ---------------------- If plugins ------------------- class UserIf { constant name = "if"; string plugin_name;
4704942001-07-20Martin Stjernholm  string|RXML.RenewablePCode rxml_code;
b156c62001-04-23Martin Nilsson  void create(string pname, string code) { plugin_name = pname; rxml_code = code; } int eval(string ind, RequestID id) { int otruth, res; string tmp; TRACE_ENTER("user defined if argument "+plugin_name, UserIf); otruth = _ok; _ok = -2;
4704942001-07-20Martin Stjernholm  if (objectp (rxml_code)) tmp = rxml_code->eval (RXML_CONTEXT); else [tmp, rxml_code] = RXML_CONTEXT->eval_and_compile (RXML.t_html (RXML.PXml), rxml_code, 1);
b156c62001-04-23Martin Nilsson  res = _ok; _ok = otruth; TRACE_LEAVE(""); if(ind==plugin_name && res!=-2) return res; return (ind==tmp); } } class IfIs { inherit RXML.Tag; constant name = "if"; constant cache = 0; constant case_sensitive = 0; function source; int eval( string value, RequestID id ) { if(cache != -1) CACHE(cache); array arr=value/" "; string|int|float var=source(id, arr[0]); if( !var && zero_type( var ) ) return 0; if(sizeof(arr)<2) return !!var; string is; if(case_sensitive) { var = var+""; if(sizeof(arr)==1) return !!var; is=arr[2..]*" "; } else { var = lower_case( (var+"") ); if(sizeof(arr)==1) return !!var; is=lower_case(arr[2..]*" "); } if(arr[1]=="==" || arr[1]=="=" || arr[1]=="is") return ((is==var)||glob(is,var)|| sizeof(filter( is/",", glob, var ))); if(arr[1]=="!=") return is!=var; string trash; if(sscanf(var,"%f%s",float f_var,trash)==2 && trash=="" && sscanf(is ,"%f%s",float f_is ,trash)==2 && trash=="") { if(arr[1]=="<") return f_var<f_is; if(arr[1]==">") return f_var>f_is; } else { if(arr[1]=="<") return (var<is); if(arr[1]==">") return (var>is); } value=source(id, value); return !!value; } } class IfMatch { inherit RXML.Tag; constant name = "if"; constant cache = 0; function source; int eval( string is, RequestID id ) { array|string value=source(id); if(cache != -1) CACHE(cache); if(!value) return 0; if(arrayp(value)) value=value*" "; value = lower_case( value ); is = lower_case( "*"+is+"*" ); return glob(is,value) || sizeof(filter( is/",", glob, value )); } }
2300802001-08-17Per Hedbor class TagIfDebug { inherit RXML.Tag; constant name = "if"; constant plugin_name = "debug"; int eval( string dbg, RequestID id, mapping m ) { #ifdef DEBUG return 1; #else return 0; #endif } } class TagIfModuleDebug { inherit RXML.Tag; constant name = "if"; constant plugin_name = "module-debug"; int eval( string dbg, RequestID id, mapping m ) { #ifdef MODULE_DEBUG return 1; #else return 0; #endif } }
b156c62001-04-23Martin Nilsson class TagIfDate { inherit RXML.Tag; constant name = "if"; constant plugin_name = "date"; int eval(string date, RequestID id, mapping m) { CACHE(60); // One minute accuracy is probably good enough... int a, b; mapping c; c=localtime(time(1)); b=(int)sprintf("%02d%02d%02d", c->year, c->mon + 1, c->mday); a=(int)replace(date,"-",""); if(a > 999999) a -= 19000000; else if(a < 901201) a += 10000000; if(m->inclusive || !(m->before || m->after) && a==b) return 1; if(m->before && a>b) return 1; else if(m->after && a<b) return 1; } } class TagIfTime { inherit RXML.Tag; constant name = "if"; constant plugin_name = "time"; int eval(string ti, RequestID id, mapping m) { CACHE(time(1)%60); // minute resolution... int tok, a, b, d; mapping c; c=localtime(time(1)); b=(int)sprintf("%02d%02d", c->hour, c->min); a=(int)replace(ti,":",""); if(m->until) { d = (int)m->until; if (d > a && (b > a && b < d) ) return 1; if (d < a && (b > a || b < d) ) return 1; if (m->inclusive && ( b==a || b==d ) ) return 1; } else if(m->inclusive || !(m->before || m->after) && a==b) return 1; if(m->before && a>b) return 1; else if(m->after && a<b) return 1; } } class TagIfUser { inherit RXML.Tag; constant name = "if"; constant plugin_name = "user"; int eval(string u, RequestID id, mapping m) { object db; if( m->database ) db = id->conf->find_user_database( m->database ); User uid = id->conf->authenticate( id, db ); if( !uid && !id->auth ) return 0; NOCACHE(); if( u == "any" ) if( m->file ) // Note: This uses the compatibility interface. Should probably // be fixed. return match_user( id->auth, id->auth[1], m->file, !!m->wwwfile, id); else return !!u; else if(m->file) // Note: This uses the compatibility interface. Should probably // be fixed. return match_user(id->auth,u,m->file,!!m->wwwfile,id); else return has_value(u/",", uid->name()); } private int match_user(array u, string user, string f, int wwwfile, RequestID id) { string s, pass; if(u[1]!=user) return 0; if(!wwwfile) s=Stdio.read_bytes(f); else s=id->conf->try_get_file(Roxen.fix_relative(f,id), id); return ((pass=simple_parse_users_file(s, u[1])) && (u[0] || match_passwd(u[2], pass))); } private int match_passwd(string try, string org) { if(!strlen(org)) return 1; if(crypt(try, org)) return 1; } private string simple_parse_users_file(string file, string u) { if(!file) return 0; foreach(file/"\n", string line) { array(string) arr = line/":"; if (arr[0] == u && sizeof(arr) > 1) return(arr[1]); } } } class TagIfGroup { inherit RXML.Tag; constant name = "if"; constant plugin_name = "group"; int eval(string u, RequestID id, mapping m) { object db; if( m->database ) db = id->conf->find_user_database( m->database ); User uid = id->conf->authenticate( id, db ); if( !uid && !id->auth ) return 0; NOCACHE(); if( m->groupfile ) return ((m->groupfile && sizeof(m->groupfile)) && group_member(id->auth, u, m->groupfile, id)); return sizeof( uid->groups() & (u/"," )) > 0; } private int group_member(array auth, string group, string groupfile, RequestID id) { if(!auth) return 0; // No auth sent string s; catch { s = Stdio.read_bytes(groupfile); }; if (!s) s = id->conf->try_get_file( Roxen.fix_relative( groupfile, id), id ); if (!s) return 0; s = replace(s,({" ","\t","\r" }), ({"","","" })); multiset(string) members = simple_parse_group_file(s, group); return members[auth[1]]; } private multiset simple_parse_group_file(string file, string g) { multiset res = (<>); array(string) arr ; foreach(file/"\n", string line) if(sizeof(arr = line/":")>1 && (arr[0] == g)) res += (< @arr[-1]/"," >); return res; } } class TagIfExists { inherit RXML.Tag; constant name = "if"; constant plugin_name = "exists"; int eval(string u, RequestID id) { CACHE(5); return id->conf->is_file(Roxen.fix_relative(u, id), id); } } class TagIfNserious { inherit RXML.Tag; constant name = "if"; constant plugin_name = "nserious"; int eval() { #ifdef NSERIOUS return 1; #else return 0; #endif } } class TagIfModule { inherit RXML.Tag; constant name = "if"; constant plugin_name = "module"; int eval(string u, RequestID id) { if (!sizeof(u)) return 0; return sizeof(glob(u+"#*", indices(id->conf->enabled_modules))); } } class TagIfTrue { inherit RXML.Tag; constant name = "if"; constant plugin_name = "true"; int eval(string u, RequestID id) { return _ok; } } class TagIfFalse { inherit RXML.Tag; constant name = "if"; constant plugin_name = "false"; int eval(string u, RequestID id) { return !_ok; } } class TagIfAccept { inherit IfMatch; constant plugin_name = "accept"; array source(RequestID id) { if( !id->request_headers->accept ) // .. there might be no header return ({}); if( arrayp(id->request_headers->accept) ) // .. there might be multiple id->request_headers->accept = id->request_headers->accept*","; // .. or there might be one. array data = id->request_headers->accept/","; array res = ({}); foreach( data, string d ) { sscanf( d, "%s;", d ); // Ignores the quality parameters etc. res += ({d}); } return res; } } class TagIfConfig { inherit IfIs; constant plugin_name = "config"; int source(RequestID id, string s) { return id->config[s]; } } class TagIfCookie { inherit IfIs; constant plugin_name = "cookie"; string source(RequestID id, string s) { return id->cookies[s]; } } class TagIfClient { inherit IfMatch; constant plugin_name = "client"; array source(RequestID id) { return id->client; } } #if ROXEN_COMPAT <= 1.3 class TagIfName { inherit TagIfClient; constant plugin_name = "name"; } #endif class TagIfDefined { inherit IfIs; constant plugin_name = "defined"; string|int|float source(RequestID id, string s) { mixed val;
6d754f2001-06-18Martin Stjernholm  if(!(val=RXML_CONTEXT->misc[s])) return 0;
b156c62001-04-23Martin Nilsson  if(stringp(val) || intp(val) || floatp(val)) return val; return 1; } } class TagIfDomain { inherit IfMatch; constant plugin_name = "domain"; string source(RequestID id) { return id->host; } } class TagIfIP { inherit IfMatch; constant plugin_name = "ip"; string source(RequestID id) { return id->remoteaddr; } } #if ROXEN_COMPAT <= 1.3 class TagIfHost { inherit TagIfIP; constant plugin_name = "host"; } #endif class TagIfLanguage { inherit IfMatch; constant plugin_name = "language"; array source(RequestID id) { return id->misc->pref_languages->get_languages(); } } class TagIfMatch { inherit IfIs; constant plugin_name = "match"; string source(RequestID id, string s) { return s; } } class TagIfMaTcH { inherit TagIfMatch; constant plugin_name = "Match"; constant case_sensitive = 1; } class TagIfPragma { inherit IfIs; constant plugin_name = "pragma"; int source(RequestID id, string s) { return id->pragma[s]; } } class TagIfPrestate { inherit IfIs; constant plugin_name = "prestate"; constant cache = -1; int source(RequestID id, string s) { return id->prestate[s]; } } class TagIfReferrer { inherit IfMatch; constant plugin_name = "referrer"; array source(RequestID id) { return id->referer; } } class TagIfSupports { inherit IfIs; constant plugin_name = "supports"; int source(RequestID id, string s) { return id->supports[s]; } } class TagIfVariable { inherit IfIs; constant plugin_name = "variable"; constant cache = 1; string source(RequestID id, string s) { mixed var=RXML.user_get_var(s); if(!var) return var; return RXML.t_text->encode (var); } } class TagIfVaRiAbLe { inherit TagIfVariable; constant plugin_name = "Variable"; constant case_sensitive = 1; } class TagIfSizeof { inherit IfIs; constant plugin_name = "sizeof"; constant cache = -1; int source(RequestID id, string s) { mixed var=RXML.user_get_var(s); if(!var) { if(zero_type(RXML.user_get_var(s))) return 0; return 1; } if(stringp(var) || arrayp(var) || multisetp(var) || mappingp(var)) return sizeof(var); if(objectp(var) && var->_sizeof) return sizeof(var); return sizeof((string)var); } } class TagIfClientvar { inherit IfIs; constant plugin_name = "clientvar"; string source(RequestID id, string s) { return id->client_var[s]; } } class TagIfExpr { inherit RXML.Tag; constant name = "if"; constant plugin_name = "expr"; int eval(string u) { return (int)sexpr_eval(u); } } // --------------------- Emit plugins ------------------- class TagEmitSources { inherit RXML.Tag; constant name="emit"; constant plugin_name="sources"; array(mapping(string:string)) get_dataset(mapping m, RequestID id) {
6d754f2001-06-18Martin Stjernholm  return Array.map( indices(RXML_CONTEXT->tag_set->get_plugins("emit")),
b156c62001-04-23Martin Nilsson  lambda(string source) { return (["source":source]); } ); } } class TagPathplugin { inherit RXML.Tag; constant name = "emit"; constant plugin_name = "path"; array get_dataset(mapping m, RequestID id) { string fp = ""; array res = ({}); string p = m->path || id->not_query; if( m->trim ) sscanf( p, "%s"+m->trim, p ); if( p[-1] == '/' ) p = p[..strlen(p)-2]; array q = p / "/"; if( m->skip ) q = q[(int)m->skip..]; if( m["skip-end"] ) q = q[..sizeof(q)-((int)m["skip-end"]+1)]; foreach( q, string elem ) { fp += "/" + elem; fp = replace( fp, "//", "/" ); res += ({ ([ "name":elem, "path":fp ]) }); } return res; } } class TagEmitValues { inherit RXML.Tag; constant name="emit"; constant plugin_name="values"; array(mapping(string:string)) get_dataset(mapping m, RequestID id) { if(m["from-scope"]) { m->values=([]);
6d754f2001-06-18Martin Stjernholm  RXML.Context context=RXML_CONTEXT;
b156c62001-04-23Martin Nilsson  map(context->list_var(m["from-scope"]), lambda(string var){ m->values[var]=context->get_var(var, m["from-scope"]); return ""; }); } if( m->variable )
6d754f2001-06-18Martin Stjernholm  m->values = RXML_CONTEXT->user_get_var( m->variable );
b156c62001-04-23Martin Nilsson  if(!m->values) return ({}); if(stringp(m->values)) { if(m->advanced) { switch(m->advanced) { case "chars": m->split=""; break; case "lines": m->values = replace(m->values, ({ "\n\r", "\r\n", "\r" }), ({ "\n", "\n", "\n" })); m->split = "\n"; break; case "words": m->values = replace(m->values, ({ "\n\r", "\r\n", "\r" }), ({ "\n", "\n", "\n" })); m->values = replace(m->values, ({ "-\n", "\n", "\t" }), ({ "", " ", " " })); m->values = map(m->values/" " - ({""}), lambda(string word) { if(word[-1]=='.' || word[-1]==',' || word[-1]==';' || word[-1]==':' || word[-1]=='!' || word[-1]=='?') return word[..sizeof(word)-2]; return word; }); break; } }
4bb4d12001-05-31Martin Nilsson  if(stringp(m->values)) m->values=m->values / (m->split || "\000");
b156c62001-04-23Martin Nilsson  } if(mappingp(m->values)) return map( indices(m->values),
4bb4d12001-05-31Martin Nilsson  lambda(mixed ind) { mixed val = m->values[ind]; if(m->trimwhites) val=String.trim_all_whites((string)val); if(m->case=="upper") val=upper_case(val); else if(m->case=="lower") val=lower_case(val); return (["index":ind,"value":val]); });
b156c62001-04-23Martin Nilsson  if(arrayp(m->values)) return map( m->values, lambda(mixed val) { if(m->trimwhites) val=String.trim_all_whites((string)val); if(m->case=="upper") val=upper_case(val); else if(m->case=="lower") val=lower_case(val); return (["value":val]); } ); RXML.run_error("Values variable has wrong type %t.\n", m->values); } } class TagEmitFonts { inherit RXML.Tag; constant name = "emit", plugin_name = "fonts"; array get_dataset(mapping args, RequestID id) { return roxen->fonts->get_font_information(args->ttf_only); } } // ---------------- API registration stuff --------------- string api_query_modified(RequestID id, string f, int|void by) { mapping m = ([ "by":by, "file":f ]); return tag_modified("modified", m, id, id); } // --------------------- Documentation ----------------------- mapping tagdocumentation() { Stdio.File file=Stdio.File(); if(!file->open(__FILE__,"r")) return 0; mapping doc=compile_string("#define manual\n"+file->read())->tagdoc; file->close(); if(!file->open("etc/supports","r")) return doc;
921da02001-07-08Martin Nilsson  Parser.HTML()-> add_container("flags", format_support)-> add_container("vars", format_support)-> set_extra(doc)-> finish(file->read())->read();
b156c62001-04-23Martin Nilsson  return doc; }
921da02001-07-08Martin Nilsson static int format_support(Parser.HTML p, mapping m, string c, mapping doc) { string key = ([ "flags":"if#supports", "vars":"if#clientvar" ])[p->tag_name()];
b156c62001-04-23Martin Nilsson  c=Roxen.html_encode_string(c)-"#! "; c=(Array.map(c/"\n", lambda(string row) { if(sscanf(row, "%*s - %*s")!=2) return ""; return "<li>"+row+"</li>"; }) - ({""})) * "\n"; doc[key]+="<ul>\n"+c+"</ul>\n"; return 0; } #ifdef manual constant tagdoc=([ "&roxen;":#"<desc scope='scope'><p><short> This scope contains information specific to this Roxen WebServer.</short> It is not possible to write any information to this scope </p></desc>", "&roxen.domain;":#"<desc ent='ent'><p> The domain name of this site. </p></desc>", "&roxen.hits;":#"<desc ent='ent'><p> The number of hits, i.e. requests the webserver has accumulated since it was last started. </p></desc>", "&roxen.hits-per-minute;":#"<desc ent='ent'><p> The number of hits per minute, in average. </p></desc>", "&roxen.pike-version;":#"<desc ent='ent'><p> The version of Pike the webserver is using. </p></desc>", "&roxen.sent;":#"<desc ent='ent'><p> The total amount of data the webserver has sent. </p></desc>", "&roxen.sent-kbit-per-second;":#"<desc ent='ent'><p> The average amount of data the webserver has sent, in Kibibits. </p></desc>", "&roxen.sent-mb;":#"<desc ent='ent'><p> The total amount of data the webserver has sent, in Mebibits. </p></desc>", "&roxen.sent-per-minute;":#"<desc ent='ent'><p> The number of bytes that the webserver sends during a minute, on average. </p></desc>", "&roxen.server;":#"<desc ent='ent'><p> The URL of the webserver. </p></desc>", "&roxen.ssl-strength;":#"<desc ent='ent'><p> How many bits encryption strength are the SSL capable of </p></desc>", "&roxen.time;":#"<desc ent='ent'><p> The current posix time. </p></desc>", "&roxen.unique-id;":#"<desc ent='ent'><p> Returns a unique id that can be used for e.g. session identification. </p></desc>", "&roxen.uptime;":#"<desc ent='ent'><p> The total uptime of the webserver, in seconds. </p></desc>", "&roxen.uptime-days;":#"<desc ent='ent'><p> The total uptime of the webserver, in days. </p></desc>", "&roxen.uptime-hours;":#"<desc ent='ent'><p> The total uptime of the webserver, in hours. </p></desc>", "&roxen.uptime-minutes;":#"<desc ent='ent'><p> The total uptime of the webserver, in minutes. </p></desc>", //---------------------------------------------------------------------- "&client;":#"<desc scope='scope'><p><short> This scope contains information specific to the client/browser that is accessing the page.</short> </p></desc>", "&client.ip;":#"<desc ent='ent'><p> The client is located on this IP-address. </p></desc>", "&client.host;":#"<desc ent='ent'><p> The host name of the client, if possible to resolve. </p></desc>", "&client.name;":#"<desc ent='ent'><p> The name of the client, i.e. \"Mozilla/4.7\". </p></desc>", "&client.Fullname;":#"<desc ent='ent'><p> The full user agent string, i.e. name of the client and additional info like; operating system, type of computer, etc. E.g. \"Mozilla/4.7 [en] (X11; I; SunOS 5.7 i86pc)\". </p></desc>", "&client.fullname;":#"<desc ent='ent'><p> The full user agent string, i.e. name of the client and additional info like; operating system, type of computer, etc. E.g. \"mozilla/4.7 [en] (x11; i; sunos 5.7 i86pc)\". </p></desc>", "&client.referrer;":#"<desc ent='ent'><p> Prints the URL of the page on which the user followed a link that brought her to this page. The information comes from the referrer header sent by the browser. </p></desc>", "&client.accept-language;":#"<desc ent='ent'><p> The client prefers to have the page contents presented in this language. </p></desc>", "&client.accept-languages;":#"<desc ent='ent'><p> The client prefers to have the page contents presented in this language but these additional languages are accepted as well. </p></desc>", "&client.language;":#"<desc ent='ent'><p> The clients most preferred language. </p></desc>", "&client.languages;":#"<desc ent='ent'><p> An ordered list of the clients most preferred languages. </p></desc>", "&client.authenticated;":#"<desc ent='ent'><p> Returns the name of the user logged on to the site, i.e. the login name, if any exists. </p></desc>", "&client.user;":#"<desc ent='ent'><p> Returns the name the user used when he/she tried to log on the site, i.e. the login name, if any exists. </p></desc>", "&client.password;":#"<desc ent='ent'><p> </p></desc>", "&client.height;":#"<desc ent='ent'><p> The presentation area height in pixels. For WAP-phones. </p></desc>", "&client.width;":#"<desc ent='ent'><p> The presentation area width in pixels. For WAP-phones. </p></desc>", "&client.robot;":#"<desc ent='ent'><p> Returns the name of the webrobot. Useful if the robot requesting pages is to be served other contents than most visitors. Use <ent>client.robot</ent> together with <xref href='../if/if.tag' />.</p> <p>Possible webrobots are: ms-url-control, architex, backrub, checkbot, fast, freecrawl, passagen, gcreep, getright, googlebot, harvest, alexa, infoseek, intraseek, lycos, webinfo, roxen, altavista, scout, slurp, url-minder, webcrawler, wget, xenu and yahoo.</p> </desc>", "&client.javascript;":#"<desc ent='ent'><p> Returns the highest version of javascript supported. </p></desc>", "&client.tm;":#"<desc ent='ent'><p><short> Generates a trademark sign in a way that the client can render.</short> Possible outcomes are \"&amp;trade;\", \"&lt;sup&gt;TM&lt;/sup&gt;\", and \"&amp;gt;TM&amp;lt;\".</p> </desc>", //---------------------------------------------------------------------- "&page;":#"<desc scope='scope'><p><short> This scope contains information specific to this page.</short></p> </desc>", "&page.realfile;":#"<desc ent='ent'><p> Path to this file in the file system. </p></desc>", "&page.virtroot;":#"<desc ent='ent'><p> The root of the present virtual filesystem. </p></desc>", // &page.virtfile; is same as &page.path; but deprecated since we want to // harmonize with SiteBuilder entities. "&page.path;":#"<desc ent='ent'><p> Absolute path to this file in the virtual filesystem. </p></desc>", "&page.pathinfo;":#"<desc ent='ent'><p> The \"path info\" part of the URL, if any. Can only get set if the \"Path info support\" module is installed. For details see the documentation for that module. </p></desc>", "&page.query;":#"<desc ent='ent'><p> The query part of the page URI. </p></desc>", "&page.url;":#"<desc ent='ent'><p> The absolute path for this file from the web server's root or point of view including query variables. </p></desc>", "&page.last-true;":#"<desc ent='ent'><p> Is \"1\" if the last <tag>if</tag>-statement succeeded, otherwise 0. (<xref href='../if/true.tag' /> and <xref href='../if/false.tag' /> is considered as <tag>if</tag>-statements here) See also: <xref href='../if/' />.</p> </desc>", "&page.language;":#"<desc ent='ent'><p> What language the contents of this file is written in. The language must be given as metadata to be found. </p></desc>", "&page.scope;":#"<desc ent='ent'><p> The name of the current scope, i.e. the scope accessible through the name \"_\". </p></desc>", "&page.filesize;":#"<desc ent='ent'><p> This file's size, in bytes. </p></desc>", "&page.ssl-strength;":#"<desc ent='ent'><p> The strength in bits of the current SSL connection. </p></desc>", "&page.self;":#"<desc ent='ent'><p> The name of this file. </p></desc>", "&page.dir;":#"<desc ent='ent'><p> The name of the directory in the virtual filesystem where the file resides. </p></desc>", //---------------------------------------------------------------------- "&form;":#"<desc scope='scope'><p><short hide='hide'> This scope contains form variables.</short>This scope contains the form variables, i.e. the answers to HTML forms sent by the client. There are no predefined entities for this scope. </p></desc>", //---------------------------------------------------------------------- "&cookie;":#"<desc scope='scope'><p><short> This scope contains the cookies sent by the client.</short> Adding, deleting or changing in this scope updates the clients cookies. There are no predefined entities for this scope. When adding cookies to this scope they are automatically set to expire after two years. </p></desc>", //---------------------------------------------------------------------- "&var;":#"<desc scope='scope'><p><short> This scope is empty when the page parsing begins.</short> There are no predefined entities for this </p></desc>", //---------------------------------------------------------------------- "roxen_automatic_charset_variable":#"<desc tag='tag'><p> If put inside a form, the right character encoding of the submitted form can be guessed by Roxen WebServer. </p></desc>", //---------------------------------------------------------------------- "colorscope":#"<desc cont='cont'><p><short>
dd54612001-07-20Johan Sundström  Makes it possible to change the autodetected colors within the tag.</short>
b156c62001-04-23Martin Nilsson  Useful when out-of-order parsing occurs, e.g.</p> <ex type=box> <define tag=\"hello\"> <colorscope bgcolor=\"red\"> <gtext>Hello</gtext> </colorscope> </define>
43ff412001-02-06Martin Nilsson  <table><tr> <td bgcolor=\"red\"> <hello/> </td> </tr></table> </ex> </desc>
b156c62001-04-23Martin Nilsson <attr name='text' value='color'><p> Set the text color within the scope.</p> </attr> <attr name='bgcolor' value='color'<p> Set the background color within the scope.</p> </attr> <attr name='link' value='color'<p> Set the link color within the scope.</p> </attr> <attr name='alink' value='color'<p> Set the active link color within the scope.</p> </attr> <attr name='vlink' value='color'<p> Set the visited link color within the scope.</p> </attr>", //---------------------------------------------------------------------- "aconf":#"<desc cont='cont'><p><short> Creates a link that can modify the persistent states in the cookie RoxenConfig.</short> In practice it will add &lt;keyword&gt;/ right after the server, i.e. if you want to remove bacon and add egg the first \"directory\" in the path will be &lt;-bacon,egg&gt;. If the user follows this link the WebServer will understand how the RoxenConfig cookie should be modified and will send a new cookie along with a redirect to the given url, but with the first \"directory\" removed. The presence of a certain keyword in can be controlled with <xref href='../if/if_config.tag' />.</p> </desc> <attr name=href value=uri> <p>Indicates which page should be linked to, if any other than the present one.</p> </attr> <attr name=add value=string> <p>The \"cookie\" or \"cookies\" that should be added, in a comma separated list.</p> </attr> <attr name=drop value=string> <p>The \"cookie\" or \"cookies\" that should be dropped, in a comma separated list.</p> </attr> <attr name=class value=string> <p>This cascading style sheet (CSS) class definition will apply to the a-element.</p> <p>All other attributes will be inherited by the generated a tag.</p> </attr>", //----------------------------------------------------------------------
5952fd2001-04-25Martin Nilsson "append":#"<desc tag='tag' cont='cont'><p><short>
b156c62001-04-23Martin Nilsson  Appends a value to a variable. The variable attribute and one more is required.</short> </p></desc> <attr name=variable value=string required='required'> <p>The name of the variable.</p> </attr> <attr name=value value=string> <p>The value the variable should have appended.</p> <ex> <set variable='var.ris' value='Roxen'/> <append variable='var.ris' value=' Internet Software'/> <ent>var.ris</ent> </ex> </attr> <attr name=from value=string> <p>The name of another variable that the value should be copied from.</p> </attr>", //---------------------------------------------------------------------- "apre":#"<desc cont='cont'><p><short> Creates a link that can modify prestates.</short> Prestates can be seen as valueless cookies or toggles that are easily modified by the user. The prestates are added to the URL. If you set the prestate \"no-images\" on \"http://www.demolabs.com/index.html\" the URL would be \"http://www.demolabs.com/(no-images)/\". Use <xref href='../if/if_prestate.tag' /> to test for the presence of a prestate. <tag>apre</tag> works just like the <tag>a href='...'</tag> container, but if no \"href\" attribute is specified, the current page is used. </p> </desc> <attr name=href value=uri> <p>Indicates which page should be linked to, if any other than the present one.</p> </attr> <attr name=add value=string> <p>The prestate or prestates that should be added, in a comma separated list.</p> </attr> <attr name=drop value=string> <p>The prestate or prestates that should be dropped, in a comma separated list.</p> </attr> <attr name=class value=string> <p>This cascading style sheet (CSS) class definition will apply to the a-element.</p> </attr>", //---------------------------------------------------------------------- "auth-required":#"<desc tag='tag'><p><short> Adds an HTTP auth required header and return code (401), that will force the user to supply a login name and password.</short> This tag is needed when using access control in RXML in order for the user to be prompted to login. </p></desc>
dcc11b2001-05-30Martin Nilsson <attr name=realm value=string default='document access'>
b156c62001-04-23Martin Nilsson  <p>The realm you are logging on to, i.e \"Demolabs Intranet\".</p> </attr> <attr name=message value=string> <p>Returns a message if a login failed or cancelled.</p> </attr>", //---------------------------------------------------------------------- "autoformat":#"<desc cont='cont'><p><short hide='hide'> Replaces newlines with <tag>br/</tag>:s'.</short>Replaces newlines with <tag>br /</tag>:s'.</p> <ex><autoformat> It is almost like using the pre tag. </autoformat></ex> </desc> <attr name=p> <p>Replace empty lines with <tag>p</tag>:s.</p> <ex><autoformat p=''> It is almost like using the pre tag. </autoformat></ex> </attr> <attr name=nobr> <p>Do not replace newlines with <tag>br /</tag>:s.</p> </attr> <attr name=nonbsp><p> Do not turn consecutive spaces into interleaved breakable/nonbreakable spaces. When this attribute is not given, the tag will behave more or less like HTML:s <tag>pre</tag> tag, making whitespace indention work, without the usually unwanted effect of really long lines extending the browser window width.</p> </attr> <attr name=class value=string> <p>This cascading style sheet (CSS) definition will be applied on the p elements.</p> </attr>", //---------------------------------------------------------------------- "cache":#"<desc cont='cont'><p><short>
c489512001-07-26Martin Stjernholm  This tag caches the evaluated result of its contents.</short> When the tag is encountered again in a later request, it can thus look up and return that result without evaluating the content again.</p> <p>Nested <tag>cache</tag> tags are normally cached separately, and they are also recognized so that the surrounding tag doesn't cache their contents too. It's thus possible to change the cache parameters or completely disable caching of a certain part of the content inside a <tag>cache</tag> tag. Note that this implies that any RXML tags
3a3a692001-08-07Martin Stjernholm  that surrounds the inner <tag>cache</tag> tag(s) won't be cached.</p>
c489512001-07-26Martin Stjernholm  <p>Besides the value produced by the content, any assignments to RXML variables in any scope are cached. I.e. an RXML code block which produces a value in a variable may be cached, and the same value will be assigned again to that variable when the cached entry is used again.</p>
41a4da2001-07-26Martin Stjernholm  <p>When the content is evaluated, the produced result is associated with a key that is built by taking the values of certain variables and other pieces of data, which thus are what the cache depends on.
0e798d2001-08-22Martin Stjernholm  The arguments \"variable\", \"key\" and \"profile\" lets you specify the cache dependencies.</p>
41a4da2001-07-26Martin Stjernholm  <p>Note that it's easy to create huge amounts of cached values if the
0e798d2001-08-22Martin Stjernholm  cache parameters are chosen badly. E.g. to depend on the contents of the form scope is typically only acceptable when combined with a fairly short cache time, since it's otherwise easy to fill up the memory on the server simply by making many requests with random variables.</p>
41a4da2001-07-26Martin Stjernholm  <p>The cache can be shared between all <tag>cache</tag> tags with identical content, which is typically useful in <tag>cache</tag> tags used in templates included into many pages. The drawback is that cache entries stick around when the <tag>cache</tag> tags change and
c489512001-07-26Martin Stjernholm  that the cache won't be persistent (see below). Only shared caches have any effect if the RXML pages aren't compiled and cached.</p>
41a4da2001-07-26Martin Stjernholm 
a64efe2001-07-26Martin Stjernholm  <p>If the page is compiled to p-code which is saved, and the cache is not shared, and there is no timeout on it, then the produced cache entries are also saved, and the cache is thus persistent. In this case it's thus especially important to limit the number of
41a4da2001-07-26Martin Stjernholm  alternative cache entries.</p>
0e798d2001-08-22Martin Stjernholm  <p>Compatibility note: If the compatibility level of the site is lower than 2.2 and there are no \"variable\" or \"profile\" arguments, the cache depends on the contents of the form scope and the path of the current page (i.e. <ent>page.path</ent>). This is often a bad policy since it's easy for a client to generate many cache entries.</p>
41a4da2001-07-26Martin Stjernholm </desc> <attr name=variable value=string> <p>This is a comma-separated list of variables and scopes that the
0e798d2001-08-22Martin Stjernholm  cache should depend on. The value can be an empty string, which is useful to only disable the default dependencies in compatibility mode.</p>
41a4da2001-07-26Martin Stjernholm  <p>Since it's important to keep down the size of the cache, this should typically be kept to only a few variables with a limited set of possible values, or else the cache should have a timeout.</p> </attr>
b156c62001-04-23Martin Nilsson  <attr name=key value=string>
41a4da2001-07-26Martin Stjernholm  <p>Use the value of this attribute directly in the key. The variable attribute is the preferred way to add depends to the cache.</p> </attr>
a64efe2001-07-26Martin Stjernholm <attr name=profile value=string> <p>A comma-separated list to choose one or more profiles from a set of preconfigured cache profiles. Which cache profiles are available depends on the RXML parser module in use; the standard RXML parser
0e798d2001-08-22Martin Stjernholm  currently has none.</p>
a64efe2001-07-26Martin Stjernholm </attr>
41a4da2001-07-26Martin Stjernholm <attr name=shared value=string> <p>Share the cache between different instances of the <tag>cache</tag> with identical content, wherever they may appear on this page or some other in the same server. See the tag description for details about shared caches.</p> </attr> <attr name=nocache> <p>Do not cache the content in any way. Typically useful to disable caching of a section inside another cache tag.</p> </attr> <attr name=propagate> <p>Propagate the cache settings to the surrounding <tag>cache</tag> tag, if there is any. Useful to locally add depends to a cache
c489512001-07-26Martin Stjernholm  without introducing a new cache level. If there is no surrounding
41a4da2001-07-26Martin Stjernholm  <tag>cache</tag> tag, this argument is ignored.
b156c62001-04-23Martin Nilsson </attr> <attr name=nohash>
41a4da2001-07-26Martin Stjernholm  <p>If the cache is shared, then the content won't be made part of the cache key. Thus the cache entries can be mixed up with other <tag>cache</tag> tags.</p>
b156c62001-04-23Martin Nilsson </attr>
77a8ac2001-06-26Martin Nilsson <attr name='not-post-method'> <p>By adding this attribute all HTTP requests using the POST method will be unaffected by the caching. The result will be calculated every time, and the result will not be stored in the cache. The contents of the cache will however remain unaffected by the POST request.</p> </attr> <attr name='flush-on-no-cache'> <p>If this attribute is used the cache will be flushed every time a client sends a pragma no-cache header to the server. These are e.g. sent when shift+reload is pressed in Netscape Navigator.</p> </attr>
b156c62001-04-23Martin Nilsson <attr name=years value=number> <p>Add this number of years to the time this entry is valid.</p> </attr> <attr name=months value=number> <p>Add this number of months to the time this entry is valid.</p> </attr> <attr name=weeks value=number> <p>Add this number of weeks to the time this entry is valid.</p> </attr> <attr name=days value=number> <p>Add this number of days to the time this entry is valid.</p> </attr> <attr name=hours value=number> <p>Add this number of hours to the time this entry is valid.</p> </attr> <attr name=beats value=number> <p>Add this number of beats to the time this entry is valid.</p> </attr> <attr name=minutes value=number> <p>Add this number of minutes to the time this entry is valid.</p> </attr> <attr name=seconds value=number> <p>Add this number of seconds to the time this entry is valid.</p> </attr>",
41a4da2001-07-26Martin Stjernholm // Intentionally left undocumented: // // <attr name=disable-key-hash> // Do not hash the key used in the cache entry. Normally the // produced key is hashed to reduce memory usage and improve speed, // but since that makes it theoretically possible that two cache // entries clash, this attribute may be used to avoid it. // </attr>
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
3a3a692001-08-07Martin Stjernholm "nocache": #"<desc cont='nocache'><p><short> Avoid caching of a part inside a <tag>cache</tag> tag.</short> This is the same as using the <tag>cache</tag> tag with the nocache argument.</p> <p>Note that when a part inside a <tag>cache</tag> tag isn't cached, it implies that any RXML tags that surround the <tag>nocache</tag> tag inside the <tag>cache</tag> tag also aren't cached.</p> </desc>", //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "catch":#"<desc cont='cont'><p><short> Evaluates the RXML code, and, if nothing goes wrong, returns the parsed contents.</short> If something does go wrong, the error message is returned instead. See also <xref href='throw.tag' />. </p> </desc>", //---------------------------------------------------------------------- "charset":#"<desc cont='cont'><p><short> </short> </p> </desc>", //---------------------------------------------------------------------- "configimage":#"<desc tag='tag'><p><short> Returns one of the internal Roxen configuration images.</short> The src attribute is required. </p></desc> <attr name=src value=string> <p>The name of the picture to show.</p> </attr> <attr name=border value=number default=0> <p>The image border when used as a link.</p> </attr> <attr name=alt value=string default='The src string'> <p>The picture description.</p> </attr> <attr name=class value=string> <p>This cascading style sheet (CSS) class definition will be applied to the image.</p> <p>All other attributes will be inherited by the generated img tag.</p> </attr>", //---------------------------------------------------------------------- "configurl":#"<desc tag='tag'><p><short> Returns a URL to the administration interface.</short> </p></desc>", //---------------------------------------------------------------------- "cset":#"<desc cont='cont'><p> Sets a variable with its content.</p> </desc> <attr name=variable value=name> <p>The variable to be set.</p> </attr> <attr name=quote value=html|none> <p>How the content should be quoted before assigned to the variable. Default is html.</p> </attr>", //---------------------------------------------------------------------- "crypt":#"<desc cont='cont'><p><short> Encrypts the contents as a Unix style password.</short> Useful when combined with services that use such passwords.</p> <p>Unix style passwords are one-way encrypted, to prevent the actual clear-text password from being stored anywhere. When a login attempt is made, the password supplied is also encrypted and then compared to the stored encrypted password.</p> </desc> <attr name=compare value=string> <p>Compares the encrypted string with the contents of the tag. The tag will behave very much like an <xref href='../if/if.tag' /> tag.</p> <ex><crypt compare=\"LAF2kkMr6BjXw\">Roxen</crypt> <then>Yepp!</then> <else>Nope!</else> </ex> </attr>", //---------------------------------------------------------------------- "date":#"<desc tag='tag'><p><short> Inserts the time and date.</short> Does not require attributes. </p></desc> <attr name=unix-time value=number of seconds> <p>Display this time instead of the current. This attribute uses the specified Unix 'time_t' time as the starting time (which is <i>01:00, January the 1st, 1970</i>), instead of the current time. This is mostly useful when the <tag>date</tag> tag is used from a Pike-script or Roxen module.</p> <ex ><date unix-time='120'/></ex> </attr> <attr name=timezone value=local|GMT default=local> <p>Display the time from another timezone.</p> </attr> <attr name=years value=number> <p>Add this number of years to the result.</p> <ex ><date date='' years='2'/></ex> </attr> <attr name=months value=number> <p>Add this number of months to the result.</p> <ex ><date date='' months='2'/></ex> </attr> <attr name=weeks value=number> <p>Add this number of weeks to the result.</p> <ex ><date date='' weeks='2'/></ex> </attr> <attr name=days value=number> <p>Add this number of days to the result.</p> </attr> <attr name=hours value=number> <p>Add this number of hours to the result.</p> <ex ><date time='' hours='2' type='iso'/></ex> </attr> <attr name=beats value=number> <p>Add this number of beats to the result.</p> <ex ><date time='' beats='10' type='iso'/></ex> </attr> <attr name=minutes value=number> <p>Add this number of minutes to the result.</p> </attr> <attr name=seconds value=number> <p>Add this number of seconds to the result.</p> </attr> <attr name=adjust value=number> <p>Add this number of seconds to the result.</p> </attr> <attr name=brief> <p>Show in brief format.</p> <ex ><date brief=''/></ex> </attr> <attr name=time> <p>Show only time.</p> <ex ><date time=''/></ex> </attr> <attr name=date> <p>Show only date.</p> <ex ><date date=''/></ex> </attr> <attr name=type value=string|ordered|iso|discordian|stardate|number|unix> <p>Defines in which format the date should be displayed in. Discordian and stardate only make a difference when not using part. Note that type=stardate has a separate companion attribute, prec, which sets the precision.</p> <xtable> <row><c><p><i>type=discordian</i></p></c><c><p><ex ><date date='' type='discordian'/> </ex></p></c></row> <row><c><p><i>type=iso</i></p></c><c><p><ex ><date date='' type='iso'/></ex></p></c></row> <row><c><p><i>type=number</i></p></c><c><p><ex ><date date='' type='number'/></ex></p></c></row> <row><c><p><i>type=ordered</i></p></c><c><p><ex ><date date='' type='ordered'/></ex></p></c></row> <row><c><p><i>type=stardate</i></p></c><c><p><ex ><date date='' type='stardate'/></ex></p></c></row> <row><c><p><i>type=string</i></p></c><c><p><ex ><date date='' type='string'/></ex></p></c></row> <row><c><p><i>type=unix</i></p></c><c><p><ex ><date date='' type='unix'/></ex></p></c></row> </xtable> </attr> <attr name=part value=year|month|day|wday|date|mday|hour|minute|second|yday|beat|week|seconds> <p>Defines which part of the date should be displayed. Day and wday is the same. Date and mday is the same. Yday is the day number of the year. Seconds is unix time type. Only the types string, number and ordered applies when the part attribute is used.</p> <xtable> <row><c><p><i>part=year</i></p></c><c><p>Display the year.<ex ><date part='year' type='number'/></ex></p></c></row> <row><c><p><i>part=month</i></p></c><c><p>Display the month. <ex ><date part='month' type='ordered'/></ex></p></c></row> <row><c><p><i>part=day</i></p></c><c><p>Display the weekday, starting with Sunday. <ex ><date part='day' type='ordered'/></ex></p></c></row> <row><c><p><i>part=wday</i></p></c><c><p>Display the weekday. Same as 'day'. <ex ><date part='wday' type='string'/></ex></p></c></row> <row><c><p><i>part=date</i></p></c><c><p>Display the day of this month. <ex ><date part='date' type='ordered'/></ex></p></c></row> <row><c><p><i>part=mday</i></p></c><c><p>Display the number of days since the last full month. <ex ><date part='mday' type='number'/></ex></p></c></row> <row><c><p><i>part=hour</i></p></c><c><p>Display the numbers of hours since midnight. <ex ><date part='hour' type='ordered'/></ex></p></c></row> <row><c><p><i>part=minute</i></p></c><c><p>Display the numbers of minutes since the last full hour. <ex ><date part='minute' type='number'/></ex></p></c></row> <row><c><p><i>part=second</i></p></c><c><p>Display the numbers of seconds since the last full minute. <ex ><date part='second' type='string'/></ex></p></c></row> <row><c><p><i>part=yday</i></p></c><c><p>Display the number of days since the first of January. <ex ><date part='yday' type='ordered'/></ex></p></c></row> <row><c><p><i>part=beat</i></p></c><c><p>Display the number of beats since midnight Central European Time(CET). There is a total of 1000 beats per day. The beats system was designed by <a href='http://www.swatch.com'>Swatch</a> as a means for a universal time, without time zones and day/night changes. <ex ><date part='beat' type='number'/></ex></p></c></row> <row><c><p><i>part=week</i></p></c><c><p>Display the number of the current week.<ex ><date part='week' type='number'/></ex></p></c></row> <row><c><p><i>part=seconds</i></p></c><c><p>Display the total number of seconds this year. <ex ><date part='seconds' type='number'/></ex></p></c></row> </xtable> </attr> <attr name=strftime value=string> <p>If this attribute is given to date, it will format the result according to the argument string.</p> <xtable> <row><c><p>%%</p></c><c><p>Percent character</p></c></row> <row><c><p>%a</p></c><c><p>Abbreviated weekday name, e.g. \"Mon\"</p></c></row> <row><c><p>%A</p></c><c><p>Weekday name</p></c></row> <row><c><p>%b</p></c><c><p>Abbreviated month name, e.g. \"Jan\"</p></c></row> <row><c><p>%B</p></c><c><p>Month name</p></c></row> <row><c><p>%c</p></c><c><p>Date and time, e.g. \"%a %b %d %H:%M:%S %Y\"</p></c></row> <row><c><p>%C</p></c><c><p>Century number, zero padded to two charachters.</p></c></row> <row><c><p>%d</p></c><c><p>Day of month (1-31), zero padded to two characters.</p></c></row> <row><c><p>%D</p></c><c><p>Date as \"%m/%d/%y\"</p></c></row> <row><c><p>%e</p></c><c><p>Day of month (1-31), space padded to two characters.</p></c></row> <row><c><p>%H</p></c><c><p>Hour (24 hour clock, 0-23), zero padded to two characters.</p></c></row> <row><c><p>%h</p></c><c><p>See %b</p></c></row> <row><c><p>%I</p></c><c><p>Hour (12 hour clock, 1-12), zero padded to two charcters.</p></c></row> <row><c><p>%j</p></c><c><p>Day numer of year (1-366), zero padded to three characters.</p></c></row> <row><c><p>%k</p></c><c><p>Hour (24 hour clock, 0-23), space padded to two characters.</p></c></row> <row><c><p>%l</p></c><c><p>Hour (12 hour clock, 1-12), space padded to two characters.</p></c></row> <row><c><p>%m</p></c><c><p>Month number (1-12), zero padded to two characters.</p></c></row> <row><c><p>%M</p></c><c><p>Minute (0-59), zero padded to two characters.</p></c></row> <row><c><p>%n</p></c><c><p>Newline</p></c></row> <row><c><p>%p</p></c><c><p>\"a.m.\" or \"p.m.\"</p></c></row> <row><c><p>%r</p></c><c><p>Time in 12 hour clock format with %p</p></c></row> <row><c><p>%R</p></c><c><p>Time as \"%H:%M\"</p></c></row> <row><c><p>%S</p></c><c><p>Seconds (0-61), zero padded to two characters.</p></c></row> <row><c><p>%t</p></c><c><p>Tab</p></c></row> <row><c><p>%T</p></c><c><p>Time as \"%H:%M:%S\"</p></c></row> <row><c><p>%u</p></c><c><p>Weekday as a decimal number (1-7), 1 is Sunday.</p></c></row> <row><c><p>%U</p></c><c><p>Week number of year as a decimal number (0-53), with sunday as the first day of week 1, zero padded to two characters.</p></c></row> <row><c><p>%V</p></c><c><p>ISO week number of the year as a decimal number (1-53), zero padded to two characters.</p></c></row> <row><c><p>%w</p></c><c><p>Weekday as a decimal number (0-6), 0 is Sunday.</p></c></row> <row><c><p>%W</p></c><c><p>Week number of year as a decimal number (0-53), with sunday as the first day of week 1, zero padded to two characters.</p></c></row> <row><c><p>%x</p></c><c><p>Date as \"%a %b %d %Y\"</p></c></row> <row><c><p>%X</p></c><c><p>See %T</p></c></row> <row><c><p>%y</p></c><c><p>Year (0-99), zero padded to two characters.</p></c></row> <row><c><p>%Y</p></c><c><p>Year (0-9999), zero padded to four characters.</p></c></row> </xtable> <ex><date strftime=\"%Y%m%d\"/></ex> </attr> <attr name=lang value=langcode> <p>Defines in what language a string will be presented in. Used together with <att>type=string</att> and the <att>part</att> attribute to get written dates in the specified language.</p> <ex><date part='day' type='string' lang='de'></ex> </attr> <attr name=case value=upper|lower|capitalize> <p>Changes the case of the output to upper, lower or capitalize.</p> <ex><date date='' lang='&client.language;' case='upper'/></ex> </attr> <attr name=prec value=number> <p>The number of decimals in the stardate.</p> </attr>", //---------------------------------------------------------------------- "debug":#"<desc tag='tag'><p><short> Helps debugging RXML-pages as well as modules.</short> When debugging mode is turned on, all error messages will be displayed in the HTML code. </p></desc> <attr name=on> <p>Turns debug mode on.</p> </attr> <attr name=off> <p>Turns debug mode off.</p> </attr> <attr name=toggle> <p>Toggles debug mode.</p> </attr> <attr name=showid value=string> <p>Shows a part of the id object. E.g. showid=\"id->request_headers\".</p> </attr> <attr name=werror value=string> <p>When you have access to the server debug log and want your RXML page to write some kind of diagnostics message or similar, the werror attribute is helpful.</p> <p>This can be used on the error page, for instance, if you'd want such errors to end up in the debug log:</p> <ex type=box> <debug werror='File &page.url; not found! (linked from &client.referrer;)'/></ex> </attr>", //---------------------------------------------------------------------- "dec":#"<desc tag='tag'><p><short> Subtracts 1 from a variable.</short> </p></desc> <attr name=variable value=string required='required'> <p>The variable to be decremented.</p> </attr> <attr name=value value=number default=1> <p>The value to be subtracted.</p> </attr>", //---------------------------------------------------------------------- "default":#"<desc cont='cont'><p><short hide='hide'> Used to set default values for form elements.</short> This tag makes it easier to give default values to \"<tag>select</tag>\" and \"<tag>input</tag>\" form elements. Simply put the <tag>default</tag> tag around the form elements to which it should give default values.</p> <p>This tag is particularly useful in combination with generated forms or forms with generated default values, e.g. by database tags.</p> </desc> <attr name=value value=string> <p>The value or values to set. If several values are given, they are separated with the separator string.</p> </attr> <attr name=separator value=string default=','> <p>If several values are to be selected, this is the string that separates them.</p> </attr> <attr name=name value=string> <p>If used, the default tag will only affect form element with this name.</p> </attr> <ex type='box'> <default name='my-select' value='&form.preset;'> <select name='my-select'> <option value='1'>First</option> <option value='2'>Second</option> <option value='3'>Third</option> </select> </default> </ex> <ex type='box'> <form> <default value=\"&form.opt1;,&form.opt2;,&form.opt3;\"> <input name=\"opt1\" value=\"yes1\" type=\"checkbox\" /> Option #1 <input name=\"opt2\" value=\"yes2\" type=\"checkbox\" /> Option #2 <input name=\"opt3\" value=\"yes3\" type=\"checkbox\" /> Option #3 <input type=\"submit\" /> </default> </form> ", "doc":#"<desc cont='cont'><p><short hide='hide'> Eases code documentation by reformatting it.</short>Eases documentation by replacing \"{\", \"}\" and \"&amp;\" with \"&amp;lt;\", \"&amp;gt;\" and \"&amp;amp;\". No attributes required. </p></desc> <attr name='quote'> <p>Instead of replacing with \"{\" and \"}\", \"&lt;\" and \"&gt;\" is replaced with \"&amp;lt;\" and \"&amp;gt;\".</p> <ex type='vert'> <doc quote=''> <table> <tr> <td> First cell </td> <td> Second cell </td> </tr> </table> </doc> </ex> </attr> <attr name='pre'><p> The result is encapsulated within a <tag>pre</tag> container.</p> <ex type='vert'><doc pre=''> {table} {tr} {td} First cell {/td} {td} Second cell {/td} {/tr} {/table} </doc> </ex> </attr> <attr name='class' value='string'> <p>This cascading style sheet (CSS) definition will be applied on the pre element.</p> </attr>", //---------------------------------------------------------------------- "expire-time":#"<desc tag='tag'><p><short hide='hide'> Sets client cache expire time for the document.</short>Sets client cache expire time for the document by sending the HTTP header \"Expires\". </p></desc> <attr name=now> <p>Notify the client that the document expires now. The headers \"Pragma: no-cache\" and \"Cache-Control: no-cache\" will be sent, besides the \"Expires\" header.</p> </attr> <attr name=years value=number> <p>Add this number of years to the result.</p> </attr> <attr name=months value=number> <p>Add this number of months to the result.</p>
43ff412001-02-06Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=weeks value=number> <p>Add this number of weeks to the result.</p>
43ff412001-02-06Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=days value=number> <p>Add this number of days to the result.</p>
43ff412001-02-06Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=hours value=number> <p>Add this number of hours to the result.</p>
43ff412001-02-06Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=beats value=number> <p>Add this number of beats to the result.</p> </attr> <attr name=minutes value=number> <p>Add this number of minutes to the result.</p> </attr> <attr name=seconds value=number> <p>Add this number of seconds to the result.</p> <p>It is not possible at the time to set the date beyond year 2038, since Unix variable <i>time_t</i> data type is used. The <i>time_t</i> data type stores the number of seconds elapsed since 00:00:00 January 1, 1970 UTC. </p>
43ff412001-02-06Martin Nilsson </attr>",
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "for":#"<desc cont='cont'><p><short> Makes it possible to create loops in RXML.</short> </p></desc>
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=from value=number> <p>Initial value of the loop variable.</p>
592ed72000-02-06Martin Nilsson </attr>
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=step value=number> <p>How much to increment the variable per loop iteration. By default one.</p>
592ed72000-02-06Martin Nilsson </attr>
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=to value=number> <p>How much the loop variable should be incremented to.</p>
e272382000-01-23Kenneth Johansson </attr>
b156c62001-04-23Martin Nilsson <attr name=variable value=name> <p>Name of the loop variable.</p> </attr>",
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson //---------------------------------------------------------------------- "fsize":#"<desc tag='tag'><p><short> Prints the size of the specified file.</short> </p></desc> <attr name=file value=string> <p>Show size for this file.</p>
9b03652001-03-07Kenneth Johansson </attr>", //----------------------------------------------------------------------
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson "gauge":#"<desc cont='cont'><p><short> Measures how much CPU time it takes to run its contents through the RXML parser.</short> Returns the number of seconds it took to parse the contents.
9b03652001-03-07Kenneth Johansson </p></desc>
592ed72000-02-06Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=define value=string> <p>The result will be put into a variable. E.g. define=\"var.gauge\" will put the result in a variable that can be reached with <ent>var.gauge</ent>.</p> </attr> <attr name=silent> <p>Don't print anything.</p> </attr> <attr name=timeonly> <p>Only print the time.</p> </attr> <attr name=resultonly> <p>Only print the result of the parsing. Useful if you want to put the time in a database or such.</p> </attr>", //---------------------------------------------------------------------- "header":#"<desc tag='tag'><p><short> Adds a HTTP header to the page sent back to the client.</short> For more information about HTTP headers please steer your browser to chapter 14, 'Header field definitions' in <a href='http://community.roxen.com/developers/idocs/rfc/rfc2616.html'>RFC 2616</a>, available at Roxen Community. </p></desc> <attr name=name value=string> <p>The name of the header.</p>
e272382000-01-23Kenneth Johansson </attr>
592ed72000-02-06Martin Nilsson <attr name=value value=string>
b156c62001-04-23Martin Nilsson  <p>The value of the header.</p> </attr>",
078b5e2000-07-14Kenneth Johansson 
b156c62001-04-23Martin Nilsson //---------------------------------------------------------------------- "imgs":#"<desc tag='tag'><p><short> Generates a image tag with the correct dimensions in the width and height attributes. These dimensions are read from the image itself, so the image must exist when the tag is generated. The image must also be in GIF, JPEG/JFIF or PNG format.</short> </p></desc> <attr name=src value=string required='required'> <p>The path to the file that should be shown.</p>
e272382000-01-23Kenneth Johansson </attr>
b156c62001-04-23Martin Nilsson <attr name=alt value=string> <p>Description of the image. If no description is provided, the filename (capitalized, without extension and with some characters replaced) will be used.</p> </attr> <p>All other attributes will be inherited by the generated img tag.</p>", //---------------------------------------------------------------------- "inc":#"<desc tag='tag'><p><short> Adds 1 to a variable.</short> </p></desc> <attr name=variable value=string required='required'> <p>The variable to be incremented.</p> </attr> <attr name=value value=number default=1> <p>The value to be added.</p>
e272382000-01-23Kenneth Johansson </attr>",
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "insert":#"<desc tag='tag'><p><short> Inserts a file, variable or other object into a webpage.</short> </p></desc>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=quote value=html|none> <p>How the inserted data should be quoted. Default is \"html\", except for href and file where it's \"none\".</p> </attr>",
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson "insert#variable":#"<desc plugin='plugin'><p><short> Inserts the value of a variable.</short> </p></desc> <attr name=variable value=string> <p>The name of the variable.</p>
e272382000-01-23Kenneth Johansson </attr>
b156c62001-04-23Martin Nilsson <attr name=scope value=string> <p>The name of the scope, unless given in the variable attribute.</p>
592ed72000-02-06Martin Nilsson </attr>
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=index value=number> <p>If the value of the variable is an array, the element with this index number will be inserted. 1 is the first element. -1 is the last element.</p> </attr> <attr name=split value=string> <p>A string with which the variable value should be splitted into an array, so that the index attribute may be used.</p> </attr>", //---------------------------------------------------------------------- "insert#variables":#"<desc plugin='plugin'><p><short> Inserts a listing of all variables in a scope.</short> Note that it is possible to create a scope with an infinite number of variables set. In this case the programme of that scope decides which variables that should be listable, i.e. this will not cause any problem except that all variables will not be listed. It is also possible to hide variables so that they are not listed with this tag. </p></desc> <attr name=variables value=full|plain> <p>Sets how the output should be formatted.</p> <ex type='vert'> <pre> <insert variables='full' scope='roxen'/> </pre> </ex>
592ed72000-02-06Martin Nilsson </attr>
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=scope> <p>The name of the scope that should be listed, if not the present scope.</p> </attr>", //---------------------------------------------------------------------- "insert#scopes":#"<desc plugin='plugin'><p><short> Inserts a listing of all present variable scopes.</short> </p></desc> <attr name=scopes value=full|plain> <p>Sets how the output should be formatted.</p> <ex type='vert'> <insert scopes='plain'/> </ex> </attr>", //---------------------------------------------------------------------- "insert#file":#"<desc plugin='plugin'><p><short> Inserts the contents of a file.</short> It reads files in a way similar to if you fetched the file with a browser, so the file may be parsed before it is inserted, depending on settings in the RXML parser. Most notably which kinds of files (extensions) that should be parsed. Since it reads files like a normal request, e.g. generated pages from location modules can be inserted. Put the tag <xref href='../programming/eval.tag' /> around <tag>insert</tag> if the file should be parsed after it is inserted in the page. This enables RXML defines and scope variables to be set in the including file (as opposed to the included file). You can also configure the file system module so that files with a certain extension can not be downloaded, but still inserted into other documents. </p></desc> <attr name=file value=string> <p>The virtual path to the file to be inserted.</p> <ex type='box'> <eval><insert file='html_header.inc'/></eval> </ex>
0da0892000-03-30Martin Nilsson </attr>",
592ed72000-02-06Martin Nilsson 
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "insert#realfile":#"<desc plugin='plugin'><p><short> Inserts a raw, unparsed file.</short> The disadvantage with the realfile plugin compared to the file plugin is that the realfile plugin needs the inserted file to exist, and can't fetch files from e.g. an arbitrary location module. Note that the realfile insert plugin can not fetch files from outside the virtual file system.
9b03652001-03-07Kenneth Johansson </p></desc>
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=realfile value=string> <p>The virtual path to the file to be inserted.</p>
592ed72000-02-06Martin Nilsson </attr>",
e272382000-01-23Kenneth Johansson 
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "maketag":({ #"<desc cont='cont'><p><short hide='hide'>
7078eb2001-05-18Martin Nilsson  Makes it possible to create tags.</short>This tag creates tags. The contents of the container will be put into the contents of the produced container.
b156c62001-04-23Martin Nilsson </p></desc>
e272382000-01-23Kenneth Johansson 
4b1c012001-07-20Johan Sundström <attr name='name' value='string'>
7078eb2001-05-18Martin Nilsson  <p>The name of the tag that should be produced. This attribute is required for tags, containers and processing instructions, i.e. for the types 'tag', 'container' and 'pi'.</p> <ex type='shor'> <maketag name='one' type='tag'></maketag> <maketag name='one' type='tag' noxml='noxml'></maketag> </ex>
c00fd22000-08-12Martin Nilsson </attr>
4b1c012001-07-20Johan Sundström <attr name='noxml'>
7078eb2001-05-18Martin Nilsson  <p>Tags should not be terminated with a trailing slash. Only makes a difference for the type 'tag'.</p>
8614702000-10-11Johan Sundström </attr>
4b1c012001-07-20Johan Sundström <attr name='type' value='tag|container|pi|comment|cdata'>
7078eb2001-05-18Martin Nilsson  <p>What kind of tag should be produced. The argument 'Pi' will produce a processing instruction tag.</p> <ex type='svert'> <maketag type='pi' name='PICS'>l gen true r (n 0 s 0 v 0 l 2)</maketag> </ex> <ex type='shor'> <maketag type='comment'>Menu starts here</maketag> </ex> <ex type='box'> <maketag type='comment'>Debug: &form.res; &var.sql;</maketag> </ex> <ex type='shor'> <maketag type='cdata'>Exact words</maketag> </ex>
592ed72000-02-06Martin Nilsson </attr>",
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson  ([ "attrib":#"<desc cont='cont'><p> Inside the maketag container the container <tag>attrib</tag> is defined. It is used to add attributes to the produced tag. The contents of the attribute container will be the attribute value. E.g.</p> </desc> <ex><eval> <maketag name=\"replace\" type=\"container\"> <attrib name=\"from\">A</attrib> <attrib name=\"to\">U</attrib> MAD </maketag> </eval> </ex>
4b1c012001-07-20Johan Sundström  <attr name='name' value='string' required='required'> <p>The name of the attribute.</p>
b156c62001-04-23Martin Nilsson  </attr>" ]) }),
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "modified":#"<desc tag='tag'><p><short hide='hide'> Prints when or by whom a page was last modified.</short> Prints when or by whom a page was last modified, by default the current page.
9b03652001-03-07Kenneth Johansson </p></desc>
e272382000-01-23Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=by> <p>Print by whom the page was modified. Takes the same attributes as <xref href='user.tag' />. This attribute requires a userdatabase. </p>
aac7152000-02-10Martin Nilsson 
b156c62001-04-23Martin Nilsson  <ex type='box'>This page was last modified by <modified by='' realname=''/>.</ex>
8c96aa2000-02-24Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=date> <p>Print the modification date. Takes all the date attributes in <xref href='date.tag' />.</p> <ex type='box'>This page was last modified <modified date='' case='lower' type='string'/>.</ex>
8c96aa2000-02-24Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson  <attr name=file value=path> <p>Get information from this file rather than the current page.</p>
8c96aa2000-02-24Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson  <attr name=realfile value=path> <p>Get information from this file in the computers filesystem rather than Roxen Webserver's virtual filesystem.</p>
e272382000-01-23Kenneth Johansson </attr>",
8859351999-11-25Martin Nilsson 
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "random":#"<desc cont='cont'><p><short> Randomly chooses a message from its contents.</short> </p></desc>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name='separator' value='string'> <p>The separator used to separate the messages, by default newline.</p>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson <ex><random separator='#'> Roxen#Pike#Foo#Bar#roxen.com </random> </ex>
21eeb02001-05-22Martin Nilsson </attr>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name='seed' value='string'>
21eeb02001-05-22Martin Nilsson  <p>Enables you to use a seed that determines which message to choose.</p> <ex type='box'> Tip of the day: <set variable='var.day'><date type='iso' date=''/></set> <random seed='var.day'><insert file='tips.txt'/></random> </ex>
b156c62001-04-23Martin Nilsson </attr> ",
9b03652001-03-07Kenneth Johansson  //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "redirect":#"<desc tag='tag'><p><short hide='hide'> Redirects the user to another page.</short> Redirects the user to
21eeb02001-05-22Martin Nilsson  another page by sending a HTTP redirect header to the client. If the redirect is local, i.e. within the server, all prestates are preserved. E.g. \"/index.html\" and \"index.html\" preserves the prestates, while \"http://server.com/index.html\" does not.
9b03652001-03-07Kenneth Johansson </p></desc>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=to value=URL required='required'> <p>The location to where the client should be sent.</p>
592ed72000-02-06Martin Nilsson </attr>
b53b751999-10-09Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=add value=string> <p>The prestate or prestates that should be added, in a comma separated list.</p>
592ed72000-02-06Martin Nilsson </attr>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=drop value=string> <p>The prestate or prestates that should be dropped, in a comma separated list.</p>
592ed72000-02-06Martin Nilsson </attr>
0be6412000-01-18Martin Nilsson 
21eeb02001-05-22Martin Nilsson <attr name='drop-all'> <p>Removes all prestates from the redirect target.</p> </attr>
b156c62001-04-23Martin Nilsson <attr name=text value=string> <p>Sends a text string to the browser, that hints from where and why the page was redirected. Not all browsers will show this string. Only special clients like Telnet uses it.</p>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <p>Arguments prefixed with \"add\" or \"drop\" are treated as prestate toggles, which are added or removed, respectively, from the current set of prestates in the URL in the redirect header (see also <xref href='apre.tag' />). Note that this only works when the to=... URL is absolute, i.e. begins with a \"/\", otherwise these state toggles have no effect.</p>
9b03652001-03-07Kenneth Johansson </attr>", //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "remove-cookie":#"<desc tag='tag'><p><short> Sets the expire-time of a cookie to a date that has already occured. This forces the browser to remove it.</short> This tag won't remove the cookie, only set it to the empty string, or what is specified in the value attribute and change it's expire-time to a date that already has occured. This is unfortunutaly the only way as there is no command in HTTP for removing cookies. We have to give a hint to the browser and let it remove the cookie.
9b03652001-03-07Kenneth Johansson </p></desc>
b156c62001-04-23Martin Nilsson <attr name=name> <p>Name of the cookie the browser should remove.</p>
9b03652001-03-07Kenneth Johansson </attr>
b156c62001-04-23Martin Nilsson <attr name=value value=text> <p>Even though the cookie has been marked as expired some browsers will not remove the cookie until it is shut down. The text provided with this attribute will be the cookies intermediate value.</p>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  <p>Note that removing a cookie won't take effect until the next page load.</p>
9b03652001-03-07Kenneth Johansson  </attr>", //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "replace":#"<desc cont='cont'><p><short> Replaces strings in the contents with other strings.</short> </p></desc>
5b0e5d2000-03-25Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=from value=string required='required'> <p>String or list of strings that should be replaced.</p>
5b0e5d2000-03-25Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=to value=string> <p>String or list of strings with the replacement strings. Default is the empty string.</p> </attr> <attr name=separator value=string default=','> <p>Defines what string should separate the strings in the from and to attributes.</p> </attr> <attr name=type value=word|words default=word> <p>Word means that a single string should be replaced. Words that from and to are lists.</p>
9b03652001-03-07Kenneth Johansson </attr>", //----------------------------------------------------------------------
5b0e5d2000-03-25Martin Nilsson 
b156c62001-04-23Martin Nilsson "return":#"<desc tag='tag'><p><short> Changes the HTTP return code for this page. </short> <!-- See the Appendix for a list of HTTP return codes. (We have no appendix) --> </p></desc>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=code value=integer> <p>The HTTP status code to return.</p> </attr>
5b0e5d2000-03-25Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=text> <p>The HTTP status message to set. If you don't provide one, a default message is provided for known HTTP status codes, e g \"No such file or directory.\" for code 404.</p>
bd44042000-07-17Kenneth Johansson </attr>",
0be6412000-01-18Martin Nilsson 
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "roxen":#"<desc tag='tag'><p><short> Returns a nice Roxen logo.</short>
9b03652001-03-07Kenneth Johansson </p></desc>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=size value=small|medium|large default=medium> <p>Defines the size of the image.</p> <ex type='vert'><roxen size='small'/> <roxen/> <roxen size='large'/></ex>
592ed72000-02-06Martin Nilsson </attr>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=color value=black|white default=white> <p>Defines the color of the image.</p> <ex type='vert'><roxen color='black'/></ex>
5b04132000-07-02Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=alt value=string default='\"Powered by Roxen\"'> <p>The image description.</p>
592ed72000-02-06Martin Nilsson </attr>
ecab8b2000-01-23Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=border value=number default=0> <p>The image border.</p>
592ed72000-02-06Martin Nilsson </attr>
72ac6d2000-01-25Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=class value=string> <p>This cascading style sheet (CSS) definition will be applied on the img element.</p>
592ed72000-02-06Martin Nilsson </attr>
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=target value=string> <p>Names a target frame for the link around the image.</p>
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson  <p>All other attributes will be inherited by the generated img tag.</p> </attr> ",
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson "scope":#"<desc cont='cont'><p><short> Creates a new variable scope.</short> Variable changes inside the scope container will not affect variables in the rest of the page. </p></desc>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=extend value=name default=form> <p>If set, all variables in the selected scope will be copied into the new scope. NOTE: if the source scope is \"magic\", as e.g. the roxen scope, the scope will not be copied, but rather linked and will behave as the original scope. It can be useful to create an alias or just for the convinience of refering to the scope as \"_\".</p>
592ed72000-02-06Martin Nilsson </attr>
ecab8b2000-01-23Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=scope value=name default=form> <p>The name of the new scope, besides \"_\".</p> </attr>", //---------------------------------------------------------------------- "set":#"<desc tag='tag'><p><short> Sets a variable.</short> </p></desc> <attr name=variable value=string required='required'> <p>The name of the variable.</p> <ex type='box'> <set variable='var.foo' value='bar'/> </ex>
592ed72000-02-06Martin Nilsson </attr>
ecab8b2000-01-23Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=value value=string> <p>The value the variable should have.</p>
592ed72000-02-06Martin Nilsson </attr>
093fd32000-01-23Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=expr value=string> <p>An expression whose evaluated value the variable should have.</p>
592ed72000-02-06Martin Nilsson </attr>
093fd32000-01-23Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=from value=string> <p>The name of another variable that the value should be copied from.</p>
592ed72000-02-06Martin Nilsson </attr>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=split value=string> <p>The value will be splitted by this string into an array.</p>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  <p>If none of the above attributes are specified, the variable is unset. If debug is currently on, more specific debug information is provided if the operation failed. See also: <xref href='append.tag' /> and <xref href='../programming/debug.tag' />.</p> </attr> ",
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson "copy-scope":#"<desc tag='tag'><p><short>
7dfc6a2001-07-20Johan Sundström  Copies the content of one scope into another scope</short></p></desc>
b156c62001-04-23Martin Nilsson  <attr name='from' value='scope name' required='1'> <p>The name of the scope the variables are copied from.</p>
592ed72000-02-06Martin Nilsson </attr>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name='to' value='scope name' required='1'> <p>The name of the scope the variables are copied to.</p> </attr>",
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
3b40e72000-06-02Martin Nilsson 
b156c62001-04-23Martin Nilsson "set-cookie":#"<desc tag='tag'><p><short> Sets a cookie that will be stored by the user's browser.</short> This is a simple and effective way of storing data that is local to the user. If no arguments specifying the time the cookie should survive is given to the tag, it will live until the end of the current browser session. Otherwise, the cookie will be persistent, and the next time the user visits the site, she will bring the cookie with her.
0c923f2001-07-20Johan Sundström </p> <p>Note that the change of a cookie will not take effect until the next page load.</p></desc>
b156c62001-04-23Martin Nilsson  <attr name=name value=string> <p>The name of the cookie.</p> </attr> <attr name=seconds value=number> <p>Add this number of seconds to the time the cookie is kept.</p>
ce9c862000-05-28Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=minutes value=number> <p>Add this number of minutes to the time the cookie is kept.</p> </attr>
de6dec2000-05-02Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=hours value=number> <p>Add this number of hours to the time the cookie is kept.</p>
592ed72000-02-06Martin Nilsson </attr>
0be6412000-01-18Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=days value=number> <p>Add this number of days to the time the cookie is kept.</p>
592ed72000-02-06Martin Nilsson </attr>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=weeks value=number> <p>Add this number of weeks to the time the cookie is kept.</p> </attr>
bcde6c1999-11-19Per Hedbor 
b156c62001-04-23Martin Nilsson <attr name=months value=number> <p>Add this number of months to the time the cookie is kept.</p> </attr>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson <attr name=years value=number> <p>Add this number of years to the time the cookie is kept.</p> </attr>
ecab8b2000-01-23Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=persistent> <p>Keep the cookie for five years.</p>
592ed72000-02-06Martin Nilsson </attr>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=domain> <p>The domain for which the cookie is valid.</p>
592ed72000-02-06Martin Nilsson </attr>
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=value value=string> <p>The value the cookie will be set to.</p>
592ed72000-02-06Martin Nilsson </attr>
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=path value=string default=\"/\"><p> The path in which the cookie should be available. Use path=\"\" to remove the path argument from the sent cookie, thus making the cookie valid only for the present directory and below.</p>
9b03652001-03-07Kenneth Johansson </attr>
0c923f2001-07-20Johan Sundström ",
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson "set-max-cache":#"<desc tag='tag'><p><short> Sets the maximum time this document can be cached in any ram caches.</short></p> <p>Default is to get this time from the other tags in the document (as an example, <xref href='../if/if_supports.tag' /> sets the time to 0 seconds since the result of the test depends on the client used.</p> <p>You must do this at the end of the document, since many of the normal tags will override this value.</p> </desc> <attr name=years value=number> <p>Add this number of years to the time this page was last loaded.</p> </attr> <attr name=months value=number> <p>Add this number of months to the time this page was last loaded.</p> </attr> <attr name=weeks value=number> <p>Add this number of weeks to the time this page was last loaded.</p> </attr> <attr name=days value=number> <p>Add this number of days to the time this page was last loaded.</p> </attr> <attr name=hours value=number> <p>Add this number of hours to the time this page was last loaded.</p> </attr> <attr name=beats value=number> <p>Add this number of beats to the time this page was last loaded.</p> </attr> <attr name=minutes value=number> <p>Add this number of minutes to the time this page was last loaded.</p> </attr> <attr name=seconds value=number> <p>Add this number of seconds to the time this page was last loaded.</p>
592ed72000-02-06Martin Nilsson </attr>",
4817401999-08-13Martin Nilsson 
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "smallcaps":#"<desc cont='cont'><p><short> Prints the contents in smallcaps.</short> If the size attribute is given, font tags will be used, otherwise big and small tags will be used. </p>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <ex> <smallcaps>Roxen WebServer</smallcaps> </ex> </desc> <attr name=space> <p>Put a space between every character.</p> <ex type='vert'> <smallcaps space=''>Roxen WebServer</smallcaps> </ex>
5b0e5d2000-03-25Martin Nilsson </attr>
b156c62001-04-23Martin Nilsson <attr name=class value=string> <p>Apply this cascading style sheet (CSS) style on all elements.</p> </attr> <attr name=smallclass value=string> <p>Apply this cascading style sheet (CSS) style on all small elements.</p> </attr> <attr name=bigclass value=string> <p>Apply this cascading style sheet (CSS) style on all big elements.</p> </attr> <attr name=size value=number> <p>Use font tags, and this number as big size.</p> </attr> <attr name=small value=number default=size-1> <p>Size of the small tags. Only applies when size is specified.</p> <ex> <smallcaps size='6' small='2'>Roxen WebServer</smallcaps> </ex>
592ed72000-02-06Martin Nilsson </attr>",
4817401999-08-13Martin Nilsson 
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "sort":#"<desc cont='cont'><p><short> Sorts the contents.</short></p>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson  <ex> <sort> 1 Hello 3 World Are 2 We 4 Communicating? </sort> </ex>
592ed72000-02-06Martin Nilsson </desc>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=separator value=string> <p>Defines what the strings to be sorted are separated with. The sorted string will be separated by the string.</p>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson  <ex type='vert'> <sort separator='#'> 1#Hello#3#World#Are#2#We#4#Communicating? </sort> </ex>
592ed72000-02-06Martin Nilsson </attr>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=reverse> <p>Reversed order sort.</p>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson  <ex> <sort reverse=''> 1 Hello 3 World Are 2 We 4 Communicating? </sort> </ex> </attr>",
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson "throw":#"<desc cont='cont'><p><short> Throws a text to be caught by <xref href='catch.tag' />.</short> Throws an exception, with the enclosed text as the error message. This tag has a close relation to <xref href='catch.tag' />. The RXML parsing will stop at the <tag>throw</tag> tag. </p></desc>",
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
425ce52000-05-09Kenneth Johansson 
b156c62001-04-23Martin Nilsson "trimlines":#"<desc cont='cont'><p><short> Removes all empty lines from the contents.</short></p> <ex> <trimlines> Are
1c79451999-10-17Martin Nilsson 
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  We
252ed52000-01-31Per Hedbor 
b156c62001-04-23Martin Nilsson  Communicating? </trimlines> </ex> </desc>",
4817401999-08-13Martin Nilsson 
9b03652001-03-07Kenneth Johansson //----------------------------------------------------------------------
b156c62001-04-23Martin Nilsson "unset":#"<desc tag='tag'><p><short> Unsets a variable, i.e. removes it.</short>
9b03652001-03-07Kenneth Johansson </p></desc>
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=variable value=string required='required'> <p>The name of the variable.</p>
9b03652001-03-07Kenneth Johansson 
b156c62001-04-23Martin Nilsson  <ex> <set variable='var.jump' value='do it'/> <ent>var.jump</ent> <unset variable='var.jump'/> <ent>var.jump</ent> </ex> </attr>",
4817401999-08-13Martin Nilsson 
b156c62001-04-23Martin Nilsson //----------------------------------------------------------------------
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson "user":#"<desc tag='tag'><p><short> Prints information about the specified user.</short> By default, the full name of the user and her e-mail address will be printed, with a mailto link and link to the home page of that user.</p>
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson  <p>The <tag>user</tag> tag requires an authentication module to work.</p> </desc>
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=email> <p>Only print the e-mail address of the user, with no link.</p> <ex type='box'>Email: <user name='foo' email=''/></ex>
592ed72000-02-06Martin Nilsson </attr>
6c13ac2000-01-31Martin Nilsson 
b156c62001-04-23Martin Nilsson <attr name=link> <p>Include links. Only meaningful together with the realname or email attribute.</p> </