Skip to content

Commit

Permalink
WIP on libxml v2.13.00+ local error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
dwarring committed May 31, 2024
1 parent 115a2ab commit 721b2ae
Show file tree
Hide file tree
Showing 15 changed files with 249 additions and 72 deletions.
1 change: 1 addition & 0 deletions META6.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"LibXML::Types": "lib/LibXML/Types.rakumod",
"LibXML::Utils": "lib/LibXML/Utils.rakumod",
"LibXML::X": "lib/LibXML/X.rakumod",
"LibXML::XInclude::Context": "lib/LibXML/XInclude/Context.rakumod",
"LibXML::XPath::Context": "lib/LibXML/XPath/Context.rakumod",
"LibXML::XPath::Expression": "lib/LibXML/XPath/Expression.rakumod",
"LibXML::XPath::Object": "lib/LibXML/XPath/Object.rakumod",
Expand Down
2 changes: 1 addition & 1 deletion Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ doc : Pod-To-Markdown-installed docs/index.md docs/Attr.md docs/Attr/Map.md docs
docs/Dtd.md docs/Dtd/AttrDecl.md docs/Dtd/Entity.md docs/Dtd/ElementDecl.md docs/Dtd/Notation.md docs/Dtd/ElementContent.md docs/DOM.md docs/Element.md docs/Enums.md docs/EntityRef.md docs/ErrorHandling.md docs/InputCallback.md docs/Item.md docs/Namespace.md docs/HashMap.md docs/Raw.md\
docs/Node.md docs/Node/List.md docs/Node/Set.md docs/PI.md docs/RelaxNG.md docs/Text.md docs/Pattern.md\
docs/Parser.md docs/PushParser.md docs/RegExp.md docs/Reader.md docs/Schema.md\
docs/XPath/Context.md docs/XPath/Expression.md\
docs/XInclude/Context.md docs/XPath/Context.md docs/XPath/Expression.md\
docs/SAX/Handler/SAX2.md docs/SAX/Handler/XML.md\
docs/SAX/Builder.md docs/Threads.md\
docs/_CharacterData.md
Expand Down
8 changes: 8 additions & 0 deletions docs/ErrorHandling.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ The column, if available.

LibXML Exceptions and Error Handling

### method init-local-error-handling

```raku
method init-local-error-handling() returns Mu
```

should be called from TWEAK

Synopsis
--------

Expand Down
2 changes: 1 addition & 1 deletion docs/Raw.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ A libxml regular expression, they can actually be far more complex thank the POS
class LibXML::Raw::xmlXIncludeCtxt
----------------------------------

An XInclude context
An XInclude context (libxml v2.13.00+)

