1430c02000-03-16Martin Nilsson // This is a roxen module. Copyright © 1996 - 2000, Roxen IS.
ea72a61999-11-27Per Hedbor // // Adds support for inline pike in documents. // // Example: // <pike> // return "Hello world!\n"; // </pike>
e123c72000-07-17Johan Sundström constant cvs_version = "$Id: piketag.pike,v 2.7 2000/07/17 19:18:39 jhs Exp $";
ea72a61999-11-27Per Hedbor constant thread_safe=1; inherit "module";
e123c72000-07-17Johan Sundström #include <module.h>
ea72a61999-11-27Per Hedbor  constant module_type = MODULE_PARSER; constant module_name = "Pike tag"; constant module_doc = #"This module adds a new tag, &lt;pike&gt;&lt;/pike&gt;. It makes it
1973552000-02-10Martin Nilsson possible to insert some pike code directly in the document. <br> <img src=\"internal-roxen-err_2\" align=\"left\" alt=\"Warning\"> <br>NOTE: Enabling this
ea72a61999-11-27Per Hedbor module is the same thing as letting your users run programs with the same right as the server! Example:<p><pre> &lt;pike&gt; return \"Hello world!\\n\"; &lt;/pike&gt;\n</pre> <p>Arguments: Any, all arguments are passed to the script in the mapping args. There are also a few helper functions available, output(string fmt, mixed ... args) is a fast way to add new data to a dynamic buffer, flush() returns the contents of the buffer as a string. A flush() is done automatically if the script does not return any data, thus, another way to write the hello world script is <tt>&lt;pike&gt;output(\"Hello %s\n\", \"World\");&lt/pike&gt</tt><p> The request id is available as id."; void create() { defvar ( "debugmode", "Log", "Error messages", TYPE_STRING_LIST | VAR_MORE, "How to report errors (e.g. backtraces generated by the Pike code):\n" "\n" "<p><ul>\n"
4f641b2000-07-03Martin Nilsson  "<li><i>Off</i> - Silent.</li>\n" "<li><i>Log</i> - System debug log.</li>\n" "<li><i>HTML comment</i> - Include in the generated page as an HTML comment.</li>\n" "<li><i>HTML text</i> - Include in the generated page as normal text.</li>\n"
ea72a61999-11-27Per Hedbor  "</ul>\n", ({"Off", "Log", "HTML comment", "HTML text"})); defvar("program_cache_limit", 256, "Program cache limit", TYPE_INT|VAR_MORE, "Maximum size of the cache for compiled programs."); } string reporterr (string header, string dump) {
4f641b2000-07-03Martin Nilsson  if (query("debugmode") == "Off") return "";
ea72a61999-11-27Per Hedbor  report_error( header + dump + "\n" );
4f641b2000-07-03Martin Nilsson  switch (query("debugmode"))
ea72a61999-11-27Per Hedbor  { case "HTML comment":
4f641b2000-07-03Martin Nilsson  return "\n<!-- " + Roxen.html_encode_string(header + dump) + "\n-->\n";
ea72a61999-11-27Per Hedbor  case "HTML text":
4f641b2000-07-03Martin Nilsson  return "\n<br><font color=\"red\"><b><pre>" + Roxen.html_encode_string (header) + "</b></pre></font><pre>\n"+Roxen.html_encode_string (dump) + "</pre><br />\n";
ea72a61999-11-27Per Hedbor  default: return ""; } } // Helper functions, to be used in the pike script. class Helpers {
4d2fc41999-12-21Per Hedbor  inherit "roxenlib";
ea72a61999-11-27Per Hedbor  string data = ""; void output(mixed ... args) { if(!sizeof(args)) return; if(sizeof(args) > 1) data += sprintf(@args); else data += args[0]; } string flush() { string r = data; data =""; return r; } constant seteuid=0; constant setegid=0; constant setuid=0; constant setgid=0; constant call_out=0; constant all_constants=0; constant Privs=0; } string functions(string page, int line) { add_constant( "__magic_helpers", Helpers ); return "inherit __magic_helpers;\n" "#"+line+" \""+replace(page,"\"","\\\"")+"\"\n"; } // Preamble string pre(string what, object id) { if(search(what, "parse(") != -1) return functions(id->not_query, id->misc->line); if(search(what, "return") != -1) return functions(id->not_query, id->misc->line) + "string|int parse(RequestID id, mapping defines, object file, mapping args) { "; else return functions(id->not_query, id->misc->line) + "string|int parse(RequestID id, mapping defines, object file, mapping args) { return "; } // Will be added at the end... string post(string what) { if(search(what, "parse(") != -1) return ""; if (!strlen(what) || what[-1] != ';') return ";}"; else return "}"; } private static mapping(string:program) program_cache = ([]); // Compile and run the contents of the tag (in s) as a pike // program. string container_pike(string tag, mapping m, string s, RequestID request_id, object file, mapping defs) { program p; object o; string res; mixed err; request_id->misc->cacheable=0; object e = ErrorContainer(); master()->set_inhibit_compile_errors(e); if(err=catch { s = pre(s,request_id)+s+post(s); p = program_cache[s]; if (!p) { // Not in the program cache. p = compile_string(s, "Pike-tag("+request_id->not_query+":"+ request_id->misc->line+")");
4f641b2000-07-03Martin Nilsson  if (sizeof(program_cache) > query("program_cache_limit"))
ea72a61999-11-27Per Hedbor  { array a = indices(program_cache); int i; // Zap somewhere between 25 & 50% of the cache.
4f641b2000-07-03Martin Nilsson  for(i = query("program_cache_limit")/2; i > 0; i--)
ea72a61999-11-27Per Hedbor  m_delete(program_cache, a[random(sizeof(a))]); } program_cache[s] = p; } }) { master()->set_inhibit_compile_errors(0); return reporterr(sprintf("Error compiling <pike> tag in %s:\n" "%s\n\n", request_id->not_query, s), e->get()); } master()->set_inhibit_compile_errors(0); if(err = catch{ res = (o=p())->parse(request_id, defs, file, m); }) { return (res || "") + (o && o->flush() || "") + reporterr ("Error in <pike> tag in " + request_id->not_query + ":\n", (describe_backtrace (err) / "\n")[0..1] * "\n"); } res = (res || "") + (o && o->flush() || ""); if(o) destruct(o); return res; }