|
|
|
|
|
|
|
|
inherit "rxmlhelp"; |
#include <config.h> |
|
|
|
|
RXML.TagSet rxml_tag_set = class |
|
{ |
inherit RXML.TagSet; |
|
string prefix = RXML_NAMESPACE; |
|
#if constant (thread_create) |
Thread.Mutex lists_mutex = Thread.Mutex(); |
|
#endif |
|
array(RoxenModule) modules; |
|
|
|
|
void sort_on_priority() |
{ |
#if constant (thread_create) |
Thread.MutexKey lock = lists_mutex->lock(); |
#endif |
int i = search (imported, Roxen.entities_tag_set); |
array(RXML.TagSet) new_imported = imported[..i-1] + imported[i+1..]; |
array(RoxenModule) new_modules = modules[..i-1] + modules[i+1..]; |
array(string) module_ids = new_modules->module_identifier(); |
|
|
|
sort (module_ids, new_imported, new_modules); |
array(int) priorities = new_modules->query ("_priority", 1); |
priorities = replace (priorities, 0, 4); |
sort (priorities, new_imported, new_modules); |
new_imported = reverse (new_imported) + ({imported[i]}); |
if (equal (imported, new_imported)) return; |
new_modules = reverse (new_modules) + ({modules[i]}); |
`->= ("imported", new_imported); |
modules = new_modules; |
} |
|
mixed `->= (string var, mixed val) |
|
{ |
if (var == "modules") modules = val; |
else ::`->= (var, val); |
return val; |
} |
|
void create (object rxml_object) |
{ |
::create (rxml_object->name + "/rxml_tag_set"); |
imported = ({Roxen.entities_tag_set}); |
modules = ({rxml_object}); |
} |
|
void prepare_context (RXML.Context ctx) |
{ |
RequestID id = ctx->id; |
|
PROF_ENTER( "rxml", "overhead" ); |
|
|
if (id->misc->defines && id->misc->defines != ctx->misc) |
ctx->misc->old_defines = id->misc->defines; |
id->misc->defines = ctx->misc; |
|
#if ROXEN_COMPAT <= 1.3 |
if (old_rxml_compat) ctx->compatible_scope = 1; |
#endif |
|
ctx->misc[" _ok"] = 1; |
ctx->misc[" _error"] = 200; |
ctx->misc[" _extra_heads"] = ([ ]); |
if(id->misc->stat) ctx->misc[" _stat"] = id->misc->stat; |
} |
|
void eval_finish (RXML.Context ctx) |
{ |
RequestID id = ctx->id; |
|
if(sizeof(ctx->misc[" _extra_heads"])) |
if (id->misc->moreheads) |
id->misc->moreheads |= ctx->misc[" _extra_heads"]; |
else |
id->misc->moreheads = ctx->misc[" _extra_heads"]; |
|
if (mapping olddefs = ctx->misc->old_defines) { |
|
if (int v = ctx->misc[" _error"]) olddefs[" _error"] = v; |
if (string v = ctx->misc[" _rettext"]) olddefs[" _rettext"] = v; |
id->misc->defines = olddefs; |
} |
|
PROF_LEAVE( "rxml", "overhead" ); |
} |
} (this_object()); |
|
RXML.Type default_content_type = RXML.t_html (RXML.PXml); |
RXML.Type default_arg_type = RXML.t_text (RXML.PEnt); |
|
int old_rxml_compat; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string parse_rxml(string what, RequestID id, |
void|Stdio.File file, |
void|mapping defines ) |
|
|
|
{ |
RXML.PXml parser; |
RXML.Context ctx = RXML_CONTEXT; |
int orig_state_updated = -1; |
|
if (ctx && ctx->id == id) { |
parser = default_content_type->get_parser (ctx, ctx->tag_set, 0); |
orig_state_updated = ctx->state_updated; |
#ifdef RXML_PCODE_UPDATE_DEBUG |
report_debug ("%O: Saved p-code update count %d before parse_rxml " |
"with inherited context\n", |
ctx, orig_state_updated); |
#endif |
} |
else { |
parser = rxml_tag_set->get_parser (default_content_type, id); |
ctx = parser->context; |
} |
parser->recover_errors = 1; |
|
if (defines) { |
ctx->misc = id->misc->defines = defines; |
if (!defines[" _error"]) |
defines[" _error"] = 200; |
if (!defines[" _extra_heads"]) |
defines[" _extra_heads"] = ([ ]); |
if (!defines[" _stat"] && id->misc->stat) |
defines[" _stat"] = id->misc->stat; |
} |
else |
defines = ctx->misc; |
|
if (file) { |
if (!defines[" _stat"]) |
defines[" _stat"] = file->stat(); |
defines["_source file"] = file; |
} |
|
mixed err = catch { |
if (ctx == RXML_CONTEXT) |
parser->finish (what); |
else |
parser->write_end (what); |
what = parser->eval(); |
}; |
|
if (file) m_delete (defines, "_source file"); |
if (orig_state_updated >= 0) { |
#ifdef RXML_PCODE_UPDATE_DEBUG |
report_debug ("%O: Restoring p-code update count from %d to %d " |
"after parse_rxml with inherited context\n", |
ctx, ctx->state_updated, orig_state_updated); |
#endif |
ctx->state_updated = orig_state_updated; |
} |
|
if (err) { |
#ifdef DEBUG |
if (!parser) { |
report_debug("RXML: Parser destructed!\n"); |
#if constant(_describe) |
_describe(parser); |
#endif /* constant(_describe) */ |
error("Parser destructed!\n"); |
} |
#endif |
if (objectp (err) && err->thrown_at_unwind) |
error ("Can't handle RXML parser unwinding in " |
"compatibility mode (error=%O).\n", err); |
else throw (err); |
} |
|
return what; |
} |
|
#define COMPAT_TAG_TYPE \ |
function(string,mapping(string:string),RequestID,void|Stdio.File,void|mapping: \ |
string|array(int|string)) |
|
#define COMPAT_CONTAINER_TYPE \ |
function(string,mapping(string:string),string,RequestID,void|Stdio.File,void|mapping: \ |
string|array(int|string)) |
|
class CompatTag |
{ |
inherit RXML.Tag; |
constant is_compat_tag=1; |
|
string name; |
int flags; |
string|COMPAT_TAG_TYPE|COMPAT_CONTAINER_TYPE fn; |
|
RXML.Type content_type = RXML.t_same; |
array(RXML.Type) result_types = |
({RXML.t_xml (RXML.PXml), RXML.t_html (RXML.PXml)}); |
|
void create (string _name, int empty, string|COMPAT_TAG_TYPE|COMPAT_CONTAINER_TYPE _fn) |
{ |
name = _name, fn = _fn; |
flags = empty && RXML.FLAG_EMPTY_ELEMENT; |
} |
|
class Frame |
{ |
inherit RXML.Frame; |
string raw_tag_text; |
|
array do_enter (RequestID id) |
{ |
if (args->preparse) |
content_type = content_type (RXML.PXml); |
} |
|
array do_return (RequestID id) |
{ |
id->misc->line = "0"; |
|
if (stringp (fn)) return ({fn}); |
if (!fn) { |
result_type = result_type (RXML.PNone); |
return ({propagate_tag()}); |
} |
|
mapping defines = RXML_CONTEXT->misc; |
Stdio.File source_file = defines["_source file"]; |
|
string|array(string) result; |
if (flags & RXML.FLAG_EMPTY_ELEMENT) |
result = fn (name, args, id, source_file, defines); |
else { |
if(args->trimwhites) content = String.trim_all_whites(content); |
result = fn (name, args, content, id, source_file, defines); |
} |
|
if (arrayp (result)) { |
result_type = result_type (RXML.PNone); |
if (sizeof (result) && result[0] == 1) { |
[string pname, mapping(string:string) pargs, string pcontent] = |
(result[1..] + ({0, 0, 0}))[..2]; |
if (!pname || pname == name) |
return ({!pargs && !pcontent ? propagate_tag () : |
propagate_tag (pargs || args, pcontent || content)}); |
else |
return ({RXML.make_unparsed_tag ( |
pname, pargs || args, pcontent || content || "")}); |
} |
else return result; |
} |
else if (result) { |
if (args->noparse) result_type = result_type (RXML.PNone); |
return ({result}); |
} |
else { |
result_type = result_type (RXML.PNone); |
return ({propagate_tag()}); |
} |
} |
} |
} |
|
class GenericTag { |
inherit RXML.Tag; |
constant is_generic_tag=1; |
string name; |
int flags; |
|
function(string,mapping(string:string),string,RequestID,RXML.Frame: |
array|string) _do_return; |
|
void create(string _name, int _flags, |
function(string,mapping(string:string),string,RequestID,RXML.Frame: |
array|string) __do_return) { |
name=_name; |
flags=_flags; |
_do_return=__do_return; |
if(flags&RXML.FLAG_DONT_PREPARSE) |
content_type = RXML.t_same; |
} |
|
class Frame { |
inherit RXML.Frame; |
|
array do_return(RequestID id, void|mixed piece) { |
|
|
if (flags & RXML.FLAG_POSTPARSE) |
result_type = result_type (RXML.PXml); |
if (!(flags & RXML.FLAG_STREAM_CONTENT)) |
piece = content || ""; |
array|string res = _do_return(name, args, piece, id, this_object()); |
return stringp (res) ? ({res}) : res; |
} |
} |
} |
|
class GenericPITag |
{ |
inherit GenericTag; |
|
void create (string _name, int _flags, |
function(string,mapping(string:string),string,RequestID,RXML.Frame: |
array|string) __do_return) |
{ |
::create (_name, _flags | RXML.FLAG_PROC_INSTR, __do_return); |
content_type = RXML.t_text; |
|
|
} |
} |
|
void add_parse_module (RoxenModule mod) |
{ |
RXML.TagSet tag_set = |
mod->query_tag_set ? mod->query_tag_set() : RXML.TagSet (mod->module_identifier()); |
mapping(string:mixed) defs; |
|
if (mod->query_tag_callers && |
mappingp (defs = mod->query_tag_callers()) && |
sizeof (defs)) |
tag_set->add_tags (map (indices (defs), |
lambda (string name) { |
return CompatTag (name, 1, defs[name]); |
})); |
|
if (mod->query_container_callers && |
mappingp (defs = mod->query_container_callers()) && |
sizeof (defs)) |
tag_set->add_tags (map (indices (defs), |
lambda (string name) { |
return CompatTag (name, 0, defs[name]); |
})); |
|
if (mod->query_simpletag_callers && |
mappingp (defs = mod->query_simpletag_callers()) && |
sizeof (defs)) |
tag_set->add_tags(Array.map(indices(defs), |
lambda(string tag){ return GenericTag(tag, @defs[tag]); })); |
|
if (mod->query_simple_pi_tag_callers && |
mappingp (defs = mod->query_simple_pi_tag_callers()) && |
sizeof (defs)) |
tag_set->add_tags (map (indices (defs), |
lambda (string name) { |
return GenericPITag (name, @defs[name]); |
})); |
|
if (search (rxml_tag_set->imported, tag_set) < 0) { |
#ifdef THREADS |
Thread.MutexKey lock = rxml_tag_set->lists_mutex->lock(); |
#endif |
rxml_tag_set->modules += ({mod}); |
rxml_tag_set->imported += ({tag_set}); |
#ifdef THREADS |
lock = 0; |
#endif |
remove_call_out (rxml_tag_set->sort_on_priority); |
call_out (rxml_tag_set->sort_on_priority, 0); |
} |
} |
|
void remove_parse_module (RoxenModule mod) |
{ |
int i = search (rxml_tag_set->modules, mod); |
if (i >= 0) { |
RXML.TagSet tag_set = rxml_tag_set->imported[i]; |
rxml_tag_set->modules = |
rxml_tag_set->modules[..i - 1] + rxml_tag_set->modules[i + 1..]; |
rxml_tag_set->imported = |
rxml_tag_set->imported[..i - 1] + rxml_tag_set->imported[i + 1..]; |
if (tag_set) destruct (tag_set); |
} |
} |
|
void ready_to_receive_requests (object this) |
{ |
remove_call_out (rxml_tag_set->sort_on_priority); |
rxml_tag_set->sort_on_priority(); |
} |
|
|