1430c0 | 2000-03-16 | Martin Nilsson | |
|
ea72a6 | 1999-11-27 | Per Hedbor | |
|
b3281f | 2000-09-10 | Martin Nilsson | | constant cvs_version = "$Id: piketag.pike,v 2.21 2000/09/10 16:47:49 nilsson Exp $";
|
ea72a6 | 1999-11-27 | Per Hedbor | | constant thread_safe=1;
|
e1e93c | 2000-08-09 | Per Hedbor | |
#if constant(Parser.C)
#define PARSER_C Parser.C
#else
|
776f87 | 2000-08-14 | Martin Stjernholm | | #define PARSER_C Roxen._Parser.C
|
e1e93c | 2000-08-09 | Per Hedbor | | #endif
|
ea72a6 | 1999-11-27 | Per Hedbor | | inherit "module";
|
e123c7 | 2000-07-17 | Johan Sundström | | #include <module.h>
|
ea72a6 | 1999-11-27 | Per Hedbor | |
|
b3281f | 2000-09-10 | Martin Nilsson | | constant module_type = MODULE_TAG;
|
ea72a6 | 1999-11-27 | Per Hedbor | | constant module_name = "Pike tag";
|
29c641 | 2000-08-11 | Martin Stjernholm | | constant module_doc = #"
This module adds a processing instruction tag, <code><?pike ...
?></code>, for evaluating Pike code directly in the document.
|
ea72a6 | 1999-11-27 | Per Hedbor | |
|
29c641 | 2000-08-11 | Martin Stjernholm | | <p><img src=\"internal-roxen-err_2\" align=\"left\" alt=\"Warning\">
NOTE: Enabling this module is the same thing as letting your users
run programs with the same right as the server!
<p>Example:
<p><pre><?pike write (\"Hello world!\\n\"); ?>\n</pre>
<p>There are a few helper functions available:
<dl>
<dt><code>write(string fmt, mixed ... args)</code></dt>
|
d2f669 | 2000-08-11 | Martin Stjernholm | | <dd>Formats a string in the same way as <code>printf</code> and
appends it to the output buffer. If given only one string
argument, it's written directly to the output buffer without being
interpreted as a format specifier.</dd>
|
29c641 | 2000-08-11 | Martin Stjernholm | |
<dt><code>flush()</code></dt>
<dd>Returns the contents of the output buffer and resets it.</dd>
<dt><code>rxml(string rxmlcode)</code></dt>
|
d2f669 | 2000-08-11 | Martin Stjernholm | | <dd>Parses the string with the RXML parser.</dd>
|
29c641 | 2000-08-11 | Martin Stjernholm | | </dl>
<p>When the pike tag returns, the contents of the output buffer is
inserted into the page. It is not reparsed with the RXML parser.
<p>These special constructs are also recognized:
<dl>
|
d2f669 | 2000-08-11 | Martin Stjernholm | | <dt><code>//O ... </code> or <code>/*O ... */</code></dt>
|
29c641 | 2000-08-11 | Martin Stjernholm | | <dd>A Pike comment with an 'O' (the letter, not the number) as the
very first character treats the rest of the text in the comment as
output text that's written directly to the output buffer.</dd>
|
d2f669 | 2000-08-11 | Martin Stjernholm | | <dt><code>//X ... </code> or <code>/*X ... */</code></dt>
|
29c641 | 2000-08-11 | Martin Stjernholm | | <dd>A Pike comment with an 'X' as the very first character treats
|
d2f669 | 2000-08-11 | Martin Stjernholm | | the rest of the text in the comment as RXML code that's executed
by the RXML parser and then written to the output buffer.</dd>
|
29c641 | 2000-08-11 | Martin Stjernholm | |
<dt><code>#include \"...\"</code></dt>
<dd>An <code>#include</code> preprocessor directive includes the
|
d2f669 | 2000-08-11 | Martin Stjernholm | | specified file.</dd>
|
29c641 | 2000-08-11 | Martin Stjernholm | |
<dt><code>#inherit \"...\"</code></dt>
<dd>An <code>#inherit</code> preprocessor directive puts a
|
d2f669 | 2000-08-11 | Martin Stjernholm | | corresponding inherit declaration in the class that's generated to
contain the Pike code in the tag.</dd>
|
29c641 | 2000-08-11 | Martin Stjernholm | | </dl>
|
d2f669 | 2000-08-11 | Martin Stjernholm | | <p>When files are included or inherited, they will be read from the
virtual filesystem in Roxen, relative to the location during whose
parsing the pike tag was encountered.
|
29c641 | 2000-08-11 | Martin Stjernholm | | <p>Note that every RXML fragment is parsed by itself, so you can't
have unmatched RXML tags in them. E.g. the following does not work:
<p><pre><?pike
//X <gtext>
write (\"Foo\");
//X </gtext>
?>\n</pre>
<p>Adjacent 'X' comments are concatenated however, so the following
works:
<p><pre><?pike
//X <gtext>
//X Foo
//X </gtext>
?>\n</pre>
<p>For compatibility this module also adds the Pike container tag,
<code><pike>...</pike></code>. It behaves exactly as it
did in Roxen 2.0 and earlier and the functionality mentioned above
does not apply to it. The use of the container tag is deprecated.";
|
654037 | 2000-08-09 | Per Hedbor | |
|
ea72a6 | 1999-11-27 | Per Hedbor | | void create()
{
defvar("program_cache_limit", 256, "Program cache limit", TYPE_INT|VAR_MORE,
"Maximum size of the cache for compiled programs.");
}
class Helpers
{
string data = "";
void output(mixed ... args)
{
|
654037 | 2000-08-09 | Per Hedbor | | write( @args );
|
ea72a6 | 1999-11-27 | Per Hedbor | | }
|
325751 | 2000-08-09 | Per Hedbor | | void write(mixed ... args)
{
if(!sizeof(args))
return;
if(sizeof(args) > 1)
data += sprintf(@args);
else
data += args[0];
}
|
ea72a6 | 1999-11-27 | Per Hedbor | | string flush()
{
string r = data;
data ="";
return r;
}
|
654037 | 2000-08-09 | Per Hedbor | | string rxml( string what )
|
3aca38 | 2000-08-09 | Per Hedbor | | {
|
654037 | 2000-08-09 | Per Hedbor | | return Roxen.parse_rxml( what, RXML.get_context()->id );
|
3aca38 | 2000-08-09 | Per Hedbor | | }
|
ea72a6 | 1999-11-27 | Per Hedbor | | constant seteuid=0;
constant setegid=0;
constant setuid=0;
constant setgid=0;
constant call_out=0;
constant all_constants=0;
constant Privs=0;
}
|
654037 | 2000-08-09 | Per Hedbor | | class HProtos
|
ea72a6 | 1999-11-27 | Per Hedbor | | {
|
654037 | 2000-08-09 | Per 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;
|
ea72a6 | 1999-11-27 | Per Hedbor | | }
|
29c641 | 2000-08-11 | Martin Stjernholm | | #define PREFN "pike-tag(preamble)"
#define POSTFN "pike-tag(postamble)"
|
654037 | 2000-08-09 | Per Hedbor | | #define PS(X) (compile_string( "mixed foo(){ return "+(X)+";}")()->foo())
|
29c641 | 2000-08-11 | Martin Stjernholm | | #define SPLIT(X,FN) PARSER_C.hide_whitespaces(PARSER_C.tokenize(PARSER_C.split(X),FN))
|
3aca38 | 2000-08-09 | Per Hedbor | | #define OCIP( ) \
if( cip ) \
{ \
|
654037 | 2000-08-09 | Per Hedbor | | cip->text=sprintf("write(rxml(%O));",cip->text); \
|
3aca38 | 2000-08-09 | Per Hedbor | | cip = 0; \
}
#define OCIPUP( ) \
if( cipup ) \
{ \
cipup->text=sprintf("write(%O);",cipup->text); \
cipup = 0; \
}
|
b191f0 | 2000-08-09 | Per Hedbor | | #define CIP(X) if( X ) \
|
3aca38 | 2000-08-09 | Per Hedbor | | { \
X->text += flat[i]->text[3..]+"\n"; \
|
b191f0 | 2000-08-09 | Per Hedbor | | flat[i]->text=flat[i]->trailing_whitespaces=""; \
|
3aca38 | 2000-08-09 | Per Hedbor | | } \
else \
{ \
X = flat[i]; \
flat[i]->text = flat[i]->text[3..]+"\n"; \
}
|
29c641 | 2000-08-11 | Martin Stjernholm | | #define R(X) PARSER_C.reconstitute_with_line_numbers(X)
array helpers()
{
add_constant( "__ps_magic_helpers", Helpers );
add_constant( "__ps_magic_protos", HProtos );
return SPLIT("inherit __ps_magic_helpers;\nimport Roxen;\n",PREFN);
}
array helper_prototypes( )
{
return SPLIT("inherit __ps_magic_protos;\nimport Roxen;\n",PREFN);
}
private static mapping(string:program) program_cache = ([]);
string simple_pi_tag_pike( string tag, mapping m, string s,RequestID id )
{
program p;
object o;
string res;
mixed err;
id->misc->__added_helpers_in_tree=0;
id->misc->cacheable=0;
object e = ErrorContainer();
master()->set_inhibit_compile_errors(e);
if(err=catch
{
p = my_compile_string( s,id,1,"pike-tag("+id->not_query+")" );
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);
if (e->get())
RXML.parse_error ("Error compiling Pike code:\n%s", e->get());
else throw (err);
}
master()->set_inhibit_compile_errors(0);
if(err = catch{
(o=p())->parse(id);
})
RXML.run_error ("Error in Pike code: %s\n", describe_error (err));
res = (o && o->flush() || "");
if(o)
destruct(o);
return res;
}
string read_roxen_file( string what, object id )
{
return id->conf->open_file(Roxen.fix_relative(what,id),"rR",id,1)
->read()[0];
}
|
9266a3 | 2000-08-09 | Per Hedbor | |
|
654037 | 2000-08-09 | Per 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();
|
29c641 | 2000-08-11 | Martin Stjernholm | | [array ip, array data] = parse_magic(s,id,dom,fn);
|
654037 | 2000-08-09 | Per Hedbor | |
int cnt;
|
29c641 | 2000-08-11 | Martin Stjernholm | | array pre;
|
654037 | 2000-08-09 | Per Hedbor | | 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 );
|
29c641 | 2000-08-11 | Martin Stjernholm | | pre += SPLIT("inherit ____ih_"+cnt++ + ";\n",PREFN);
|
654037 | 2000-08-09 | Per Hedbor | | }
|
29c641 | 2000-08-11 | Martin Stjernholm | | if (dom)
|
d2f669 | 2000-08-11 | Martin Stjernholm | | pre += SPLIT("void parse(RequestID id)\n{\n",PREFN) +
|
29c641 | 2000-08-11 | Martin Stjernholm | | data + SPLIT("}",POSTFN);
else
pre += data;
program p = compile_string(R(pre), fn);
|
654037 | 2000-08-09 | Per Hedbor | | program_cache[ s ] = p;
|
3aca38 | 2000-08-09 | Per Hedbor | |
|
654037 | 2000-08-09 | Per Hedbor | | cnt=0;
foreach( ip, program ipc ) add_constant( "____ih_"+cnt++, 0 );
destruct( key );
return p;
}
|
ea72a6 | 1999-11-27 | Per Hedbor | |
|
654037 | 2000-08-09 | Per Hedbor | | program handle_inherit( string what, RequestID id )
{
array err;
|
29c641 | 2000-08-11 | Martin Stjernholm | | return my_compile_string( read_roxen_file( what, id ),id,0,what);
|
654037 | 2000-08-09 | Per Hedbor | | }
|
29c641 | 2000-08-11 | Martin Stjernholm | | array parse_magic( string data, RequestID id, int add_md, string filename )
|
654037 | 2000-08-09 | Per Hedbor | | {
|
29c641 | 2000-08-11 | Martin Stjernholm | | array flat=SPLIT(data,filename);
|
654037 | 2000-08-09 | Per Hedbor | | object cip, cipup;
array inherits = ({});
for( int i = 0; i<sizeof( flat ); i++ )
{
switch( strlen(flat[i]->text) && flat[i]->text[0] )
|
ea72a6 | 1999-11-27 | Per Hedbor | | {
|
654037 | 2000-08-09 | Per Hedbor | | case '.':
OCIP(); OCIPUP();
|
e1e93c | 2000-08-09 | Per Hedbor | | if( flat[i] == "." )
|
1343ce | 2000-08-11 | Per Hedbor | | {
flat[i]->text = "[";
flat[i+1]->text = "\"" + flat[++i]->text + "\"]";
}
|
654037 | 2000-08-09 | Per Hedbor | | break;
case '/':
|
29c641 | 2000-08-11 | Martin Stjernholm | | if( flat[i]->text[2..2] == "X" )
|
654037 | 2000-08-09 | Per Hedbor | | {
|
29c641 | 2000-08-11 | Martin Stjernholm | | if (flat[i]->text[1] == '*')
flat[i]->text = flat[i]->text[..sizeof (flat[i]->text) - 3];
|
654037 | 2000-08-09 | Per Hedbor | | OCIPUP();
CIP( cip );
}
|
29c641 | 2000-08-11 | Martin Stjernholm | | else if( flat[i]->text[2..2] == "O" )
|
654037 | 2000-08-09 | Per Hedbor | | {
|
29c641 | 2000-08-11 | Martin Stjernholm | | if (flat[i]->text[1] == '*')
flat[i]->text = flat[i]->text[..sizeof (flat[i]->text) - 3];
|
654037 | 2000-08-09 | Per Hedbor | | OCIP();
CIP( cipup );
}
else
{
OCIPUP();
OCIP();
}
break;
case '#':
OCIP(); OCIPUP();
|
29c641 | 2000-08-11 | Martin Stjernholm | | if( sscanf( flat[i]->text, "#%*[ \t]inherit%[ \t]%s",
string ws, string fn) == 3 && sizeof (ws))
{
inherits += ({ handle_inherit( PS(fn), id ) });
}
else if( sscanf( flat[i]->text, "#%*[ \t]include%[ \t]%s",
string ws, string fn) == 3 && sizeof (ws))
|
654037 | 2000-08-09 | Per Hedbor | | {
sscanf( fn, "%*s<%s>", fn );
sscanf( fn, "%*s\"%s\"", fn );
|
29c641 | 2000-08-11 | Martin Stjernholm | | [array ih,flat[i]] = parse_magic(read_roxen_file(fn,id), id, 0, fn);
|
654037 | 2000-08-09 | Per Hedbor | | inherits += ih;
}
break;
default:
OCIP();
OCIPUP();
}
}
OCIP();
OCIPUP();
|
29c641 | 2000-08-11 | Martin Stjernholm | | return ({ inherits, flat });
}
class CompatHelpers
{
inherit "roxenlib";
string data = "";
void output(mixed ... args)
{
if(!sizeof(args))
return;
if(sizeof(args) > 1)
data += sprintf(@args);
else
data += args[0];
}
string flush()
|
654037 | 2000-08-09 | Per Hedbor | | {
|
29c641 | 2000-08-11 | Martin Stjernholm | | string r = data;
data ="";
return r;
|
654037 | 2000-08-09 | Per Hedbor | | }
|
29c641 | 2000-08-11 | Martin Stjernholm | |
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", CompatHelpers );
return
"inherit __magic_helpers;\n"
"#"+line+" \""+replace(page,"\"","\\\"")+"\"\n";
}
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 ";
}
string post(string what)
{
if(search(what, "parse(") != -1)
return "";
if (!strlen(what) || what[-1] != ';')
return ";}";
else
return "}";
|
654037 | 2000-08-09 | Per Hedbor | | }
|
9266a3 | 2000-08-09 | Per Hedbor | |
|
654037 | 2000-08-09 | Per Hedbor | |
|
29c641 | 2000-08-11 | Martin Stjernholm | | string container_pike(string tag, mapping m, string s, RequestID request_id,
object file, mapping defs)
|
654037 | 2000-08-09 | Per Hedbor | | {
program p;
object o;
string res;
mixed err;
|
325751 | 2000-08-09 | Per Hedbor | |
|
654037 | 2000-08-09 | Per Hedbor | | request_id->misc->cacheable=0;
|
ea72a6 | 1999-11-27 | Per Hedbor | |
|
654037 | 2000-08-09 | Per Hedbor | | object e = ErrorContainer();
master()->set_inhibit_compile_errors(e);
if(err=catch
{
|
29c641 | 2000-08-11 | Martin Stjernholm | | s = pre(s,request_id)+s+post(s);
p = program_cache[s];
|
654037 | 2000-08-09 | Per Hedbor | |
|
29c641 | 2000-08-11 | Martin Stjernholm | | if (!p)
{
p = compile_string(s, "Pike-tag("+request_id->not_query+":"+
request_id->misc->line+")");
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))]);
}
program_cache[s] = p;
|
ea72a6 | 1999-11-27 | Per Hedbor | | }
})
{
master()->set_inhibit_compile_errors(0);
|
29c641 | 2000-08-11 | Martin Stjernholm | | if (e->get())
|
15a185 | 2000-08-16 | Per Hedbor | | {
|
29c641 | 2000-08-11 | Martin Stjernholm | | RXML.parse_error ("Error compiling Pike code:\n%s", e->get());
|
15a185 | 2000-08-16 | Per Hedbor | | }
else
throw (err);
|
ea72a6 | 1999-11-27 | Per Hedbor | | }
master()->set_inhibit_compile_errors(0);
if(err = catch{
|
29c641 | 2000-08-11 | Martin Stjernholm | | res = (o=p())->parse(request_id, defs, file, m);
|
ea72a6 | 1999-11-27 | Per Hedbor | | })
|
29c641 | 2000-08-11 | Martin Stjernholm | | RXML.run_error ("Error in Pike code: %s\n", describe_error (err));
|
ea72a6 | 1999-11-27 | Per Hedbor | |
res = (res || "") + (o && o->flush() || "");
if(o)
destruct(o);
return res;
}
|
3a2097 | 2000-08-29 | Kenneth Johansson | |
TAGDOCUMENTATION;
#ifdef manual
constant tagdoc=([
|
c84cdf | 2000-08-30 | Martin Nilsson | | "<?pike":#"<desc pi><short hide>
|
3a2097 | 2000-08-29 | Kenneth Johansson | | Pike processing instruction tag.</short>This processing intruction
tag allows for evaluating Pike code directly in the document.
<p>Note: With this tag, users are able to run programs with the same
right as the server. This is a serious security hasard.</p>
<p>When the pike tag returns, the contents of the output buffer is
inserted into the page. It is not reparsed with the RXML parser.
</desc>
<attr name='write' value='(string fmt, mixed ... args)'>
write() is a helper function. It formats a string in the same way as
printf and appends it to the output buffer. If given only one string
argument, it's written directly to the output buffer without being
interpreted as a format specifier.
</attr>
<attr name='flush' value='()'>
flush() is a helper function. It returns the contents of the output
buffer and resets it.
</attr>
<attr name='rxml' value='(string rxmlcode)'>
rxml() is a helper function. It parses the string with the RXML parser.
</attr>
",
]);
#endif
|