24c6c12000-02-20Martin Nilsson // The Roxen RXML Parser. See also the RXML Pike modules. // Copyright © 1996 - 2000, Roxen IS. // // Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others. // New parser by Martin Stjernholm // New RXML, scopes and entities by Martin Nilsson //
1e770a2001-02-01Per Hedbor // $Id: rxml.pike,v 1.277 2001/02/01 02:54:18 per Exp $
e5bab52000-04-06Kenneth Johansson 
7bf1451999-07-27David Hedbor 
b8b31d2000-01-10Martin Nilsson inherit "rxmlhelp";
6234e52000-01-05Per Hedbor #include <request_trace.h>
cd7d5f2000-02-16Martin Stjernholm #include <config.h>
94892e2000-01-05Martin Stjernholm 
cce7142000-01-26Martin Nilsson #ifndef manual
7517d42000-02-16Martin Stjernholm #define _stat defines[" _stat"] #define _error defines[" _error"] #define _extra_heads defines[" _extra_heads"] #define _ok defines[" _ok"] // ----------------------- Error handling -------------------------
e1f1f72000-02-24Martin Nilsson function _run_error;
4cc2452000-03-03Martin Nilsson string handle_run_error (RXML.Backtrace err, RXML.Type type)
4254f62000-02-13Martin Stjernholm // This is used to report thrown RXML run errors. See
5ed0132000-02-13Martin Stjernholm // RXML.run_error().
4e56af2000-01-25Martin Stjernholm {
4cc2452000-03-03Martin Nilsson  RequestID id=RXML.get_context()->id;
c774db2000-08-28Martin Nilsson #ifdef MODULE_DEBUG
5b987e2001-01-29Per Hedbor  report_notice ("Error in %s.\n%s", id->not_query, describe_error (err));
c774db2000-08-28Martin Nilsson #endif
e1f1f72000-02-24Martin Nilsson  if(id->conf->get_provider("RXMLRunError")) { if(!_run_error) _run_error=id->conf->get_provider("RXMLRunError")->rxml_run_error; string res=_run_error(err, type, id); if(res) return res; }
0b7adb2000-02-25Martin Nilsson  else _run_error=0;
c774db2000-08-28Martin Nilsson  NOCACHE();
0b7adb2000-02-25Martin Nilsson  id->misc->defines[" _ok"]=0;
8008a52000-02-20Martin Stjernholm  if (type->subtype_of (RXML.t_html) || type->subtype_of (RXML.t_xml))
e1f1f72000-02-24Martin Nilsson  return "<br clear=\"all\" />\n<pre>" +
a39b5a2000-03-19Martin Nilsson  Roxen.html_encode_string (describe_error (err)) + "</pre>\n";
c774db2000-08-28Martin Nilsson  return describe_error (err);
4e56af2000-01-25Martin Stjernholm }
e1f1f72000-02-24Martin Nilsson function _parse_error;
4cc2452000-03-03Martin Nilsson string handle_parse_error (RXML.Backtrace err, RXML.Type type)
4254f62000-02-13Martin Stjernholm // This is used to report thrown RXML parse errors. See
5ed0132000-02-13Martin Stjernholm // RXML.parse_error().
97022d2000-01-14Martin Stjernholm {
4cc2452000-03-03Martin Nilsson  RequestID id=RXML.get_context()->id;
c774db2000-08-28Martin Nilsson #ifdef MODULE_DEBUG
5b987e2001-01-29Per Hedbor  report_notice ("Error in %s.\n%s", id->not_query, describe_error (err));
c774db2000-08-28Martin Nilsson #endif
e1f1f72000-02-24Martin Nilsson  if(id->conf->get_provider("RXMLParseError")) { if(!_parse_error) _parse_error=id->conf->get_provider("RXMLParseError")->rxml_parse_error; string res=_parse_error(err, type, id); if(res) return res; }
0b7adb2000-02-25Martin Nilsson  else _parse_error=0;
c774db2000-08-28Martin Nilsson  NOCACHE();
0b7adb2000-02-25Martin Nilsson  id->misc->defines[" _ok"]=0;
8008a52000-02-20Martin Stjernholm  if (type->subtype_of (RXML.t_html) || type->subtype_of (RXML.t_xml))
e1f1f72000-02-24Martin Nilsson  return "<br clear=\"all\" />\n<pre>" +
a39b5a2000-03-19Martin Nilsson  Roxen.html_encode_string (describe_error (err)) + "</pre>\n";
c774db2000-08-28Martin Nilsson  return describe_error (err);
97022d2000-01-14Martin Stjernholm }
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
36aaa12000-01-23Martin Nilsson RoxenModule rxml_warning_cache; 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 // ------------------------- RXML Parser ------------------------------
f599312000-01-19Martin Stjernholm RXML.TagSet rxml_tag_set = class
41940b2000-01-25Martin Stjernholm // This tag set always has the highest priority.
4806252000-01-11Martin Stjernholm {
f599312000-01-19Martin Stjernholm  inherit RXML.TagSet;
84fff02000-01-18Martin Stjernholm 
f599312000-01-19Martin Stjernholm  string prefix = RXML_NAMESPACE;
0d7a532000-08-28Martin Stjernholm #ifdef THREADS Thread.Mutex lists_mutex = Thread.Mutex(); // Locks destructive changes to the arrays modules and imported. #endif
41940b2000-01-25Martin Stjernholm  array(RoxenModule) modules;
f599312000-01-19Martin Stjernholm  // Each element in the imported array is the registered tag set of a // parser module. This array contains the corresponding module // object. void sort_on_priority() {
0d7a532000-08-28Martin Stjernholm #ifdef THREADS Thread.MutexKey lock = lists_mutex->lock(); #endif
69e4cd2000-03-09Martin Stjernholm  int i = search (imported, Roxen.entities_tag_set);
89584d2000-02-10Martin Stjernholm  array(RXML.TagSet) new_imported = imported[..i-1] + imported[i+1..];
5bb5722000-02-10Martin Stjernholm  array(RoxenModule) new_modules = modules[..i-1] + modules[i+1..];
41940b2000-01-25Martin Stjernholm  array(int) priorities = new_modules->query ("_priority", 1);
f599312000-01-19Martin Stjernholm  priorities = replace (priorities, 0, 4); sort (priorities, new_imported, new_modules);
89584d2000-02-10Martin Stjernholm  new_imported = reverse (new_imported) + ({imported[i]});
f599312000-01-19Martin Stjernholm  if (equal (imported, new_imported)) return;
89584d2000-02-10Martin Stjernholm  new_modules = reverse (new_modules) + ({modules[i]}); `->= ("imported", new_imported); modules = new_modules;
f599312000-01-19Martin Stjernholm  }
89584d2000-02-10Martin Stjernholm  mixed `->= (string var, mixed val) // Currently necessary due to misfeature in Pike.
f599312000-01-19Martin Stjernholm  {
89584d2000-02-10Martin Stjernholm  if (var == "modules") modules = val; else ::`->= (var, val); return val;
f599312000-01-19Martin Stjernholm  }
5bb5722000-02-10Martin Stjernholm  void create (object rxml_object)
41940b2000-01-25Martin Stjernholm  {
5bb5722000-02-10Martin Stjernholm  ::create ("rxml_tag_set");
a700042000-03-16Martin Stjernholm  // Fix a better name later when we know the name of the
5bb5722000-02-10Martin Stjernholm  // configuration. call_out (lambda () {
2ac97c2000-03-18Martin Stjernholm  string cname = sprintf ("%O", rxml_object); if (sscanf (cname, "Configuration(%s", cname) == 1 && sizeof (cname) && cname[-1] == ')') cname = cname[..sizeof (cname) - 2]; name = sprintf ("rxml_tag_set,%s", cname);
5bb5722000-02-10Martin Stjernholm  }, 0);
69e4cd2000-03-09Martin Stjernholm  imported = ({Roxen.entities_tag_set});
41940b2000-01-25Martin Stjernholm  modules = ({rxml_object}); }
5bb5722000-02-10Martin Stjernholm } (this_object());
e7ed2e2000-01-08Martin Stjernholm 
cede492000-02-15Martin Stjernholm RXML.Type default_content_type = RXML.t_html (RXML.PXml);
5a31102000-02-15Martin Stjernholm RXML.Type default_arg_type = RXML.t_text (RXML.PEnt);
49a74b2000-01-14Martin Stjernholm 
8e29c32000-03-04Martin Stjernholm int old_rxml_compat;
f599312000-01-19Martin Stjernholm 
68d85b2000-02-11Martin Stjernholm // A note on tag overriding: It's possible for old style tags to
76b5932000-06-23Martin Stjernholm // propagate their results to the tags they have overridden (new style // tags can use RXML.Frame.propagate_tag()). This is done by an // extension to the return value:
68d85b2000-02-11Martin Stjernholm // // If an array of the form // // ({int 1, string name, mapping(string:string) args, void|string content}) // // is returned, the tag function with the given name is called with // these arguments. If the name is the same as the current tag, the // overridden tag function is called. If there's no overridden // function, the tag is generated in the output. Any argument may be // left out to default to its value in the current tag. ({1, 0, 0}) or // ({1, 0, 0, 0}) may be shortened to ({1}). // // Note that there's no other way to handle tag overriding -- the page // is no longer parsed multiple times.
1c1cb02000-08-05Martin Stjernholm string parse_rxml(string what, RequestID id, void|Stdio.File file, void|mapping defines ) // Note: Don't use this function to do recursive parsing inside an // rxml parse session. The RXML module provides several different ways // to accomplish that.
b796b51998-11-18Per Hedbor {
1c1cb02000-08-05Martin Stjernholm  id->misc->_rxml_recurse++; #ifdef RXML_DEBUG werror("parse_rxml( "+strlen(what)+" ) -> "); int time = gethrtime();
b796b51998-11-18Per Hedbor #endif
1c1cb02000-08-05Martin Stjernholm  if(!defines) defines = id->misc->defines||([]);
c774db2000-08-28Martin Nilsson  if(!_error) _error=200; if(!_extra_heads) _extra_heads=([ ]);
0824642000-08-29Martin Nilsson  if(!_stat) {
c774db2000-08-28Martin Nilsson  if(id->misc->stat) _stat=id->misc->stat; else if(file) _stat=file->stat();
0824642000-08-29Martin Nilsson  }
ac67522000-08-29Per Hedbor 
1c1cb02000-08-05Martin Stjernholm  id->misc->defines = defines;
05aee52000-01-13Martin Nilsson 
1c1cb02000-08-05Martin Stjernholm  RXML.PXml parent_parser = id->misc->_parser; // Don't count on that this exists.
4254f62000-02-13Martin Stjernholm  RXML.PXml parser;
49a74b2000-01-14Martin Stjernholm  RXML.Context ctx;
211b9a2000-01-10Martin Stjernholm 
6725432000-10-19Martin Stjernholm  if (parent_parser && (ctx = parent_parser->context) && ctx->id == id) {
cede492000-02-15Martin Stjernholm  parser = default_content_type->get_parser (ctx, 0, parent_parser);
6725432000-10-19Martin Stjernholm  parser->recover_errors = parent_parser->recover_errors; }
1f47d92000-01-30Per Hedbor  else {
cede492000-02-15Martin Stjernholm  parser = rxml_tag_set (default_content_type, id);
6725432000-10-19Martin Stjernholm  parser->recover_errors = 1;
8200702000-02-06Martin Stjernholm  parent_parser = 0;
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
bf70062000-03-20Martin Stjernholm  if (old_rxml_compat) parser->context->compatible_scope = 1; #endif
d2e56f2000-01-25Martin Nilsson  }
211b9a2000-01-10Martin Stjernholm  id->misc->_parser = parser;
1c1cb02000-08-05Martin Stjernholm  // Hmm, how does this propagation differ from id->misc? Does it // matter? This is only used by the compatibility code for old style // tags.
49a74b2000-01-14Martin Stjernholm  parser->_defines = defines;
1c1cb02000-08-05Martin Stjernholm  parser->_source_file = file;
05aee52000-01-13Martin Nilsson 
211b9a2000-01-10Martin Stjernholm  if (mixed err = catch {
71a5c92000-02-12Martin Stjernholm  if (parent_parser && ctx == RXML.get_context())
1c1cb02000-08-05Martin Stjernholm  parser->finish (what);
211b9a2000-01-10Martin Stjernholm  else
1c1cb02000-08-05Martin Stjernholm  parser->write_end (what); what = parser->eval();
6a795d2000-01-21Martin Stjernholm  parser->_defines = 0;
211b9a2000-01-10Martin Stjernholm  id->misc->_parser = parent_parser; }) {
1c1cb02000-08-05Martin Stjernholm #ifdef DEBUG
95f91d2000-06-19Henrik Grubbström (Grubba)  if (!parser) { werror("RXML: Parser destructed!\n"); #if constant(_describe) _describe(parser); #endif /* constant(_describe) */ error("Parser destructed!\n"); }
1c1cb02000-08-05Martin Stjernholm #endif
6a795d2000-01-21Martin Stjernholm  parser->_defines = 0;
211b9a2000-01-10Martin Stjernholm  id->misc->_parser = parent_parser; if (objectp (err) && err->thrown_at_unwind) error ("Can't handle RXML parser unwinding in " "compatibility mode (error=%O).\n", err); else throw (err); }
7517d42000-02-16Martin Stjernholm  if(sizeof(_extra_heads) && !id->misc->moreheads) { id->misc->moreheads= ([]); id->misc->moreheads |= _extra_heads; } id->misc->_rxml_recurse--; #ifdef RXML_DEBUG werror("%d (%3.3fs)\n%s", strlen(what),(gethrtime()-time)/1000000.0, (" "*id->misc->_rxml_recurse)); #endif return what; }
76b5932000-06-23Martin Stjernholm #define COMPAT_TAG_TYPE \ function(string,mapping(string:string),RequestID,void|Stdio.File,void|mapping: \ string|array(int|string)) #define COMPAT_CONTAINER_TYPE \ function(string,mapping(string:string),string,RequestID,void|Stdio.File,void|mapping: \ string|array(int|string)) class CompatTag { inherit RXML.Tag;
5e71002000-12-19Anders Johansson  constant is_compat_tag=1;
76b5932000-06-23Martin Stjernholm  string name; int flags; string|COMPAT_TAG_TYPE|COMPAT_CONTAINER_TYPE fn; RXML.Type content_type = RXML.t_same; // No preparsing. array(RXML.Type) result_types = ({RXML.t_xml (RXML.PXml), RXML.t_html (RXML.PXml)}); // Postparsing. void create (string _name, int empty, string|COMPAT_TAG_TYPE|COMPAT_CONTAINER_TYPE _fn) { name = _name, fn = _fn; flags = empty && RXML.FLAG_EMPTY_ELEMENT; } class Frame { inherit RXML.Frame; string raw_tag_text;
a49d432000-07-03Martin Stjernholm  array do_enter (RequestID id) { if (args->preparse) content_type = content_type (RXML.PXml); }
76b5932000-06-23Martin Stjernholm  array do_return (RequestID id) { id->misc->line = "0"; // No working system for this yet. if (stringp (fn)) return ({fn});
eebd9b2000-11-06Martin Stjernholm  if (!fn) { result_type = result_type (RXML.PNone); return ({propagate_tag()}); }
76b5932000-06-23Martin Stjernholm  Stdio.File source_file; mapping defines; if (id->misc->_parser) { source_file = id->misc->_parser->_source_file; defines = id->misc->_parser->_defines; } string|array(string) result; if (flags & RXML.FLAG_EMPTY_ELEMENT) result = fn (name, args, id, source_file, defines);
a49d432000-07-03Martin Stjernholm  else { if(args->trimwhites) content = String.trim_all_whites(content);
76b5932000-06-23Martin Stjernholm  result = fn (name, args, content, id, source_file, defines);
a49d432000-07-03Martin Stjernholm  }
76b5932000-06-23Martin Stjernholm  if (arrayp (result)) { result_type = result_type (RXML.PNone); if (sizeof (result) && result[0] == 1) { [string pname, mapping(string:string) pargs, string pcontent] = (result[1..] + ({0, 0, 0}))[..2]; if (!pname || pname == name) return ({!pargs && !pcontent ? propagate_tag () : propagate_tag (pargs || args, pcontent || content)}); else return ({RXML.make_unparsed_tag (pname, pargs || args, pcontent || content)}); } else return result; } else if (result) { if (args->noparse) result_type = result_type (RXML.PNone); return ({result}); }
eebd9b2000-11-06Martin Stjernholm  else { result_type = result_type (RXML.PNone); return ({propagate_tag()}); }
76b5932000-06-23Martin Stjernholm  } } }
d734522000-01-31Martin Nilsson class GenericTag { inherit RXML.Tag;
0970f92000-03-16Martin Nilsson  constant is_generic_tag=1;
d734522000-01-31Martin Nilsson  string name; int flags;
0970f92000-03-16Martin Nilsson 
38bfe52000-02-08Martin Stjernholm  function(string,mapping(string:string),string,RequestID,RXML.Frame: array|string) _do_return;
d734522000-01-31Martin Nilsson  void create(string _name, int _flags,
38bfe52000-02-08Martin Stjernholm  function(string,mapping(string:string),string,RequestID,RXML.Frame: array|string) __do_return) {
d734522000-01-31Martin Nilsson  name=_name; flags=_flags; _do_return=__do_return; if(flags&RXML.FLAG_DONT_PREPARSE)
7b73ef2000-02-08Martin Stjernholm  content_type = RXML.t_same;
d734522000-01-31Martin Nilsson  } class Frame { inherit RXML.Frame;
38bfe52000-02-08Martin Stjernholm  array do_return(RequestID id, void|mixed piece) {
1c1cb02000-08-05Martin Stjernholm  // Note: args may be zero here since this function is inherited // by GenericPITag.
7b73ef2000-02-08Martin Stjernholm  if (flags & RXML.FLAG_POSTPARSE)
4254f62000-02-13Martin Stjernholm  result_type = result_type (RXML.PXml);
0cac272000-02-08Martin Stjernholm  if (!(flags & RXML.FLAG_STREAM_CONTENT))
38bfe52000-02-08Martin Stjernholm  piece = content || ""; array|string res = _do_return(name, args, piece, id, this_object());
7b73ef2000-02-08Martin Stjernholm  return stringp (res) ? ({res}) : res;
d734522000-01-31Martin Nilsson  } } }
1c1cb02000-08-05Martin Stjernholm class GenericPITag { inherit GenericTag; void create (string _name, int _flags, function(string,mapping(string:string),string,RequestID,RXML.Frame: array|string) __do_return) { ::create (_name, _flags | RXML.FLAG_PROC_INSTR, __do_return); content_type = RXML.t_text; // The content is always treated literally; // RXML.FLAG_DONT_PREPARSE has no effect. } }
f599312000-01-19Martin Stjernholm void add_parse_module (RoxenModule mod)
b796b51998-11-18Per Hedbor {
f599312000-01-19Martin Stjernholm  RXML.TagSet tag_set =
72005e2000-03-23Martin Stjernholm  mod->query_tag_set ? mod->query_tag_set() : RXML.TagSet (mod->module_identifier());
f599312000-01-19Martin Stjernholm  mapping(string:mixed) defs; if (mod->query_tag_callers && mappingp (defs = mod->query_tag_callers()) && sizeof (defs))
76b5932000-06-23Martin Stjernholm  tag_set->add_tags (map (indices (defs), lambda (string name) { return CompatTag (name, 1, defs[name]); }));
f599312000-01-19Martin Stjernholm  if (mod->query_container_callers && mappingp (defs = mod->query_container_callers()) && sizeof (defs))
76b5932000-06-23Martin Stjernholm  tag_set->add_tags (map (indices (defs), lambda (string name) { return CompatTag (name, 0, defs[name]); }));
adc9df2000-03-14Martin Nilsson  if (mod->query_simpletag_callers && mappingp (defs = mod->query_simpletag_callers()) &&
d734522000-01-31Martin Nilsson  sizeof (defs)) tag_set->add_tags(Array.map(indices(defs), lambda(string tag){ return GenericTag(tag, @defs[tag]); }));
1c1cb02000-08-05Martin Stjernholm  if (mod->query_simple_pi_tag_callers && mappingp (defs = mod->query_simple_pi_tag_callers()) && sizeof (defs)) tag_set->add_tags (map (indices (defs), lambda (string name) { return GenericPITag (name, @defs[name]); }));
f599312000-01-19Martin Stjernholm  if (search (rxml_tag_set->imported, tag_set) < 0) {
0d7a532000-08-28Martin Stjernholm #ifdef THREADS Thread.MutexKey lock = rxml_tag_set->lists_mutex->lock(); #endif
4efd212000-02-13Martin Stjernholm  rxml_tag_set->modules += ({mod}); rxml_tag_set->imported += ({tag_set});
ac67522000-08-29Per Hedbor #ifdef THREADS
0d7a532000-08-28Martin Stjernholm  lock = 0;
ac67522000-08-29Per Hedbor #endif
0d7a532000-08-28Martin Stjernholm  remove_call_out (rxml_tag_set->sort_on_priority);
f599312000-01-19Martin Stjernholm  call_out (rxml_tag_set->sort_on_priority, 0); }
b796b51998-11-18Per Hedbor }
f599312000-01-19Martin Stjernholm void remove_parse_module (RoxenModule mod)
b796b51998-11-18Per Hedbor {
f599312000-01-19Martin Stjernholm  int i = search (rxml_tag_set->modules, mod); if (i >= 0) { RXML.TagSet tag_set = rxml_tag_set->imported[i];
71a5c92000-02-12Martin Stjernholm  rxml_tag_set->modules = rxml_tag_set->modules[..i - 1] + rxml_tag_set->modules[i + 1..];
f599312000-01-19Martin Stjernholm  rxml_tag_set->imported = rxml_tag_set->imported[..i - 1] + rxml_tag_set->imported[i + 1..]; if (tag_set) destruct (tag_set);
49a74b2000-01-14Martin Stjernholm  }
f599312000-01-19Martin Stjernholm }
b796b51998-11-18Per Hedbor 
7517d42000-02-16Martin Stjernholm void ready_to_receive_requests (object this)
b796b51998-11-18Per Hedbor {
7517d42000-02-16Martin Stjernholm  remove_call_out (rxml_tag_set->sort_on_priority); rxml_tag_set->sort_on_priority();
b796b51998-11-18Per Hedbor }
36aaa12000-01-23Martin Nilsson // ------------------------- RXML Core tags --------------------------
762a6c2000-02-15Martin Nilsson class TagHelp { inherit RXML.Tag; constant name = "help";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
b796b51998-11-18Per Hedbor 
762a6c2000-02-15Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) {
39e0362000-08-30Martin Nilsson  array tags=map(indices(RXML.get_context()->tag_set->get_tag_names()), lambda(string tag) { if(tag[..3]=="!--#" || !has_value(tag, "#")) return tag; return ""; } ) - ({ "" }); tags += map(indices(RXML.get_context()->tag_set->get_proc_instr_names()), 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"});
762a6c2000-02-15Martin Nilsson  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) {
39e0362000-08-30Martin Nilsson  if(tag[0]!='&' && lower_case(tag[0..0])!=char) {
762a6c2000-02-15Martin Nilsson  if(tag_links && char!="/") ret+="<h3>"+upper_case(char)+"</h3>\n<p>"+ String.implode_nicely(tag_links)+"</p>";
2d791b2000-07-03Martin Nilsson  char=lower_case(tag[0..0]);
762a6c2000-02-15Martin Nilsson  tag_links=({}); }
39e0362000-08-30Martin Nilsson  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];
9a669a2000-09-19Per Hedbor  if(undocumented_tags && undocumented_tags[tag])
762a6c2000-02-15Martin Nilsson  tag_links += ({ tag }); else tag_links += ({ sprintf("<a href=\"%s?_r_t_h=%s\">%s</a>\n",
39e0362000-08-30Martin Nilsson  id->not_query, Roxen.http_encode_url(enc), tag) }); }
762a6c2000-02-15Martin Nilsson  }
024ca12000-08-07Martin 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>"; RXML.Context context=RXML.get_context(); 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 });
8fae782000-01-12Martin Nilsson  }
762a6c2000-02-15Martin Nilsson  result=ret+find_tag_doc(help_for, id); }
b796b51998-11-18Per Hedbor  } }
762a6c2000-02-15Martin Nilsson class TagNumber { inherit RXML.Tag; constant name = "number";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
762a6c2000-02-15Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) {
8798f42000-07-31Martin Nilsson  if(args->type=="roman") return ({ Roxen.int2roman((int)args->num) }); if(args->type=="memory") return ({ Roxen.sizetostring((int)args->num) });
ae41332000-02-16Per Hedbor  result=roxen.language(args->lang||args->language|| id->misc->defines->theme_language, args->type||"number",id)( (int)args->num );
762a6c2000-02-15Martin Nilsson  } }
728f401999-02-16Marcus Comstedt }
74747a1999-04-22Per Hedbor 
ba60c32000-12-30Martin Nilsson class TagUse { inherit RXML.Tag; constant name = "use"; constant flags = RXML.FLAG_EMPTY_ELEMENT;
74747a1999-04-22Per Hedbor 
ba60c32000-12-30Martin 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; }); }
b796b51998-11-18Per Hedbor 
ba60c32000-12-30Martin 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;
762a6c2000-02-15Martin Nilsson  }
ba60c32000-12-30Martin 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>";
13b5a52000-02-17Martin Nilsson 
ba60c32000-12-30Martin Nilsson  array pack = parse_use_package(data, RXML.get_context()); cache_set("macrofiles", "|"+f, pack, 300);
74747a1999-04-22Per Hedbor 
ba60c32000-12-30Martin Nilsson  constant types = ({ "if plugin", "tag", "variable" }); pack = pack + ({}); pack[0] = indices(pack[0]); pack[1] = pack[1]->name; pack[2] = indices(pack[2])+indices(pack[3]); for(int i; i<3; i++) if(sizeof(pack[i])) { res += "Defines the following " + types[i] + (sizeof(pack[i])!=1?"s":"") + ": " + String.implode_nicely( sort(pack[i]) ) + ".<br />"; } if(help) res+="<br /><br />All tags accept the <i>help</i> attribute."; return res; } private array parse_use_package(string data, RXML.Context ctx) { array res = allocate(4); multiset before=ctx->get_runtime_tags(); if(!ctx->id->misc->_ifs) ctx->id->misc->_ifs = ([]); mapping before_ifs = mkmapping(indices(ctx->id->misc->_ifs), indices(ctx->id->misc->_ifs)); mapping scope_form = mkmapping(ctx->list_var("form"), map(ctx->list_var("form"), lambda(string v) { return ctx->get_var(v, "form"); } )); mapping scope_var = mkmapping(ctx->list_var("var"), map(ctx->list_var("var"), lambda(string v) { return ctx->get_var(v, "var"); } )); parse_rxml( data, ctx->id ); foreach( ctx->list_var("form"), string var ) { mixed val = ctx->get_var(var, "form"); if(scope_form[var]==val) m_delete(scope_form, var); else scope_form[var]=val; } foreach( ctx->list_var("var"), string var ) { mixed val = ctx->get_var(var, "var"); if(scope_var[var]==val) m_delete(scope_var, var); else scope_var[var]=val; } res[0] = ctx->id->misc->_ifs - before_ifs; res[1] = indices(RXML.get_context()->get_runtime_tags()-before); res[2] = scope_form; res[3] = scope_var; return res; }
f4d2801999-10-18Per Hedbor 
863c942000-02-15Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) { if(args->packageinfo) {
4350622000-08-23Martin Nilsson  NOCACHE();
863c942000-02-15Martin Nilsson  string res ="<dl>"; foreach(list_packages(), string f) res += use_file_doc(f, read_package( f )); return ({ res+"</dl>" }); }
b796b51998-11-18Per Hedbor 
863c942000-02-15Martin Nilsson  if(!args->file && !args->package)
39271c2000-02-23Martin Stjernholm  parse_error("No file or package selected.\n");
36aaa12000-01-23Martin Nilsson 
863c942000-02-15Martin Nilsson  array res;
886f4f2000-07-31Johan Sundström  string name, filename; if(args->file) { filename = Roxen.fix_relative(args->file, id); name = id->conf->get_config_id() + "|" + filename; } else name = "|" + args->package; RXML.Context ctx = RXML.get_context();
74747a1999-04-22Per Hedbor 
863c942000-02-15Martin Nilsson  if(args->info || id->pragma["no-cache"] || !(res=cache_lookup("macrofiles",name)) ) {
762a6c2000-02-15Martin Nilsson 
863c942000-02-15Martin Nilsson  string file;
886f4f2000-07-31Johan Sundström  if(filename)
ba60c32000-12-30Martin Nilsson  file = id->conf->try_get_file( filename, id );
863c942000-02-15Martin Nilsson  else file = read_package( args->package );
762a6c2000-02-15Martin Nilsson 
863c942000-02-15Martin Nilsson  if(!file)
39271c2000-02-23Martin Stjernholm  run_error("Failed to fetch "+(args->file||args->package)+".\n");
f4d2801999-10-18Per Hedbor 
863c942000-02-15Martin Nilsson  if( args->info ) return ({"<dl>"+use_file_doc( args->file || args->package, file )+"</dl>"});
ba60c32000-12-30Martin Nilsson  res = parse_use_package(file, ctx);
863c942000-02-15Martin Nilsson  cache_set("macrofiles", name, res); } id->misc->_ifs += res[0]; foreach(res[1], RXML.Tag tag) ctx->add_runtime_tag(tag);
ba60c32000-12-30Martin Nilsson  foreach(indices(res[2]), string var) ctx->set_var(var, res[2][var], "form"); foreach(indices(res[3]), string var) ctx->set_var(var, res[3][var], "var");
863c942000-02-15Martin Nilsson  return 0; } }
b796b51998-11-18Per Hedbor }
411cdf2000-02-20Martin Stjernholm class UserTagContents { inherit RXML.Tag; constant name = "contents";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
411cdf2000-02-20Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_any (RXML.PXml)}); class Frame { inherit RXML.Frame; RXML.Frame user_tag_up; array do_return() { RXML.Frame frame = up; while (frame && !frame->user_tag_contents) frame = frame->user_tag_up || frame->up;
d483192000-02-20Martin Stjernholm  if (!frame) parse_error ("No contents to insert.\n");
411cdf2000-02-20Martin Stjernholm  user_tag_up = frame->up; return ({frame->user_tag_contents}); } } } RXML.TagSet user_tag_contents_tag_set = RXML.TagSet ("user_tag_contents", ({UserTagContents()}));
762a6c2000-02-15Martin Nilsson class UserTag { inherit RXML.Tag; string name; int flags = 0;
411cdf2000-02-20Martin Stjernholm  RXML.Type content_type = RXML.t_same;
5a31102000-02-15Martin Stjernholm  array(RXML.Type) result_types = ({ RXML.t_any(RXML.PXml) });
762a6c2000-02-15Martin Nilsson  string c; mapping defaults;
5d4c852000-02-20Martin Nilsson  string scope;
762a6c2000-02-15Martin Nilsson 
5d4c852000-02-20Martin Nilsson  void create(string _name, string _c, mapping _defaults, int tag, void|string scope_name) {
762a6c2000-02-15Martin Nilsson  name=_name; c=_c; defaults=_defaults;
d5e1082000-08-20Martin Nilsson  if(tag) flags=RXML.FLAG_EMPTY_ELEMENT;
5d4c852000-02-20Martin Nilsson  scope=scope_name;
c2dd2a1999-09-10Martin Nilsson  }
762a6c2000-02-15Martin Nilsson  class Frame { inherit RXML.Frame;
411cdf2000-02-20Martin Stjernholm  RXML.TagSet additional_tags = user_tag_contents_tag_set;
762a6c2000-02-15Martin Nilsson  mapping vars; string scope_name;
411cdf2000-02-20Martin Stjernholm  string user_tag_contents;
762a6c2000-02-15Martin Nilsson  array do_return(RequestID id) {
863c942000-02-15Martin Nilsson  mapping nargs=defaults+args; id->misc->last_tag_args = nargs;
5d4c852000-02-20Martin Nilsson  scope_name=scope||name;
863c942000-02-15Martin Nilsson  vars = nargs;
762a6c2000-02-15Martin Nilsson 
c0f5082000-02-21Martin Stjernholm  if(!(RXML.FLAG_EMPTY_ELEMENT&flags) && args->trimwhites)
13b5a52000-02-17Martin Nilsson  content=String.trim_all_whites(content);
b796b51998-11-18Per Hedbor 
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
8e29c32000-03-04Martin Stjernholm  if(old_rxml_compat) {
8008a52000-02-20Martin Stjernholm  array replace_from, replace_to;
c0f5082000-02-21Martin Stjernholm  if (flags & RXML.FLAG_EMPTY_ELEMENT) {
a39b5a2000-03-19Martin Nilsson  replace_from = map(indices(nargs),Roxen.make_entity)+({"#args#"}); replace_to = values(nargs)+({ Roxen.make_tag_attributes(nargs)[1..] });
8008a52000-02-20Martin Stjernholm  } else {
a39b5a2000-03-19Martin Nilsson  replace_from = map(indices(nargs),Roxen.make_entity)+({"#args#", "<contents>"}); replace_to = values(nargs)+({ Roxen.make_tag_attributes(nargs)[1..], content });
8008a52000-02-20Martin Stjernholm  }
b2c49b2000-02-18Martin Nilsson  string c2; c2 = replace(c, replace_from, replace_to); if(c2!=c) { vars=([]);
8008a52000-02-20Martin Stjernholm  return ({c2});
b2c49b2000-02-18Martin Nilsson  }
74747a1999-04-22Per Hedbor  }
778d141999-08-20Martin Nilsson #endif
63775e1999-07-24Martin Nilsson 
a39b5a2000-03-19Martin Nilsson  vars->args = Roxen.make_tag_attributes(nargs)[1..]; vars["rest-args"] = Roxen.make_tag_attributes(args - defaults)[1..];
411cdf2000-02-20Martin Stjernholm  user_tag_contents = vars->contents = content;
762a6c2000-02-15Martin Nilsson  return ({ c }); } } } class TagDefine { inherit RXML.Tag; constant name = "define";
d88d2b2000-08-30Martin Stjernholm  constant flags = RXML.FLAG_DONT_REPORT_ERRORS;
762a6c2000-02-15Martin Nilsson  class Frame { inherit RXML.Frame;
a00b912000-02-21Martin Nilsson  array do_enter(RequestID id) { if(args->preparse) m_delete(args, "preparse"); else content_type = RXML.t_xml; return 0; }
762a6c2000-02-15Martin Nilsson  array do_return(RequestID id) { result = ""; string n; if(n=args->variable) {
5041522000-03-28Martin Nilsson  if(args->trimwhites) content=String.trim_all_whites(content); RXML.user_set_var(n, content, args->scope);
762a6c2000-02-15Martin Nilsson  return 0;
c4ccda1999-08-02Martin Nilsson  }
762a6c2000-02-15Martin Nilsson  if (n=args->tag||args->container) {
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
a318fa2000-04-02Martin Nilsson  n = old_rxml_compat?lower_case(n):n; #endif
5d4c852000-02-20Martin Nilsson  int tag=0; if(args->tag) { tag=1;
762a6c2000-02-15Martin Nilsson  m_delete(args, "tag");
5d4c852000-02-20Martin Nilsson  } else
762a6c2000-02-15Martin Nilsson  m_delete(args, "container"); mapping defaults=([]);
0d87d72000-01-30Martin Nilsson 
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
8e29c32000-03-04Martin Stjernholm  if(old_rxml_compat)
b2c49b2000-02-18Martin Nilsson  foreach( indices(args), string arg ) if( arg[..7] == "default_" ) { defaults[arg[8..]] = args[arg]; old_rxml_warning(id, "define attribute "+arg,"attrib container"); m_delete( args, arg ); }
c2dd2a1999-09-10Martin Nilsson #endif
a700042000-03-16Martin Stjernholm  content=parse_html(content||"",([]), (["attrib": lambda(string tag, mapping m, string cont) { if(m->name) defaults[m->name]=parse_rxml(cont,id); return ""; } ])); if(args->trimwhites) { content=String.trim_all_whites(content); m_delete (args, "trimwhites"); }
b796b51998-11-18Per Hedbor 
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
8e29c32000-03-04Martin Stjernholm  if(old_rxml_compat) content = replace( content, indices(args), values(args) );
778d141999-08-20Martin Nilsson #endif
63775e1999-07-24Martin Nilsson 
5d4c852000-02-20Martin Nilsson  RXML.get_context()->add_runtime_tag(UserTag(n, content, defaults, tag, args->scope));
762a6c2000-02-15Martin Nilsson  return 0;
c4ccda1999-08-02Martin Nilsson  }
762a6c2000-02-15Martin Nilsson  if (n=args->if) { if(!id->misc->_ifs) id->misc->_ifs=([]); id->misc->_ifs[args->if]=UserIf(args->if, content); return 0; }
0d87d72000-01-30Martin Nilsson 
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
762a6c2000-02-15Martin Nilsson  if (n=args->name) { id->misc->defines[n]=content; old_rxml_warning(id, "attempt to define name ","variable"); return 0; }
c2dd2a1999-09-10Martin Nilsson #endif
36aaa12000-01-23Martin Nilsson 
39271c2000-02-23Martin Stjernholm  parse_error("No tag, variable, if or container specified.\n");
762a6c2000-02-15Martin Nilsson  } }
b796b51998-11-18Per Hedbor }
762a6c2000-02-15Martin Nilsson class TagUndefine { inherit RXML.Tag;
c0f5082000-02-21Martin Stjernholm  int flags = RXML.FLAG_EMPTY_ELEMENT;
762a6c2000-02-15Martin Nilsson  constant name = "undefine"; class Frame { inherit RXML.Frame; array do_enter(RequestID id) { string n; if(n=args->variable) { RXML.get_context()->user_delete_var(n, args->scope); return 0; } if (n=args->tag||args->container) { RXML.get_context()->remove_runtime_tag(n); return 0; } if (n=args->if) { m_delete(id->misc->_ifs, n); return 0; }
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
762a6c2000-02-15Martin Nilsson  if (n=args->name) { m_delete(id->misc->defines, args->name); return 0; }
c2dd2a1999-09-10Martin Nilsson #endif
778d141999-08-20Martin Nilsson 
39271c2000-02-23Martin Stjernholm  parse_error("No tag, variable, if or container specified.\n");
762a6c2000-02-15Martin Nilsson  } }
b796b51998-11-18Per Hedbor }
74747a1999-04-22Per Hedbor class Tracer {
8a13d22000-09-02Martin Stjernholm  // Note: \n is used sparingly in output to make it look nice even // inside <pre>.
74747a1999-04-22Per Hedbor  string resolv="<ol>"; int level;
ec91501999-11-23Per Hedbor  string _sprintf() { return "Tracer()"; }
8a13d22000-09-02Martin Stjernholm #if constant (gethrtime)
74747a1999-04-22Per Hedbor  mapping et = ([]);
8a13d22000-09-02Martin Stjernholm #endif #if constant (gethrvtime)
74747a1999-04-22Per Hedbor  mapping et2 = ([]); #endif
8a13d22000-09-02Martin Stjernholm  local void start_clock() { #if constant (gethrvtime) et2[level] = gethrvtime(); #endif #if constant (gethrtime) et[level] = gethrtime(); #endif } local string stop_clock()
74747a1999-04-22Per Hedbor  {
8a13d22000-09-02Martin Stjernholm  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;
74747a1999-04-22Per Hedbor  }
8a13d22000-09-02Martin Stjernholm  void trace_enter_ol(string type, function|object thing)
74747a1999-04-22Per Hedbor  {
36aaa12000-01-23Martin Nilsson  level++;
74747a1999-04-22Per Hedbor 
8a13d22000-09-02Martin Stjernholm  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; }
74747a1999-04-22Per Hedbor  string efont="", font="";
36aaa12000-01-23Martin Nilsson  if(level>2) {efont="</font>";font="<font size=-1>";}
8a13d22000-09-02Martin Stjernholm  resolv += font + "<li><b>»</b> " + type + "<ol>" + efont; start_clock();
74747a1999-04-22Per Hedbor  } void trace_leave_ol(string desc) { level--;
8a13d22000-09-02Martin Stjernholm 
74747a1999-04-22Per Hedbor  string efont="", font="";
36aaa12000-01-23Martin Nilsson  if(level>1) {efont="</font>";font="<font size=-1>";}
74747a1999-04-22Per Hedbor 
8a13d22000-09-02Martin Stjernholm  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";
74747a1999-04-22Per Hedbor  } string res() { while(level>0) trace_leave_ol("");
8a13d22000-09-02Martin Stjernholm  return resolv + "</ol>";
74747a1999-04-22Per Hedbor  } }
b2c49b2000-02-18Martin Nilsson class TagTrace { inherit RXML.Tag; constant name = "trace"; class Frame { inherit RXML.Frame; function a,b; Tracer t; array do_enter(RequestID id) { NOCACHE(); // if(args->summary) // t = SumTracer(); // else t = Tracer(); 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;
8a13d22000-09-02Martin Stjernholm  t->start_clock();
b2c49b2000-02-18Martin Nilsson  return 0; } array do_return(RequestID id) { id->misc->trace_enter = a; id->misc->trace_leave = b;
8a13d22000-09-02Martin Stjernholm  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>";
b2c49b2000-02-18Martin Nilsson  return 0; } } } class TagNoParse { inherit RXML.Tag; constant name = "noparse"; RXML.Type content_type = RXML.t_same; class Frame { inherit RXML.Frame; }
74747a1999-04-22Per Hedbor }
2d6fb02000-09-07Martin Nilsson class TagPINoParse { inherit TagNoParse; constant flags = RXML.FLAG_PROC_INSTR;
0cefbe2001-01-15Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) { result = content[1..]; return 0; } }
2d6fb02000-09-07Martin Nilsson }
d3dc902000-09-08Martin Stjernholm 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; } }
2d6fb02000-09-07Martin Nilsson 
f296ac2000-02-06Martin Nilsson class TagEval { inherit RXML.Tag; constant name = "eval";
762a6c2000-02-15Martin Nilsson  array(RXML.Type) result_types = ({ RXML.t_any(RXML.PXml) });
f296ac2000-02-06Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) { return ({ content }); } } }
762a6c2000-02-15Martin Nilsson class TagNoOutput { inherit RXML.Tag; constant name = "nooutput";
d88d2b2000-08-30Martin Stjernholm  constant flags = RXML.FLAG_DONT_REPORT_ERRORS;
762a6c2000-02-15Martin Nilsson  class Frame { inherit RXML.Frame;
7b6da72000-03-11Martin Nilsson  array do_process() {
762a6c2000-02-15Martin Nilsson  return ({""}); } }
74747a1999-04-22Per Hedbor }
762a6c2000-02-15Martin Nilsson class TagStrLen { inherit RXML.Tag; constant name = "strlen";
d88d2b2000-08-30Martin Stjernholm  constant flags = RXML.FLAG_DONT_REPORT_ERRORS;
762a6c2000-02-15Martin Nilsson  class Frame { inherit RXML.Frame;
23cf702000-02-15Martin Nilsson  array do_return() { if(!stringp(content)) { result="0"; return 0; } result = (string)strlen(content); }
762a6c2000-02-15Martin Nilsson  }
74747a1999-04-22Per Hedbor }
b2c49b2000-02-18Martin Nilsson class TagCase { inherit RXML.Tag; constant name = "case";
3b6d792000-08-27Martin Stjernholm  static Parser.HTML lowercaser = lambda () { Parser.HTML p = Parser.HTML(); p->_set_data_callback ( lambda (Parser.HTML p, string data) { return ({lower_case (data)}); }); p->_set_entity_callback ( lambda (Parser.HTML p, string data) { if (string char = Roxen.decode_charref (data)) return ({Roxen.encode_charref (lower_case (char))}); return 0; }); return p; }(); static Parser.HTML uppercaser = lambda () { Parser.HTML p = Parser.HTML(); p->_set_data_callback ( lambda (Parser.HTML p, string data) { return ({upper_case (data)}); }); p->_set_entity_callback ( lambda (Parser.HTML p, string data) { if (string char = Roxen.decode_charref (data)) return ({Roxen.encode_charref (upper_case (char))}); return 0; }); return p; }(); static Parser.HTML capitalizer = lambda () { Parser.HTML p = Parser.HTML(); p->_set_data_callback ( lambda (Parser.HTML p, string data) { p->_set_data_callback (0); p->_set_entity_callback (0); return ({String.capitalize (data)}); }); p->_set_entity_callback ( lambda (Parser.HTML p, string data) { p->_set_data_callback (0); p->_set_entity_callback (0); if (string char = Roxen.decode_charref (data)) return ({Roxen.encode_charref (upper_case (char))}); return 0; }); return p; }();
b2c49b2000-02-18Martin Nilsson  class Frame { inherit RXML.Frame;
7b6da72000-03-11Martin Nilsson  int cap=0; array do_process(RequestID id) {
b2c49b2000-02-18Martin Nilsson  if(args->case) switch(lower_case(args->case)) {
3b6d792000-08-27Martin Stjernholm  case "lower": return ({content_type->encoding_type == "xml" ? lowercaser->clone()->finish (content)->read() : lower_case (content)});
d480632000-08-27Martin Nilsson  case "upper":
3b6d792000-08-27Martin Stjernholm  return ({content_type->encoding_type == "xml" ? uppercaser->clone()->finish (content)->read() : upper_case (content)});
7b6da72000-03-11Martin Nilsson  case "capitalize":
3b6d792000-08-27Martin Stjernholm  if(cap) return ({content}); if (sizeof (content)) cap=1; return ({content_type->encoding_type == "xml" ? capitalizer->clone()->finish (content)->read() : String.capitalize (content)});
b2c49b2000-02-18Martin Nilsson  }
63775e1999-07-24Martin Nilsson 
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
b2c49b2000-02-18Martin Nilsson  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"); }
778d141999-08-20Martin Nilsson #endif
b2c49b2000-02-18Martin Nilsson  return ({ content }); } }
74747a1999-04-22Per Hedbor } #define LAST_IF_TRUE id->misc->defines[" _ok"]
4efd212000-02-13Martin Stjernholm class FrameIf { inherit RXML.Frame; int do_iterate = -1;
74747a1999-04-22Per Hedbor 
4efd212000-02-13Martin Stjernholm  array do_enter(RequestID id) { int and = 1;
74747a1999-04-22Per Hedbor 
4efd212000-02-13Martin Stjernholm  if(args->not) { m_delete(args, "not"); do_enter(id); do_iterate=do_iterate==1?-1:1; return 0; }
c0d5461999-05-08Per Hedbor 
4efd212000-02-13Martin Stjernholm  if(args->or) { and = 0; m_delete( args, "or" ); } if(args->and) { and = 1; m_delete( args, "and" ); } mapping plugins=get_plugins(); if(id->misc->_ifs) plugins+=id->misc->_ifs; array possible = indices(args) & indices(plugins);
e693092000-02-06Martin Nilsson 
4efd212000-02-13Martin Stjernholm  int ifval=0; foreach(possible, string s) {
1dd3652000-02-14Martin Nilsson  ifval = plugins[ s ]->eval( args[s], id, args, and, s );
dab3962000-02-08Martin Nilsson  if(ifval) {
4efd212000-02-13Martin Stjernholm  if(!and) { do_iterate = 1; return 0; }
e693092000-02-06Martin Nilsson  }
4efd212000-02-13Martin Stjernholm  else
daf2542000-03-13Martin Nilsson  if(and)
4efd212000-02-13Martin Stjernholm  return 0;
74747a1999-04-22Per Hedbor  }
4efd212000-02-13Martin Stjernholm  if(ifval) { do_iterate = 1;
5e3acc2000-02-07Martin Nilsson  return 0; }
4efd212000-02-13Martin Stjernholm  return 0; } array do_return(RequestID id) {
7b6da72000-03-11Martin Nilsson  if(do_iterate==1) { LAST_IF_TRUE = 1; result = content; }
daf2542000-03-13Martin Nilsson  else LAST_IF_TRUE = 0;
4efd212000-02-13Martin Stjernholm  return 0;
74747a1999-04-22Per Hedbor  } }
4efd212000-02-13Martin Stjernholm class TagIf { inherit RXML.Tag; constant name = "if";
4254f62000-02-13Martin Stjernholm  constant flags = RXML.FLAG_SOCKET_TAG; program Frame = FrameIf;
4efd212000-02-13Martin Stjernholm }
762a6c2000-02-15Martin Nilsson class TagElse { inherit RXML.Tag; constant name = "else"; constant flags = 0; class Frame { inherit RXML.Frame;
863c942000-02-15Martin Nilsson  int do_iterate=1;
762a6c2000-02-15Martin Nilsson  array do_enter(RequestID id) {
863c942000-02-15Martin Nilsson  if(LAST_IF_TRUE) do_iterate=-1;
762a6c2000-02-15Martin Nilsson  return 0; } }
74747a1999-04-22Per Hedbor }
863c942000-02-15Martin Nilsson class TagThen { inherit RXML.Tag; constant name = "then"; constant flags = 0; class Frame { inherit RXML.Frame; int do_iterate=1; array do_enter(RequestID id) { if(!LAST_IF_TRUE) do_iterate=-1; return 0; } }
63775e1999-07-24Martin Nilsson }
b2c49b2000-02-18Martin Nilsson class TagElseif { inherit RXML.Tag; constant name = "elseif"; class Frame { inherit FrameIf;
7192472000-05-10Martin Nilsson  int last;
b2c49b2000-02-18Martin Nilsson  array do_enter(RequestID id) {
7192472000-05-10Martin Nilsson  last=LAST_IF_TRUE; if(last) return 0;
b2c49b2000-02-18Martin Nilsson  return ::do_enter(id); }
8f5eaa2000-03-13Martin Nilsson  array do_return(RequestID id) {
7192472000-05-10Martin Nilsson  if(last) return 0;
8f5eaa2000-03-13Martin Nilsson  return ::do_return(id); }
b2c49b2000-02-18Martin Nilsson  mapping(string:RXML.Tag) get_plugins() { return RXML.get_context()->tag_set->get_plugins ("if"); } }
74747a1999-04-22Per Hedbor }
b2c49b2000-02-18Martin Nilsson class TagTrue { inherit RXML.Tag; constant name = "true";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
b2c49b2000-02-18Martin Nilsson  class Frame { inherit RXML.Frame; array do_enter(RequestID id) { LAST_IF_TRUE = 1; } }
74747a1999-04-22Per Hedbor }
b2c49b2000-02-18Martin Nilsson class TagFalse { inherit RXML.Tag; constant name = "false";
c0f5082000-02-21Martin Stjernholm  constant flags = RXML.FLAG_EMPTY_ELEMENT;
b2c49b2000-02-18Martin Nilsson  class Frame { inherit RXML.Frame; array do_enter(RequestID id) { LAST_IF_TRUE = 0; } }
74747a1999-04-22Per Hedbor }
4efd212000-02-13Martin Stjernholm class TagCond
74747a1999-04-22Per Hedbor {
4efd212000-02-13Martin Stjernholm  inherit RXML.Tag; constant name = "cond";
3461df2000-08-12Martin Stjernholm  RXML.Type content_type = RXML.t_nil (RXML.PXml);
4efd212000-02-13Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_any});
74747a1999-04-22Per Hedbor 
4efd212000-02-13Martin Stjernholm  class TagCase { inherit RXML.Tag; constant name = "case";
3461df2000-08-12Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil});
4efd212000-02-13Martin Stjernholm  class Frame { inherit FrameIf; array do_enter (RequestID id) { if (up->result != RXML.Void) return 0;
4254f62000-02-13Martin Stjernholm  content_type = up->result_type (RXML.PXml);
4efd212000-02-13Martin Stjernholm  return ::do_enter (id); } array do_return (RequestID id) { ::do_return (id);
8c6d5f2000-06-29Martin Stjernholm  if (up->result != RXML.Void) return 0;
4efd212000-02-13Martin Stjernholm  up->result = result; result = RXML.Void; return 0; } // Must override this since it's used by FrameIf. mapping(string:RXML.Tag) get_plugins() {return RXML.get_context()->tag_set->get_plugins ("if");} } } class TagDefault { inherit RXML.Tag; constant name = "default";
3461df2000-08-12Martin Stjernholm  array(RXML.Type) result_types = ({RXML.t_nil});
4efd212000-02-13Martin Stjernholm  class Frame { inherit RXML.Frame; int do_iterate = 1; array do_enter() { if (up->result != RXML.Void) { do_iterate = -1; return 0; } content_type = up->result_type (RXML.PNone); return 0; } array do_return() { up->default_data = content; return 0; } } } RXML.TagSet cond_tags = RXML.TagSet ("TagCond.cond_tags", ({TagCase(), TagDefault()})); class Frame { inherit RXML.Frame; RXML.TagSet local_tags = cond_tags; string default_data; array do_return (RequestID id) { if (result == RXML.Void && default_data) { LAST_IF_TRUE = 0;
4254f62000-02-13Martin Stjernholm  return ({RXML.parse_frame (result_type (RXML.PXml), default_data)});
4efd212000-02-13Martin Stjernholm  } return 0; } }
74747a1999-04-22Per Hedbor }
884b232000-02-05Martin Nilsson class TagEmit { inherit RXML.Tag; constant name = "emit";
d88d2b2000-08-30Martin Stjernholm  constant flags = RXML.FLAG_SOCKET_TAG|RXML.FLAG_DONT_REPORT_ERRORS;
e8eb692000-08-12Martin Nilsson  mapping(string:RXML.Type) req_arg_types = (["source":RXML.t_text(RXML.PEnt)]);
e6bf912000-11-15Martin Nilsson 
31c9532000-12-12Martin Nilsson  int(0..1) should_filter(mapping vs, mapping filter) { foreach(indices(filter), string v) { if(!vs[v]) return 1; if(!glob(filter[v], vs[v])) return 1; } return 0; }
8e15042000-12-06Martin Nilsson  class TagDelimiter { inherit RXML.Tag; constant name = "delimiter";
31c9532000-12-12Martin Nilsson  // FIXME: Add lookahead here. static int(0..1) more_rows(array res, mapping filter) { if(!sizeof(res)) return 0; foreach(res[RXML.get_var("real-counter")..], mapping v) { if(!should_filter(v, filter)) return 1; } return 0; }
8e15042000-12-06Martin Nilsson  class Frame { inherit RXML.Frame; array do_return(RequestID id) {
31c9532000-12-12Martin Nilsson  if(!id->misc->emit_filter) { if( RXML.get_var("counter") < sizeof(id->misc->emit_rows) ) result = content; return 0; } if(id->misc->emit_args->maxrows && (int)id->misc->emit_args->maxrows == RXML.get_var("counter")) return 0; if(more_rows(id->misc->emit_rows, id->misc->emit_filter))
8e15042000-12-06Martin Nilsson  result = content; return 0; } } } RXML.TagSet internal = RXML.TagSet("TagEmit.internal", ({ TagDelimiter() }) );
e6bf912000-11-15Martin Nilsson  // A slightly modified Array.dwim_sort_func
63e01a2000-12-11Martin Nilsson  // used as emits sort function.
e6bf912000-11-15Martin Nilsson  static int compare(string a0,string b0) { if (!a0) { if (b0)
cac3242000-07-05Marcus Wellhardh  return -1;
e6bf912000-11-15Martin Nilsson  return 0; } if (!b0)
cac3242000-07-05Marcus Wellhardh  return 1;
e6bf912000-11-15Martin Nilsson  string a2="",b2=""; int a1,b1; sscanf(a0,"%s%d%s",a0,a1,a2); sscanf(b0,"%s%d%s",b0,b1,b2); if (a0>b0) return 1; if (a0<b0) return -1; if (a1>b1) return 1; if (a1<b1) return -1; if (a2==b2) return 0; return compare(a2,b2);
cac3242000-07-05Marcus Wellhardh  }
e6bf912000-11-15Martin Nilsson 
884b232000-02-05Martin Nilsson  class Frame { inherit RXML.Frame;
8e15042000-12-06Martin Nilsson  RXML.TagSet additional_tags = internal;
884b232000-02-05Martin Nilsson  string scope_name;
8e15042000-12-06Martin Nilsson  mapping vars;
884b232000-02-05Martin Nilsson 
31c9532000-12-12Martin Nilsson  array outer_rows; mapping outer_filter; mapping outer_args;
884b232000-02-05Martin Nilsson  object plugin; array(mapping(string:mixed))|function res;
9a23172000-12-10Martin Nilsson  mapping filter;
884b232000-02-05Martin Nilsson  array do_enter(RequestID id) {
4254f62000-02-13Martin Stjernholm  if(!(plugin=get_plugins()[args->source]))
fa5a7f2000-11-19Martin Stjernholm  parse_error("The emit source %O doesn't exist.\n", args->source);
884b232000-02-05Martin Nilsson  scope_name=args->scope||args->source;
9a23172000-12-10Martin Nilsson 
4e72c92000-09-06Martin Nilsson  TRACE_ENTER("Fetch emit dataset for source "+args->source, 0);
884b232000-02-05Martin Nilsson  res=plugin->get_dataset(args, id);
4e72c92000-09-06Martin Nilsson  TRACE_LEAVE("");
9a23172000-12-10Martin Nilsson 
63e01a2000-12-11Martin Nilsson  if(plugin->skiprows && args->skiprows) m_delete(args, "skiprows"); if(plugin->maxrows && args->maxrows) m_delete(args, "maxrows");
9ca8e02000-12-11Martin Nilsson  if(functionp(res)) { // FIXME: API (function/object) do_iterate=function_iterate; if(args->skiprows) { args->skiprow = (int)args->skiprows; while(args->skiprows--) res(args, id); } LAST_IF_TRUE = 1; return 0; }
884b232000-02-05Martin Nilsson  if(arrayp(res)) {
8e15042000-12-06Martin Nilsson  vars = (["counter":0]);
ce8aec2000-08-11Martin Nilsson  if(args->sort && !plugin->sort)
cac3242000-07-05Marcus Wellhardh  { array(string) order = (args->sort - " ")/"," - ({ "" }); res = Array.sort_array( res, lambda (mapping(string:string) m1, mapping(string:string) m2) { foreach (order, string field) {
9ca8e02000-12-11Martin Nilsson  int(-1..1) tmp;
cac3242000-07-05Marcus Wellhardh  if (field[0] == '-') tmp = compare( m2[field[1..]], m1[field[1..]] ); else if (field[0] == '+') tmp = compare( m1[field[1..]], m2[field[1..]] ); else tmp = compare( m1[field], m2[field] );
e6bf912000-11-15Martin Nilsson 
cac3242000-07-05Marcus Wellhardh  if (tmp == 1) return 1; else if (tmp == -1) return 0; } return 0; } ); }
9a23172000-12-10Martin Nilsson  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; }
9ca8e02000-12-11Martin Nilsson  if(args->rowinfo || (args->skiprows && args->skiprows[-1]=='-')) {
9a23172000-12-10Martin Nilsson  m_delete(args, "filter"); for(int i; i<sizeof(res); i++)
31c9532000-12-12Martin Nilsson  if(should_filter(res[i], filter)) {
9a23172000-12-10Martin Nilsson  res = res[..i-1] + res[i+1..]; i--; } } else {
31c9532000-12-12Martin Nilsson  if(args->skiprows) { int skiprows = (int)args->skiprows; if(skiprows > sizeof(res)) res = ({}); else { int i; for(; i<sizeof(res) && skiprows; i++) if(!should_filter(res[i], filter)) skiprows--; res = res[i..]; } } vars["real-counter"] = 0;
9a23172000-12-10Martin Nilsson  do_iterate = array_filter_iterate; }
7b05d02000-05-15Martin Nilsson  }
e693092000-02-06Martin Nilsson 
9a23172000-12-10Martin Nilsson  if(!args->filter) {
63e01a2000-12-11Martin Nilsson  if(args->skiprows) {
9a23172000-12-10Martin Nilsson  if(args->skiprows[0]=='-') args->skiprows=sizeof(res)-(int)args->skiprows-1; res=res[(int)args->skiprows..]; } if(args->remainderinfo) RXML.user_set_var(args->remainderinfo, (int)args->maxrows? max(sizeof(res)-(int)args->maxrows, 0): 0);
8e15042000-12-06Martin Nilsson 
63e01a2000-12-11Martin Nilsson  if(args->maxrows) res=res[..(int)args->maxrows-1];
9a23172000-12-10Martin Nilsson  if(args->rowinfo) RXML.user_set_var(args->rowinfo, sizeof(res)); if(args["do-once"] && sizeof(res)==0) res=({ ([]) }); do_iterate = array_iterate; }
4ebd842000-03-30Martin Nilsson 
31c9532000-12-12Martin Nilsson  outer_rows = id->misc->emit_rows; outer_filter = id->misc->emit_filter; outer_args = id->misc->emit_args; id->misc->emit_rows = res; id->misc->emit_filter = filter; id->misc->emit_args = args;
4ebd842000-03-30Martin Nilsson  if(sizeof(res)) LAST_IF_TRUE = 1; else LAST_IF_TRUE = 0;
884b232000-02-05Martin Nilsson  return 0; }
9a23172000-12-10Martin Nilsson 
39271c2000-02-23Martin Stjernholm  parse_error("Wrong return type from emit source plugin.\n");
884b232000-02-05Martin Nilsson  }
63e01a2000-12-11Martin Nilsson  int(0..1) do_once_more() {
31c9532000-12-12Martin Nilsson  if(vars->counter || !args["do-once"]) return 0;
9ca8e02000-12-11Martin Nilsson  vars = (["counter":1]);
63e01a2000-12-11Martin Nilsson  return 1; }
884b232000-02-05Martin Nilsson  function do_iterate;
9a23172000-12-10Martin Nilsson  int(0..1) function_iterate(RequestID id) {
63e01a2000-12-11Martin Nilsson  int counter = vars->counter;
31c9532000-12-12Martin Nilsson  if(args->maxrows && counter == (int)args->maxrows) return do_once_more(); while(should_filter(vars=res(args, id), filter));
63e01a2000-12-11Martin Nilsson  vars->counter = counter++;
9ca8e02000-12-11Martin Nilsson  return mappingp(vars) || do_once_more();
884b232000-02-05Martin Nilsson  }
9a23172000-12-10Martin Nilsson  int(0..1) array_iterate(RequestID id) {
884b232000-02-05Martin Nilsson  int counter=vars->counter; if(counter>=sizeof(res)) return 0; vars=res[counter++]; vars->counter=counter; return 1; }
4cc2452000-03-03Martin Nilsson 
9a23172000-12-10Martin Nilsson  int(0..1) array_filter_iterate(RequestID id) {
31c9532000-12-12Martin Nilsson  int real_counter = vars["real-counter"];
9a23172000-12-10Martin Nilsson  int counter = vars->counter;
63e01a2000-12-11Martin Nilsson  if(real_counter>=sizeof(res)) return do_once_more();
31c9532000-12-12Martin Nilsson 
63e01a2000-12-11Martin Nilsson  if(args->maxrows && counter == (int)args->maxrows) return do_once_more();
31c9532000-12-12Martin Nilsson  while(should_filter(res[real_counter++], filter))
63e01a2000-12-11Martin Nilsson  if(real_counter>=sizeof(res)) return do_once_more();
31c9532000-12-12Martin Nilsson 
9a23172000-12-10Martin Nilsson  vars=res[real_counter-1];
31c9532000-12-12Martin Nilsson  vars["real-counter"] = real_counter;
9a23172000-12-10Martin Nilsson  vars->counter = counter+1; return 1; }
8e15042000-12-06Martin Nilsson  array do_return(RequestID id) { result = content;
31c9532000-12-12Martin Nilsson  id->misc->emit_rows = outer_rows; id->misc->emit_filter = outer_filter; id->misc->emit_args = outer_args;
9a23172000-12-10Martin Nilsson  if(args->filter && args->remainderinfo) { int rem;
31c9532000-12-12Martin Nilsson  if(vars["real-counter"] < sizeof(res)) for(int i=vars["real-counter"]; i<sizeof(res); i++) if(!should_filter(res[i], filter))
9a23172000-12-10Martin Nilsson  rem++; RXML.user_set_var(args->remainderinfo, rem); }
8e15042000-12-06Martin Nilsson  return 0; }
884b232000-02-05Martin Nilsson  } }
5b04da2000-05-28Martin Nilsson class TagEmitSources { inherit RXML.Tag; constant name="emit"; constant plugin_name="sources"; array(mapping(string:string)) get_dataset(mapping m, RequestID id) { return Array.map( indices(RXML.get_context()->tag_set->get_plugins("emit")), lambda(string source) { return (["source":source]); } ); } }
79ca872000-11-24Per Hedbor  class TagPathplugin { inherit RXML.Tag; constant name = "emit"; constant plugin_name = "path"; array get_dataset(mapping m, RequestID id) { string fp = ""; array res = ({});
1e770a2001-02-01Per Hedbor  string p = m->path || id->not_query;
79ca872000-11-24Per Hedbor  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..];
1e770a2001-02-01Per Hedbor  if( m["skip-end"] ) q = q[..sizeof(q)-((int)m["skip-end"]+1)];
79ca872000-11-24Per Hedbor  foreach( q, string elem ) { fp += "/" + elem; fp = replace( fp, "//", "/" ); res += ({ ([ "name":elem, "path":fp ]) }); } return res; } }
ced78d2000-09-18Martin Nilsson class TagEmitValues {
d74f382000-08-11Martin Nilsson  inherit RXML.Tag; constant name="emit";
95ea872000-09-16Martin Nilsson  constant plugin_name="values";
d74f382000-08-11Martin Nilsson  array(mapping(string:string)) get_dataset(mapping m, RequestID id) {
95ea872000-09-16Martin Nilsson  if(m["from-scope"]) { m->values=([]); RXML.Context context=RXML.get_context(); map(context->list_var(m["from-scope"]), lambda(string var){ m->values[var]=context->get_var(var, m["from-scope"]); return ""; }); }
e6bf912000-11-15Martin Nilsson 
4fac202000-11-06Per Hedbor  if( m->variable ) m->values = RXML.get_context()->user_get_var( m->variable );
e6bf912000-11-15Martin Nilsson 
4fac202000-11-06Per Hedbor  if(!m->values) return ({});
e6bf912000-11-15Martin Nilsson  if(stringp(m->values)) { if(m->advanced) { switch(m->advanced) {
2c358b2000-12-06Martin Nilsson  case "chars": m->split=""; break;
e6bf912000-11-15Martin Nilsson  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; } } m->values=m->values / (m->split || "\000"); }
95ea872000-09-16Martin Nilsson  if(mappingp(m->values)) return map( indices(m->values), lambda(mixed ind) { return (["index":ind,"value":m->values[ind]]); });
e6bf912000-11-15Martin Nilsson 
95ea872000-09-16Martin Nilsson  if(arrayp(m->values)) return map( m->values,
e6bf912000-11-15Martin Nilsson  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]); } );
95ea872000-09-16Martin Nilsson  RXML.run_error("Values variable has wrong type %t.\n", m->values);
d74f382000-08-11Martin Nilsson  } }
b2c49b2000-02-18Martin Nilsson class TagComment { inherit RXML.Tag; constant name = "comment";
d88d2b2000-08-30Martin Stjernholm  constant flags = RXML.FLAG_DONT_REPORT_ERRORS;
b2c49b2000-02-18Martin Nilsson  class Frame { inherit RXML.Frame; int do_iterate=-1; array do_enter() {
3fdcd42000-08-15Martin Stjernholm  if(args && args->preparse)
b2c49b2000-02-18Martin Nilsson  do_iterate=1;
3fdcd42000-08-15Martin Stjernholm  return 0;
b2c49b2000-02-18Martin Nilsson  }
3fdcd42000-08-15Martin Stjernholm  array do_return = ({});
b2c49b2000-02-18Martin Nilsson  }
74747a1999-04-22Per Hedbor }
1c1cb02000-08-05Martin Stjernholm class TagPIComment { inherit TagComment; constant flags = RXML.FLAG_PROC_INSTR; }
2127b42000-01-07Martin Stjernholm RXML.TagSet query_tag_set() {
f599312000-01-19Martin Stjernholm  // Note: By putting the tags in rxml_tag_set, they will always have // the highest priority. rxml_tag_set->add_tags (filter (rows (this_object(), glob ("Tag*", indices (this_object()))), functionp)());
69e4cd2000-03-09Martin Stjernholm  return Roxen.entities_tag_set;
2127b42000-01-07Martin Stjernholm }
36aaa12000-01-23Martin Nilsson // ---------------------------- If callers -------------------------------
74747a1999-04-22Per Hedbor class UserIf {
1dd3652000-02-14Martin Nilsson  inherit RXML.Tag; constant name = "if"; string plugin_name;
74747a1999-04-22Per Hedbor  string rxml_code;
36aaa12000-01-23Martin Nilsson 
1dd3652000-02-14Martin Nilsson  void create(string pname, string code) { plugin_name = pname; rxml_code = code;
50c7e41999-11-23Per Hedbor  }
1dd3652000-02-14Martin Nilsson  int eval(string ind, RequestID id) {
e3d42b1999-08-16Martin Nilsson  int otruth, res; string tmp;
74747a1999-04-22Per Hedbor 
1dd3652000-02-14Martin Nilsson  TRACE_ENTER("user defined if argument "+plugin_name, UserIf);
e3d42b1999-08-16Martin Nilsson  otruth = LAST_IF_TRUE; LAST_IF_TRUE = -2;
1dd3652000-02-14Martin Nilsson  tmp = parse_rxml(rxml_code, id);
74747a1999-04-22Per Hedbor  res = LAST_IF_TRUE;
e3d42b1999-08-16Martin Nilsson  LAST_IF_TRUE = otruth;
74747a1999-04-22Per Hedbor  TRACE_LEAVE("");
1dd3652000-02-14Martin Nilsson  if(ind==plugin_name && res!=-2)
e3d42b1999-08-16Martin Nilsson  return res; return (ind==tmp); }
74747a1999-04-22Per Hedbor } class IfIs {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if";
50c7e41999-11-23Per Hedbor 
e693092000-02-06Martin Nilsson  constant cache = 0;
571f712001-01-30Martin Nilsson  constant case_sensitive = 0;
e693092000-02-06Martin Nilsson  function source;
74747a1999-04-22Per Hedbor 
571f712001-01-30Martin Nilsson  int eval( string value, RequestID id )
74747a1999-04-22Per Hedbor  {
571f712001-01-30Martin Nilsson  if(cache != -1) CACHE(cache);
ff52db1999-08-07Martin Nilsson  array arr=value/" ";
c2004b2000-04-28Martin Nilsson  string|int|float var=source(id, arr[0]); if( !var && zero_type( var ) ) return 0;
5041522000-03-28Martin Nilsson  if(sizeof(arr)<2) return !!var;
571f712001-01-30Martin Nilsson  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..]*" "); }
5041522000-03-28Martin Nilsson 
ff52db1999-08-07Martin Nilsson  if(arr[1]=="==" || arr[1]=="=" || arr[1]=="is") return ((is==var)||glob(is,var)||
1f47d92000-01-30Per Hedbor  sizeof(filter( is/",", glob, var )));
d2d2f12000-03-31Martin Nilsson  if(arr[1]=="!=") return is!=var;
5041522000-03-28Martin Nilsson  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); }
e693092000-02-06Martin Nilsson  value=source(id, value);
e3d42b1999-08-16Martin Nilsson  return !!value;
74747a1999-04-22Per Hedbor  } } class IfMatch {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if";
50c7e41999-11-23Per Hedbor 
e693092000-02-06Martin Nilsson  constant cache = 0; function source;
50c7e41999-11-23Per Hedbor 
1dd3652000-02-14Martin Nilsson  int eval( string is, RequestID id ) {
e693092000-02-06Martin Nilsson  array|string value=source(id);
453f2b2000-08-16Per Hedbor  if(!this_object()->cache) NOCACHE();
74747a1999-04-22Per Hedbor  if(!value) return 0; if(arrayp(value)) value=value*" "; value = lower_case( value ); is = lower_case( "*"+is+"*" );
1f47d92000-01-30Per Hedbor  return (glob(is,value)||sizeof(filter( is/",", glob, value )));
74747a1999-04-22Per Hedbor  } }
1537962000-02-06Martin Nilsson class TagIfDate {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if"; constant plugin_name = "date";
1dd3652000-02-14Martin Nilsson  int eval(string date, RequestID id, mapping m) {
e693092000-02-06Martin Nilsson  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; } }
74747a1999-04-22Per Hedbor 
1537962000-02-06Martin Nilsson class TagIfTime {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if"; constant plugin_name = "time";
1dd3652000-02-14Martin Nilsson  int eval(string ti, RequestID id, mapping m) {
e693092000-02-06Martin Nilsson  CACHE(time(1)%60); // minute resolution... int tok, a, b, d; mapping c;
add34e2000-08-17Per Hedbor  c=localtime(time(1));
e693092000-02-06Martin Nilsson  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)
74747a1999-04-22Per Hedbor  return 1;
e693092000-02-06Martin Nilsson  if(m->before && a>b)
74747a1999-04-22Per Hedbor  return 1;
e693092000-02-06Martin Nilsson  else if(m->after && a<b)
74747a1999-04-22Per Hedbor  return 1; } }
1537962000-02-06Martin Nilsson class TagIfUser {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if"; constant plugin_name = "user";
1dd3652000-02-14Martin Nilsson  int eval(string u, RequestID id, mapping m) {
e693092000-02-06Martin Nilsson  if(!id->auth) return 0; NOCACHE(); if(u == "any") if(m->file) return match_user(id->auth,id->auth[1],m->file,!!m->wwwfile, id); else return id->auth[0]; else if(m->file) // FIXME: wwwfile attribute doesn't work. return match_user(id->auth,u,m->file,!!m->wwwfile,id); else return id->auth[0] && (search(u/",", id->auth[1]) != -1); } 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
a39b5a2000-03-19Martin Nilsson  s=id->conf->try_get_file(Roxen.fix_relative(f,id), id);
e693092000-02-06Martin Nilsson  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]); } }
74747a1999-04-22Per Hedbor }
1537962000-02-06Martin Nilsson class TagIfGroup {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if"; constant plugin_name = "group";
1dd3652000-02-14Martin Nilsson  int eval(string u, RequestID id, mapping m) {
e693092000-02-06Martin Nilsson  if( !id->auth ) return 0; NOCACHE(); return ((m->groupfile && sizeof(m->groupfile)) && group_member(id->auth, m->group, m->groupfile, id)); } 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)
a39b5a2000-03-19Martin Nilsson  s = id->conf->try_get_file( Roxen.fix_relative( groupfile, id), id );
e693092000-02-06Martin Nilsson  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;
74747a1999-04-22Per Hedbor  } }
1537962000-02-06Martin Nilsson class TagIfExists {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if"; constant plugin_name = "exists";
1dd3652000-02-14Martin Nilsson  int eval(string u, RequestID id) {
e693092000-02-06Martin Nilsson  CACHE(5);
a39b5a2000-03-19Martin Nilsson  return id->conf->is_file(Roxen.fix_relative(u, id), id);
e693092000-02-06Martin Nilsson  }
74747a1999-04-22Per Hedbor }
b054242000-09-19Martin Nilsson 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) {
571f712001-01-30Martin Nilsson  if (!sizeof(u)) return 0;
b054242000-09-19Martin Nilsson  return sizeof(glob(u+"#*", indices(id->conf->enabled_modules))); } }
1537962000-02-06Martin Nilsson class TagIfTrue {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if"; constant plugin_name = "true";
1dd3652000-02-14Martin Nilsson  int eval(string u, RequestID id) {
e693092000-02-06Martin Nilsson  return LAST_IF_TRUE; }
74747a1999-04-22Per Hedbor }
1537962000-02-06Martin Nilsson class TagIfFalse {
e693092000-02-06Martin Nilsson  inherit RXML.Tag; constant name = "if"; constant plugin_name = "false";
74747a1999-04-22Per Hedbor 
1dd3652000-02-14Martin Nilsson  int eval(string u, RequestID id) {
e693092000-02-06Martin Nilsson  return !LAST_IF_TRUE; } }
74747a1999-04-22Per Hedbor 
1537962000-02-06Martin Nilsson class TagIfAccept {
e693092000-02-06Martin Nilsson  inherit IfMatch; constant plugin_name = "accept"; array source(RequestID id) { return id->misc->accept; } }
74747a1999-04-22Per Hedbor 
1537962000-02-06Martin Nilsson class TagIfConfig {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "config";
c2004b2000-04-28Martin Nilsson  int source(RequestID id, string s) {
e693092000-02-06Martin Nilsson  return id->config[s]; } }
74747a1999-04-22Per Hedbor 
1537962000-02-06Martin Nilsson class TagIfCookie {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "cookie"; string source(RequestID id, string s) { return id->cookies[s]; } }
74747a1999-04-22Per Hedbor 
1537962000-02-06Martin Nilsson class TagIfClient {
e693092000-02-06Martin Nilsson  inherit IfMatch; constant plugin_name = "client"; array source(RequestID id) { return id->client; }
74747a1999-04-22Per Hedbor }
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
f518472000-02-10Martin Nilsson class TagIfName { inherit TagIfClient; constant plugin_name = "name"; } #endif
1537962000-02-06Martin Nilsson class TagIfDefined {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "defined";
c2004b2000-04-28Martin Nilsson  string|int|float source(RequestID id, string s) { mixed val; if(!id->misc->defines || !(val=id->misc->defines[s])) return 0; if(stringp(val) || intp(val) || floatp(val)) return val; return 1;
e693092000-02-06Martin Nilsson  }
74747a1999-04-22Per Hedbor }
1537962000-02-06Martin Nilsson class TagIfDomain {
e693092000-02-06Martin Nilsson  inherit IfMatch; constant plugin_name = "domain"; string source(RequestID id) { return id->host; }
74747a1999-04-22Per Hedbor }
1537962000-02-06Martin Nilsson class TagIfIP {
e693092000-02-06Martin Nilsson  inherit IfMatch; constant plugin_name = "ip"; string source(RequestID id) { return id->remoteaddr; } }
51d4d22001-01-04Martin Nilsson #if ROXEN_COMPAT <= 1.3
f518472000-02-10Martin Nilsson class TagIfHost { inherit TagIfIP; constant plugin_name = "host"; } #endif
e693092000-02-06Martin Nilsson class TagIfLanguage { inherit IfMatch; constant plugin_name = "language"; array source(RequestID id) {
8798f42000-07-31Martin Nilsson  return id->misc->pref_languages->get_languages();
e693092000-02-06Martin Nilsson  } }
1537962000-02-06Martin Nilsson class TagIfMatch {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "match"; string source(RequestID id, string s) { return s; } }
571f712001-01-30Martin Nilsson class TagIfMaTcH { inherit TagIfMatch; constant plugin_name = "Match"; constant case_sensitive = 1; }
1537962000-02-06Martin Nilsson class TagIfPragma {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "pragma";
9ceb8b2000-09-25Per Hedbor  int source(RequestID id, string s) {
e693092000-02-06Martin Nilsson  return id->pragma[s]; } }
1537962000-02-06Martin Nilsson class TagIfPrestate {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "prestate";
571f712001-01-30Martin Nilsson  constant cache = -1;
c2004b2000-04-28Martin Nilsson  int source(RequestID id, string s) {
e693092000-02-06Martin Nilsson  return id->prestate[s]; } }
1537962000-02-06Martin Nilsson class TagIfReferrer {
e693092000-02-06Martin Nilsson  inherit IfMatch; constant plugin_name = "referrer"; array source(RequestID id) { return id->referer; } }
1537962000-02-06Martin Nilsson class TagIfSupports {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "supports";
c2004b2000-04-28Martin Nilsson  int source(RequestID id, string s) {
e693092000-02-06Martin Nilsson  return id->supports[s]; } }
1537962000-02-06Martin Nilsson class TagIfVariable {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "variable"; constant cache = 1; string source(RequestID id, string s) {
5041522000-03-28Martin Nilsson  mixed var=RXML.user_get_var(s);
e6d1392000-04-19Martin Nilsson  if(!var) return var;
a183022000-08-14Martin Stjernholm  return RXML.t_text->encode (var);
e693092000-02-06Martin Nilsson  } }
571f712001-01-30Martin Nilsson class TagIfVaRiAbLe { inherit TagIfVariable; constant plugin_name = "Variable"; constant case_sensitive = 1; }
024ca12000-08-07Martin Nilsson class TagIfSizeof { inherit IfIs; constant plugin_name = "sizeof";
571f712001-01-30Martin Nilsson  constant cache = -1;
024ca12000-08-07Martin Nilsson  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); } }
1537962000-02-06Martin Nilsson class TagIfClientvar {
e693092000-02-06Martin Nilsson  inherit IfIs; constant plugin_name = "clientvar"; string source(RequestID id, string s) { return id->client_var[s]; }
b796b51998-11-18Per Hedbor }
cce7142000-01-26Martin Nilsson  #endif
e693092000-02-06Martin Nilsson // ------------------------ Documentation -----------------------------
cce7142000-01-26Martin Nilsson mapping tagdocumentation() { Stdio.File file=Stdio.File(); if(!file->open(__FILE__,"r")) return 0;
e3aa002000-02-09Martin Nilsson  mapping doc=compile_string("#define manual\n"+file->read())->tagdoc; file->close(); if(!file->open("etc/supports","r")) return doc; parse_html(file->read(), ([]), (["flags":format_support, "vars":format_support]), doc); return doc; }
e6bf912000-11-15Martin Nilsson static int format_support(string t, mapping m, string c, mapping doc) {
e3aa002000-02-09Martin Nilsson  string key=(["flags":"if#supports","vars":"if#clientvar"])[t];
a39b5a2000-03-19Martin Nilsson  c=Roxen.html_encode_string(c)-"#! ";
e3aa002000-02-09Martin Nilsson  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;
cce7142000-01-26Martin Nilsson } #ifdef manual
9ac3182000-01-27Kenneth Johansson constant tagdoc=([
6c92942000-04-15Per Hedbor "&roxen;":#"<desc scope><short>This scope contains information specific to this Roxen WebServer.</short></desc>",
1dd64a2000-09-19Mattias Wingstedt "&roxen.domain;":#"<desc ent>The domain name of this site.</desc>",
3f40352000-03-01Martin Nilsson "&roxen.hits;":#"<desc ent>The number of hits, i.e. requests the webserver has accumulated since it was last started.</desc>", "&roxen.hits-per-minute;":"<desc ent>The number of hits per minute, in average.</desc>", "&roxen.pike-version;":"<desc ent>The version of Pike the webserver is using.</desc>", "&roxen.sent;":"<desc ent>The total amount of data the webserver has sent. </desc>", "&roxen.sent-kbit-per-second;":"<desc ent>The average amount of data the webserver has sent, in Kibibits.</desc>", "&roxen.sent-mb;":"<desc ent>The total amount of data the webserver has sent, in Mebibits.</desc>", "&roxen.sent-per-minute;":"<desc ent></desc>", "&roxen.server;":"<desc ent>The URL of the webserver.</desc>",
43c8c32000-03-02Martin Nilsson "&roxen.ssl-strength;":"<desc ent>How many bits encryption strength are the SSL capable of</desc>",
3f40352000-03-01Martin Nilsson "&roxen.time;":"<desc ent>The current posix time.</desc>", "&roxen.uptime;":"<desc ent>The total uptime of the webserver, in seconds.</desc>", "&roxen.uptime-days;":"<desc ent>The total uptime of the webserver, in days.</desc>", "&roxen.uptime-hours;":"<desc ent>The total uptime of the webserver, in hours.</desc>", "&roxen.uptime-minutes;":"<desc ent>The total uptime of the webserver, in minutes.</desc>", "&roxen.version;":"<desc ent>Which version of Roxen WebServer that is running.</desc>",
6c92942000-04-15Per Hedbor "&client;":#"<desc scope><short>
3f40352000-03-01Martin Nilsson  This scope contains information specific to the client/browser that
6c92942000-04-15Per Hedbor  is accessing the page.</short>
e59a5a2000-03-01Kenneth Johansson </desc>",
6c92942000-04-15Per Hedbor "&page;":"<desc scope><short>This scope contains information specific to this page.</short></desc>",
6468192000-09-21Kenneth Johansson  "&form;":#"<desc scope><short 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. </desc>", "&cookie;":#"<desc scope><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.</short> </desc>", "&var;":#"<desc scope><short> This scope is empty when the page parsing begins.</short> There are no predefined entities for this scope. </desc>",
e59a5a2000-03-01Kenneth Johansson 
6c92942000-04-15Per Hedbor "case":#"<desc cont><short> Alters the case of the contents.</short>
9ac3182000-01-27Kenneth Johansson </desc>
5da7c12000-07-14Kenneth Johansson <attr name='case' value='upper|lower|capitalize' required>
30b42a2000-02-20Martin Nilsson  Changes all characters to upper or lower case letters, or capitalizes the first letter in the content.
5da7c12000-07-14Kenneth Johansson  <ex><case upper=''>upper</case></ex> <ex><case lower=''>lower</case></ex> <ex><case capitalize=''>captalize</case></ex>
9ac3182000-01-27Kenneth Johansson </attr>",
f518472000-02-10Martin Nilsson 
6c92942000-04-15Per Hedbor "cond":({ #"<desc cont><short hide>This tag makes a boolean test on a specified list of cases.</short> This tag is almost eqvivalent to the <tag>if</tag>/<tag>else</tag>
e5bab52000-04-06Kenneth Johansson  tag combination. The main diffirence is that the <tag>default</tag> tag may be put whereever you want it within the <tag>cond</tag> tag. This will of course affect the order the content is parsed. The <tag>case</tag> tag is required.</desc>", (["case":#"<desc cont> This tag takes the argument that is to be tested and if it's true, it's content is executed before exiting the <tag>cond</tag>. If the argument is false the content is skipped and the next <tag>case</tag> tag is parsed.</desc>
112cfd2000-09-15Kenneth Johansson <ex type='vert'>
5da7c12000-07-14Kenneth Johansson <set variable='var.foo' value='17'/>
e5bab52000-04-06Kenneth Johansson <cond>
3f62e22000-09-20Kenneth Johansson  <case true=''><ent>var.foo</ent><set variable='var.foo' expr='&var.foo;+1'/></case> <default><ent>var.foo</ent><set variable='var.foo' expr='&var.foo;+2'/></default>
e5bab52000-04-06Kenneth Johansson </cond>
82d4bd2000-08-07Kenneth Johansson <ent>var.foo</ent>
e5bab52000-04-06Kenneth Johansson </ex>", "default":#"<desc cont> The <tag>default</tag> tag is eqvivalent to the <tag>else</tag> tag
6c92942000-04-15Per Hedbor  in an <tag>if</tag> statement. The difference between the two is that
e5bab52000-04-06Kenneth Johansson  the <tag>default</tag> may be put anywhere in the <tag>cond</tag> statement. This affects the parseorder of the statement. If the <tag>default</tag> tag is put first in the statement it will allways be executed, then the next <tag>case</tag> tag will be executed and perhaps add to the result the <tag>default</tag> performed.</desc>
112cfd2000-09-15Kenneth Johansson <ex type='vert'>
e5bab52000-04-06Kenneth Johansson <set variable=\"var.foo\" value=\"17\"/> <cond>
3f62e22000-09-20Kenneth Johansson  <default><ent>var.foo</ent><set variable=\"var.foo\" expr=\"&var.foo;+2\"/></default> <case true=''><ent>var.foo</ent><set variable=\"var.foo\" expr=\"&var.foo;+1\"/></case>
e5bab52000-04-06Kenneth Johansson </cond>
82d4bd2000-08-07Kenneth Johansson <ent>var.foo</ent>
e5bab52000-04-06Kenneth Johansson </ex> <br/>
112cfd2000-09-15Kenneth Johansson <ex type='vert'>
e5bab52000-04-06Kenneth Johansson <set variable=\"var.foo\" value=\"17\"/> <cond>
3f62e22000-09-20Kenneth Johansson  <case false=''><ent>var.foo</ent><set variable=\"var.foo\" expr=\"&var.foo;+1\"/></case> <default><ent>var.foo</ent><set variable=\"var.foo\" expr=\"&var.foo;+2\"/></default>
e5bab52000-04-06Kenneth Johansson </cond>
82d4bd2000-08-07Kenneth Johansson <ent>var.foo</ent>
e5bab52000-04-06Kenneth Johansson </ex>" ]) }),
9ac3182000-01-27Kenneth Johansson 
6c92942000-04-15Per Hedbor "comment":#"<desc cont><short>
1c1cb02000-08-05Martin Stjernholm  The enclosed text will be removed from the document.</short> The difference from a normal SGML (HTML/XML) comment is that the text is removed from the document, and can not be seen even with <i>view source</i> in the browser. <p>Note that since this is a normal tag, it requires that the content is properly formatted. Therefore it's ofter better to use the &lt;?comment&nbsp;...&nbsp;?&gt; processing instruction tag to comment out arbitrary text (which doesn't contain '?&gt;').</p> <p>Just like any normal tag, the <tag>comment</tag> tag nests inside other <tag>comment</tag> tags. E.g:</p> <ex> <comment> a <comment> b </comment> c </comment> </ex> <p>Here 'c' is not output since the comment starter before 'a' matches the ender after 'c' and not the one before it.</p> </desc> <attr name=preparse> Parse and execute any RXML inside the comment tag. This is useful to do stuff without producing any output in the response. </attr>",
9ac3182000-01-27Kenneth Johansson 
6e39682000-09-20Kenneth Johansson 
e1f2102000-09-20Kenneth Johansson "<?comment":#"<desc pi><short>
6e39682000-09-20Kenneth Johansson  Processing instruction tag for comments.</short> This tag is similar to the RXML <ref type='tag'><tag>comment</tag> tag but should be used when commenting arbitrary text that doesn't contain '?&gt;'. </desc>",
6c92942000-04-15Per Hedbor "define":({ #"<desc cont><short> Defines variables, tags, containers and if-callers.</short> One, and only one,
9ac3182000-01-27Kenneth Johansson  attribute must be set. </desc> <attr name=variable value=name> Sets the value of the variable to the contents of the container. </attr> <attr name=tag value=name> Defines a tag that outputs the contents of the container. </attr> <attr name=container value=name> Defines a container that outputs the contents of the container. </attr> <attr name=if value=name> Defines an if-caller that compares something with the contents of the container. </attr>
0d87d72000-01-30Martin Nilsson  <attr name=trimwhites>
5d4c852000-02-20Martin Nilsson  Trim all white space characters from the begining and the end of the contents.
0d87d72000-01-30Martin Nilsson </attr>
30b42a2000-02-20Martin Nilsson The values of the attributes given to the defined tag are available in the scope created within the define tag.
9ac3182000-01-27Kenneth Johansson 
82d4bd2000-08-07Kenneth Johansson <ex><define tag=\"hi\">Hello <ent>_.name</ent>!</define>
30b42a2000-02-20Martin Nilsson <hi name=\"Martin\"/></ex>", (["attrib":#"<desc cont> When defining a tag or a container the container <tag>attrib</tag>
9ac3182000-01-27Kenneth Johansson  can be used to define default values of the attributes that the
30b42a2000-02-20Martin Nilsson  tag/container can have.</desc> <attr name=name value=name> The name of the attribute which default value is to be set. </attr>",
82d4bd2000-08-07Kenneth Johansson "&_.args;":#"<desc ent> The full list of the attributes, and their arguments, given to the tag. </desc>", "&_.rest-args;":#"<desc ent> A list of the attributes, and their arguments, given to the tag, excluding attributes with default values defined. </desc>", "&_.contents;":#"<desc ent> The containers contents. </desc>", "contents":#"<desc tag> As the contents entity, but unquoted. </desc>"
30b42a2000-02-20Martin Nilsson  ]) }),
9ac3182000-01-27Kenneth Johansson 
97f6622000-04-15Martin Nilsson "else":#"<desc cont><short hide> Show the contents if the previous <if> tag didn't, or if there was a <false> tag above.</short>Show the contents if the previous <tag><ref type='tag'>if</ref></tag> tag didn't, or if there was a <tag><ref type='tag'>false</ref></tag> tag above. The result is undefined if there has been no <tag><ref type='tag'>if</ref></tag>, <true> or <tag><ref type='tag'>false</ref></tag> tag above. </desc>", "elseif":#"<desc cont><short hide> Same as the <if> tag, but it will only evaluate if the previous <if> tag returned false.</short>Same as the <tag><ref type='tag'>if</ref></tag>, but it will only evaluate if the previous <tag><ref type='tag'>if</ref></tag> tag returned false. </desc>", "false":#"<desc tag><short hide> Internal tag used to set the return value of <if> tags. </short>Internal tag used to set the return value of <tag><ref type='tag'>if</ref></tag> tags. It will ensure that the next <tag><ref type='tag'>else</ref></tag> tag will show its contents. It can be useful if you are writing your own <tag><ref type='tag'>if</ref></tag> lookalike tag. </desc>",
9ac3182000-01-27Kenneth Johansson 
6c92942000-04-15Per Hedbor "help":#"<desc tag><short>
036d622000-05-03Kenneth Johansson  Gives help texts for tags.</short> If given no arguments, it will list all available tags. By inserting <tag>help/</tag> in a page, a full index of the tags available in that particular Roxen WebServer will be presented. If a particular tag is missing from that index, it is not available at that moment. All tags are available through modules, hence that particular tags' module hasn't been added to the Roxen WebServer. Ask an administrator to add the module.
9ac3182000-01-27Kenneth Johansson </desc> <attr name=for value=tag> Gives the help text for that tag.
036d622000-05-03Kenneth Johansson <ex type='vert'><help for='roxen'/></ex>
f518472000-02-10Martin Nilsson </attr>",
9ac3182000-01-27Kenneth Johansson 
97f6622000-04-15Martin Nilsson "if":#"<desc cont><short hide>
1d0f312000-07-26Kenneth Johansson  <if> is used to conditionally show its contents.</short><tag><ref
5da7c12000-07-14Kenneth Johansson  type='tag'>If</ref></tag> is used to conditionally show its contents.
97f6622000-04-15Martin Nilsson  <tag><ref type='tag'>else</ref></tag>, <tag><ref type='tag'>elif</ref></tag> or <tag><ref type='tag'>elseif</ref></tag> can be used to suggest alternative
5da7c12000-07-14Kenneth Johansson  content. <p>It is possible to use glob patterns in almost all attributes, where * means match zero or more characters while ? matches one character. * Thus t*f?? will match trainfoo as well as * tfoo but not
1d0f312000-07-26Kenneth Johansson  trainfork or tfo. It is not possible to use regexp's together
5da7c12000-07-14Kenneth Johansson  with any of the if-plugins.</p>
33ba3a2000-07-21Kenneth Johansson  <p>The <ref type='tag'>if</ref> tag itself is useless without its plugins. Its main functionality is to provide a framework for the plugins.</p> <p>It is mandatory to add a plugin as one attribute. The other attributes provided are and, or and not, used for combining plugins or logical negation.</p> <ex type='box'>
82d4bd2000-08-07Kenneth Johansson  <if variable='var.foo > 0' and='' match='var.bar is No'>
33ba3a2000-07-21Kenneth Johansson  ... </if> </ex> <ex type='box'>
1d0f312000-07-26Kenneth Johansson  <if variable='var.foo > 0' not=''>
82d4bd2000-08-07Kenneth Johansson  <ent>var.foo</ent> is lesser than 0
33ba3a2000-07-21Kenneth Johansson  </if> <else>
82d4bd2000-08-07Kenneth Johansson  <ent>var.foo</ent> is greater than 0
33ba3a2000-07-21Kenneth Johansson  </else> </ex> <p>Operators valid in attribute expressions are: '=', '==', 'is', '!=', '&lt;' and '&gt;'.</p> <p>The If plugins are sorted according to their function into five categories: Eval, Match, State, Utils and SiteBuilder.</p> <p>The Eval category is the one corresponding to the regular tests made in programming languages, and perhaps the most used. They evaluate expressions containing variables, entities, strings etc and are a sort of multi-use plugins. All If-tag operators and global patterns are allowed.</p> <ex> <set variable='var.x' value='6'/> <if variable='var.x > 5'>More than one hand</if> </ex> <p>The Match category contains plugins that match contents of something, e.g. an IP package header, with arguments given to the plugin as a string or a list of strings.</p> <ex>
82d4bd2000-08-07Kenneth Johansson  Your domain <if ip='130.236.*'> is </if>
33ba3a2000-07-21Kenneth Johansson  <else> isn't </else> liu.se. </ex> <p>State plugins check which of the possible states something is in, e.g. if a flag is set or not, if something is supported or not, if something is defined or not etc.</p> <ex> Your browser <if supports='javascript'>
82d4bd2000-08-07Kenneth Johansson  supports Javascript version <ent>client.javascript</ent>
33ba3a2000-07-21Kenneth Johansson  </if> <else>doesn't support Javascript</else>. </ex> <p>Utils are additonal plugins specialized for certain tests, e.g. date and time tests.</p> <ex>
cedad02000-07-26Kenneth Johansson  <if time='1700' after=''>
33ba3a2000-07-21Kenneth Johansson  Are you still at work? </if>
1d0f312000-07-26Kenneth Johansson  <elseif time='0900' before=''>
33ba3a2000-07-21Kenneth Johansson  Wow, you work early! </elseif> <else> Somewhere between 9 to 5. </else </ex> <p>SiteBuilder plugins requires a Roxen Platform SiteBuilder installed to work. They are adding test capabilities to web pages contained in a SiteBuilder administrated site.</p>
5da7c12000-07-14Kenneth Johansson </desc>
9ac3182000-01-27Kenneth Johansson  <attr name=not>
1d0f312000-07-26Kenneth Johansson  Inverts the result (true-&gt;false, false-&gt;true).
9ac3182000-01-27Kenneth Johansson </attr>
1d0f312000-07-26Kenneth Johansson 
9ac3182000-01-27Kenneth Johansson <attr name=or> If any criterion is met the result is true. </attr> <attr name=and> If all criterions are met the result is true. And is default.
5da7c12000-07-14Kenneth Johansson </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#true":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  This will always be true if the truth value is set to be true.</short> Equivalent with <tag><ref type=cont>then</ref></tag>.
cedad02000-07-26Kenneth Johansson  True is a <i>State</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc>
33ba3a2000-07-21Kenneth Johansson <attr name='true' required>
cedad02000-07-26Kenneth Johansson  Show contents if truth value is false.
5da7c12000-07-14Kenneth Johansson </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#false":#"<desc plugin><short>
cedad02000-07-26Kenneth Johansson  This will always be true if the truth value is set to be false.</short> Equivalent with <tag><ref type='tag'>else</ref></tag>. False is a <i>State</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc>
33ba3a2000-07-21Kenneth Johansson <attr name='false' required>
cedad02000-07-26Kenneth Johansson  Show contents if truth value is true.
5da7c12000-07-14Kenneth Johansson </attr>",
9ac3182000-01-27Kenneth Johansson 
b054242000-09-19Martin Nilsson "if#module":#"<desc plugin><short>Enables true if the selected module is enabled in the current server.</short></desc> <attr name='module' value='name'> The \"real\" name of the module to look for, i.e. its filename without extension. </attr>",
5da7c12000-07-14Kenneth Johansson "if#accept":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Returns true if the browser accepts certain content types as specified
5da7c12000-07-14Kenneth Johansson  by it's Accept-header, for example image/jpeg or text/html.</short> If
9ac3182000-01-27Kenneth Johansson  browser states that it accepts */* that is not taken in to account as
33ba3a2000-07-21Kenneth Johansson  this is always untrue. Accept is a <i>Match</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='accept' value='type1[,type2,...]' required> </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#config":#"<desc plugin><short>
9ac3182000-01-27Kenneth Johansson  Has the config been set by use of the <tag><ref
33ba3a2000-07-21Kenneth Johansson  type='tag'>aconf</ref></tag> tag?</short> Config is a <i>State</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='config' value='name' required> </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#cookie":#"<desc plugin><short>
9ac3182000-01-27Kenneth Johansson  Does the cookie exist and if a value is given, does it contain that
33ba3a2000-07-21Kenneth Johansson  value?</short> Cookie is an <i>Eval</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='cookie' value='name[ is value]' required> </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#client":#"<desc plugin><short> Compares the user agent string with a pattern.</short> Client and name is an
33ba3a2000-07-21Kenneth Johansson  <i>Match</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='client' value='' required> </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#date":#"<desc plugin><short> Is the date yyyymmdd?</short> The attributes before, after and inclusive
33ba3a2000-07-21Kenneth Johansson  modifies the behavior. Date is a <i>Utils</i> plugin.
9ac3182000-01-27Kenneth Johansson </desc>
5da7c12000-07-14Kenneth Johansson <attr name='date' value='yyyymmdd' required>
33ba3a2000-07-21Kenneth Johansson  Choose what date to test.
5da7c12000-07-14Kenneth Johansson </attr>
9ac3182000-01-27Kenneth Johansson  <attr name=after>
33ba3a2000-07-21Kenneth Johansson  The date after todays date.
9ac3182000-01-27Kenneth Johansson </attr> <attr name=before>
33ba3a2000-07-21Kenneth Johansson  The date before todays date.
9ac3182000-01-27Kenneth Johansson </attr> <attr name=inclusive>
33ba3a2000-07-21Kenneth Johansson  Adds todays date to after and before. <ex> <if date='19991231' before='' inclusive=''> - 19991231 </if> <else> 20000101 - </else> </ex>
9ac3182000-01-27Kenneth Johansson </attr>",
33ba3a2000-07-21Kenneth Johansson "if#defined":#"<desc plugin><short hide> Tests if a certain RXML define is defined by use of the <define> tag. </short> Tests if a certain RXML define is defined by use of the <tag>define</tag> tag.Defined is a <i>State</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='defined' value='define' required>
33ba3a2000-07-21Kenneth Johansson  Choose what define to test. </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#domain":#"<desc plugin><short> Does the user's computer's DNS name match any of the patterns?</short> Note
33ba3a2000-07-21Kenneth Johansson  that domain names are resolved asynchronously, and that the first time
9ac3182000-01-27Kenneth Johansson  someone accesses a page, the domain name will probably not have been
33ba3a2000-07-21Kenneth Johansson  resolved. Domain is a <i>Match</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='domain' value='pattern1[,pattern2,...]' required>
33ba3a2000-07-21Kenneth Johansson  Choose what pattern to test.
5da7c12000-07-14Kenneth Johansson </attr> ",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#exists":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Returns true if the file path exists.</short> If path does not begin with /, it is assumed to be a URL relative to the directory containing the page with the <tag><ref
cedad02000-07-26Kenneth Johansson  type='tag'>if</ref></tag>-statement. Exists is a <i>Utils</i>
33ba3a2000-07-21Kenneth Johansson  plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='exists' value='path' required>
33ba3a2000-07-21Kenneth Johansson  Choose what path to test.
cedad02000-07-26Kenneth Johansson </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#group":#"<desc plugin><short>
9ac3182000-01-27Kenneth Johansson  Checks if the current user is a member of the group according
cedad02000-07-26Kenneth Johansson  the groupfile.</short> Group is a <i>Utils</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc>
33ba3a2000-07-21Kenneth Johansson <attr name='group' value='name' required> Choose what group to test. </attr> <attr name='groupfile' value='path' required> Specify where the groupfile is located.
cedad02000-07-26Kenneth Johansson </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#ip":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson  Does the users computers IP address match any of the
33ba3a2000-07-21Kenneth Johansson  patterns?</short> This plugin replaces the Host plugin of earlier RXML versions. Ip is a <i>Match</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='ip' value='pattern1[,pattern2,...]' required>
33ba3a2000-07-21Kenneth Johansson  Choose what IP-adress pattern to test.
5da7c12000-07-14Kenneth Johansson </attr> ",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#language":#"<desc plugin><short>
9ac3182000-01-27Kenneth Johansson  Does the client prefer one of the languages listed, as specified by the
33ba3a2000-07-21Kenneth Johansson  Accept-Language header?</short> Language is a <i>Match</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='language' value='language1[,language2,...]' required>
33ba3a2000-07-21Kenneth Johansson  Choose what language to test.
5da7c12000-07-14Kenneth Johansson </attr> ",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#match":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Evaluates patterns.</short> Match is an <i>Eval</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc>
33ba3a2000-07-21Kenneth Johansson <attr name='match' value='pattern' required> Choose what pattern to test.
5da7c12000-07-14Kenneth Johansson </attr> ",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#pragma":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Compares the HTTP header pragma with a string.</short> Pragma is a <i>State</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='pragma' value='string' required>
33ba3a2000-07-21Kenneth Johansson  Choose what pragma to test.
5da7c12000-07-14Kenneth Johansson <ex>
cedad02000-07-26Kenneth Johansson  <if pragma='no-cache'>The page has been reloaded!</if> <else>Reload this page!</else>
5da7c12000-07-14Kenneth Johansson </ex> </attr> ",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#prestate":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Are all of the specified prestate options present in the URL?</short> Prestate is a <i>State</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='prestate' value='option1[,option2,...]' required>
33ba3a2000-07-21Kenneth Johansson  Choose what prestate to test.
5da7c12000-07-14Kenneth Johansson </attr> ",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#referrer":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Does the referrer header match any of the patterns?</short> Referrer is a <i>Match</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='referrer' value='pattern1[,pattern2,...]' required>
33ba3a2000-07-21Kenneth Johansson  Choose what pattern to test.
5da7c12000-07-14Kenneth Johansson </attr> ",
9ac3182000-01-27Kenneth Johansson 
e3aa002000-02-09Martin Nilsson // The list of support flags is extracted from the supports database and // concatenated to this entry.
5da7c12000-07-14Kenneth Johansson "if#supports":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Does the browser support this feature?</short> Supports is a <i>State</i> plugin.
9ac3182000-01-27Kenneth Johansson </desc>
5da7c12000-07-14Kenneth Johansson <attr name=supports'' value='feature' required required>
33ba3a2000-07-21Kenneth Johansson  Choose what supports feature to test.
5da7c12000-07-14Kenneth Johansson </attr>
bd24792000-07-17Kenneth Johansson The following features are supported:",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#time":#"<desc plugin><short> Is the time hhmm?</short> The attributes before, after and inclusive modifies
33ba3a2000-07-21Kenneth Johansson  the behavior. Time is a <i>Utils</i> plugin.
f518472000-02-10Martin Nilsson </desc>
5da7c12000-07-14Kenneth Johansson <attr name='time' value='hhmm' required>
33ba3a2000-07-21Kenneth Johansson  Choose what time to test.
5da7c12000-07-14Kenneth Johansson </attr>
f518472000-02-10Martin Nilsson  <attr name=after>
33ba3a2000-07-21Kenneth Johansson  The time after present time.
f518472000-02-10Martin Nilsson </attr> <attr name=before>
33ba3a2000-07-21Kenneth Johansson  The time before present time.
f518472000-02-10Martin Nilsson </attr> <attr name=inclusive>
33ba3a2000-07-21Kenneth Johansson  Adds present time to after and before. <ex>
cedad02000-07-26Kenneth Johansson  <if time='1200' before='' inclusive=''>
33ba3a2000-07-21Kenneth Johansson  ante meridiem </if> <else> post meridiem </else> </ex>
f518472000-02-10Martin Nilsson </attr>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#user":#"<desc plugin><short>
cedad02000-07-26Kenneth Johansson  Has the user been authenticated as one of these users?</short> If any is given as argument, any authenticated user will do. User is a <i>Utils</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='user' value='name1[,name2,...]|any' required>
cedad02000-07-26Kenneth Johansson  Specify which users to test.
5da7c12000-07-14Kenneth Johansson </attr> ",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "if#variable":#"<desc plugin><short>
33ba3a2000-07-21Kenneth Johansson  Does the variable exist and, optionally, does it's content match the pattern?</short> Variable is an <i>Eval</i> plugin.
5da7c12000-07-14Kenneth Johansson </desc> <attr name='variable' value='name[ is pattern]' required>
33ba3a2000-07-21Kenneth Johansson  Choose variable to test. Valid operators are '=', '==', 'is', '!=', '&lt;' and '&gt;'.
5da7c12000-07-14Kenneth Johansson </attr> ",
e7fdb22000-02-06Martin Nilsson 
f518472000-02-10Martin Nilsson // The list of support flags is extracted from the supports database and // concatenated to this entry.
33ba3a2000-07-21Kenneth Johansson "if#clientvar":#"<desc plugin><short> Evaluates expressions with client specific values.</short> Clientvar is an <i>Eval</i> plugin. </desc> <attr name='clientvar' value='variable [is value]' required> Choose which variable to evaluate against. Valid operators are '=', '==', 'is', '!=', '&lt;' and '&gt;'.
5da7c12000-07-14Kenneth Johansson </attr>
bd24792000-07-17Kenneth Johansson Available variables are:",
9ac3182000-01-27Kenneth Johansson 
d74f382000-08-11Martin Nilsson "if#sizeof":#"<desc plugin><short>Compares the size of a variable with a number.</short> <ex> <set variable=\"var.x\" value=\"hello\"/> <set variable=\"var.y\" value=\"\"/> <if sizeof=\"var.x == 5\">Five</if> <if sizeof=\"var.y > 0\">Nonempty</if> </ex>
14022b2000-08-08Kenneth Johansson </desc>",
6c92942000-04-15Per Hedbor "nooutput":#"<desc cont><short> The contents will not be sent through to the page.</short> Side effects, for
9ac3182000-01-27Kenneth Johansson  example sending queries to databases, will take effect. </desc>",
f518472000-02-10Martin Nilsson 
6c92942000-04-15Per Hedbor "noparse":#"<desc cont><short> The contents of this container tag won't be RXML parsed.</short>
9ac3182000-01-27Kenneth Johansson </desc>",
f518472000-02-10Martin Nilsson 
6c92942000-04-15Per Hedbor "number":#"<desc tag><short> Prints a number as a word.</short>
9ac3182000-01-27Kenneth Johansson </desc>
a6400f2000-03-31Martin Nilsson <attr name=num value=number required>
9ac3182000-01-27Kenneth Johansson  Print this number.
036d622000-05-03Kenneth Johansson <ex type='vert'><number num='4711'/></ex>
9ac3182000-01-27Kenneth Johansson </attr>
1262232000-03-22Martin Nilsson <attr name=language value=langcodes> The language to use. <lang/>
5da7c12000-07-14Kenneth Johansson  <ex type='vert'>Mitt favoritnummer är <number num='11' language='sv'/>.</ex>
82d4bd2000-08-07Kenneth Johansson  <ex type='vert'>Il mio numero preferito <ent>egrave</ent><number num='15' language='it'/>.</ex>
9ac3182000-01-27Kenneth Johansson </attr>
8798f42000-07-31Martin Nilsson <attr name=type value=number|ordered|roman|memory default=number>
a6400f2000-03-31Martin Nilsson  Sets output format.
8798f42000-07-31Martin Nilsson  <ex type='vert'>It was his <number num='15' type='ordered'/> birthday yesterday.</ex> <ex type='vert'>Only <number num='274589226' type='memory'/> left on the Internet.</ex> <ex type='vert'>Spock Garfield <number num='17' type='roman'/> rests here.</ex>
9ac3182000-01-27Kenneth Johansson </attr>",
6c92942000-04-15Per Hedbor "strlen":#"<desc cont><short> Returns the length of the contents.</short>
9ac3182000-01-27Kenneth Johansson </desc>",
f518472000-02-10Martin Nilsson 
6c92942000-04-15Per Hedbor "then":#"<desc cont><short>
33ba3a2000-07-21Kenneth Johansson  Shows its content if the truth value is true.</short>
5da7c12000-07-14Kenneth Johansson  <ex>There is <strlen>foo bar gazonk</strlen> characters inside the tag.</ex>
9ac3182000-01-27Kenneth Johansson </desc>",
f518472000-02-10Martin Nilsson 
6c92942000-04-15Per Hedbor "trace":#"<desc cont><short>
9ac3182000-01-27Kenneth Johansson  Executes the contained RXML code and makes a trace report about how
6c92942000-04-15Per Hedbor  the contents are parsed by the RXML parser.</short>
9ac3182000-01-27Kenneth Johansson </desc>",
97f6622000-04-15Martin Nilsson "true":#"<desc tag><short hide> An internal tag used to set the return value of <if> tags. </short>An internal tag used to set the return value of <tag><ref type='tag'>if</ref></tag> tags. It will ensure that the next
7ff3292000-04-05Martin Nilsson  <tag><ref type='tag'>else</ref></tag> tag will not show its contents.
95f91d2000-06-19Henrik Grubbström (Grubba)  It can be useful if you are writing your own <tag><ref type='tag'>if</ref></tag> lookalike tag. </desc>",
9ac3182000-01-27Kenneth Johansson 
5da7c12000-07-14Kenneth Johansson "undefine":#"<desc tag><short> Removes a definition made by the define container.</short> One attribute is required.
9ac3182000-01-27Kenneth Johansson </desc> <attr name=variable value=name> Undefines this variable.
5da7c12000-07-14Kenneth Johansson  <ex> <define variable='var.hepp'>hopp</define>
82d4bd2000-08-07Kenneth Johansson  <ent>var.hepp</ent>
5da7c12000-07-14Kenneth Johansson  <undefine variable='var.hepp'/>
82d4bd2000-08-07Kenneth Johansson  <ent>var.hepp</ent>
5da7c12000-07-14Kenneth Johansson  </ex>
9ac3182000-01-27Kenneth Johansson </attr> <attr name=tag value=name> Undefines this tag. </attr> <attr name=container value=name> Undefines this container. </attr> <attr name=if value=name>
e7fdb22000-02-06Martin Nilsson  Undefines this if-plugin.
9ac3182000-01-27Kenneth Johansson </attr>",
6c92942000-04-15Per Hedbor "use":#"<desc cont><short>
43425c2000-12-30Martin Nilsson  Reads tag definitions, user defined if plugins and variables from a file or package and includes into the current page. Note that the file itself is not inserted into the page. This only affects the environment in which the page is parsed. The benefit is that the package file needs only be parsed once, and the compiled versions of the user defined tags can then be used, thus saving time. It is also a fairly good way of creating templates for your website. Just define your own tags for constructions that appears frequently and save both space and time. Since the tag definitions are cached in memory, make sure that the file is not dependent on anything dynamic, such as form variables or client settings, at the compile time. Also note that the use tag only lets you define variables in the form and var scope in advance. Variables with the same name will be overwritten when the use tag is parsed.
6c92942000-04-15Per Hedbor </short></desc>
9ac3182000-01-27Kenneth Johansson  <attr name=packageinfo>
43425c2000-12-30Martin Nilsson  Show a list of all available packages.
9ac3182000-01-27Kenneth Johansson </attr> <attr name=package value=name> Reads all tags, container tags and defines from the given package.
4e72c92000-09-06Martin Nilsson  Packages are files located in rxml_packages/ and local/rxml_packages/.
9ac3182000-01-27Kenneth Johansson </attr> <attr name=file value=path> Reads all tags and container tags and defines from the file. <p>This file will be fetched just as if someone had tried to fetch it with an HTTP request. This makes it possible to use Pike script results and other dynamic documents. Note, however, that the results of the parsing are heavily cached for performance reasons. If you do
b610e32000-12-30Martin Nilsson  not want this cache, use <tag><ref type='tag'>insert file='...' nocache='1'</ref></tag> instead.</p>
9ac3182000-01-27Kenneth Johansson </attr> <attr name=info> Show a list of all defined tags/containers and if arguments in the file
43425c2000-12-30Martin Nilsson </attr>",
f296ac2000-02-06Martin Nilsson 
5da7c12000-07-14Kenneth Johansson "eval":#"<desc cont><short> Postparses its content.</short> Useful when an entity contains RXML-code. <tag>eval</tag> is then placed around the entity to get its content parsed. </desc>",
f296ac2000-02-06Martin Nilsson 
79ca872000-11-24Per Hedbor "emit#path":({ #"<desc plugin><short> Prints paths.</short> This plugin traverses over all directories in the path from the root up to the current one. </desc>
1e770a2001-02-01Per Hedbor <attr name='path' value='string'> Use this path instead of the document path </attr>
79ca872000-11-24Per Hedbor <attr name='trim' value='string'> Removes all of the remaining path after and including the specified string. </attr> <attr name='skip' value='number'> Skips the 'number' of slashes ('/') specified, with beginning from the root.
1e770a2001-02-01Per Hedbor </attr> <attr name='skip-end' value='number'> Skips the 'number' of slashes ('/') specified, with beginning from the end.
79ca872000-11-24Per Hedbor </attr>", ([ "&_.name;":#"<desc ent> Returns the name of the most recently traversed directory. </desc>", "&_.path;":#"<desc ent> Returns the path to the most recently traversed directory. </desc>" ])
9f2da52000-12-15Martin Nilsson }),
79ca872000-11-24Per Hedbor 
82d4bd2000-08-07Kenneth Johansson "emit#sources":({ #"<desc plugin> Provides a list of all available emit sources. </desc>",
5b04da2000-05-28Martin Nilsson  ([ "&_.source;":"<desc ent>The name of the source.</desc>" ]) }),
d74f382000-08-11Martin Nilsson 
95ea872000-09-16Martin Nilsson "emit#values":({ #"<desc plugin>
d74f382000-08-11Martin Nilsson  Splits the string provided in the values attribute and outputs the parts in a loop. The
95ea872000-09-16Martin Nilsson  value in the values attribute may also be an array or mapping.
d74f382000-08-11Martin Nilsson </desc>
95ea872000-09-16Martin Nilsson <attr name=values value='string, mapping or array' required> An array or the string to be splitted into an array.
d74f382000-08-11Martin Nilsson </attr> <attr name=split value=string default=NULL> The string the values string is splitted with.
95ea872000-09-16Martin Nilsson </attr>
2c358b2000-12-06Martin Nilsson <attr name=advanced value=lines|words|chars> If the input is a string it can be splitted into separate lines, words or characters by using this attribute.
e6bf912000-11-15Martin Nilsson </attr> <attr name=case value=upper|lower> Changes the case of the value. </attr> <attr name=trimwhites> Trims away all leading and trailing white space charachters from the values. </attr> <attr name=from-scope value=name>
95ea872000-09-16Martin Nilsson Create a mapping out of a scope and give it as indata to the emit. </attr> ", ([ "&_.value;":"<desc ent>The value of one part of the splitted string</desc>", "&_.index;":"<desc ent>The index of this mapping entry, if input was a mapping</desc>" ]) }),
5b04da2000-05-28Martin Nilsson 
cedad02000-07-26Kenneth Johansson "emit":({ #"<desc cont><short>Provides data, fetched from different sources, as
6c92942000-04-15Per Hedbor  entities</short></desc>
ea074d2000-03-07Martin Nilsson 
a6400f2000-03-31Martin Nilsson <attr name=source value=plugin required>
ea074d2000-03-07Martin Nilsson  The source from which the data should be fetched.
a6400f2000-03-31Martin Nilsson </attr> <attr name=scope value=name default='The emit source'> The name of the scope within the emit tag. </attr> <attr name=maxrows value=number> Limits the number of rows to this maximum. </attr> <attr name=skiprows value=number>
5b04da2000-05-28Martin Nilsson  Makes it possible to skip the first rows of the result. Negative numbers means to skip everything execept the last n rows.
a6400f2000-03-31Martin Nilsson </attr> <attr name=rowinfo value=variable> The number of rows in the result, after it has been limited by maxrows and skiprows, will be put in this variable, if given. </attr> <attr name=do-once> Indicate that at least one loop should be made. All variables in the emit scope will be empty.
ea074d2000-03-07Martin Nilsson </attr>",
cedad02000-07-26Kenneth Johansson  ([ "&_.counter;":#"<desc ent> Gives the current number of loops inside the <tag>emit</tag> tag. </desc>" ]) }),
14022b2000-08-08Kenneth Johansson 
9ac3182000-01-27Kenneth Johansson ]);
cce7142000-01-26Martin Nilsson #endif
14022b2000-08-08Kenneth Johansson