// OpenSP.xs -- OpenSP XS Wrapper
//
// $Id: OpenSP.xs,v 1.28 2005/08/16 15:30:22 hoehrmann Exp $
// workaround for broken math.h in VC++ 6.0
#if defined(_MSC_VER) && _MSC_VER < 1300
#include <math.h>
#endif
#define PERL_NO_GET_CONTEXT
#define SPO_SMALL_STRINGS_LENGTH 1024
extern "C"
{
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
}
// these are specific to the system and might need to
// be changed before the Perl extension can compile
#ifdef WIN32
#include "generic/ParserEventGeneratorKit.h"
#else
#include "OpenSP/ParserEventGeneratorKit.h"
#endif
///////////////////////////////////////////////////////////////////////////
// Class SgmlParserOpenSP
///////////////////////////////////////////////////////////////////////////
class SgmlParserOpenSP : private SGMLApplication {
public:
// ...
SgmlParserOpenSP();
public:
// ...
void parse(SV* file_sv);
SV* get_location();
void halt();
// ...
SV* m_self;
private:
// OpenSP event handler
void appinfo (const AppinfoEvent& e);
void pi (const PiEvent& e);
void startElement (const StartElementEvent& e);
void endElement (const EndElementEvent& e);
void data (const DataEvent& e);
void sdata (const SdataEvent& e);
void externalDataEntityRef (const ExternalDataEntityRefEvent& e);
void subdocEntityRef (const SubdocEntityRefEvent& e);
void startDtd (const StartDtdEvent& e);
void endDtd (const EndDtdEvent& e);
void endProlog (const EndPrologEvent& e);
void generalEntity (const GeneralEntityEvent& e);
void commentDecl (const CommentDeclEvent& e);
void markedSectionStart (const MarkedSectionStartEvent& e);
void markedSectionEnd (const MarkedSectionEndEvent& e);
void ignoredChars (const IgnoredCharsEvent& e);
void error (const ErrorEvent& e);
// OpenSP entity change handler
void openEntityChange (const OpenEntityPtr& p);
// ...
void dispatchEvent (const char* name,
const HV* hv);
bool handler_can (const char* method);
// ...
SV* cs2sv (const SGMLApplication::CharString s);
HV* location2hv (const SGMLApplication::Location l);
HV* notation2hv (const SGMLApplication::Notation n);
HV* externalid2hv (const SGMLApplication::ExternalId id);
HV* entity2hv (const SGMLApplication::Entity e);
HV* attributes2hv (const SGMLApplication::Attribute* attrs,
const size_t n);
HV* attribute2hv (const SGMLApplication::Attribute a);
// ...
bool _hv_fetch_SvTRUE(HV* hv, const char* key, const I32 klen);
void _hv_fetch_pk_setOption(HV* hv, const char* key, const I32 klen,
ParserEventGeneratorKit& pk,
const enum ParserEventGeneratorKit::OptionWithArg o);
// ...
SV* m_handler;
bool m_parsing;
SGMLApplication::Position m_pos;
SGMLApplication::OpenEntityPtr m_openEntityPtr;
EventGenerator* m_egp;
// ...
PerlInterpreter* my_perl;
// ...
U8 m_temp[SPO_SMALL_STRINGS_LENGTH * UTF8_MAXLEN + 1];
};
///////////////////////////////////////////////////////////////////////////
// computed hash values
///////////////////////////////////////////////////////////////////////////
static U32 HvvAttributes;
static U32 HvvByteOffset;
static U32 HvvCdataChunks;
static U32 HvvColumnNumber;
static U32 HvvComment;
static U32 HvvComments;
static U32 HvvContentType;
static U32 HvvData;
static U32 HvvDataType;
static U32 HvvDeclType;
static U32 HvvDefaulted;
static U32 HvvEntities;
static U32 HvvEntity;
static U32 HvvEntityName;
static U32 HvvEntityOffset;
static U32 HvvExternalId;
static U32 HvvFileName;
static U32 HvvGeneratedSystemId;
static U32 HvvIncluded;
static U32 HvvIndex;
static U32 HvvIsGroup;
static U32 HvvIsId;
static U32 HvvIsInternal;
static U32 HvvIsNonSgml;
static U32 HvvIsSdata;
static U32 HvvLineNumber;
static U32 HvvMessage;
static U32 HvvName;
static U32 HvvNonSgmlChar;
static U32 HvvNone;
static U32 HvvNotation;
static U32 HvvParams;
static U32 HvvPublicId;
static U32 HvvSeparator;
static U32 HvvStatus;
static U32 HvvString;
static U32 HvvSystemId;
static U32 HvvText;
static U32 HvvTokens;
static U32 HvvType;
///////////////////////////////////////////////////////////////////////////
// Helper functions
///////////////////////////////////////////////////////////////////////////
SV* SgmlParserOpenSP::cs2sv(const SGMLApplication::CharString s)
{
SV* result;
unsigned int i = 0;
U8* d;
// optimized memory-intensive version for small strings
if (s.len < SPO_SMALL_STRINGS_LENGTH)
{
d = m_temp;
for (i = 0; i < s.len; ++i)
d = uvuni_to_utf8_flags(d, s.ptr[i], 0);
result = newSVpvn((const char*)m_temp, d - m_temp);
}
else
{
result = newSVpvn("", 0);
for (i = 0; i < s.len; ++i)
{
d = (U8 *)SvGROW(result, SvCUR(result) + UTF8_MAXLEN + 1);
d = uvuni_to_utf8_flags(d + SvCUR(result), s.ptr[i], 0);
SvCUR_set(result, d - (U8 *)SvPVX(result));
}
}
SvUTF8_on(result);
return result;
}
///////////////////////////////////////////////////////////////////////////
// OpenSP data structure conversion helper functions
///////////////////////////////////////////////////////////////////////////
#define uv_or_undef(x) (x == (unsigned long)-1 ? &PL_sv_undef : newSVuv(x))
HV* SgmlParserOpenSP::location2hv(const SGMLApplication::Location l)
{
HV* hv = newHV();
hv_store(hv, "LineNumber", 10, uv_or_undef(l.lineNumber), HvvLineNumber);
hv_store(hv, "ColumnNumber", 12, uv_or_undef(l.columnNumber), HvvColumnNumber);
hv_store(hv, "ByteOffset", 10, uv_or_undef(l.byteOffset), HvvByteOffset);
hv_store(hv, "EntityOffset", 12, uv_or_undef(l.entityOffset), HvvEntityOffset);
hv_store(hv, "EntityName", 10, cs2sv(l.entityName), HvvEntityName);
hv_store(hv, "FileName", 8, cs2sv(l.filename), HvvFileName);
return hv;
}
HV* SgmlParserOpenSP::notation2hv(const SGMLApplication::Notation n)
{
HV* hv = newHV();
if (n.name.len > 0)
{
SV* sv = newRV_noinc((SV*)externalid2hv(n.externalId));
hv_store(hv, "Name", 4, cs2sv(n.name), HvvName);
hv_store(hv, "ExternalId", 10, sv, HvvExternalId);
}
return hv;
}
HV* SgmlParserOpenSP::externalid2hv(const SGMLApplication::ExternalId id)
{
HV* hv = newHV();
if (id.haveSystemId)
hv_store(hv, "SystemId", 8, cs2sv(id.systemId), HvvSystemId);
if (id.havePublicId)
hv_store(hv, "PublicId", 8, cs2sv(id.publicId), HvvPublicId);
if (id.haveGeneratedSystemId)
{
SV* sv = cs2sv(id.generatedSystemId);
hv_store(hv, "GeneratedSystemId", 17, sv, HvvGeneratedSystemId);
}
return hv;
}
HV* SgmlParserOpenSP::entity2hv(const SGMLApplication::Entity e)
{
HV* hv = newHV();
hv_store(hv, "Name", 4, cs2sv(e.name), HvvName);
// dataType
switch (e.dataType)
{
case SGMLApplication::Entity::sgml:
hv_store(hv, "DataType", 8, newSVpvn("sgml", 4), HvvDataType);
break;
case SGMLApplication::Entity::cdata:
hv_store(hv, "DataType", 8, newSVpvn("cdata", 5), HvvDataType);
break;
case SGMLApplication::Entity::sdata:
hv_store(hv, "DataType", 8, newSVpvn("sdata", 5), HvvDataType);
break;
case SGMLApplication::Entity::ndata:
hv_store(hv, "DataType", 8, newSVpvn("ndata", 5), HvvDataType);
break;
case SGMLApplication::Entity::subdoc:
hv_store(hv, "DataType", 8, newSVpvn("subdoc", 6), HvvDataType);
break;
case SGMLApplication::Entity::pi:
hv_store(hv, "DataType", 8, newSVpvn("pi", 2), HvvDataType);
break;
}
// declType
switch (e.declType)
{
case SGMLApplication::Entity::general:
hv_store(hv, "DeclType", 8, newSVpvn("general", 7), HvvDeclType);
break;
case SGMLApplication::Entity::parameter:
hv_store(hv, "DeclType", 8, newSVpvn("parameter", 9), HvvDeclType);
break;
case SGMLApplication::Entity::doctype:
hv_store(hv, "DeclType", 8, newSVpvn("doctype", 7), HvvDeclType);
break;
case SGMLApplication::Entity::linktype:
hv_store(hv, "DeclType", 8, newSVpvn("linktype", 8), HvvDeclType);
break;
}
if (e.isInternal)
{
hv_store(hv, "IsInternal", 10, newSViv(1), HvvIsInternal);
hv_store(hv, "Text", 4, cs2sv(e.text), HvvText);
}
else
{
SV* sv1 = newRV_noinc((SV*)externalid2hv(e.externalId));
SV* sv2 = newRV_noinc((SV*)attributes2hv(e.attributes, e.nAttributes));
SV* sv3 = newRV_noinc((SV*)notation2hv(e.notation));
hv_store(hv, "ExternalId", 10, sv1, HvvExternalId);
hv_store(hv, "Attributes", 10, sv2, HvvAttributes);
hv_store(hv, "Notation", 8, sv3, HvvNotation);
}
return hv;
}
HV* SgmlParserOpenSP::attributes2hv(const SGMLApplication::Attribute* attrs, size_t n)
{
HV* hv = newHV();
for (unsigned int i = 0; i < n; ++i)
{
HV* a = attribute2hv(attrs[i]);
hv_store(a, "Index", 5, newSViv(i), HvvIndex);
hv_store_ent(hv, sv_2mortal(cs2sv(attrs[i].name)), newRV_noinc((SV*)a), 0);
}
return hv;
}
HV* SgmlParserOpenSP::attribute2hv(const SGMLApplication::Attribute a)
{
HV* hv = newHV();
// Name => ...
hv_store(hv, "Name", 4, cs2sv(a.name), HvvName);
// Type => ...
if (a.type == SGMLApplication::Attribute::cdata)
{
AV* av = newAV();
for (unsigned int i = 0; i < a.nCdataChunks; ++i)
{
HV* cc = newHV();
if (a.cdataChunks[i].isSdata)
{
SV* sv = cs2sv(a.cdataChunks[i].entityName);
// redundant?
hv_store(cc, "IsSdata", 7, newSViv(1), HvvIsSdata);
hv_store(cc, "EntityName", 10, sv, HvvEntityName);
}
else if (a.cdataChunks[i].isNonSgml)
{
SV* sv = newSViv(a.cdataChunks[i].nonSgmlChar);
// redundant?
hv_store(cc, "IsNonSgml", 9, newSViv(1), HvvIsNonSgml);
hv_store(cc, "NonSgmlChar", 11, sv, HvvNonSgmlChar);
}
hv_store(cc, "Data", 4, cs2sv(a.cdataChunks[i].data), HvvData);
av_push(av, newRV_noinc((SV*)cc));
}
hv_store(hv, "Type", 4, newSVpvn("cdata", 5), HvvType);
hv_store(hv, "CdataChunks", 11, newRV_noinc((SV*)av), HvvCdataChunks);
}
else if (a.type == SGMLApplication::Attribute::tokenized)
{
AV* entities = newAV();
hv_store(hv, "Type", 4, newSVpvn("tokenized", 9), HvvType);
hv_store(hv, "Tokens", 6, cs2sv(a.tokens), HvvTokens);
hv_store(hv, "IsGroup", 7, newSViv((int)a.isGroup), HvvIsGroup);
hv_store(hv, "IsId", 4, newSViv((int)a.isId), HvvIsId);
for (unsigned int i = 0; i < a.nEntities; ++i)
{
av_push(entities, newRV_noinc((SV*)entity2hv(a.entities[i])));
}
SV* sv1 = newRV_noinc((SV*)notation2hv(a.notation));
SV* sv2 = newRV_noinc((SV*)entities);
hv_store(hv, "Notation", 8, sv1, HvvNotation);
hv_store(hv, "Entities", 8, sv2, HvvEntities);
}
else if (a.type == SGMLApplication::Attribute::implied)
{
hv_store(hv, "Type", 4, newSVpvn("implied", 7), HvvType);
}
else if (a.type == SGMLApplication::Attribute::invalid)
{
hv_store(hv, "Type", 4, newSVpvn("invalid", 7), HvvType);
}
if (a.type == SGMLApplication::Attribute::cdata ||
a.type == SGMLApplication::Attribute::tokenized)
{
switch (a.defaulted)
{
case SGMLApplication::Attribute::specified:
hv_store(hv, "Defaulted", 9, newSVpvn("specified", 9), HvvDefaulted);
break;
case SGMLApplication::Attribute::definition:
hv_store(hv, "Defaulted", 9, newSVpvn("definition", 10), HvvDefaulted);
break;
case SGMLApplication::Attribute::current:
hv_store(hv, "Defaulted", 9, newSVpvn("current", 7), HvvDefaulted);
break;
}
}
return hv;
}
///////////////////////////////////////////////////////////////////////////
// ...
///////////////////////////////////////////////////////////////////////////
bool SgmlParserOpenSP::_hv_fetch_SvTRUE(HV* hv, const char* key, const I32 klen)
{
SV** svp = hv_fetch(hv, key, klen, 0);
return (svp && SvTRUE(*svp));
}
void SgmlParserOpenSP::_hv_fetch_pk_setOption(HV* hv, const char* key, const I32 klen,
ParserEventGeneratorKit& pk,
const enum ParserEventGeneratorKit::OptionWithArg o)
{
SV** svp = hv_fetch(hv, key, klen, 0);
SV* rv;
if (!svp || !*svp)
return;
// character string
if (SvPOK(*svp))
{
pk.setOption(o, SvPV_nolen(*svp));
return;
}
if (!SvROK(*svp))
return;
rv = SvRV(*svp);
if (!rv)
return;
if (!(SvTYPE(rv) == SVt_PVAV))
return;
// array reference
AV* av = (AV*)rv;
I32 len = av_len(av);
for (I32 i = 0; i < len; ++i)
{
SV** svp = av_fetch(av, i, 0);
if (!svp || !*svp || !SvPOK(*svp))
{
warn("not a legal argument in %s\n", key);
continue;
}
#ifndef SP_WIDE_SYSTEM
pk.setOption(o, SvPV_nolen(*svp));
#else
croak("SP_WIDE_SYSTEM is not supported\n");
#endif
}
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP implementation
///////////////////////////////////////////////////////////////////////////
SgmlParserOpenSP::SgmlParserOpenSP()
{
dTHX;
this->my_perl = my_perl;
// compute hashes to improve performance
PERL_HASH(HvvAttributes, "Attributes", 10);
PERL_HASH(HvvByteOffset, "ByteOffset", 10);
PERL_HASH(HvvCdataChunks, "CdataChunks", 11);
PERL_HASH(HvvColumnNumber, "ColumnNumber", 12);
PERL_HASH(HvvComment, "Comment", 7);
PERL_HASH(HvvComments, "Comments", 8);
PERL_HASH(HvvContentType, "ContentType", 11);
PERL_HASH(HvvData, "Data", 4);
PERL_HASH(HvvDataType, "DataType", 8);
PERL_HASH(HvvDeclType, "DeclType", 8);
PERL_HASH(HvvDefaulted, "Defaulted", 9);
PERL_HASH(HvvEntities, "Entities", 8);
PERL_HASH(HvvEntity, "Entity", 6);
PERL_HASH(HvvEntityName, "EntityName", 10);
PERL_HASH(HvvEntityOffset, "EntityOffset", 12);
PERL_HASH(HvvExternalId, "ExternalId", 10);
PERL_HASH(HvvFileName, "FileName", 8);
PERL_HASH(HvvGeneratedSystemId, "GeneratedSystemId", 17);
PERL_HASH(HvvIncluded, "Included", 8);
PERL_HASH(HvvIndex, "Index", 5);
PERL_HASH(HvvIsGroup, "IsGroup", 7);
PERL_HASH(HvvIsId, "IsId", 4);
PERL_HASH(HvvIsInternal, "IsInternal", 10);
PERL_HASH(HvvIsNonSgml, "IsNonSgml", 9);
PERL_HASH(HvvIsSdata, "IsSdata", 7);
PERL_HASH(HvvLineNumber, "LineNumber", 10);
PERL_HASH(HvvMessage, "Message", 7);
PERL_HASH(HvvName, "Name", 4);
PERL_HASH(HvvNonSgmlChar, "NonSgmlChar", 11);
PERL_HASH(HvvNone, "None", 4);
PERL_HASH(HvvNotation, "Notation", 8);
PERL_HASH(HvvParams, "Params", 6);
PERL_HASH(HvvPublicId, "PublicId", 8);
PERL_HASH(HvvSeparator, "Separator", 9);
PERL_HASH(HvvStatus, "Status", 6);
PERL_HASH(HvvString, "String", 6);
PERL_HASH(HvvSystemId, "SystemId", 8);
PERL_HASH(HvvText, "Text", 4);
PERL_HASH(HvvTokens, "Tokens", 6);
PERL_HASH(HvvType, "Type", 4);
// initialize member variables
m_openEntityPtr = NULL;
m_parsing = false;
m_handler = NULL;
m_self = NULL;
m_pos = 0;
m_egp = NULL;
}
SV* SgmlParserOpenSP::get_location()
{
if (!m_parsing)
croak("get_location() must be called from event handlers\n");
SGMLApplication::Location l(m_openEntityPtr, m_pos);
return newRV_noinc((SV*)location2hv(l));
}
void SgmlParserOpenSP::halt()
{
if (!m_parsing)
croak("halt() must be called from event handlers\n");
if (!m_egp)
croak("egp not available, object corrupted\n");
m_egp->halt();
}
bool SgmlParserOpenSP::handler_can(const char* method)
{
if (!method || !m_handler)
return false;
if (!SvROK(m_handler) || !sv_isobject(m_handler))
return false;
HV* stash = SvSTASH(SvRV(m_handler));
if (!stash)
return false;
// todo: this could benefit from caching the result
// todo: this does not look for autoloaded methods, should it?
if (!gv_fetchmethod_autoload(stash, method, FALSE))
return false;
return true;
}
void SgmlParserOpenSP::dispatchEvent(const char* name, const HV* hv)
{
dSP;
ENTER;
SAVETMPS;
PUSHMARK(SP);
XPUSHs(m_handler);
XPUSHs(hv ? sv_2mortal(newRV_noinc((SV*)hv)) : &PL_sv_undef);
PUTBACK;
// call the callback method; should this use G_KEEPER?
call_method(name, G_DISCARD | G_SCALAR | G_EVAL);
// Refetch the stack pointer.
SPAGAIN;
// graceful recovery
if (SvTRUE(ERRSV))
{
m_egp->halt();
POPs;
}
PUTBACK;
FREETMPS;
LEAVE;
}
void SgmlParserOpenSP::parse(SV* file_sv)
{
ParserEventGeneratorKit pk;
HV* hv;
SV** svp;
if (!file_sv)
croak("you must specify a file name\n");
if (!SvPOK(file_sv))
croak("not a proper file name\n");
if (m_parsing)
croak("parse must not be called during parse\n");
if (!m_self || !sv_isobject(m_self))
croak("not a proper SGML::Parser::OpenSP object\n");
hv = (HV*)SvRV(m_self);
svp = hv_fetch(hv, "handler", 7, 0);
if (!svp || !*svp)
croak("you must specify a handler first\n");
if (!sv_isobject(*svp))
croak("handler must be a blessed reference\n");
m_handler = *svp;
// Boolean Options
if (_hv_fetch_SvTRUE(hv, "show_open_entities", 18))
pk.setOption(ParserEventGeneratorKit::showOpenEntities);
if (_hv_fetch_SvTRUE(hv, "show_open_elements", 18))
pk.setOption(ParserEventGeneratorKit::showOpenElements);
if (_hv_fetch_SvTRUE(hv, "show_error_numbers", 18))
pk.setOption(ParserEventGeneratorKit::showErrorNumbers);
if (_hv_fetch_SvTRUE(hv, "output_comment_decls", 20))
pk.setOption(ParserEventGeneratorKit::outputCommentDecls);
if (_hv_fetch_SvTRUE(hv, "output_marked_sections", 22))
pk.setOption(ParserEventGeneratorKit::outputMarkedSections);
if (_hv_fetch_SvTRUE(hv, "output_general_entities", 23))
pk.setOption(ParserEventGeneratorKit::outputGeneralEntities);
if (_hv_fetch_SvTRUE(hv, "map_catalog_document", 20))
pk.setOption(ParserEventGeneratorKit::mapCatalogDocument);
if (_hv_fetch_SvTRUE(hv, "restrict_file_reading", 21))
pk.setOption(ParserEventGeneratorKit::restrictFileReading);
// Options with argument
_hv_fetch_pk_setOption(hv, "warnings", 8, pk,
ParserEventGeneratorKit::enableWarning);
_hv_fetch_pk_setOption(hv, "catalogs", 8, pk,
ParserEventGeneratorKit::addCatalog);
_hv_fetch_pk_setOption(hv, "search_dirs", 11, pk,
ParserEventGeneratorKit::addSearchDir);
_hv_fetch_pk_setOption(hv, "include_params", 14, pk,
ParserEventGeneratorKit::includeParam);
_hv_fetch_pk_setOption(hv, "active_links", 12, pk,
ParserEventGeneratorKit::activateLink);
char* file = SvPV_nolen(file_sv);
#ifndef SP_WIDE_SYSTEM
m_egp = pk.makeEventGenerator(1, &file);
#else
croak("SP_WIDE_SYSTEM is not supported\n");
#endif
m_egp->inhibitMessages(true);
m_parsing = true;
m_egp->run(*this);
m_parsing = false;
// all entities closed now
m_openEntityPtr = NULL;
delete m_egp;
// no longer valid
m_egp = NULL;
// After graceful recovery croak here to propagate the exception to
// the caller. I am not sure how useful this behavior actually is,
// but it's better than silently ignoring the error or to croak
// before this point as the object would be unusable and leak memory.
if (SvTRUE(ERRSV))
croak(Nullch);
}
///////////////////////////////////////////////////////////////////////////
// OpenSP event handler
///////////////////////////////////////////////////////////////////////////
#define updatePosition(pos) m_pos = pos
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::appinfo
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::appinfo(const AppinfoEvent& e)
{
if (!handler_can("appinfo"))
return;
updatePosition(e.pos);
HV* hv = newHV();
if (!e.none)
{
hv_store(hv, "None", 4, newSViv(0), HvvNone);
hv_store(hv, "String", 6, cs2sv(e.string), HvvString);
}
else
{
hv_store(hv, "None", 4, newSViv(1), HvvNone);
}
dispatchEvent("appinfo", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::pi
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::pi(const PiEvent& e)
{
if (!handler_can("processing_instruction"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "EntityName", 10, cs2sv(e.entityName), HvvEntityName);
hv_store(hv, "Data", 4, cs2sv(e.data), HvvData);
dispatchEvent("processing_instruction", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::startElement
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::startElement(const StartElementEvent& e)
{
if (!handler_can("start_element"))
return;
updatePosition(e.pos);
HV* hv = newHV();
SV* sv = newRV_noinc((SV*)attributes2hv(e.attributes, e.nAttributes));
hv_store(hv, "Name", 4, cs2sv(e.gi), HvvName);
hv_store(hv, "Attributes", 10, sv, HvvAttributes);
switch (e.contentType)
{
case SGMLApplication::StartElementEvent::empty:
hv_store(hv, "ContentType", 11, newSVpvn("empty", 5), HvvContentType);
break;
case SGMLApplication::StartElementEvent::cdata:
hv_store(hv, "ContentType", 11, newSVpvn("cdata", 5), HvvContentType);
break;
case SGMLApplication::StartElementEvent::rcdata:
hv_store(hv, "ContentType", 11, newSVpvn("rcdata", 6), HvvContentType);
break;
case SGMLApplication::StartElementEvent::mixed:
hv_store(hv, "ContentType", 11, newSVpvn("mixed", 5), HvvContentType);
break;
case SGMLApplication::StartElementEvent::element:
hv_store(hv, "ContentType", 11, newSVpvn("element", 7), HvvContentType);
break;
}
hv_store(hv, "Included", 8, newSViv(e.included ? 1 : 0), HvvIncluded);
dispatchEvent("start_element", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::endElement
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::endElement(const EndElementEvent& e)
{
if (!handler_can("end_element"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Name", 4, cs2sv(e.gi), HvvName);
dispatchEvent("end_element", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::data
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::data(const DataEvent& e)
{
if (!handler_can("data"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Data", 4, cs2sv(e.data), HvvData);
dispatchEvent("data", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::sdata
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::sdata(const SdataEvent& e)
{
if (!handler_can("sdata"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "EntityName", 10, cs2sv(e.entityName), HvvEntityName);
hv_store(hv, "Text", 4, cs2sv(e.text), HvvText);
dispatchEvent("sdata", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::externalDataEntityRef
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::externalDataEntityRef(const ExternalDataEntityRefEvent& e)
{
if (!handler_can("external_data_entity_ref"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Entity", 6, newRV_noinc((SV*)entity2hv(e.entity)), HvvEntity);
dispatchEvent("external_data_entity_ref", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::subdocEntityRef
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::subdocEntityRef(const SubdocEntityRefEvent& e)
{
if (!handler_can("subdoc_entity_ref"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Entity", 6, newRV_noinc((SV*)entity2hv(e.entity)), HvvEntity);
dispatchEvent("subdoc_entity_ref", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::startDtd
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::startDtd(const StartDtdEvent& e)
{
if (!handler_can("start_dtd"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Name", 4, cs2sv(e.name), HvvName);
if (e.haveExternalId)
{
SV* sv = newRV_noinc((SV*)externalid2hv(e.externalId));
hv_store(hv, "ExternalId", 10, sv, HvvExternalId);
}
dispatchEvent("start_dtd", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::endDtd
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::endDtd(const EndDtdEvent& e)
{
if (!handler_can("end_dtd"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Name", 4, cs2sv(e.name), HvvName);
dispatchEvent("end_dtd", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::endProlog
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::endProlog(const EndPrologEvent& e)
{
if (!handler_can("end_prolog"))
return;
updatePosition(e.pos);
// ???
dispatchEvent("end_prolog", NULL);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::generalEntity
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::generalEntity(const GeneralEntityEvent& e)
{
if (!handler_can("general_entity"))
return;
HV* hv = newHV();
hv_store(hv, "Entity", 6, newRV_noinc((SV*)entity2hv(e.entity)), HvvEntity);
dispatchEvent("general_entity", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::commentDecl
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::commentDecl(const CommentDeclEvent& e)
{
if (!handler_can("comment_decl"))
return;
updatePosition(e.pos);
AV* av = newAV();
HV* hv = newHV();
for (unsigned int i = 0; i < e.nComments; ++i)
{
HV* comment = newHV();
hv_store(comment, "Comment", 7, cs2sv(e.comments[i]), HvvComment);
hv_store(comment, "Separator", 9, cs2sv(e.seps[i]), HvvSeparator);
av_push(av, newRV_noinc((SV*)comment));
}
hv_store(hv, "Comments", 8, newRV_noinc((SV*)av), HvvComments);
dispatchEvent("comment_decl", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::markedSectionStart
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::markedSectionStart(const MarkedSectionStartEvent& e)
{
if (!handler_can("marked_section_start"))
return;
updatePosition(e.pos);
HV* hv = newHV();
AV* av = newAV();
switch (e.status)
{
case SGMLApplication::MarkedSectionStartEvent::include:
hv_store(hv, "Status", 6, newSVpvn("include", 7), HvvStatus);
break;
case SGMLApplication::MarkedSectionStartEvent::rcdata:
hv_store(hv, "Status", 6, newSVpvn("rcdata", 6), HvvStatus);
break;
case SGMLApplication::MarkedSectionStartEvent::cdata:
hv_store(hv, "Status", 6, newSVpvn("cdata", 5), HvvStatus);
break;
case SGMLApplication::MarkedSectionStartEvent::ignore:
hv_store(hv, "Status", 6, newSVpvn("ignore", 6), HvvStatus);
break;
}
for (unsigned int i = 0; i < e.nParams; ++i)
{
HV* param = newHV();
switch (e.params[i].type)
{
case SGMLApplication::MarkedSectionStartEvent::Param::temp:
hv_store(param, "Type", 6, newSVpvn("temp", 4), HvvType);
break;
case SGMLApplication::MarkedSectionStartEvent::Param::include:
hv_store(param, "Type", 6, newSVpvn("include", 7), HvvType);
break;
case SGMLApplication::MarkedSectionStartEvent::Param::rcdata:
hv_store(param, "Type", 6, newSVpvn("rcdata", 6), HvvType);
break;
case SGMLApplication::MarkedSectionStartEvent::Param::cdata:
hv_store(param, "Type", 6, newSVpvn("cdata", 5), HvvType);
break;
case SGMLApplication::MarkedSectionStartEvent::Param::ignore:
hv_store(param, "Type", 6, newSVpvn("ignore", 6), HvvType);
break;
case SGMLApplication::MarkedSectionStartEvent::Param::entityRef:
hv_store(param, "Type", 6, newSVpvn("entityRef", 9), HvvType);
hv_store(param, "EntityName", 10, cs2sv(e.params[i].entityName), HvvEntityName);
break;
}
av_push(av, newRV_noinc((SV*)av));
}
hv_store(hv, "Params", 6, newRV_noinc((SV*)av), HvvParams);
dispatchEvent("marked_section_start", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::markedSectionEnd
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::markedSectionEnd(const MarkedSectionEndEvent& e)
{
if (!handler_can("marked_section_end"))
return;
updatePosition(e.pos);
HV* hv = newHV();
switch (e.status)
{
case SGMLApplication::MarkedSectionEndEvent::include:
hv_store(hv, "Status", 6, newSVpvn("include", 7), HvvStatus);
break;
case SGMLApplication::MarkedSectionEndEvent::rcdata:
hv_store(hv, "Status", 6, newSVpvn("rcdata", 6), HvvStatus);
break;
case SGMLApplication::MarkedSectionEndEvent::cdata:
hv_store(hv, "Status", 6, newSVpvn("cdata", 5), HvvStatus);
break;
case SGMLApplication::MarkedSectionEndEvent::ignore:
hv_store(hv, "Status", 6, newSVpvn("ignore", 6), HvvStatus);
break;
}
dispatchEvent("marked_section_end", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::ignoredChars
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::ignoredChars(const IgnoredCharsEvent& e)
{
if (!handler_can("ignored_chars"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Data", 4, cs2sv(e.data), HvvData);
dispatchEvent("ignored_chars", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::error
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::error(const ErrorEvent& e)
{
if (!handler_can("error"))
return;
updatePosition(e.pos);
HV* hv = newHV();
hv_store(hv, "Message", 7, cs2sv(e.message), HvvMessage);
switch (e.type)
{
case SGMLApplication::ErrorEvent::quantity:
hv_store(hv, "Type", 4, newSVpvn("quantity", 8), HvvType);
break;
case SGMLApplication::ErrorEvent::idref:
hv_store(hv, "Type", 4, newSVpvn("idref", 5), HvvType);
break;
case SGMLApplication::ErrorEvent::capacity:
hv_store(hv, "Type", 4, newSVpvn("capacity", 8), HvvType);
break;
case SGMLApplication::ErrorEvent::otherError:
hv_store(hv, "Type", 4, newSVpvn("otherError", 10), HvvType);
break;
case SGMLApplication::ErrorEvent::warning:
hv_store(hv, "Type", 4, newSVpvn("warning", 7), HvvType);
break;
case SGMLApplication::ErrorEvent::info:
hv_store(hv, "Type", 4, newSVpvn("info", 4), HvvType);
break;
}
dispatchEvent("error", hv);
}
///////////////////////////////////////////////////////////////////////////
// SgmlParserOpenSP::openEntityChange
///////////////////////////////////////////////////////////////////////////
void SgmlParserOpenSP::openEntityChange(const OpenEntityPtr& p)
{
// remember the current open entity
m_openEntityPtr = p;
if (handler_can("open_entity_change"))
dispatchEvent("open_entity_change", newHV());
}
///////////////////////////////////////////////////////////////////////////
// XS code
///////////////////////////////////////////////////////////////////////////
MODULE = SGML::Parser::OpenSP PACKAGE = SGML::Parser::OpenSP
PROTOTYPES: DISABLE
SgmlParserOpenSP*
SgmlParserOpenSP::new()
INIT:
SV* os;
int pfd;
CODE:
RETVAL = new SgmlParserOpenSP();
ST(0) = sv_newmortal();
sv_upgrade(ST(0), SVt_RV);
SvRV(ST(0)) = (SV*)newHV();
SvROK_on(ST(0));
sv_bless(ST(0), gv_stashpv(CLASS, 1));
hv_store((HV*)SvRV(ST(0)), "__o", 3, newSViv(PTR2IV(RETVAL)), 0);
os = get_sv("\017", 0);
pfd = (os && !strEQ("MSWin32", SvPV_nolen(os))) ? 1 : 0;
hv_store((HV*)SvRV(ST(0)), "pass_file_descriptor", 20, newSViv(pfd), 0);
void
SgmlParserOpenSP::parse(SV* file_sv)
SV*
SgmlParserOpenSP::get_location()
void
SgmlParserOpenSP::halt()
void
SgmlParserOpenSP::DESTROY()