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>
3aca382000-08-09Per Hedbor constant cvs_version = "$Id: piketag.pike,v 2.10 2000/08/09 05:15:43 per 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]; }
3257512000-08-09Per Hedbor  void write(mixed ... args) { if(!sizeof(args)) return; if(sizeof(args) > 1) data += sprintf(@args); else data += args[0]; }
ea72a61999-11-27Per Hedbor  string flush() { string r = data; data =""; return r; }
3aca382000-08-09Per Hedbor  string rxml( string what, object id ) { return parse_rxml( what, id ); }
ea72a61999-11-27Per Hedbor  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) {
3257512000-08-09Per Hedbor  add_constant( "__ps_magic_helpers", Helpers ); return "inherit __ps_magic_helpers;\n" + "#"+line+" \""+replace(page,"\"","\\\"")+"\"\n";
ea72a61999-11-27Per Hedbor } // Preamble
9266a32000-08-09Per Hedbor string pre(array fl, object id)
ea72a61999-11-27Per Hedbor {
9266a32000-08-09Per Hedbor  foreach( fl, object token ) if( token == "parse" ) return functions(id->not_query, id->misc->line); return functions(id->not_query, id->misc->line) + "string|int parse(RequestID id) { ";
ea72a61999-11-27Per Hedbor } // Will be added at the end...
9266a32000-08-09Per Hedbor string post(array fl)
ea72a61999-11-27Per Hedbor {
9266a32000-08-09Per Hedbor  foreach( fl, object token ) if( token == "parse" ) return "";
3257512000-08-09Per Hedbor  return "}";
ea72a61999-11-27Per Hedbor } private static mapping(string:program) program_cache = ([]);
3257512000-08-09Per Hedbor string simple_pi_tag_pike( string tag, mapping m, string s,RequestID id ) { return simpletag_pike( tag, ([]), s, id ); }
ea72a61999-11-27Per Hedbor // Compile and run the contents of the tag (in s) as a pike // program.
3257512000-08-09Per Hedbor string simpletag_pike(string tag, mapping m, string s,RequestID request_id )
ea72a61999-11-27Per Hedbor { program p; object o; string res; mixed err; request_id->misc->cacheable=0;
9266a32000-08-09Per Hedbor  array flat=Parser.C.hide_whitespaces(Parser.C.tokenize(Parser.C.split(s)));
ea72a61999-11-27Per Hedbor  object e = ErrorContainer(); master()->set_inhibit_compile_errors(e); if(err=catch {
3aca382000-08-09Per Hedbor  object cip, cipup; #define OCIP( ) \ if( cip ) \ { \ cip->text=sprintf("write(rxml(%O,id));",cip->text); \ cip = 0; \ } #define OCIPUP( ) \ if( cipup ) \ { \ cipup->text=sprintf("write(%O);",cipup->text); \ cipup = 0; \ } #define CIP(X) if( X ) \ { \ flat[i]->text=flat[i]->trailing_whitespaces=""; \ X->text += flat[i]->text[3..]+"\n"; \ } \ else \ { \ X = flat[i]; \ flat[i]->text = flat[i]->text[3..]+"\n"; \ }
9266a32000-08-09Per Hedbor 
3aca382000-08-09Per Hedbor  for( int i = 0; i<sizeof( flat ); i++ ) { if( flat[i] == "." && flat[++i] != "." ) // Parser.C in 7.0 does not flat[i-1]->text = "->"; // recognize .. as a single token. else if( flat[i]->text[..2] == "//#" ) { OCIPUP(); CIP( cip ); } else if( flat[i]->text[..2] == "//@" ) { OCIP(); CIP( cipup ); } else { OCIP(); OCIPUP(); } } OCIP(); OCIPUP(); s = pre(flat,request_id)+"\n"+ Parser.C.simple_reconstitute( flat )+ post(flat);
ea72a61999-11-27Per Hedbor  p = program_cache[s]; if (!p) { // Not in the program cache.
3257512000-08-09Per Hedbor  object key = Roxen.add_scope_constants();
9266a32000-08-09Per Hedbor 
ea72a61999-11-27Per Hedbor  p = compile_string(s, "Pike-tag("+request_id->not_query+":"+ request_id->misc->line+")");
3257512000-08-09Per Hedbor  destruct( key );
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"
3257512000-08-09Per Hedbor  "%s\n\n", request_id->not_query, s),
ea72a61999-11-27Per Hedbor  e->get()); } master()->set_inhibit_compile_errors(0); if(err = catch{
3257512000-08-09Per Hedbor  res = (o=p())->parse(request_id);
ea72a61999-11-27Per Hedbor  }) { 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; }