|
|
|
|
|
|
|
|
|
constant cvs_version = "$Id: piketag.pike,v 2.13 2000/08/09 11:12:42 per Exp $"; |
constant thread_safe=1; |
|
|
#if constant(Parser.C) |
#define PARSER_C Parser.C |
#else |
#define PARSER_C Roxen.Parser.C |
#endif |
|
|
inherit "module"; |
#include <module.h> |
|
constant module_type = MODULE_PARSER; |
constant module_name = "Pike tag"; |
constant module_doc = |
#"This module adds a new tag, <pike></pike>. It makes it |
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 |
module is the same thing as letting your users run programs with the |
same right as the server! Example:<p><pre> <pike> return |
\"Hello world!\\n\"; </pike>\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><pike>output(\"Hello %s\n\", |
\"World\");</pike></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" |
"<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" |
"</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) |
{ |
if (query("debugmode") == "Off") return ""; |
|
report_error( header + dump + "\n" ); |
switch (query("debugmode")) |
{ |
case "HTML comment": |
return "\n<!-- " + Roxen.html_encode_string(header + dump) + "\n-->\n"; |
case "HTML text": |
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"; |
default: |
return ""; |
} |
} |
|
|
class Helpers |
{ |
string data = ""; |
void output(mixed ... args) |
{ |
write( @args ); |
} |
|
void write(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; |
} |
|
string rxml( string what ) |
{ |
return Roxen.parse_rxml( what, RXML.get_context()->id ); |
} |
constant seteuid=0; |
constant setegid=0; |
constant setuid=0; |
constant setgid=0; |
constant call_out=0; |
constant all_constants=0; |
constant Privs=0; |
} |
|
class HProtos |
{ |
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; |
} |
|
string helpers() |
{ |
add_constant( "__ps_magic_helpers", Helpers ); |
add_constant( "__ps_magic_protos", HProtos ); |
return "inherit __ps_magic_helpers;\nimport Roxen;\n"; |
} |
|
string helper_prototypes( ) |
{ |
return "inherit __ps_magic_protos;\nimport Roxen;\n"; |
} |
|
private static mapping(string:program) program_cache = ([]); |
|
string simple_pi_tag_pike( string tag, mapping m, string s,RequestID id ) |
{ |
return simpletag_pike( tag, ([]), s, id ); |
} |
|
string read_roxen_file( string what, object id ) |
{ |
|
return id->conf->open_file(Roxen.fix_relative(what,id),"rR",id,1) |
->read()[0]; |
} |
|
|
#define PS(X) (compile_string( "mixed foo(){ return "+(X)+";}")()->foo()) |
#define SPLIT(X) PARSER_C.hide_whitespaces(PARSER_C.tokenize(PARSER_C.split(X))) |
#define OCIP( ) \ |
if( cip ) \ |
{ \ |
cip->text=sprintf("write(rxml(%O));",cip->text); \ |
cip = 0; \ |
} |
|
#define OCIPUP( ) \ |
if( cipup ) \ |
{ \ |
cipup->text=sprintf("write(%O);",cipup->text); \ |
cipup = 0; \ |
} |
|
#define CIP(X) if( X ) \ |
{ \ |
X->text += flat[i]->text[3..]+"\n"; \ |
flat[i]->text=flat[i]->trailing_whitespaces=""; \ |
} \ |
else \ |
{ \ |
X = flat[i]; \ |
flat[i]->text = flat[i]->text[3..]+"\n"; \ |
} |
|
#define R(X) PARSER_C.simple_reconstitute(X) |
|
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; |
|
cnt=0; |
foreach( ip, program ipc ) add_constant( "____ih_"+cnt++, 0 ); |
destruct( key ); |
return p; |
} |
|
program handle_inherit( string what, RequestID id ) |
{ |
array err; |
|
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] ) |
{ |
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" ) |
add_md = 0; |
break; |
|
case '.': |
OCIP(); OCIPUP(); |
if( flat[i] == "." ) |
flat[i]->text = "->"; |
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 }); |
} |
|
|
|
string simpletag_pike(string tag, mapping m, string s,RequestID request_id ) |
{ |
program p; |
object o; |
string res; |
mixed err; |
|
request_id->misc->__added_helpers_in_tree=0; |
request_id->misc->cacheable=0; |
|
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; |
|
|
for(i = query("program_cache_limit")/2; i > 0; i--) |
m_delete(program_cache, a[random(sizeof(a))]); |
} |
}) |
{ |
master()->set_inhibit_compile_errors(0); |
return reporterr(sprintf("Error handling <pike> tag in %s:\n%s\n" |
"%s\n\n", |
request_id->not_query, |
s, describe_backtrace(err[..1])), |
e->get()); |
} |
master()->set_inhibit_compile_errors(0); |
|
if(err = catch{ |
res = (o=p())->parse(request_id); |
}) |
{ |
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; |
} |
|
|