---
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.
+// <<srb[at]cuci.nl>>
+//
+// 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:<srb[at]cuci.nl>'>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 <<srb[at]cuci.nl>>");
+}
+
+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]?():0; // strip one colon per pass
+ }
+ else if(!ctx->get_scope(cscope))
+ return cscope[0]==':'?():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 ();
+ });
+
+ 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
|