class LibXML::Raw::xmlXPathAxis
-------------------------------
Expand Down
39 changes: 39 additions & 0 deletions docs/XInclude/Context.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
[[Raku LibXML Project]](https://libxml-raku.github.io)
/ [[LibXML Module]](https://libxml-raku.github.io/LibXML-raku)
/ [XInclude](https://libxml-raku.github.io/LibXML-raku/XInclude)
:: [Context](https://libxml-raku.github.io/LibXML-raku/XInclude/Context)

class LibXML::XInclude::Context
-------------------------------

XInclude Processing Context

Synopsis
--------

use LibXML::XInclude::Context;
my LibXML::XInclude::Context $xic .= new();
$xic.process-xincludes($doc);

Description
-----------

XInclude processing context.

Methods
-------

Copyright
---------

2001-2007, AxKit.com Ltd.

2002-2006, Christian Glahn.

2006-2009, Petr Pajas.

License
-------

This program is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0 [http://www.perlfoundation.org/artistic_license_2_0](http://www.perlfoundation.org/artistic_license_2_0).

2 changes: 1 addition & 1 deletion docs/XPath/Context.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ XPath Evaluation Context
Synopsis
--------

use LibXML::XPathContext;
use LibXML::XPath::Context;
use LibXML::Node;
my LibXML::XPath::Context $xpc .= new();

Expand Down
22 changes: 16 additions & 6 deletions lib/LibXML/ErrorHandling.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,13 @@ role LibXML::ErrorHandling {
has Lock $.lock .= new;
has X::LibXML @!errors;
has UInt $.max-errors = self.config.max-errors;
has $.global-error-handling is built = True;

#| should be called from TWEAK
method init-local-error-handling {
$!global-error-handling = False;
self.raw.SetErrorHandler: &structured-error-cb, Pointer;
}

# SAX External Callback
sub generic-error-cb(Str:D $msg) is export(:generic-error-cb) {
Expand All @@ -225,8 +232,8 @@ role LibXML::ErrorHandling {

# SAX External Callback
sub structured-error-cb($ctx, xmlError:D $err) is export(:structured-error-cb) {
CATCH { default { note "error handling XML structured error: $_" } }
$*XML-CONTEXT.structured-error($err);
CATCH { default { note "error handling XML structured error: $_" } }
$*XML-CONTEXT.structured-error($err);
}

# API Callback - structured
Expand Down Expand Up @@ -371,19 +378,22 @@ role LibXML::ErrorHandling {

protected sub () is hidden-from-backtrace {
my $*XML-CONTEXT = self;
my $handlers = xml6_gbl::save-error-handlers();
$raw.SetStructuredErrorFunc: &structured-error-cb;
my $handlers;
if $!global-error-handling {
$handlers := xml6_gbl::save-error-handlers();
$raw.SetStructuredErrorFunc: &structured-error-cb;
}
my @prev = self.config.setup;

$rv := &action();

self.flush-errors;
LEAVE {
self.config.restore(@prev);
xml6_gbl::restore-error-handlers($handlers);
xml6_gbl::restore-error-handlers($_)
with $handlers;
}
}

$rv;
}
}
Expand Down
20 changes: 14 additions & 6 deletions lib/LibXML/Parser.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
unit class LibXML::Parser;

use LibXML::Parser::Context;
use LibXML::XInclude::Context;
use LibXML::_Configurable;
use LibXML::_Options;

Expand Down Expand Up @@ -86,15 +87,22 @@ method !publish(Str :$URI, LibXML::Parser::Context :$ctx!) {
}

method processXIncludes (
LibXML::Document $_,
LibXML::Document:D $doc,
*%opts --> Int
) is also<process-xincludes> {
my xmlDoc $doc = .raw;
my $ctx = self!make-handler(:raw(xmlParserCtxt.new));
my $flags = self.get-flags(|%opts);
my $rv := $ctx.do: { $doc.XIncludeProcessFlags($flags) }
$ctx.publish();
$rv;
if self.config.version >= v2.13.00 {
LibXML::XInclude::Context.process-xincludes(:$doc, :$flags);
}
else {
# old-style XInclude processing
my xmlParserCtxt $raw .= new;
my $ctx = self!make-handler(:$raw);
my $rv := $ctx.do: { $doc.raw.XIncludeProcessFlags($flags) }
$ctx.publish();
$rv;

}
}

proto method parse(|c) is also<load> {*}
Expand Down
12 changes: 9 additions & 3 deletions lib/LibXML/Parser/Context.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ method set-raw(xmlParserCtxt $_) {
.UseOptions($!flags); # Note: sets ctxt.linenumbers = 1
.linenumbers = +?$!line-numbers;
$!raw.sax = .raw with $!sax-handler;
self.init-local-error-handling
unless self.config.version < v2.13.00;
}
with $old {
unless $!published {
Expand Down Expand Up @@ -116,8 +118,11 @@ method do(&action, Bool :$recover = $.recover, Bool :$check-valid) is hidden-fro
die "LibXML::Config.parser-locking needs to be enabled to allow parser-level input-callbacks"
if @input-contexts && !LibXML::Config.parser-locking;

my $handlers = xml6_gbl::save-error-handlers();
$*XML-CONTEXT.SetStructuredErrorFunc: &structured-error-cb;
my $handlers;
if $*XML-CONTEXT.global-error-handling {
$handlers := xml6_gbl::save-error-handlers();
$*XML-CONTEXT.SetStructuredErrorFunc: &structured-error-cb;
}
&*chdir(~$*CWD);
my @prev = self.config.setup();

Expand All @@ -133,7 +138,8 @@ method do(&action, Bool :$recover = $.recover, Bool :$check-valid) is hidden-fro

.deactivate with $*XML-CONTEXT && $*XML-CONTEXT.input-callbacks;

xml6_gbl::restore-error-handlers($handlers);
xml6_gbl::restore-error-handlers($_)
with $handlers;
}
}
$rv;
Expand Down
19 changes: 17 additions & 2 deletions lib/LibXML/Raw.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,20 @@ class xmlRegexp is repr(Opaque) is export {
}
}

#| An XInclude context
class xmlXIncludeCtxt is repr(Opaque) is export {}
#| An XInclude context (libxml v2.13.00+)
class xmlXIncludeCtxt is repr(Opaque) is export {
our sub New(xmlDoc --> xmlXIncludeCtxt) is native($XML2) is symbol('xmlXIncludeNewContext') {*}
method new(xmlDoc:D :$doc!) { New($doc) }
method SetFlags(int32) is native($XML2) is symbol('xmlXIncludeSetFlags') {*}
# recommended libxml 2.13.0+
method SetErrorHandler(&error-func (xmlXIncludeCtxt $, xmlError $)) is native($XML2) is symbol('xmlXIncludeSetErrorHandler') {*};
# legacy
method SetStructuredErrorFunc(&error-func (xmlXIncludeCtxt $, xmlError $)) is native($XML2) is symbol('xmlSetStructuredErrorFunc') {*};
method ProcessNode(xmlNode --> int32) is native($XML2) is symbol('xmlXIncludeProcessNode') {*}
our sub ProcessNodeWTF(Pointer:D, xmlNode --> int32) is native($XML2) is symbol('xmlXIncludeProcessNode') {*}
method Free() is native($XML2) is symbol('xmlXIncludeFreeContext') {*}

}

#| A mapping of name to axis function
class xmlXPathAxis is repr(Opaque) is export {}
Expand Down Expand Up @@ -1613,7 +1625,10 @@ class xmlParserCtxt is export {
method UseOptions(int32 --> int32) is native($XML2) is symbol('xmlCtxtUseOptions') { * }
method NewInputStream(xmlParserInputBuffer, int32 $enc --> xmlParserInput) is native($XML2) is symbol('xmlNewIOInputStream') is export {*}
method NewInputFile(Str --> xmlParserInput) is native($XML2) is export is symbol('xmlNewInputFromFile') {*}
# deprecated
method SetStructuredErrorFunc( &error-func (xmlParserCtxt $, xmlError $)) is native($XML2) is symbol('xmlSetStructuredErrorFunc') {*};
# recommended libxml 2.13.0+
method SetErrorHandler(&error-func (xmlParserCtxt $, xmlError $)) is native($XML2) is symbol('xmlCtxtSetErrorHandler') {*};
method GetLastError(--> xmlError) is native($XML2) is symbol('xmlCtxtGetLastError') is native($XML2) {*}
method Close(--> int32) is native($BIND-XML2) is symbol('xml6_parser_ctx_close') {*}
method ParserError(Str $msg) is native($XML2) is symbol('xmlParserError') {*}
Expand Down
84 changes: 84 additions & 0 deletions lib/LibXML/XInclude/Context.rakumod
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#| XInclude Processing Context
unit class LibXML::XInclude::Context;

use LibXML::_Configurable;
also does LibXML::_Configurable;

use LibXML::ErrorHandling;
also does LibXML::ErrorHandling;

use LibXML::_Options;
use LibXML::Parser::Context;
constant %Opts = %(
%LibXML::Parser::Context::Opts, %(:config);
);
also does LibXML::_Options[%Opts];

use NativeCall;

=begin pod
=head2 Synopsis
use LibXML::XInclude::Context;
my LibXML::XInclude::Context $xic .= new();
$xic.process-xincludes($doc);
=head2 Description
XInclude processing context.
=end pod

use LibXML::Config;
use LibXML::Document;
use LibXML::Raw;

has LibXML::Document:D $.doc is required;
has xmlXIncludeCtxt:D $.raw .= new: :doc($!doc.raw);
has uint32 $.flags = self.config.parser-flags;

# for the LibXML::ErrorHandling role
has Bool ($.recover, $.suppress-errors, $.suppress-warnings) is rw;

=head2 Methods

submethod TWEAK(:raw($), *%opts) is hidden-from-backtrace {

fail "This version of libxml ({self.config.version}) is too old to use XInclude contexts"
unless self.config.version >= v2.13.00;

$!raw.SetFlags($!flags);
self.init-local-error-handling;
}

submethod DESTROY {
.Free with $!raw;
}

multi method process-xincludes(::?CLASS:U: LibXML::Document:D :$doc!, *%opts --> Int) is hidden-from-backtrace {
self.new(:$doc, |%opts).process-xincludes;
}

multi method process-xincludes(::?CLASS:D: LibXML::Element:D :$elem = $!doc.root --> Int) is hidden-from-backtrace {
self.do: :$!raw, {
$!raw.ProcessNode($elem.raw);
}
}

=begin pod
=head2 Copyright
2001-2007, AxKit.com Ltd.
2002-2006, Christian Glahn.
2006-2009, Petr Pajas.
=head2 License
This program is free software; you can redistribute it and/or modify it under
the terms of the Artistic License 2.0 L<http://www.perlfoundation.org/artistic_license_2_0>.
=end pod
2 changes: 1 addition & 1 deletion lib/LibXML/XPath/Context.rakumod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ also does LibXML::ErrorHandling;
=begin pod
=head2 Synopsis
use LibXML::XPathContext;
use LibXML::XPath::Context;
use LibXML::Node;
my LibXML::XPath::Context $xpc .= new();
Expand Down
15 changes: 7 additions & 8 deletions src/domXPath.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ DLLEXPORT xmlNodeSetPtr domReverseNodeSet(xmlNodeSetPtr rv) {
}

static void
_domNodeSetDeallocator(void *entry, unsigned char *key ATTRIBUTE_UNUSED) {
_domNodeSetGC(void *entry, unsigned char *key ATTRIBUTE_UNUSED) {
xmlNodePtr twig = (xmlNodePtr) entry;
xmlNodePtr owner = _domItemOwner(twig);
if (owner) {
Expand Down Expand Up @@ -341,7 +341,7 @@ DLLEXPORT int domDeleteNodeSetItem(xmlNodeSetPtr self, xmlNodePtr item) {
}
else if (elem == item) {
_domUnreferenceItem(elem);
_domNodeSetDeallocator(elem, NULL);
_domNodeSetGC(elem, NULL);
pos = i;
}
}
Expand All @@ -354,18 +354,17 @@ DLLEXPORT int domDeleteNodeSetItem(xmlNodeSetPtr self, xmlNodePtr item) {
DLLEXPORT void
domUnreferenceNodeSet(xmlNodeSetPtr self) {
int i;
xmlHashTablePtr hash = xmlHashCreate(self->nodeNr);
xmlHashTablePtr gc = xmlHashCreate(self->nodeNr);
xmlNodePtr last_twig = NULL;

for (i = 0; i < self->nodeNr; i++) {
xmlNodePtr cur = self->nodeTab[i];

if (cur != NULL) {
xmlNodePtr twig = _domUnreferenceItem(cur);

if (!twig) {
if (cur->type == XML_NAMESPACE_DECL) {
_domNodeSetDeallocator(cur, NULL);
_domNodeSetGC(cur, NULL);
}
}
else {
Expand All @@ -375,8 +374,8 @@ domUnreferenceNodeSet(xmlNodeSetPtr self) {
char key[20];
sprintf(key, "%p", cur);

if (xmlHashLookup(hash, (xmlChar*)key) == NULL) {
xmlHashAddEntry(hash, xmlStrdup((xmlChar*)key), twig);
if (xmlHashLookup(gc, (xmlChar*)key) == NULL) {
xmlHashAddEntry(gc, xmlStrdup((xmlChar*)key), twig);
}

last_twig = twig;
Expand All @@ -385,7 +384,7 @@ domUnreferenceNodeSet(xmlNodeSetPtr self) {
}
}

xmlHashFree(hash, (xmlHashDeallocator) _domNodeSetDeallocator);
xmlHashFree(gc, (xmlHashDeallocator) _domNodeSetGC);
xmlFree(self);
}

Expand Down
Loading

0 comments on commit 721b2ae

Please sign in to comment.