7bf1451999-07-27David Hedbor /*
1f47d92000-01-30Per Hedbor  * $Id: rxml.pike,v 1.90 2000/01/30 22:28:44 per Exp $
7bf1451999-07-27David Hedbor  * * The Roxen Challenger RXML Parser. * * Per Hedbor, Henrik Grubbström, Pontus Hagland, David Hedbor and others. */
b796b51998-11-18Per Hedbor inherit "roxenlib";
b8b31d2000-01-10Martin Nilsson inherit "rxmlhelp";
6234e52000-01-05Per Hedbor #include <request_trace.h>
b796b51998-11-18Per Hedbor 
8fae782000-01-12Martin Nilsson #define OLD_RXML_COMPAT
94892e2000-01-05Martin Stjernholm #define TAGMAP_COMPAT
84fff02000-01-18Martin Stjernholm #define RXML_NAMESPACE "rxml"
05aee52000-01-13Martin Nilsson 
cce7142000-01-26Martin Nilsson #ifndef manual
74747a1999-04-22Per Hedbor mapping (string:function) real_if_callers;
b796b51998-11-18Per Hedbor 
f98e321999-11-29Per Hedbor string rxml_error(string tag, string error, RequestID id) {
778d141999-08-20Martin Nilsson  return (id->misc->debug?sprintf("(%s: %s)",capitalize(tag),error):"")+"<false>"; }
97022d2000-01-14Martin Stjernholm string handle_rxml_error (mixed err, RXML.Type type)
4e56af2000-01-25Martin Stjernholm // This is used for RXML errors thrown in the new parser. See // RXML.Context.rxml_error(). { #ifdef MODULE_DEBUG // FIXME: Make this a user option. report_notice (describe_error (err)); #endif if (type->subtype_of (RXML.t_html)) return "<br clear=all>\n<pre>" + html_encode_string (describe_error (err)) + "</pre>"; else return describe_error (err); } string handle_rxml_fatal (mixed err, RXML.Type type) // This is used for RXML fatal errors thrown in the new parser. See // RXML.Context.rxml_fatal().
97022d2000-01-14Martin Stjernholm { #ifdef MODULE_DEBUG // FIXME: Make this a user option. report_notice (describe_error (err)); #endif
84fff02000-01-18Martin Stjernholm  if (type->subtype_of (RXML.t_html))
97022d2000-01-14Martin Stjernholm  return "<br clear=all>\n<pre>" + html_encode_string (describe_error (err)) + "</pre>"; else return describe_error (err); }
36aaa12000-01-23Martin Nilsson #ifdef OLD_RXML_COMPAT 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
e7ed2e2000-01-08Martin Stjernholm // A note on tag overriding: It's possible for old style tags to
94892e2000-01-05Martin Stjernholm // propagate their results to the tags they have overridden. This is // done by an extension to the return value: //
925b4a2000-01-08Martin 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
211b9a2000-01-10Martin Stjernholm // left out to default to its value in the current tag. ({1, 0, 0}) or // ({1, 0, 0, 0}) may be shortened to ({1}).
94892e2000-01-05Martin Stjernholm // // Note that there's no other way to handle tag overriding -- the page // is no longer parsed multiple times.
36aaa12000-01-23Martin Nilsson  // ----------------------- Default scopes -------------------------
6d0d452000-01-18Martin Nilsson class Scope_roxen { inherit RXML.Scope; string|int `[] (string var, void|RXML.Context c, void|string scope) {
cfc5ca2000-01-25Per Hedbor  switch(var) { case "uptime": return (time(1)-roxen->start_time); case "uptime-days": return (time(1)-roxen->start_time)/3600/24; case "uptime-hours": return (time(1)-roxen->start_time)/3600 % 24; case "uptime-minutes": return (time(1)-roxen->start_time)/60 % 60; case "hits-per-minute":
46881c2000-01-25Martin Nilsson  return c->id->conf->requests / (time(1)-roxen->start_time || 1);
cfc5ca2000-01-25Per Hedbor  case "hits": return c->id->conf->requests; case "sent-mb": return sprintf("%1.2f",c->id->conf->sent / (1024.0*1024.0)); case "sent": return c->id->conf->sent; case "sent-per-minute":
46881c2000-01-25Martin Nilsson  return c->id->conf->sent / ((time(1)-roxen->start_time)/60 || 1);
cfc5ca2000-01-25Per Hedbor  case "sent-kbit-per-second": return sprintf("%1.2f",((c->id->conf->sent*8)/1024.0/
46881c2000-01-25Martin Nilsson  (time(1)-roxen->start_time || 1)));
cfc5ca2000-01-25Per Hedbor  case "pike-version": return predef::version(); case "version": return roxen.version(); case "time": return time(1); case "server": return c->id->conf->query("MyWorldLocation");
6d0d452000-01-18Martin Nilsson  } :: `[] (var, c, scope); }
05aee52000-01-13Martin Nilsson 
6d0d452000-01-18Martin Nilsson  array(string) _indices() {
46881c2000-01-25Martin Nilsson  return ({"uptime", "uptime-days", "uptime-hours", "uptime-minutes",
2b83da2000-01-25Martin Nilsson  "hits-per-minute", "hits", "sent-mb", "sent",
46881c2000-01-25Martin Nilsson  "sent-per-minute", "sent-kbit-per-second", "pike-version", "version", "time", "server"});
6d0d452000-01-18Martin Nilsson  }
36aaa12000-01-23Martin Nilsson  string _sprintf() { return "RXML.Scope(roxen)"; }
05aee52000-01-13Martin Nilsson }
de18202000-01-23Martin Nilsson class Scope_page { inherit RXML.Scope;
46881c2000-01-25Martin Nilsson  constant converter=(["fgcolor":"fgcolor", "bgcolor":"bgcolor",
e81ae82000-01-25Martin Nilsson  "theme-bgcolor":"theme_bgcolor", "theme-fgcolor":"theme_fgcolor", "theme-language":"theme_language"]); constant in_defines=aggregate_multiset(@indices(converter));
de18202000-01-23Martin Nilsson  mixed `[] (string var, void|RXML.Context c, void|string scope) {
46881c2000-01-25Martin Nilsson  if(in_defines[var]) return c->id->misc->defines[converter[var]];
de18202000-01-23Martin Nilsson  if(objectp(c->id->misc->page[var])) return c->id->misc->page[var]->rxml_var_eval(c); return c->id->misc->page[var]; } mixed `[]= (string var, mixed val, void|RXML.Context c, void|string scope_name) {
46881c2000-01-25Martin Nilsson  if(in_defines[var]) return c->id->misc->defines[converter[var]]=val;
de18202000-01-23Martin Nilsson  return c->id->misc->page[var]=val; } array(string) _indices(void|RXML.Context c) { if(!c) return ({}); array ind=indices(c->id->misc->page);
46881c2000-01-25Martin Nilsson  foreach(indices(in_defines), string def) if(c->id->misc->defines[converter[def]]) ind+=({def});
de18202000-01-23Martin Nilsson  return ind; }
36aaa12000-01-23Martin Nilsson  void m_delete (string var, void|RXML.Context c, void|string scope_name) { if(!c) return;
46881c2000-01-25Martin Nilsson  if(in_defines[var]) {
36aaa12000-01-23Martin Nilsson  if(var[0..4]=="theme")
46881c2000-01-25Martin Nilsson  predef::m_delete(c->id->misc->defines, converter[var]);
36aaa12000-01-23Martin Nilsson  else ::m_delete(var, c, scope_name); } predef::m_delete(c->id->misc->page, var); } string _sprintf() { return "RXML.Scope(page)"; }
de18202000-01-23Martin Nilsson }
6d0d452000-01-18Martin Nilsson RXML.Scope scope_roxen=Scope_roxen();
de18202000-01-23Martin Nilsson RXML.Scope scope_page=Scope_page();
49a74b2000-01-14Martin Stjernholm 
36aaa12000-01-23Martin Nilsson  // ------------------------- RXML Parser ------------------------------
41940b2000-01-25Martin Stjernholm RXML.TagSet entities_tag_set = class // This tag set always has the lowest priority. { inherit RXML.TagSet;
e81ae82000-01-25Martin Nilsson  void prepare_context (RXML.Context c) { c->add_scope("roxen",scope_roxen); c->id->misc->page=([]); c->extend_scope("page",scope_page); c->extend_scope("cookie" ,c->id->cookies); c->extend_scope("form", c->id->variables); c->extend_scope("client", c->id->client_var); c->extend_scope("var", ([]) ); }
41940b2000-01-25Martin Stjernholm  // These are only used in new style tags. constant low_entities = ([ "quot": "\"", "amp": "&", "lt": "<", "gt": ">", "nbsp": "\240", // FIXME: More... ]); } ("entities_tag_set");
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;
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() {
41940b2000-01-25Martin Stjernholm  array(RXML.TagSet) new_imported = imported[..sizeof (imported) - 2]; array(RoxenModule) new_modules = modules[..sizeof (modules) - 2]; array(int) priorities = new_modules->query ("_priority", 1);
f599312000-01-19Martin Stjernholm  priorities = replace (priorities, 0, 4); sort (priorities, new_imported, new_modules);
41940b2000-01-25Martin Stjernholm  new_imported = reverse (new_imported) + ({imported[-1]});
f599312000-01-19Martin Stjernholm  if (equal (imported, new_imported)) return;
41940b2000-01-25Martin Stjernholm  new_modules = reverse (new_modules) + ({modules[-1]});
f599312000-01-19Martin Stjernholm  imported = new_imported, modules = new_modules; } void set_modules (array(RoxenModule) _modules) // Kludge currently necessary in Pike 7. { modules = _modules; }
41940b2000-01-25Martin Stjernholm  void create (string name, object rxml_object) { ::create (name); imported = ({entities_tag_set}); modules = ({rxml_object}); } } ("rxml_tag_set", this_object());
e7ed2e2000-01-08Martin Stjernholm 
b828382000-01-28Martin Stjernholm RXML.Type default_arg_type = RXML.t_text (RXML.PEntCompat);
49a74b2000-01-14Martin Stjernholm 
f599312000-01-19Martin Stjernholm int parse_html_compat;
49a74b2000-01-14Martin Stjernholm class BacktraceFrame // Only used to get old style tags in the RXML backtraces. { inherit RXML.Frame; void create (RXML.Frame _up, string name, mapping(string:string) _args) { up = _up; tag = class {inherit RXML.Tag; string name;}(); tag->name = name; args = _args; } }
94892e2000-01-05Martin Stjernholm 
925b4a2000-01-08Martin Stjernholm array|string call_overridden (array call_to, RXML.PHtml parser, string name, mapping(string:string) args,
49a74b2000-01-14Martin Stjernholm  string content, RequestID id)
925b4a2000-01-08Martin Stjernholm { mixed tdef, cdef; if (sizeof (call_to) > 1 && call_to[1] && call_to[1] != name) // Another tag. if (sizeof (call_to) == 3) tdef = parser->tags()[call_to[1]]; else cdef = parser->containers()[call_to[1]]; else { // Same tag. mixed curdef = id->misc->__tag_overrider_def || // Yep, ugly.. (content ? parser->containers()[name] : parser->tags()[name]); #ifdef DEBUG if (!curdef) error ("Can't find tag definition for %s.\n", name); #endif if (array tagdef = parser->get_overridden_low_tag (name, curdef)) { [tdef, cdef] = tagdef; id->misc->__tag_overrider_def = tdef || cdef; if (sizeof (call_to) == 1) call_to = ({1, 0, args, content}); } } array|string result; if (tdef) // Call an overridden tag. if (stringp (tdef)) result = ({tdef}); else if (arrayp (tdef))
49a74b2000-01-14Martin Stjernholm  result = tdef[0] (parser, call_to[2] || args, @tdef[1..]);
925b4a2000-01-08Martin Stjernholm  else
49a74b2000-01-14Martin Stjernholm  result = tdef (parser, call_to[2] || args);
925b4a2000-01-08Martin Stjernholm  else if (cdef) // Call an overridden container. if (stringp (cdef)) result = ({cdef}); else if (arrayp (cdef))
49a74b2000-01-14Martin Stjernholm  result = cdef[0] (parser, call_to[2] || args, call_to[3] || content, @cdef[1..]);
925b4a2000-01-08Martin Stjernholm  else
49a74b2000-01-14Martin Stjernholm  result = cdef (parser, call_to[2] || args, call_to[3] || content);
925b4a2000-01-08Martin Stjernholm  else // Nothing is overridden. if (sizeof (call_to) == 3) result = make_tag (call_to[1] || name, call_to[2] || args); else if (sizeof (call_to) == 4) result = make_container (call_to[1] || name, call_to[2] || args, call_to[3] || content); m_delete (id->misc, "__tag_overrider_def"); return result; }
49a74b2000-01-14Martin Stjernholm array|string call_tag(RXML.PHtml parser, mapping args, string|function rf)
b796b51998-11-18Per Hedbor {
49a74b2000-01-14Martin Stjernholm  RXML.Context ctx = parser->context; RequestID id = ctx->id;
94892e2000-01-05Martin Stjernholm  string tag = parser->tag_name();
0d87d72000-01-30Martin Nilsson  id->misc->line = parser->at_line();
49a74b2000-01-14Martin Stjernholm 
b8b31d2000-01-10Martin Nilsson  if(args->help) { TRACE_ENTER("tag &lt;"+tag+" help&gt", rf);
8fae782000-01-12Martin Nilsson  string h = find_tag_doc(tag, id);
b8b31d2000-01-10Martin Nilsson  TRACE_LEAVE(""); return h; }
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor  if(stringp(rf)) return rf;
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor  TRACE_ENTER("tag &lt;" + tag + "&gt;", rf);
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor #ifdef MODULE_LEVEL_SECURITY
93e3341998-11-22Per Hedbor  if(check_security(rf, id, id->misc->seclevel))
b796b51998-11-18Per Hedbor  { TRACE_LEAVE("Access denied"); return 0; } #endif
49a74b2000-01-14Martin Stjernholm  mixed result; RXML.Frame orig_frame = ctx->frame; ctx->frame = BacktraceFrame (orig_frame, tag, args); mixed err = catch { foreach (indices (args), string arg) // Parse variable entities in arguments.
71ef9d2000-01-28Martin Stjernholm  args[arg] = default_arg_type->eval (args[arg], 0, rxml_tag_set, parser, 1);
49a74b2000-01-14Martin Stjernholm  result=rf(tag,args,id,parser->_source_file,parser->_defines); }; ctx->frame = orig_frame; if (err) throw (err);
b796b51998-11-18Per Hedbor  TRACE_LEAVE("");
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor  if(args->noparse && stringp(result)) return ({ result });
925b4a2000-01-08Martin Stjernholm  if (arrayp (result) && sizeof (result) && result[0] == 1)
49a74b2000-01-14Martin Stjernholm  return call_overridden (result, parser, tag, args, 0, id);
b796b51998-11-18Per Hedbor  return result; }
e7ed2e2000-01-08Martin Stjernholm array(string)|string call_container(RXML.PHtml parser, mapping args,
49a74b2000-01-14Martin Stjernholm  string contents, string|function rf)
b796b51998-11-18Per Hedbor {
49a74b2000-01-14Martin Stjernholm  RXML.Context ctx = parser->context; RequestID id = ctx->id;
94892e2000-01-05Martin Stjernholm  string tag = parser->tag_name();
0d87d72000-01-30Martin Nilsson  id->misc->line = parser->at_line();
49a74b2000-01-14Martin Stjernholm 
b8b31d2000-01-10Martin Nilsson  if(args->help) { TRACE_ENTER("container &lt;"+tag+" help&gt", rf);
8fae782000-01-12Martin Nilsson  string h = find_tag_doc(tag, id);
b8b31d2000-01-10Martin Nilsson  TRACE_LEAVE(""); return h; }
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor  if(stringp(rf)) return rf;
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor  TRACE_ENTER("container &lt;"+tag+"&gt", rf);
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor  if(args->preparse) contents = parse_rxml(contents, id); if(args->trimwhites) { sscanf(contents, "%*[ \t\n\r]%s", contents); contents = reverse(contents); sscanf(contents, "%*[ \t\n\r]%s", contents); contents = reverse(contents); }
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor #ifdef MODULE_LEVEL_SECURITY
93e3341998-11-22Per Hedbor  if(check_security(rf, id, id->misc->seclevel))
b796b51998-11-18Per Hedbor  { TRACE_LEAVE("Access denied"); return 0; } #endif
49a74b2000-01-14Martin Stjernholm  mixed result; RXML.Frame orig_frame = ctx->frame; ctx->frame = BacktraceFrame (orig_frame, tag, args); mixed err = catch { foreach (indices (args), string arg) // Parse variable entities in arguments.
71ef9d2000-01-28Martin Stjernholm  args[arg] = default_arg_type->eval (args[arg], 0, rxml_tag_set, parser, 1);
49a74b2000-01-14Martin Stjernholm  result=rf(tag,args,contents,id,parser->_source_file,parser->_defines); }; ctx->frame = orig_frame; if (err) throw (err);
b796b51998-11-18Per Hedbor  TRACE_LEAVE("");
49a74b2000-01-14Martin Stjernholm 
b796b51998-11-18Per Hedbor  if(args->noparse && stringp(result)) return ({ result });
925b4a2000-01-08Martin Stjernholm  if (arrayp (result) && sizeof (result) && result[0] == 1)
49a74b2000-01-14Martin Stjernholm  return call_overridden (result, parser, tag, args, contents, id);
b796b51998-11-18Per Hedbor 
49a74b2000-01-14Martin Stjernholm  return result;
05aee52000-01-13Martin Nilsson }
94892e2000-01-05Martin Stjernholm string do_parse(string to_parse, RequestID id,
e7ed2e2000-01-08Martin Stjernholm  Stdio.File file, mapping defines)
b796b51998-11-18Per Hedbor {
211b9a2000-01-10Martin Stjernholm  RXML.PHtml parent_parser = id->misc->_parser; // Don't count on that this exists. RXML.PHtml parser;
49a74b2000-01-14Martin Stjernholm  RXML.Context ctx;
211b9a2000-01-10Martin Stjernholm 
49a74b2000-01-14Martin Stjernholm  if ((ctx = parent_parser && parent_parser->context) && ctx->id == id) { parser = RXML.t_html (RXML.PHtmlCompat)->get_parser (ctx); parser->_parent = parent_parser; }
1f47d92000-01-30Per Hedbor  else {
49a74b2000-01-14Martin Stjernholm  parser = rxml_tag_set (RXML.t_html (RXML.PHtmlCompat), id);
d2e56f2000-01-25Martin Nilsson #ifdef OLD_RXML_COMPAT parser->context->add_scope("_", id->variables); #endif }
4806252000-01-11Martin Stjernholm  parser->parse_html_compat (parse_html_compat);
211b9a2000-01-10Martin Stjernholm  id->misc->_parser = parser;
49a74b2000-01-14Martin Stjernholm  parser->_source_file = file; parser->_defines = defines;
05aee52000-01-13Martin Nilsson 
94892e2000-01-05Martin Stjernholm #ifdef TAGMAP_COMPAT if (id->misc->_tags) { parser->tagmap_tags = id->misc->_tags; parser->tagmap_containers = id->misc->_containers; } else { id->misc->_tags = parser->tagmap_tags; id->misc->_containers = parser->tagmap_containers; } #endif
b796b51998-11-18Per Hedbor 
94892e2000-01-05Martin Stjernholm  if(!id->misc->_ifs) id->misc->_ifs = copy_value(real_if_callers);
b796b51998-11-18Per Hedbor 
211b9a2000-01-10Martin Stjernholm  if (mixed err = catch { if (parent_parser) parser->finish (to_parse); else parser->write_end (to_parse);
4806252000-01-11Martin Stjernholm  string result = parser->eval();
6a795d2000-01-21Martin Stjernholm  parser->_defines = 0;
211b9a2000-01-10Martin Stjernholm  id->misc->_parser = parent_parser;
4806252000-01-11Martin Stjernholm  return result;
211b9a2000-01-10Martin Stjernholm  }) {
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); }
b796b51998-11-18Per Hedbor }
f599312000-01-19Martin Stjernholm void build_if_callers()
b796b51998-11-18Per Hedbor {
74747a1999-04-22Per Hedbor  real_if_callers=([]);
b796b51998-11-18Per Hedbor 
f599312000-01-19Martin Stjernholm  foreach (rxml_tag_set->modules, RoxenModule mod) { mapping(string:function) defs;
94892e2000-01-05Martin Stjernholm  if (mod->query_if_callers && mappingp (defs = mod->query_if_callers()) && sizeof (defs)) real_if_callers |= defs;
b796b51998-11-18Per Hedbor  } }
f599312000-01-19Martin Stjernholm void add_parse_module (RoxenModule mod)
b796b51998-11-18Per Hedbor {
f599312000-01-19Martin Stjernholm  RXML.TagSet tag_set = mod->query_tag_set ? mod->query_tag_set() : RXML.TagSet (sprintf ("%O", mod)); mapping(string:mixed) defs; if (mod->query_tag_callers && mappingp (defs = mod->query_tag_callers()) && sizeof (defs)) tag_set->low_tags = mkmapping (indices (defs), Array.transpose (({({call_tag}) * sizeof (defs), values (defs)}))); if (mod->query_container_callers && mappingp (defs = mod->query_container_callers()) && sizeof (defs)) tag_set->low_containers = mkmapping (indices (defs), Array.transpose (({({call_container}) * sizeof (defs), values (defs)}))); if (search (rxml_tag_set->imported, tag_set) < 0) { rxml_tag_set->set_modules (rxml_tag_set->modules + ({mod})); array(RXML.Tag) foo = rxml_tag_set->imported; rxml_tag_set->imported = foo + ({tag_set}); remove_call_out (rxml_tag_set->sort_on_priority); call_out (rxml_tag_set->sort_on_priority, 0); } remove_call_out (build_if_callers); call_out (build_if_callers, 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]; rxml_tag_set->set_modules ( rxml_tag_set->modules[..i - 1] + rxml_tag_set->modules[i + 1..]); 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  }
b796b51998-11-18Per Hedbor 
f599312000-01-19Martin Stjernholm  remove_call_out (build_if_callers); call_out (build_if_callers, 0); }
b796b51998-11-18Per Hedbor 
49a74b2000-01-14Martin Stjernholm string call_user_tag(RXML.PHtml parser, mapping args)
b796b51998-11-18Per Hedbor {
49a74b2000-01-14Martin Stjernholm  RequestID id = parser->context->id;
94892e2000-01-05Martin Stjernholm  string tag = parser->tag_name();
0d87d72000-01-30Martin Nilsson  id->misc->line = parser->at_line();
b796b51998-11-18Per Hedbor  args = id->misc->defaults[tag]|args; TRACE_ENTER("user defined tag &lt;"+tag+"&gt;", call_user_tag);
1f47d92000-01-30Per Hedbor  array replace_from = map(indices(args),make_entity)+({"#args#"});
dc2d9c2000-01-10Martin Nilsson  array replace_to = values(args)+({make_tag_attributes( args ) });
b796b51998-11-18Per Hedbor  string r = replace(id->misc->tags[ tag ], replace_from, replace_to); TRACE_LEAVE(""); return r; }
49a74b2000-01-14Martin Stjernholm array|string call_user_container(RXML.PHtml parser, mapping args, string contents)
b796b51998-11-18Per Hedbor {
49a74b2000-01-14Martin Stjernholm  RequestID id = parser->context->id;
94892e2000-01-05Martin Stjernholm  string tag = parser->tag_name();
b796b51998-11-18Per Hedbor  if(!id->misc->defaults[tag] && id->misc->defaults[""]) tag = "";
0d87d72000-01-30Martin Nilsson  id->misc->line = parser->at_line();
b796b51998-11-18Per Hedbor  args = id->misc->defaults[tag]|args;
8cbe091999-08-20Per Hedbor  if( args->preparse )
54260d1999-08-06Per Hedbor  { if( id->misc->do_not_recurse_for_ever_please++ > 10000 ) error("Too deep Recursion.\n");
b796b51998-11-18Per Hedbor  contents = parse_rxml(contents, id);
54260d1999-08-06Per Hedbor  id->misc->do_not_recurse_for_ever_please--; }
36aaa12000-01-23Martin Nilsson  if(args->trimwhites)
8cbe091999-08-20Per Hedbor  { sscanf(contents, "%*[ \t\n\r]%s", contents); contents = reverse(contents); sscanf(contents, "%*[ \t\n\r]%s", contents); contents = reverse(contents); }
b796b51998-11-18Per Hedbor  TRACE_ENTER("user defined container &lt;"+tag+"&gt", call_user_container);
54260d1999-08-06Per Hedbor  id->misc->do_not_recurse_for_ever_please++;
1f47d92000-01-30Per Hedbor  array i = indices( args ); array v = values( args ); array replace_from = map(i,make_entity)+({"#args#", "<contents>"}); array replace_to = v + ({make_tag_attributes( args ), contents });
b796b51998-11-18Per Hedbor  string r = replace(id->misc->containers[ tag ], replace_from, replace_to); TRACE_LEAVE("");
8cbe091999-08-20Per Hedbor  if( args->noparse ) return ({ r });
b796b51998-11-18Per Hedbor  return r; } #define _stat defines[" _stat"] #define _error defines[" _error"] #define _extra_heads defines[" _extra_heads"] #define _rettext defines[" _rettext"] #define _ok defines[" _ok"]
36aaa12000-01-23Martin Nilsson string parse_rxml(string what, RequestID id,
f98e321999-11-29Per Hedbor  void|Stdio.File file,
b796b51998-11-18Per Hedbor  void|mapping defines ) {
7c92b91998-11-19Per Hedbor  id->misc->_rxml_recurse++;
b796b51998-11-18Per Hedbor #ifdef RXML_DEBUG werror("parse_rxml( "+strlen(what)+" ) -> "); int time = gethrtime(); #endif
36aaa12000-01-23Martin Nilsson  if(!defines)
b796b51998-11-18Per Hedbor  { defines = id->misc->defines||([]); if(!_error) _error=200; if(!_extra_heads) _extra_heads=([ ]); } if(!defines->sizefmt) { set_start_quote(set_end_quote(0));
36aaa12000-01-23Martin Nilsson  defines->sizefmt = "abbrev";
b796b51998-11-18Per Hedbor  _error=200; _extra_heads=([ ]); if(id->misc->stat) _stat=id->misc->stat; else if(file) _stat=file->stat(); } id->misc->defines = defines;
e7ed2e2000-01-08Martin Stjernholm  what = do_parse(what, id, file, defines);
b796b51998-11-18Per Hedbor  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; }
36aaa12000-01-23Martin Nilsson // ------------------------- RXML Core tags --------------------------
74747a1999-04-22Per Hedbor string tag_help(string t, mapping args, RequestID id)
b796b51998-11-18Per Hedbor {
49a74b2000-01-14Martin Stjernholm  RXML.PHtml parser = rxml_tag_set (RXML.t_html (RXML.PHtmlCompat), id);
8fae782000-01-12Martin Nilsson  array tags = sort(indices(parser->tags()+parser->containers()));
b8b31d2000-01-10Martin Nilsson  string help_for = args->for || id->variables->_r_t_h;
2b339e2000-01-21Martin Nilsson  string ret="<h2>Roxen Interactive RXML Help</h2>";
b796b51998-11-18Per Hedbor  if(!help_for) {
2b339e2000-01-21Martin Nilsson  string char; ret += "<b>Here is a list of all defined tags. Click on the name to "
b383752000-01-13Martin Nilsson  "receive more detailed information. All these tags are also availabe " "in the \""+RXML_NAMESPACE+"\" namespace.</b><p>\n";
8fae782000-01-12Martin Nilsson  array tag_links;
b8b31d2000-01-10Martin Nilsson 
8fae782000-01-12Martin Nilsson  foreach(tags, string tag) { if(tag[0..0]!=char) { if(tag_links && char!="/") ret+="<h3>"+upper_case(char)+"</h3>\n<p>"+String.implode_nicely(tag_links)+"</p>"; char=tag[0..0]; tag_links=({}); }
2b339e2000-01-21Martin Nilsson  if(tag[0..sizeof(RXML_NAMESPACE)]!=RXML_NAMESPACE+":")
6fc05f2000-01-24Martin Nilsson  if(undocumented_tags[tag]) tag_links += ({ tag }); else tag_links += ({ sprintf("<a href=\"%s?_r_t_h=%s\">%s</a>\n", id->not_query, http_encode_url(tag), tag) });
8fae782000-01-12Martin Nilsson  } return ret + "<h3>"+upper_case(char)+"</h3>\n<p>"+String.implode_nicely(tag_links)+"</p>";
b796b51998-11-18Per Hedbor  }
b8b31d2000-01-10Martin Nilsson 
2b339e2000-01-21Martin Nilsson  return ret+find_tag_doc(help_for, id);
b796b51998-11-18Per Hedbor }
36aaa12000-01-23Martin Nilsson string tag_number(string t, mapping args, RequestID id)
728f401999-02-16Marcus Comstedt {
36aaa12000-01-23Martin Nilsson  return roxen.language(args->lang||args->language||id->misc->defines->theme_language,
8cbe091999-08-20Per Hedbor  args->type||"number")( (int)args->num );
728f401999-02-16Marcus Comstedt }
74747a1999-04-22Per Hedbor array(string) list_packages()
b796b51998-11-18Per Hedbor {
1f47d92000-01-30Per Hedbor  return filter(((get_dir("../local/rxml_packages")||({})) |(get_dir("../rxml_packages")||({}))), lambda( string s ) { return (Stdio.file_size("../local/rxml_packages/"+s)+ Stdio.file_size( "../rxml_packages/"+s )) > 0; });
74747a1999-04-22Per Hedbor  } string read_package( string p ) { string data;
434a611999-12-11Henrik Grubbström (Grubba)  p = replace(p, ({"/", "\\"}), ({"",""}));
74747a1999-04-22Per Hedbor  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;
b796b51998-11-18Per Hedbor }
f98e321999-11-29Per Hedbor string use_file_doc( string f, string data, RequestID nid, Stdio.File id )
74747a1999-04-22Per Hedbor { string res="";
36aaa12000-01-23Martin Nilsson  catch
74747a1999-04-22Per Hedbor  { string doc = ""; int help=0; /* If true, all tags support the 'help' argument. */ sscanf(data, "%*sdoc=\"%s\"", doc);
36aaa12000-01-23Martin Nilsson  sscanf(data, "%*sdoc=%d", help);
74747a1999-04-22Per Hedbor  parse_rxml("<scope>"+data+"</scope>", nid); res += "<dt><b>"+f+"</b><dd>"+(doc?doc+"<br>":""); array tags = indices(nid->misc->tags||({})); array containers = indices(nid->misc->containers||({})); array ifs = indices(nid->misc->_ifs||({}))- indices(id->misc->_ifs); array defines = indices(nid->misc->defines||({}))- indices(id->misc->defines); if(sizeof(tags)) res += "defines the following tag"+ (sizeof(tags)!=1?"s":"") +": "+ String.implode_nicely( sort(tags) )+"<br>"; if(sizeof(containers)) res += "defines the following container"+ (sizeof(tags)!=1?"s":"") +": "+ String.implode_nicely( sort(containers) )+"<br>"; if(sizeof(ifs)) res += "defines the following if argument"+ (sizeof(ifs)!=1?"s":"") +": "+ String.implode_nicely( sort(ifs) )+"<br>"; if(sizeof(defines)) res += "defines the following macro"+ (sizeof(defines)!=1?"s":"") +": "+ String.implode_nicely( sort(defines) )+"<br>"; }; nid->misc->tags = 0; nid->misc->containers = 0; nid->misc->defines = ([]); nid->misc->_tags = 0; nid->misc->_containers = 0; nid->misc->defaults = ([]); nid->misc->_ifs = ([]);
211b9a2000-01-10Martin Stjernholm  nid->misc->_parser = 0;
74747a1999-04-22Per Hedbor  return res; }
f4d2801999-10-18Per Hedbor string|array tag_use(string tag, mapping m, string c, RequestID id)
b796b51998-11-18Per Hedbor { mapping res = ([]);
f4d2801999-10-18Per Hedbor  #define SETUP_NID() \
f98e321999-11-29Per Hedbor  RequestID nid = id->clone_me(); \
f4d2801999-10-18Per Hedbor  nid->misc->tags = 0; \ nid->misc->containers = 0; \ nid->misc->defines = ([]); \ nid->misc->_tags = 0; \ nid->misc->_containers = 0; \ nid->misc->defaults = ([]); \
211b9a2000-01-10Martin Stjernholm  nid->misc->_ifs = ([]); \ nid->misc->_parser = 0;
b796b51998-11-18Per Hedbor  if(m->packageinfo) {
f4d2801999-10-18Per Hedbor  SETUP_NID();
b796b51998-11-18Per Hedbor  string res ="<dl>";
74747a1999-04-22Per Hedbor  foreach(list_packages(), string f)
f4d2801999-10-18Per Hedbor  res += use_file_doc( f, read_package( f ), id, id );
74747a1999-04-22Per Hedbor  return ({res+"</dl>"});
b796b51998-11-18Per Hedbor  }
36aaa12000-01-23Martin Nilsson  if(!m->file && !m->package)
f4d2801999-10-18Per Hedbor  return "<use help>";
36aaa12000-01-23Martin Nilsson  if(id->pragma["no-cache"] ||
74747a1999-04-22Per Hedbor  !(res=cache_lookup("macrofiles:"+name,(m->file||("pkg!"+m->package)))))
b796b51998-11-18Per Hedbor  {
f4d2801999-10-18Per Hedbor  SETUP_NID();
b796b51998-11-18Per Hedbor  res = ([]); string foo; if(m->file)
f4d2801999-10-18Per Hedbor  foo = try_get_file( fix_relative(m->file, nid), nid );
36aaa12000-01-23Martin Nilsson  else
f4d2801999-10-18Per Hedbor  foo = read_package( m->package );
36aaa12000-01-23Martin Nilsson 
b796b51998-11-18Per Hedbor  if(!foo)
778d141999-08-20Martin Nilsson  return ({ rxml_error(tag, "Failed to fetch "+(m->file||m->package)+".", id)-"<false>" });
74747a1999-04-22Per Hedbor  if( m->info ) return ({"<dl>"+use_file_doc( m->file || m->package, foo, nid,id )+"</dl>"});
b796b51998-11-18Per Hedbor  parse_rxml( foo, nid ); res->tags = nid->misc->tags||([]); res->_tags = nid->misc->_tags||([]); foreach(indices(res->_tags), string t) if(!res->tags[t]) m_delete(res->_tags, t); res->containers = nid->misc->containers||([]); res->_containers = nid->misc->_containers||([]); foreach(indices(res->_containers), string t) if(!res->containers[t]) m_delete(res->_containers, t); res->defines = nid->misc->defines||([]); res->defaults = nid->misc->defaults||([]);
f4d2801999-10-18Per Hedbor  res->_ifs = nid->misc->_ifs - id->misc->_ifs; m_delete( res->defines, " _stat" ); m_delete( res->defines, " _error" ); m_delete( res->defines, " _extra_heads" ); m_delete( res->defines, " _rettext" ); m_delete( res->defines, " _ok" ); m_delete( res->defines, "line"); m_delete( res->defines, "sizefmt");
74747a1999-04-22Per Hedbor  cache_set("macrofiles:"+name, (m->file || ("pkg!"+m->package)), res);
b796b51998-11-18Per Hedbor  }
fe538d1999-08-15David Hedbor  id->misc->tags += copy_value(res->tags);
74747a1999-04-22Per Hedbor  id->misc->containers += res->containers; id->misc->defaults += res->defaults;
fe538d1999-08-15David Hedbor  id->misc->defines += copy_value(res->defines);
74747a1999-04-22Per Hedbor  id->misc->_tags += res->_tags; id->misc->_containers += res->_containers; id->misc->_ifs += res->_ifs;
f4d2801999-10-18Per Hedbor  c = parse_rxml( c, id ); return ({ c });
b796b51998-11-18Per Hedbor }
36aaa12000-01-23Martin Nilsson string tag_define(string tag, mapping m, string str, RequestID id,
f98e321999-11-29Per Hedbor  Stdio.File file, mapping defines)
36aaa12000-01-23Martin Nilsson {
c2dd2a1999-09-10Martin Nilsson  if(m->variable)
b796b51998-11-18Per Hedbor  id->variables[m->variable] = str;
8fae782000-01-12Martin Nilsson #ifdef OLD_RXML_COMPAT
c2dd2a1999-09-10Martin Nilsson  else if (m->name) { defines[m->name]=str;
d0d1511999-12-18Martin Nilsson  old_rxml_warning(id, "attempt to define name ","variable");
c2dd2a1999-09-10Martin Nilsson  } #endif
36aaa12000-01-23Martin Nilsson  else if (m->tag)
b796b51998-11-18Per Hedbor  {
74747a1999-04-22Per Hedbor  m->tag = lower_case(m->tag); string n = m->tag; m_delete( m, "tag" );
b796b51998-11-18Per Hedbor  if(!id->misc->tags) id->misc->tags = ([]); if(!id->misc->defaults) id->misc->defaults = ([]);
dcc5b21999-12-08Martin Stjernholm  id->misc->defaults[n] = ([]);
b796b51998-11-18Per Hedbor 
8fae782000-01-12Martin Nilsson #ifdef OLD_RXML_COMPAT
c4ccda1999-08-02Martin Nilsson  // This is not part of RXML 1.4
b796b51998-11-18Per Hedbor  foreach( indices(m), string arg )
74747a1999-04-22Per Hedbor  if( arg[..7] == "default_" ) { id->misc->defaults[n][arg[8..]] = m[arg];
d0d1511999-12-18Martin Nilsson  old_rxml_warning(id, "define attribute "+arg,"attrib container");
74747a1999-04-22Per Hedbor  m_delete( m, arg ); }
778d141999-08-20Martin Nilsson #endif
63775e1999-07-24Martin Nilsson 
c4ccda1999-08-02Martin Nilsson  str=parse_html(str,([]),(["attrib":
ebb7601999-12-28Martin Nilsson  lambda(string tag, mapping m, string cont, mapping c) {
6d0d452000-01-18Martin Nilsson  if(m->name) id->misc->defaults[n][m->name]=parse_rxml(cont,id);
c4ccda1999-08-02Martin Nilsson  return ""; }
ebb7601999-12-28Martin Nilsson  ]));
c4ccda1999-08-02Martin Nilsson 
0d87d72000-01-30Martin Nilsson  if(m->trimwhites) { sscanf(str, "%*[ \t\n\r]%s", str); str = reverse(str); sscanf(str, "%*[ \t\n\r]%s", str); str = reverse(str); }
8fae782000-01-12Martin Nilsson #ifdef OLD_RXML_COMPAT
c2dd2a1999-09-10Martin Nilsson  id->misc->tags[n] = replace( str, indices(m), values(m) ); #else id->misc->tags[n] = str; #endif
74747a1999-04-22Per Hedbor  id->misc->_tags[n] = call_user_tag;
b796b51998-11-18Per Hedbor  }
36aaa12000-01-23Martin Nilsson  else if (m->container)
b796b51998-11-18Per Hedbor  {
74747a1999-04-22Per Hedbor  string n = lower_case(m->container); m_delete( m, "container" );
b796b51998-11-18Per Hedbor  if(!id->misc->containers) id->misc->containers = ([]); if(!id->misc->defaults) id->misc->defaults = ([]);
dcc5b21999-12-08Martin Stjernholm  id->misc->defaults[n] = ([]);
b796b51998-11-18Per Hedbor 
8fae782000-01-12Martin Nilsson #ifdef OLD_RXML_COMPAT
c4ccda1999-08-02Martin Nilsson  // This is not part of RXML 1.4
b796b51998-11-18Per Hedbor  foreach( indices(m), string arg ) if( arg[0..7] == "default_" )
74747a1999-04-22Per Hedbor  { id->misc->defaults[n][arg[8..]] = m[arg];
d0d1511999-12-18Martin Nilsson  old_rxml_warning(id, "define attribute "+arg,"attrib container");
74747a1999-04-22Per Hedbor  m_delete( m, arg ); }
778d141999-08-20Martin Nilsson #endif
63775e1999-07-24Martin Nilsson 
c4ccda1999-08-02Martin Nilsson  str=parse_html(str,([]),(["attrib":
ebb7601999-12-28Martin Nilsson  lambda(string tag, mapping m, string cont, mapping c) {
6d0d452000-01-18Martin Nilsson  if(m->name) id->misc->defaults[n][m->name]=parse_rxml(cont,id);
c4ccda1999-08-02Martin Nilsson  return ""; }
ebb7601999-12-28Martin Nilsson  ]));
c4ccda1999-08-02Martin Nilsson 
0d87d72000-01-30Martin Nilsson  if(m->trimwhites) { sscanf(str, "%*[ \t\n\r]%s", str); str = reverse(str); sscanf(str, "%*[ \t\n\r]%s", str); str = reverse(str); }
8fae782000-01-12Martin Nilsson #ifdef OLD_RXML_COMPAT
c2dd2a1999-09-10Martin Nilsson  id->misc->containers[n] = replace( str, indices(m), values(m) ); #else id->misc->containers[n] = str; #endif
74747a1999-04-22Per Hedbor  id->misc->_containers[n] = call_user_container; } else if (m["if"]) id->misc->_ifs[ lower_case(m["if"]) ] = UserIf( str );
36aaa12000-01-23Martin Nilsson  else
778d141999-08-20Martin Nilsson  return rxml_error(tag, "No tag, variable, if or container specified.", id);
36aaa12000-01-23Martin Nilsson  return "";
b796b51998-11-18Per Hedbor }
36aaa12000-01-23Martin Nilsson string tag_undefine(string tag, mapping m, RequestID id,
f98e321999-11-29Per Hedbor  Stdio.File file, mapping defines)
36aaa12000-01-23Martin Nilsson {
c2dd2a1999-09-10Martin Nilsson  if(m->variable)
b796b51998-11-18Per Hedbor  m_delete(id->variables,m->variable);
8fae782000-01-12Martin Nilsson #ifdef OLD_RXML_COMPAT
36aaa12000-01-23Martin Nilsson  else if (m->name)
c2dd2a1999-09-10Martin Nilsson  m_delete(defines,m->name); #endif
36aaa12000-01-23Martin Nilsson  else if (m->tag)
b796b51998-11-18Per Hedbor  { m_delete(id->misc->tags,m->tag); m_delete(id->misc->_tags,m->tag); }
36aaa12000-01-23Martin Nilsson  else if (m["if"])
74747a1999-04-22Per Hedbor  m_delete(id->misc->_ifs,m["if"]);
36aaa12000-01-23Martin Nilsson  else if (m->container)
b796b51998-11-18Per Hedbor  { m_delete(id->misc->containers,m->container); m_delete(id->misc->_containers,m->container); }
778d141999-08-20Martin Nilsson  else return rxml_error(tag, "No tag, variable, if or container specified.", id);
36aaa12000-01-23Martin Nilsson  return "";
b796b51998-11-18Per Hedbor }
74747a1999-04-22Per Hedbor class Tracer { inherit "roxenlib"; string resolv="<ol>"; int level;
ec91501999-11-23Per Hedbor  string _sprintf() { return "Tracer()"; }
74747a1999-04-22Per Hedbor  mapping et = ([]); #if efun(gethrvtime) mapping et2 = ([]); #endif
f98e321999-11-29Per Hedbor  string module_name(function|RoxenModule m)
74747a1999-04-22Per Hedbor  { if(!m)return ""; if(functionp(m)) m = function_object(m);
c0d5461999-05-08Per Hedbor  catch { return (strlen(m->query("_name")) ? m->query("_name") : (m->query_name&&m->query_name()&&strlen(m->query_name()))? m->query_name():m->register_module()[1]); }; return "Internal RXML tag";
74747a1999-04-22Per Hedbor  }
f98e321999-11-29Per Hedbor  void trace_enter_ol(string type, function|RoxenModule module)
74747a1999-04-22Per Hedbor  {
36aaa12000-01-23Martin Nilsson  level++;
74747a1999-04-22Per Hedbor  string efont="", font="";
36aaa12000-01-23Martin Nilsson  if(level>2) {efont="</font>";font="<font size=-1>";}
74747a1999-04-22Per Hedbor  resolv += (font+"<b><li></b> "+type+" "+module_name(module)+"<ol>"+efont); #if efun(gethrvtime) et2[level] = gethrvtime(); #endif #if efun(gethrtime) et[level] = gethrtime(); #endif } void trace_leave_ol(string desc) { #if efun(gethrtime) int delay = gethrtime()-et[level]; #endif #if efun(gethrvtime) int delay2 = gethrvtime()-et2[level]; #endif level--; string efont="", font="";
36aaa12000-01-23Martin Nilsson  if(level>1) {efont="</font>";font="<font size=-1>";}
74747a1999-04-22Per Hedbor  resolv += (font+"</ol>"+ #if efun(gethrtime) "Time: "+sprintf("%.5f",delay/1000000.0)+ #endif #if efun(gethrvtime) " (CPU = "+sprintf("%.2f)", delay2/1000000.0)+ #endif /* efun(gethrvtime) */ "<br>"+html_encode_string(desc)+efont)+"<p>"; } string res() { while(level>0) trace_leave_ol(""); return resolv+"</ol>"; } }
bde4a51999-06-11Martin Stjernholm array(string) tag_trace(string t, mapping args, string c , RequestID id)
74747a1999-04-22Per Hedbor { NOCACHE();
f98e321999-11-29Per Hedbor  Tracer t; // if(args->summary) // t = SumTracer(); // else
74747a1999-04-22Per Hedbor  t = Tracer(); function a = id->misc->trace_enter; function b = id->misc->trace_leave; id->misc->trace_enter = t->trace_enter_ol; id->misc->trace_leave = t->trace_leave_ol; t->trace_enter_ol( "tag &lt;trace&gt;", tag_trace); string r = parse_rxml(c, id); id->misc->trace_enter = a; id->misc->trace_leave = b;
bde4a51999-06-11Martin Stjernholm  return ({r + "<h1>Trace report</h1>"+t->res()+"</ol>"});
74747a1999-04-22Per Hedbor } array(string) tag_noparse(string t, mapping m, string c) { return ({ c }); } string tag_nooutput(string t, mapping m, string c, RequestID id) { parse_rxml(c, id); return ""; } string tag_strlen(string t, mapping m, string c, RequestID id) { return (string)strlen(c); } string tag_case(string t, mapping m, string c, RequestID id) {
63775e1999-07-24Martin Nilsson  if(m["case"]) switch(lower_case(m["case"])) { case "lower": return lower_case(c); case "upper": return upper_case(c); case "capitalize": return capitalize(c); }
8fae782000-01-12Martin Nilsson #ifdef OLD_RXML_COMPAT
778d141999-08-20Martin Nilsson  if(m->lower) {
74747a1999-04-22Per Hedbor  c = lower_case(c);
d0d1511999-12-18Martin Nilsson  old_rxml_warning(id, "attribute lower","case=lower");
778d141999-08-20Martin Nilsson  } if(m->upper) {
74747a1999-04-22Per Hedbor  c = upper_case(c);
d0d1511999-12-18Martin Nilsson  old_rxml_warning(id, "attribute upper","case=upper");
778d141999-08-20Martin Nilsson  } if(m->capitalize){
74747a1999-04-22Per Hedbor  c = capitalize(c);
d0d1511999-12-18Martin Nilsson  old_rxml_warning(id, "attribute capitalize","case=capitalize");
778d141999-08-20Martin Nilsson  } #endif
74747a1999-04-22Per Hedbor  return c; } #define LAST_IF_TRUE id->misc->defines[" _ok"] string tag_if( string t, mapping m, string c, RequestID id ) { int res, and = 1;
36aaa12000-01-23Martin Nilsson  if(m->not)
74747a1999-04-22Per Hedbor  { m_delete( m, "not" ); tag_if( t, m, c, id ); LAST_IF_TRUE = !LAST_IF_TRUE; if(LAST_IF_TRUE) return c+"<true>"; return "<false>"; } if(m->or) { and = 0; m_delete( m, "or" ); } if(m->and) { and = 1; m_delete( m, "and" ); }
e3d42b1999-08-16Martin Nilsson  array possible = indices(m) & indices(id->misc->_ifs);
c0d5461999-05-08Per Hedbor 
b1d7a61999-10-18Martin Nilsson  int last=0;
74747a1999-04-22Per Hedbor  foreach(possible, string s) {
e3d42b1999-08-16Martin Nilsson  res = id->misc->_ifs[ s ]( m[s], id, m, and, s );
c0d5461999-05-08Per Hedbor  LAST_IF_TRUE=res;
b1d7a61999-10-18Martin Nilsson  last=res;
c0d5461999-05-08Per Hedbor  if(res)
74747a1999-04-22Per Hedbor  {
36aaa12000-01-23Martin Nilsson  if(!and)
c0d5461999-05-08Per Hedbor  return c+"<true>"; }
36aaa12000-01-23Martin Nilsson  else
c0d5461999-05-08Per Hedbor  {
36aaa12000-01-23Martin Nilsson  if(and)
c0d5461999-05-08Per Hedbor  return "<false>";
74747a1999-04-22Per Hedbor  } }
b1d7a61999-10-18Martin Nilsson  if( last )
74747a1999-04-22Per Hedbor  return c+"<true>"; return "<false>"; } string tag_else( string t, mapping m, string c, RequestID id ) { if(!LAST_IF_TRUE) return c; return ""; }
63775e1999-07-24Martin Nilsson string tag_then( string t, mapping m, string c, RequestID id ) { if(LAST_IF_TRUE) return c; return ""; }
74747a1999-04-22Per Hedbor string tag_elseif( string t, mapping m, string c, RequestID id ) { if(!LAST_IF_TRUE) return tag_if( t, m, c, id ); return ""; }
63775e1999-07-24Martin Nilsson string tag_true( string t, mapping m, RequestID id )
74747a1999-04-22Per Hedbor { LAST_IF_TRUE = 1; return ""; }
63775e1999-07-24Martin Nilsson string tag_false( string t, mapping m, RequestID id )
74747a1999-04-22Per Hedbor { LAST_IF_TRUE = 0; return ""; } void internal_tag_case( string t, mapping m, string c, int l, RequestID id, mapping res ) { if(res->res) return; LAST_IF_TRUE = 0; tag_if( t, m, c, id ); if(LAST_IF_TRUE) res->res = c+"<true>"; return; } string tag_cond( string t, mapping m, string c, RequestID id ) { mapping result = ([]);
36aaa12000-01-23Martin Nilsson  parse_html_lines(c,([]),(["case":internal_tag_case,
74747a1999-04-22Per Hedbor  "default":lambda(mixed ... a){ result->def = a[2]+"<false>"; }]),id,result); return result->res||result->def; }
b796b51998-11-18Per Hedbor mapping query_container_callers() { return ([
74747a1999-04-22Per Hedbor  "comment":lambda(){ return ""; }, "if":tag_if, "else":tag_else,
36aaa12000-01-23Martin Nilsson  "then":tag_then,
74747a1999-04-22Per Hedbor  "elseif":tag_elseif, "elif":tag_elseif, "noparse":tag_noparse, "nooutput":tag_nooutput, "case":tag_case, "cond":tag_cond,
c2dd2a1999-09-10Martin Nilsson  "strlen":tag_strlen,
b796b51998-11-18Per Hedbor  "define":tag_define,
74747a1999-04-22Per Hedbor  "trace":tag_trace, "use":tag_use,
b796b51998-11-18Per Hedbor  ]); } mapping query_tag_callers() { return ([
f3132f1999-07-20David Hedbor  "true":tag_true, "false":tag_false,
728f401999-02-16Marcus Comstedt  "number":tag_number,
b796b51998-11-18Per Hedbor  "undefine":tag_undefine,
36aaa12000-01-23Martin Nilsson  "help": tag_help
74747a1999-04-22Per Hedbor  ]); }
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)()); return entities_tag_set;
2127b42000-01-07Martin Stjernholm }
36aaa12000-01-23Martin Nilsson // ---------------------------- If callers -------------------------------
74747a1999-04-22Per Hedbor class UserIf { string rxml_code; void create( string what ) { rxml_code = what; }
36aaa12000-01-23Martin Nilsson 
50c7e41999-11-23Per Hedbor  string _sprintf() { return "UserIf("+rxml_code+")"; }
74747a1999-04-22Per Hedbor  int `()( string ind, RequestID id, mapping args, int and, string a ) {
e3d42b1999-08-16Martin Nilsson  int otruth, res; string tmp;
74747a1999-04-22Per Hedbor  TRACE_ENTER("user defined if argument &lt;"+a+"&gt;", UserIf);
e3d42b1999-08-16Martin Nilsson  otruth = LAST_IF_TRUE; LAST_IF_TRUE = -2; 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("");
e3d42b1999-08-16Martin Nilsson  if(ind==a && res!=-2) return res; return (ind==tmp); }
74747a1999-04-22Per Hedbor } class IfIs { string index; int cache, misc; function `() = match_in_map;
50c7e41999-11-23Per Hedbor  string _sprintf() { return "IfIS("+index+")"; }
74747a1999-04-22Per Hedbor  void create( string ind, int c, int|void m ) { index = ind; if(!ind) `() = match_in_string; cache = c; misc = m; } int match_in_string( string value, RequestID id ) { string is; if(!cache) CACHE(0); sscanf( value, "%s is %s", value, is ); if(!is) return strlen(value); value = lower_case( value ); is = lower_case( is );
c0d5461999-05-08Per Hedbor  return ((is==value)||glob(is,value)||
1f47d92000-01-30Per Hedbor  sizeof(filter( is/",", glob, value )));
74747a1999-04-22Per Hedbor  } int match_in_map( string value, RequestID id ) {
ff52db1999-08-07Martin Nilsson  string is,var;
74747a1999-04-22Per Hedbor  if(!cache) CACHE(0);
ff52db1999-08-07Martin Nilsson  array arr=value/" "; var = misc? id->misc[index][arr[0]] : id[index][arr[0]];
32f9451999-08-13Martin Nilsson  if(sizeof(arr)<2 || !var) return !!var;
fe538d1999-08-15David Hedbor  var = lower_case( (var+"") );
ff52db1999-08-07Martin Nilsson  if(sizeof(arr)==1) return !!var; is=lower_case(arr[2..]*" "); if(arr[1]=="==" || arr[1]=="=" || arr[1]=="is") return ((is==var)||glob(is,var)||
1f47d92000-01-30Per Hedbor  sizeof(filter( is/",", glob, var )));
ff52db1999-08-07Martin Nilsson  if(arr[1]=="!=") return (is!=var); if(arr[1]=="<") return ((int)var<(int)is); if(arr[1]==">") return ((int)var>(int)is);
e3d42b1999-08-16Martin Nilsson  value = misc?id->misc[index][value]:id[index][value]; return !!value;
74747a1999-04-22Per Hedbor  } } class IfMatch { string index; int cache, misc;
50c7e41999-11-23Per Hedbor  string _sprintf() { return "IfMatch("+index+")"; }
74747a1999-04-22Per Hedbor  void create(string ind, int c, int|void m) { index = ind; cache = c; misc = m; }
50c7e41999-11-23Per Hedbor 
53c6051999-11-22Henrik Grubbström (Grubba)  int `()( string is, RequestID id )
74747a1999-04-22Per Hedbor  { array|string value = misc?id->misc[index]:id[index]; if(!cache) CACHE(0); 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  } } int if_date( string date, RequestID id, mapping m ) {
8cbe091999-08-20Per Hedbor  CACHE(60); // One minute accuracy is probably good enough...
74747a1999-04-22Per Hedbor  int a, b; mapping c; c=localtime(time(1)); b=(int)sprintf("%02d%02d%02d", c->year, c->mon + 1, c->mday);
c4ccda1999-08-02Martin Nilsson  a=(int)replace(date,"-","");
74747a1999-04-22Per Hedbor  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; } int if_time( string ti, RequestID id, mapping m ) {
8cbe091999-08-20Per Hedbor  CACHE(time(1)%60); // minute resolution...
74747a1999-04-22Per Hedbor  int tok, a, b, d; mapping c; c=localtime(time());
36aaa12000-01-23Martin Nilsson 
74747a1999-04-22Per Hedbor  b=(int)sprintf("%02d%02d", c->hour, c->min);
c2dd2a1999-09-10Martin Nilsson  a=(int)replace(ti,":","");
74747a1999-04-22Per Hedbor  if(m->until) { d = (int)m->until; if (d > a && (b > a && b < d) ) return 1; if (d < a && (b > a || b < d) ) return 1; if (m->inclusive && ( b==a || b==d ) ) return 1; } else if(m->inclusive || !(m->before || m->after) && a==b) return 1; if(m->before && a>b) return 1; else if(m->after && a<b) return 1; } int match_passwd(string try, string org) { if(!strlen(org)) return 1; if(crypt(try, org)) return 1; } 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]); } }
f98e321999-11-29Per Hedbor int match_user(array u, string user, string f, int wwwfile, RequestID id)
74747a1999-04-22Per Hedbor { string s, pass;
36aaa12000-01-23Martin Nilsson  if(u[1]!=user)
74747a1999-04-22Per Hedbor  return 0; if(!wwwfile) s=Stdio.read_bytes(f); else s=id->conf->try_get_file(fix_relative(f,id), id);
8b5e3c1999-11-22Henrik Grubbström (Grubba)  return ((pass=simple_parse_users_file(s, u[1])) &&
74747a1999-04-22Per Hedbor  (u[0] || match_passwd(u[2], pass))); } 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; }
f98e321999-11-29Per Hedbor int group_member(array auth, string group, string groupfile, RequestID id)
74747a1999-04-22Per Hedbor { if(!auth) return 0; // No auth sent string s; catch { s = Stdio.read_bytes(groupfile); }; if (!s) s = id->conf->try_get_file( fix_relative( groupfile, id), id );
36aaa12000-01-23Martin Nilsson  if (!s)
74747a1999-04-22Per Hedbor  return 0; s = replace(s,({" ","\t","\r" }), ({"","","" })); multiset(string) members = simple_parse_group_file(s, group); return members[auth[1]]; } int if_user( string u, RequestID id, mapping m ) { if(!id->auth) return 0;
8cbe091999-08-20Per Hedbor  NOCACHE();
74747a1999-04-22Per Hedbor  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); } int if_group( string u, RequestID id, mapping m) {
8cbe091999-08-20Per Hedbor  if( !id->auth ) return 0;
74747a1999-04-22Per Hedbor  NOCACHE();
36aaa12000-01-23Martin Nilsson  return ((m->groupfile && sizeof(m->groupfile))
74747a1999-04-22Per Hedbor  && group_member(id->auth, m->group, m->groupfile, id)); }
bac4771999-07-27David Hedbor int if_exists( string u, RequestID id, mapping m) {
8cbe091999-08-20Per Hedbor  CACHE(5);
bac4771999-07-27David Hedbor  return id->conf->is_file(fix_relative(m->exists,id), id); }
74747a1999-04-22Per Hedbor mapping query_if_callers() { return ([
b1d7a61999-10-18Martin Nilsson  "true":lambda(string u, RequestID id){ return LAST_IF_TRUE; }, "false":lambda(string u, RequestID id){ return !LAST_IF_TRUE; },
74747a1999-04-22Per Hedbor  "accept":IfMatch( "accept", 0, 1), "config":IfIs( "config", 0 ), "cookie":IfIs( "cookies", 0 ), "client":IfMatch( "client", 0 ), "date":if_date,
dbe8d41999-05-19David Hedbor  "defined":IfIs( "defines", 1, 1 ),
74747a1999-04-22Per Hedbor  "domain":IfMatch( "host", 0 ),
bac4771999-07-27David Hedbor  "exists":if_exists,
74747a1999-04-22Per Hedbor  "group":if_group, "host":IfMatch( "remoteaddr", 0 ), "ip":IfMatch( "remoteaddr", 0 ), "language":IfMatch( "accept-language", 0, 1), "match":IfIs( 0, 0 ), "name":IfMatch( "client", 0 ), "pragma":IfIs( "pragma", 0 ), "prestate":IfIs( "prestate", 1 ), "referrer":IfMatch( "referrer", 0 ), "supports":IfIs( "supports", 0 ), "time":if_time, "user":if_user, "variable":IfIs( "variables", 1 ),
b796b51998-11-18Per Hedbor  ]); }
cce7142000-01-26Martin Nilsson  #endif mapping tagdocumentation() { Stdio.File file=Stdio.File(); if(!file->open(__FILE__,"r")) return 0; return compile_string("#define manual\n"+file->read())->tagdoc; } #ifdef manual
9ac3182000-01-27Kenneth Johansson constant tagdoc=([ "case":#"<desc cont> Alters the case of the contents. </desc> <attr name=lower> Changes all upper case letters to lower case. </attr> <attr name=upper> Changes all lower case letters to upper case. </attr> <attr name=capitalize> Capitalizes the first letter in the content. </attr>", "cond":#"<desc> </desc>", "comment":#"<desc cont> The enclosed text will be removed from the document. 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 view source. Another difference is that any RXML tags inside this container will not be parsed. </desc>", "define":#"<desc cont> Defines variables, tags, containers, if-callers. One, and only one, 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> Trim all white space characters fromt the begining and the end of the contents. </attr>
9ac3182000-01-27Kenneth Johansson  When defining a container the tag <tag>contents</tag> can be used to insert the contents of the defined container. <p>When defining a tag or a container the container <tag>attrib</tag> can be used to define default values of the attributes that the tag/container can have. The attrib container has the attribute attrib=name, and sets the default value of the attribute indicated with attrib=name to the contents of the attrib container. The
0d87d72000-01-30Martin Nilsson  attribute values can be accessed with enteties such as &amp;name;</p>",
9ac3182000-01-27Kenneth Johansson  "elif":#"<desc cont> Shows its content if the truth-value is false and the criterions in its attributes are met. Uses the same syntax as <tag><ref type=cont>if</ref><tag>. Sets the truth-value in the same way as if. </desc>", "else":#"<desc cont> Show the contents if the previous <tag><ref type=cont>if</ref></tag> tag didn't, or if there was a <tag><ref type=tag>false</ref></tag> above. The result is undefined if there has been no <tag><ref type=cont>if</ref></tag>, <true> or <tag><ref type=tag>false</ref></tag> tag above. </desc>", "elseif":#"<desc cont> Same as the <tag><ref type=cont>if</ref></tag>, but it will only evaluate if the previous <tag><ref type=cont>if</ref></tag> tag returned false. </desc>", "false":#"<desc tag> Internal tag used to set the return value of <tag><ref type=cont>if</ref></tag> tags. It will ensure that the next <tag><ref type=cont>else</ref></tag> tag will show its contents. It can be useful if you are writing your own <tag><ref type=cont>if</ref></tag> lookalike tag. </desc>", "help":#"<desc tag> Gives help texts for tags. If given no arguments, it will list all available tags. </desc> <attr name=for value=tag> Gives the help text for that tag. </attr> <ex>help for=modified</ex>", "if":#"<desc cont> <tag><ref type=cont>if</ref></tag> is used to conditionally show its contents. <tag><ref type=cont>else</ref></tag>, <tag><ref type=cont>elif</ref></tag> or <tag><ref type=cont>elseif</ref></tag> can be used to suggest alternative content. 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 trainfork or tfo. </desc> <attr name=not> Inverts the result (true->false, false->true). </attr> <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. </attr> if-caller In the rxml.pike file the main if functionality is defined. There are two main types of if callers defined in rxml.pike,\"IfIs\" and \"IfMatch\". If the if caller is of an IfMatch type the if statement will be matched as a glob, i.e. * is considered a multicharacter wildcard. E.g. <tag><ref type=cont>if ip=\"130.236.*\"</ref></tag>Your domain is liu.se<tag><ref type=cont>/if</ref></tag>. If the if caller is of an IfIs type the if statement will be compared with one of the following operators is, =, ==, !=, &lt; and &gt. The operators is, = and == are the same. E.g. <tag><ref type=cont>if variable=\"x &gt; 5\"</ref></tag>More than one hand<tag><ref type=cont/if</ref></tag>", "true":#"<desc if-caller> This will always be true if the truth value is set to be true. Equivalent with <tag><ref type=cont>then</ref></tag>. </desc>", "false":#"<desc if-caller> This will always be true if the truth value is set to be false. Equivalent with <tag><ref type=cont>else</ref></tag>. </desc>", "accept":#"<desc if-caller> Returns true is the browser accept certain content types as specified by it's Accept-header, for example image/jpeg or text/html. If browser states that it accepts */* that is not taken in to account as this is always untrue. Accept is an IfMatch if caller. </desc>", "config":#"<desc if-caller> Has the config been set by use of the <tag><ref type=cont>aconf</ref></tag> tag? (Config is an IfIs if caller, although that functionality does not apply here.). </desc>", "cookie":#"<desc if-caller> Does the cookie exist and if a value is given, does it contain that value? Cookie is av IfIs if caller. </desc>", "client and name":#"<desc if-caller> Compares the user agent string with a pattern. Client and name is an IfMatch if caller. </desc>", "date":#"<desc if-caller> Is the date yyyymmdd? The attributes before, after and inclusive modifies the behavior. </desc> <attr name=after> </attr> <attr name=before> </attr> <attr name=inclusive> </attr>", "defined":#"<desc if-caller> Tests if a certain define is defined? Defined is an IfIs if caller. </desc>", "domain":#"<desc if-caller> Does the user'\s computer'\s DNS name match any of the patterns? Note that domain names are resolved asynchronously, and the the first time someone accesses a page, the domain name will probably not have been resolved. Domain is an IfMatch if caller. </desc>", "exists":#"<desc if-caller> Returns true if the file path exists. If path does not begin with /, it is assumed to be a URL relative to the directory containing the page with the <tag><ref type=cont>if</ref></tag>-statement. </desc>", "expr":#"<desc if-caller> Evaluates expressions. The following characters may be used: \"1, 2, 3, 4, 5, 6, 7, 8, 9, x, a, b, c, d, e, f, n, t, \, X. A, B, C, D, E, F, l, o, &lt;, &gt;, =, 0, -, +, /, %, &, |, (, )\". </desc>", "group":#"<desc if-caller> Checks if the current user is a member of the group according the groupfile. </desc>", "host and ip":#"<desc if-caller> Does the users computers IP address match any of the patterns? Host and ip are IfMatch if callers. </desc>", "language":#"<desc if-caller> Does the client prefer one of the languages listed, as specified by the Accept-Language header? Language is an IfMatch if caller. </desc>", "match":#"<desc if-caller> Does the string match one of the patterns? Match is an IfMatch if caller. </desc>", "pragma":#"<desc if-caller> Compares the pragma with a string. Pragma is an IfIs if caller. </desc>", "prestate":#"<desc if-caller> Are all of the specified prestate options present in the URL? Prestate is an IfIs if caller. </desc>", "referrer":#"<desc if-caller> Does the referrer header match any of the patterns? Referrer is an IfMatch if caller. </desc>", "supports":#"<desc if-caller> Does the browser support this feature? Supports is an IfIs if caller. </desc> <attr name=activex> The browser handles active-X contents. </attr> <attr name=align> The browser supports the align attribute in its tags. </attr> <attr name=autogunzip> The browser can decode a gunzipped file on the fly. </attr> <attr name=backgrounds> The browser supports backgrounds according to the HTML3 specifications. </attr> <attr name=bigsmall> The browser supports the <tag>big</tag> and <tag>small</tag> tags. </attr> <attr name=center> The browser supports the <tag>center</tag> tag. </attr> <attr name=cookies> The browser can receive cookies. </attr> <attr name=divisions> The browser supports <tag>div align=...</tag>. </attr> <attr name=div> Same as divisions. </attr> <attr name=epsinline> The browser can show encapsulated postscript files inline. </attr> <attr name=font> The browser supports <tag>font size=num</tag>. </attr> <attr name=fontcolor> The browser can change color of individual characters. </attr> <attr name=fonttype> The browser can set the font. </attr> <attr name=forms> The browser supports forms according to the HTML 2.0 and 3.0 specifications. </attr> <attr name=frames> The browser supports frames. </attr> <attr name=gifinline> The browser can show GIF images inlined. </attr> <attr name=html> This is a HTML browser (as opposed to e.g. a WAP browser). </attr> <attr name=imagealign> The browser supports align=left and align=right in images. </attr> <attr name=images> The browser can display images. </attr> <attr name=java> The browser supports Java applets. </attr> <attr name=javascript> The browser supports Java Scripts. </attr> <attr name=javascript1.2> The browser supports Java Scripts version 1.2. </attr> <attr name=jpeginline> The browser can show JPEG images inlined. </attr> <attr name=mailto> The browser supports mailto URLs. </attr> <attr name=math> The <tag>math</tag> tag is correctly displayed by the browser. </attr> <attr name=msie> This is a Microsoft Internet Explorer browser. </attr> <attr name=netscape_javascript> The browser needs netscape styled javascript. </attr> <attr name=perl> The browser supports Perl applets. </attr> <attr name=phone> The client is a phone. </attr> <attr name=pjpeginline> The browser can handle progressive JPEG images, .pjpeg, inline. </attr> <attr name=pnginline> The browser can handle PNG images inlined. </attr> <attr name=pull> The browser handles Client Pull. </attr> <attr name=push> The browser handles Server Push. </attr> <attr name=python> The browser supports Python applets. </attr> <attr name=requests_are_utf8_encoded> The requests are UTF8 encoded. </attr> <attr name=robot value=name ot the searchengine> The request really comes from a search robot, not an actual browser. <p>Examples of robots are: architex, backrub, checkbot, fast, freecrawl, passagen, gcreep, googlebot, harvest, alexa, infoseek, intraseek, lycos, webinfo, roxen, altavista, scout, hotbot, url-minder, webcrawler, wget, xenu, yahoo, unknown. For more information search in the &lt;roxen-dir&gt;/server/etc/supports file.</p> </attr> <attr name=ssl> The browser handles secure sockets layer. </attr> <attr name=stylesheets> The browser supports stylesheets. </attr> <attr name=supsub> The browser handles <sup> and <sub> tags correctly. </attr> <attr name=tables> The browser handles tables according to the HTML3.0 specification. </attr> <attr name=tablecolor> It is possible to set the background color in the browser. </attr> <attr name=tableimages> It is possible to set a backgroud image in a table in the browser. </attr> <attr name=tcl> The browser supports TCL applets. </attr> <attr name=unknown> The browser is not known, hence the supports classes can not be trusted. </attr> <attr name=vrml> The browser supports VRML </attr> <attr name=wbmp0> The browser supports Wireless Bitmap Picture Format, type 0. </attr> <attr name=wml1.0> The browser supports Wireless Markup Language 1.0. </attr> <attr name=wml1.1> The browser supports Wireless Markup Language 1.1. </attr> Other supports variables are: <p>Width - The presentation area width in pixels.<br> Height - The presentation area height in pixels.</p>", "time":#"<desc if-caller> Is the date ttmm? The attributes before, after and inclusive modifies the behavior. The attributes are used in the same fashion as with the date if-caller. </desc>", "user":#"<desc if-caller> Has the user been authenticated as one of these users? If any is given as argument, any authenticated user will do. </desc>", "variable":#"<desc if-caller> Does the variable exist and, optionally, does it's content match the pattern? Variable is an IfIs if-caller. </desc>", "nooutput":#"<desc cont> The contents will not be sent through to the page. Side effects, for example sending queries to databases, will take effect. </desc>", "noparse":#"<desc cont> The contents of this container tag won't be RXML parsed. </desc>", "number":#"<desc tag> Prints a number as a word. </desc> <attr name=num value=number> Print this number. </attr> <attr name=language value=ca, es_CA, hr, cs, nl, en, fi, fr, de, hu, it, jp, mi, no, pt, ru, sr, si, es, sv> The language to use. Available languages are ca, es_CA (Catala), hr (Croatian), cs (Czech), nl (Dutch), en (English), fi (Finnish), fr (French), de (German), hu (Hungarian), it (Italian), jp (Japanese), mi (Maori), no (Norwegian), pt (Portuguese), ru (Russian), sr (Serbian), si (Slovenian), es (Spanish) and sv (Swedish). </attr> <attr name=type value=foo> Default is number. What more??????????????? </attr>", "strlen":#"<desc cont> Returns the length of the contents. Strlen can be used with <tag><ref type=cont>if eval=...</ref></tag> to test the length of variables. </desc>", "then":#"<desc cont> Shows its content if the truth-value is true. </desc>", "trace":#"<desc cont> Executes the contained RXML code and makes a trace report about how the contents are parsed by the RXML parser. </desc>", "true":#"<desc tag> An internal tag used to set the return value of tag><ref type=cont>if</ref></tag> tags. It will ensure that the next tag><ref type=cont>else</ref></tag> tag will not show its contents. It can be useful if you are writing your own tag><ref type=cont>if</ref></tag> lookalike tag. </desc>", "undefine":#"<desc tag> Removes a definition made by the define container. One attribute is required. </desc> <attr name=variable value=name> Undefines this variable. </attr> <attr name=tag value=name> Undefines this tag. </attr> <attr name=container value=name> Undefines this container. </attr> <attr name=if value=name> Undefines this if-caller. </attr>", "use":#"<desc cont> Reads tags, container tags and defines from a file or package. </desc> <attr name=packageinfo> Show a all available packages. <ex><use packageinfo></ex> </attr> <attr name=package value=name> Reads all tags, container tags and defines from the given package. Packages are files located in local/rxml_packages/. <p>By default, the package gtext_headers is available, that replaces normal headers with graphical headers. It redefines the h1, h2, h3, h4, h5 and h6 container tags.</p> </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 not want this cache, use <tag><ref type=tag>insert file=... nocache</ref></tag> instead.</p> </attr> <attr name=info> Show a list of all defined tags/containers and if arguments in the file </attr> The <tag><ref type=tag>use</ref></tag> tag is much faster than the <tag><ref type=tag>insert</ref></tag>, since the parsed definitions is cached.", ]);
cce7142000-01-26Martin Nilsson #endif