--- server/modules/tags/expandvariables.pike | 146 ++++++++++++++++++++++++++++++ 1 files changed, 146 insertions(+), 0 deletions(-) create mode 100644 server/modules/tags/expandvariables.pike
diff --git a/server/modules/tags/expandvariables.pike b/server/modules/tags/expandvariables.pike new file mode 100644 index 0000000..eaf5fe6 --- /dev/null +++ b/server/modules/tags/expandvariables.pike @@ -0,0 +1,146 @@ +// This is a roxen module which provides controlled variable expansion +// capabilities. +// Copyright (c) 2004-2009, Stephen R. van den Berg, The Netherlands. +// <[email protected]> +// +// This module is open source software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2, or (at your option) any +// later version. +// + +//<locale-token project="mod_expandvariables">_</locale-token> +#define _(X,Y) _DEF_LOCALE("mod_expandvariables",X,Y) + +constant thread_safe = 1; + +#include <module.h> + +inherit "module"; + +// ---------------- Module registration stuff ---------------- + +constant module_type = MODULE_TAG; +LocaleString module_name = _(1,"Tags: Expand variables"); +LocaleString module_doc = _(2, + "This module provides the expand-variables RXML tag.<br />" + "<p>Copyright © 2004-2009, by " + "<a href='mailto:[email protected]'>Stephen R. van den Berg</a>, " + "The Netherlands.</p>" + "<p>This module is open source software; you can redistribute it and/or " + "modify it under the terms of the GNU General Public License as published " + "by the Free Software Foundation; either version 2, or (at your option) any " + "later version.</p>"); + +void create() +{ + set_module_creator("Stephen R. van den Berg <[email protected]>"); +} + +static mapping(string:int) replacecounts=([]); + +string status() { + string s="<tr><td colspan=2>None yet</td></tr>"; + if(sizeof(replacecounts)) + { s=""; + foreach(sort(indices(replacecounts)),string scope) + s+=sprintf("<tr><td>%s</td><td align=right>%d</td></tr>", + scope,replacecounts[scope]); + } + return _(5,"<table border=1><tr><th>Scope</th><th>Substitutions</th></tr>"+ + s+"</table>"); +} + +#define IS(arg) ((arg) && sizeof(arg)) + +// ------------------- Containers ---------------- + +class TagExpandVariables +{ + inherit RXML.Tag; + constant name = "expand-variables"; + + mapping(string:RXML.Type) req_arg_types = ([ + ]); + mapping(string:RXML.Type) opt_arg_types = ([ + "scope":RXML.t_text(RXML.PEnt), + "from":RXML.t_text(RXML.PEnt), + ]); + + class Frame + { + inherit RXML.Frame; + + array do_return(RequestID id) + { + RXML.Context ctx = RXML_CONTEXT; + multiset scope; + result = IS(args->from)?ctx->user_get_var(args->from):content||""; + + if(IS(args->scope)) + scope = mkmultiset(args["scope"]/","); + Parser.HTML p = Parser.HTML(); + //p->mixed_mode(1); DO NOT USE THIS, mayhem lies ahead + p->ignore_tags(1); + p->lazy_entity_end(1); + p->_set_entity_callback(lambda(Parser.HTML p,string ent) + { int i; + string s=p->tag_name(); + if((i=search(s,"."))<1) + return 0; // exit early if no scope present + string cscope=s[..i-1]; + s=s[i+1..]; + if(scope) + { if(!scope[cscope]) + return cscope[0]==':' + && 2==sscanf(cscope,":%*[:]%[^:]",cscope) + && scope[cscope]?({"&"+ent[2..]}):0; // strip one colon per pass + } + else if(!ctx->get_scope(cscope)) + return cscope[0]==':'?({"&"+ent[2..]}):0; + else if(2!=sscanf(s+";;","%*[-.:a-zA-Z0-9];%*c")) + return 0; + string encoding; + sscanf(s,"%[^:]:%s",s,encoding); + array splitted=ctx->parse_user_var(s,cscope); + s=ctx->get_var(splitted[1..],cscope)||""; + replacecounts[cscope]++; + return ({encoding?Roxen.roxen_encode(s,encoding):s}); + }); + + if(!stringp(result)) + if(!arrayp(result)) + result = ""; + result=p->finish(result)->read(); + + return 0; + } + } +} + +// --------------------- Documentation ----------------------- + +TAGDOCUMENTATION; +#ifdef manual +constant tagdoc=([ +"expand-variables":#"<desc type='cont'><p><short hide='hide'> + Expand certain scopes only.</short>The <expand-variables> + tag allows one to specify which scopes to parse and expand, while + leaving all other entities and tags untouched.</p> +<p> + The tag is intended for situations where external data needs to be parsed + for certain entities only, not affecting RXML code nor other + entities/variables. +</p></desc> + +<attr name='scope' value='list'><p> + Comma-separated array of scopes to expand. If omitted, all known scopes + are parsed and replaced.</p> +</attr> + +<attr name='from'><p> + Variable to use as source instead of the content of the container.</p> +</attr> +", + ]); +#endif
