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>
b191f02000-08-09Per Hedbor constant cvs_version = "$Id: piketag.pike,v 2.12 2000/08/09 07:35:28 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.";
6540372000-08-09Per Hedbor 
ea72a61999-11-27Per Hedbor 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 { string data = ""; void output(mixed ... args) {
6540372000-08-09Per Hedbor  write( @args );
ea72a61999-11-27Per Hedbor  }
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; }
6540372000-08-09Per Hedbor  string rxml( string what )
3aca382000-08-09Per Hedbor  {
6540372000-08-09Per Hedbor  return Roxen.parse_rxml( what, RXML.get_context()->id );
3aca382000-08-09Per Hedbor  }
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; }
6540372000-08-09Per Hedbor class HProtos
ea72a61999-11-27Per Hedbor {
6540372000-08-09Per Hedbor  void output(mixed ... args); void write(mixed ... args); string flush(); string rxml( string what, object id ); constant seteuid=0; constant setegid=0; constant setuid=0; constant setgid=0; constant call_out=0; constant all_constants=0; constant Privs=0;
ea72a61999-11-27Per Hedbor }
6540372000-08-09Per Hedbor string helpers()
ea72a61999-11-27Per Hedbor {
6540372000-08-09Per Hedbor  add_constant( "__ps_magic_helpers", Helpers ); add_constant( "__ps_magic_protos", HProtos ); return "inherit __ps_magic_helpers;\nimport Roxen;\n";
ea72a61999-11-27Per Hedbor }
6540372000-08-09Per Hedbor string helper_prototypes( )
ea72a61999-11-27Per Hedbor {
6540372000-08-09Per Hedbor  return "inherit __ps_magic_protos;\nimport Roxen;\n";
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 ); }
6540372000-08-09Per Hedbor string read_roxen_file( string what, object id )
ea72a61999-11-27Per Hedbor {
6540372000-08-09Per Hedbor  // let there be magic return id->conf->open_file(Roxen.fix_relative(what,id),"rR",id,1) ->read()[0]; }
9266a32000-08-09Per Hedbor 
3aca382000-08-09Per Hedbor 
6540372000-08-09Per Hedbor #define PS(X) (compile_string( "mixed foo(){ return "+(X)+";}")()->foo()) #define SPLIT(X) Parser.C.hide_whitespaces(Parser.C.tokenize(Parser.C.split(X)))
3aca382000-08-09Per Hedbor #define OCIP( ) \ if( cip ) \ { \
6540372000-08-09Per Hedbor  cip->text=sprintf("write(rxml(%O));",cip->text); \
3aca382000-08-09Per Hedbor  cip = 0; \ } #define OCIPUP( ) \ if( cipup ) \ { \ cipup->text=sprintf("write(%O);",cipup->text); \ cipup = 0; \ }
b191f02000-08-09Per Hedbor #define CIP(X) if( X ) \
3aca382000-08-09Per Hedbor  { \ X->text += flat[i]->text[3..]+"\n"; \
b191f02000-08-09Per Hedbor  flat[i]->text=flat[i]->trailing_whitespaces=""; \
3aca382000-08-09Per Hedbor  } \ else \ { \ X = flat[i]; \ flat[i]->text = flat[i]->text[3..]+"\n"; \ }
6540372000-08-09Per Hedbor #define R(X) Parser.C.simple_reconstitute(X)
9266a32000-08-09Per Hedbor 
6540372000-08-09Per Hedbor program my_compile_string(string s, object id, int dom, string fn) { if( program_cache[ s ] ) return program_cache[ s ]; object key = Roxen.add_scope_constants(); [array ip, array data] = parse_magic(s,id,dom); if( !fn )fn = "pike-tag("+id->not_query+")"; int cnt; string pre; if( !id->misc->__added_helpers_in_tree && !sizeof(ip)) { id->misc->__added_helpers_in_tree=1; pre = helpers(); } else pre = helper_prototypes(); foreach( ip, program ipc ) { add_constant( "____ih_"+cnt, ipc ); pre += "inherit ____ih_"+cnt++ + ";\n"; } program p = compile_string(pre+R(data), fn); program_cache[ s ] = p;
3aca382000-08-09Per Hedbor 
6540372000-08-09Per Hedbor  cnt=0; foreach( ip, program ipc ) add_constant( "____ih_"+cnt++, 0 ); destruct( key ); return p; }
ea72a61999-11-27Per Hedbor 
6540372000-08-09Per Hedbor program handle_inherit( string what, RequestID id ) { array err; // ouch ouch ouch. return my_compile_string( read_roxen_file( what, id ),id,0,0); } array parse_magic( string data, RequestID id, int add_md ) { array flat=SPLIT(data); object cip, cipup; array inherits = ({}); for( int i = 0; i<sizeof( flat ); i++ ) { switch( strlen(flat[i]->text) && flat[i]->text[0] )
ea72a61999-11-27Per Hedbor  {
6540372000-08-09Per Hedbor  case 'i': OCIP(); OCIPUP(); if( flat[i] == "inherit" ) { flat[i]->text=""; int start = ++i; while( flat[++i] != ";" ) ; inherits += ({ handle_inherit( PS(R(flat[start..i])), id ) }); flat = flat[..start-1] + flat[i+1..]; i = start; } break; case 'p': OCIP(); OCIPUP(); if( flat[i] == "parse" && flat[i+1] == "(") add_md = 0; break; case '.': OCIP(); OCIPUP(); if( flat[i] == "." && flat[++i] != "." ) // Parser.C in 7.0 does not flat[i-1]->text = "->"; // recognize .. as a single token. break; case '/': if( flat[i]->text[..2] == "//#" ) { OCIPUP(); CIP( cip ); } else if( flat[i]->text[..2] == "//@" ) { OCIP(); CIP( cipup ); } else { OCIPUP(); OCIP(); } break; case '#': OCIP(); OCIPUP(); if( sscanf( flat[i]->text, "#include%s", string fn) ) { sscanf( fn, "%*s<%s>", fn ); sscanf( fn, "%*s\"%s\"", fn ); [array ih,flat[i]] = parse_magic(read_roxen_file(fn,id), id, 0); inherits += ih; } break; default: OCIP(); OCIPUP(); } } OCIP(); OCIPUP(); if( add_md ) { flat =SPLIT( "string|int parse(RequestID id)\n{\n" ) + flat + SPLIT( "}\n" ); } return ({ inherits, flat }); }
9266a32000-08-09Per Hedbor 
6540372000-08-09Per Hedbor // Compile and run the contents of the tag (in s) as a pike // program. string simpletag_pike(string tag, mapping m, string s,RequestID request_id ) { program p; object o; string res; mixed err;
3257512000-08-09Per Hedbor 
6540372000-08-09Per Hedbor  request_id->misc->__added_helpers_in_tree=0; request_id->misc->cacheable=0;
ea72a61999-11-27Per Hedbor 
6540372000-08-09Per Hedbor  object e = ErrorContainer(); master()->set_inhibit_compile_errors(e); if(err=catch { p = my_compile_string( s,request_id,1,0 ); if (sizeof(program_cache) > query("program_cache_limit")) { array a = indices(program_cache); int i; // Zap somewhere between 25 & 50% of the cache. for(i = query("program_cache_limit")/2; i > 0; i--) m_delete(program_cache, a[random(sizeof(a))]);
ea72a61999-11-27Per Hedbor  } }) { master()->set_inhibit_compile_errors(0);
6540372000-08-09Per Hedbor  return reporterr(sprintf("Error handling <pike> tag in %s:\n%s\n" "%s\n\n", request_id->not_query, s, describe_backtrace(err[..1])),
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; }