Commits

Anonymous committed b1d8b2e

Modified Files:
Changes MANIFEST
+ version notes and file infos

LibXML.xs LibXML.pm
+ findnode()/ find() will return correct values now if statements
have no result
+ threaded perl patch?

perl-libxml-sax.c
+ threaded perl patch supplied mainly by andreas koenig
+ basic error and warning functions

Added Files:
ppport.h
+ required to make XML::LibXML work with older and newer perls

Comments (0)

Files changed (6)

 1.51
    - fixed parser bug with broken XML declarations
    - fixed memory management within documents that have subsets
+   - fixed some threaded perl issues
+     (very special thanks to andreas koenig for the patch)
+   - fixed findnodes() and find() to return empty arrays in array context
+     if the statement was legal but produced no result.
    - pretty formating to all serializing functions
      *NOTE* the XML::LibXML::Node::toString interface changed
      check the XML::LibXML::Node man page 
                                                  Data   => $data} );
 }
 
+# these functions will use SAX exceptions as soon i know how things really work
+sub warning {
+    my ( $parser, $message ) = @_;
+    warn( $message );
+}
+
+sub error {
+    my ( $parser, $message ) = @_;
+    warn( $message );
+}
+
+sub fatal_error {
+    my ( $parser, $message ) = @_;
+    warn( $message );
+}
+
 1;
 __END__
 
 
   my $doc = $parser->parse_file($filename);
 
-=head1 PARSING HTML
+=head2 Parsing Html
 
 As of version 0.96, XML::LibXML is capable of parsing HTML into a
 regular XML DOM. This gives you the full power of XML::LibXML on HTML
 
   my $doc = $parser->parse_html_file($filename);
 
-=head2 Extra parsing methods
-
-B<processXIncludes>
-
-  $parser->processXIncludes( $doc );
-
-While the document class implements a separate XInclude processing,
-this method, is stricly related to the parser. The use of this method
-is only required, if the parser implements special callbacks that
-should to be used for the XInclude as well.
-
-If expand_xincludes is set to 1, the method is only required to process
-XIncludes appended to the DOM after its original parsing.
-
-=head1 PUSH PARSER
+=head2 Push Parser
 
 XML::LibXML supports also a push parser interface. This allows one to
 parse large documents without actually loading the entire document
 
 =back
 
-=head1 SERIALIZATION
+=head2 Extra parsing methods
+
+B<processXIncludes>
+
+  $parser->processXIncludes( $doc );
+
+While the document class implements a separate XInclude processing,
+this method, is stricly related to the parser. The use of this method
+is only required, if the parser implements special callbacks that
+should to be used for the XInclude as well.
+
+If expand_xincludes is set to 1, the method is only required to process
+XIncludes appended to the DOM after its original parsing.
+
+=head2 Error Handling
+
+XML::LibXML throws exceptions during parseing, validation or XPath
+processing. These errors can be catched by useing eval blocks. The
+error then will be stored in B<$@>. Alternatively one can use the
+get_last_error() function of XML::LibXML. It will return the same
+string that is stored in $@. Using get_last_error() makes it still
+nessecary to eval the statement, since these function groups will
+die() on errors.
+
+get_last_error() can be called either by the class itself or by a
+parser instance:
+
+   $errstring = XML::LibXML->get_last_error();
+   $errstring = $parser->get_last_error();
+
+Note that XML::LibXML exceptions are global. That means if
+get_last_error is called on an parser instance, the last B<global>
+error will be returned. This is not nessecarily the error caused by
+the parser instance itself.
+
+=head2 Serialization
 
 The oposite of parsing is serialization. In XML::LibXML this can be
 done by using the functions toString(), toFile() and toFH(). All
 flag. This flag is an easy way to format complex xml documents without
 adding ignoreable whitespaces.
 
-=head1 XML::LibXML::Document
-
-The objects returned above have a few methods available to them:
-
-=head2 C<$doc-E<gt>toString>
-
-Convert the document to a string.
-
-=head2 C<$doc-E<gt>is_valid>
-
-Post parse validation. Returns true if the document is valid against the
-DTD specified in the DOCTYPE declaration
-
-=head2 C<$doc-E<gt>is_valid($dtd)>
-
-Same as the above, but allows you to pass in a DTD created from
-L<"XML::LibXML::Dtd">.
-
-=head2 C<$doc-E<gt>process_xinclude>
-
-Process any xinclude tags in the file. (currently using B<only> libxml2's
-default callbacks)
-
-=head1 Input Callbacks
+=head2 Input Callbacks
 
 The input callbacks are used whenever LibXML has to get something B<other
 than external parsed entities> from somewhere. The input callbacks in LibXML
 The previous code snippet will set the callbacks from the first
 example as global callbacks.
 
-=head1 Encoding
+=head2 Encoding
 
 All data will be stored UTF-8 encoded. Nevertheless the input and
 output functions are aware about the encoding of the owner
 #include "EXTERN.h"
 #include "perl.h"
 #include "XSUB.h"
+#include "ppport.h"
 
 #include <fcntl.h>
 #include <unistd.h>
 int
 LibXML_read_perl (SV * ioref, char * buffer, int len)
 {   
+    dTHX;
     dSP;
     
     int cnt;
         int count;
         SV * res;
 
+        dTHX;
         dSP;
 
         ENTER;
     if (callback) {
         int count;
 
+        dTHX;
         dSP;
 
         ENTER;
     if (callback) {
         int count;
 
+        dTHX;
         dSP;
 
         ENTER;
     if (callback) {
         int count;
 
+        dTHX;
         dSP;
 
         ENTER;
 LibXML_output_write_handler(void * ioref, char * buffer, int len)
 {   
     if ( buffer != NULL && len > 0) {
+        dTHX;
         dSP;
 
         int cnt; 
     func = hv_fetch(real_obj, "ext_ent_handler", 15, 0);
     
     if (func) {
+        dTHX;
         dSP;
         
         ENTER;
 
 char *
 get_last_error(CLASS)
-        char * CLASS 
+        SV * CLASS 
     PREINIT: 
         STRLEN len;
     CODE:
             xs_warn( "bad xpath\n" );
             if ( xpath ) 
                 xmlFree(xpath);
+            croak( "empty XPath found" );
             XSRETURN_UNDEF;
         }
     PPCODE:
             if ( SvCUR( LibXML_error ) > 0 ) {
                 croak(SvPV(LibXML_error, len));
             }
-            XSRETURN_UNDEF;
         }
 
 void
             xs_warn( "bad xpath\n" );
             if ( xpath ) 
                 xmlFree(xpath);
+            croak( "empty XPath found" );
             XSRETURN_UNDEF;
         }
     PPCODE:
             if ( SvCUR( LibXML_error ) > 0 ) {
                 croak(SvPV(LibXML_error, len));
             }
-            XSRETURN_UNDEF;
         }
         
 MODULE = XML::LibXML         PACKAGE = XML::LibXML::Element
 MANIFEST
 PHISHS.CHANGES
 README
+ppport.h
 dom.c
 dom.h
 xpath.c

perl-libxml-sax.c

 #ifdef __cplusplus
 extern "C" {
 #endif
+#define PERL_NO_GET_CONTEXT     /* we want efficiency */
+
 
 #include "EXTERN.h"
 #include "perl.h"
+#include "XSUB.h"
+#include "ppport.h"
 
 
 #include <stdlib.h>
 PmmSAXInitContext( xmlParserCtxtPtr ctxt, SV * parser ) {
     xmlNodePtr ns_stack = NULL;
     PmmSAXVectorPtr vec = NULL;
+    dTHX;
+
     vec = (PmmSAXVector*) xmlMalloc( sizeof(PmmSAXVector) );
     vec->ns_stack = xmlNewNode( NULL, "stack" );
     SvREFCNT_inc( parser );
 void 
 PmmSAXCloseContext( xmlParserCtxtPtr ctxt ) {
     PmmSAXVector * vec = (PmmSAXVectorPtr) ctxt->_private;
+    dTHX;
+
     vec = (PmmSAXVector*) ctxt->_private;
     SvREFCNT_dec( vec->parser );
     xmlFreeNode( vec->ns_stack );
 }
 
 HV *
-PmmGenElementSV( PmmSAXVectorPtr sax, const xmlChar * name ) {
+PmmGenElementSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar * name ) {
     HV * retval = newHV();
     SV *empty_sv = sv_2mortal(C2Sv("", NULL));
+
     xmlNsPtr ns = NULL;
     if ( name != NULL && xmlStrlen( name )  ) {
         const xmlChar * pos = PmmDetectNamespace( name );
 }
 
 HV *
-PmmGenAttributeSV( PmmSAXVectorPtr sax,
+PmmGenAttributeSV( pTHX_ PmmSAXVectorPtr sax,
                    const xmlChar * name,
                    const xmlChar * value ) {
     HV * retval = newHV();
     SV *empty_sv = sv_2mortal(C2Sv("", NULL));
 
+
     if ( name != NULL && xmlStrlen( name )  ) {
         const xmlChar * pos = PmmDetectNamespaceDecl( name );
 
 }
 
 HV *
-PmmGenAttributeHashSV( PmmSAXVectorPtr sax, const xmlChar **attr ) {
+PmmGenAttributeHashSV( pTHX_ PmmSAXVectorPtr sax, const xmlChar **attr ) {
     HV * retval = newHV();
     SV * atV = NULL;
     U32 atnameHash;
     const xmlChar **ta = attr;
     const xmlChar * name = NULL;
     const xmlChar * value = NULL;
+
     if ( attr != NULL ) {
         while ( *ta != NULL ) {
             if ( PmmDetectNamespaceDecl( *ta ) ) {
         while ( *ta != NULL ) {
             name = *ta; ta++;
             value = *ta; ta++;
-            atV = (SV*) PmmGenAttributeSV( sax, name, value );
+            atV = (SV*) PmmGenAttributeSV( aTHX_ sax, name, value );
             len = xmlStrlen( name );
             PERL_HASH( atnameHash, name, len );
             hv_store(retval, name, len, newRV_noinc(atV), atnameHash );
     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
     PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
+
+    dTHX;
     dSP;
     
     ENTER;
     SAVETMPS;
 
     PUSHMARK(SP) ;
-    PUSHs(sax->parser);
+    XPUSHs(sax->parser);
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::start_document", 0 );
     SPAGAIN;
 
     PUSHMARK(SP) ;
-    PUSHs(sax->parser);
+    XPUSHs(sax->parser);
 
     if ( ctxt->version != NULL ) {
-        PUSHs(C2Sv(ctxt->version, NULL));
+        XPUSHs(C2Sv(ctxt->version, NULL));
     }
 
     if ( ctxt->encoding != NULL ) {
-        PUSHs(C2Sv(ctxt->encoding, NULL));
+        XPUSHs(C2Sv(ctxt->encoding, NULL));
     }
 
     PUTBACK;
     PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
 
+    dTHX;
     dSP;
     
     ENTER;
     SAVETMPS;
 
     PUSHMARK(SP) ;
-    PUSHs(sax->parser);
+    XPUSHs(sax->parser);
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::end_document", 0 );
     int count = 0;
     SV * attrhash = NULL;
  
+    dTHX;
     dSP;
     
     ENTER;
     SAVETMPS;
 
     PmmExtendNsStack(sax);
-    attrhash = (SV*) PmmGenAttributeHashSV( sax, attr );
+    attrhash = (SV*) PmmGenAttributeHashSV(aTHX_  sax, attr );
     
     PUSHMARK(SP) ;
-    PUSHs(sax->parser);
-    XPUSHs(newRV_noinc((SV*)PmmGenElementSV(sax,name)));
+    XPUSHs(sax->parser);
+    XPUSHs(newRV_noinc((SV*)PmmGenElementSV(aTHX_ sax,name)));
     XPUSHs(newRV_noinc(attrhash));
     PUTBACK;
 
     int count = 0;
     PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
 
+    dTHX;
     dSP;
     
     ENTER;
     SAVETMPS;
 
     PUSHMARK(SP) ;
-    PUSHs(sax->parser);
-    PUSHs(C2Sv(name, NULL));
+    XPUSHs(sax->parser);
+    XPUSHs(C2Sv(name, NULL));
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::end_element", 0 );
     if ( ch != NULL ) {
         xmlChar * data = xmlStrndup( ch, len );
 
+        dTHX;
         dSP;
     
         ENTER;
         SAVETMPS;
 
         PUSHMARK(SP) ;
-        PUSHs(sax->parser);
-        PUSHs(C2Sv(data, NULL));
+        XPUSHs(sax->parser);
+        XPUSHs(C2Sv(data, NULL));
         PUTBACK;
 
         count = perl_call_pv( "XML::LibXML::_SAXParser::characters", 0 );
     if ( ch != NULL ) {
         xmlChar * data = xmlStrdup( ch );
 
+        dTHX;
         dSP;
     
         ENTER;
         SAVETMPS;
 
         PUSHMARK(SP) ;
-        PUSHs(sax->parser);
-        PUSHs(C2Sv(data, NULL));
+        XPUSHs(sax->parser);
+        XPUSHs(C2Sv(data, NULL));
         PUTBACK;
 
         count = perl_call_pv( "XML::LibXML::_SAXParser::comment", 0 );
     if ( ch != NULL ) {
         xmlChar * data = xmlStrndup( ch, len );
 
+        dTHX;
         dSP;
     
         ENTER;
         SAVETMPS;
 
         PUSHMARK(SP) ;
-        PUSHs(sax->parser);
-        PUSHs(C2Sv(data, NULL));
+        XPUSHs(sax->parser);
+        XPUSHs(C2Sv(data, NULL));
         PUTBACK;
 
         count = perl_call_pv( "XML::LibXML::_SAXParser::cdata_block", 0 );
     PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
     int count = 0;
 
+    dTHX;
     dSP;
     
     ENTER;
     SAVETMPS;
 
     PUSHMARK(SP) ;
-    PUSHs(sax->parser);
-    PUSHs(C2Sv(target, NULL));
-    PUSHs(C2Sv(data, NULL));
+    XPUSHs(sax->parser);
+    XPUSHs(C2Sv(target, NULL));
+    XPUSHs(C2Sv(data, NULL));
     PUTBACK;
 
     count = perl_call_pv( "XML::LibXML::_SAXParser::processing_instruction", 0 );
     return 1;
 }
 
+int
+PmmSaxWarning(void * ctx, const char * msg, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
+
+    va_list args;
+    SV * svMessage;
+
+    dTHX;
+    dSP;
+    svMessage = NEWSV(0,512);
+
+    va_start(args, msg);
+    sv_vsetpvfn(svMessage, msg, xmlStrlen(msg), &args, NULL, 0, NULL);
+    va_end(args);
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP) ;
+    XPUSHs(sax->parser);
+
+    XPUSHs(svMessage);
+    PUTBACK;
+
+    perl_call_pv( "XML::LibXML::_SAXParser::warning", 0 );
+    
+    FREETMPS ;
+    LEAVE ;
+    SvREFCNT_dec(svMessage);
+    return 1;
+}
+
+
+int
+PmmSaxError(void * ctx, const char * msg, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
+
+    va_list args;
+    SV * svMessage;
+ 
+    dTHX;
+    dSP;
+
+
+    svMessage = NEWSV(0,512);
+
+    va_start(args, msg);
+    sv_vsetpvfn(svMessage, msg, xmlStrlen(msg), &args, NULL, 0, NULL);
+    va_end(args);
+
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP) ;
+    XPUSHs(sax->parser);
+
+    XPUSHs(svMessage);
+    PUTBACK;
+    perl_call_pv( "XML::LibXML::_SAXParser::error", 0 );
+    
+    FREETMPS ;
+    LEAVE ;
+    SvREFCNT_dec(svMessage);
+    return 1;
+}
+
+
+int
+PmmSaxFatalError(void * ctx, const char * msg, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr)ctx;
+    PmmSAXVectorPtr sax = (PmmSAXVectorPtr)ctxt->_private;
+
+    va_list args;
+    SV * svMessage;
+ 
+    dTHX;
+    dSP;
+
+    svMessage = NEWSV(0,512);
+
+    va_start(args, msg);
+    sv_vsetpvfn(svMessage, msg, xmlStrlen(msg), &args, NULL, 0, NULL);
+    va_end(args);
+
+    ENTER;
+    SAVETMPS;
+
+    PUSHMARK(SP) ;
+    XPUSHs(sax->parser);
+
+    XPUSHs(svMessage);
+    PUTBACK;
+    perl_call_pv( "XML::LibXML::_SAXParser::fatal_error", 0 );
+    
+    FREETMPS ;
+    LEAVE ;
+    SvREFCNT_dec(svMessage);
+    return 1;
+}
+
 /* NOTE:
  * end document is not handled by the parser itself! use 
  * XML::LibXML::SAX instead!
     retval->processingInstruction = (processingInstructionSAXFunc)&PSaxProcessingInstruction;
 
     /* warning functions should be internal */
-    retval->warning    = &xmlParserWarning;
-    retval->error      = &xmlParserError;
-    retval->fatalError = &xmlParserError;
+    retval->warning    = &PmmSaxWarning;
+    retval->error      = &PmmSaxError;
+    retval->fatalError = &PmmSaxFatalError;
 
     return retval;
 }
+
+/* ppport.h -- Perl/Pollution/Portability Version 2.0002 
+ *
+ * Automatically Created by Devel::PPPort on Wed May 22 03:48:07 2002 
+ *
+ * Do NOT edit this file directly! -- Edit PPPort.pm instead.
+ *
+ * Version 2.x, Copyright (C) 2001, Paul Marquess.
+ * Version 1.x, Copyright (C) 1999, Kenneth Albanowski.
+ * This code may be used and distributed under the same license as any
+ * version of Perl.
+ * 
+ * This version of ppport.h is designed to support operation with Perl
+ * installations back to 5.004, and has been tested up to 5.8.0.
+ *
+ * If this version of ppport.h is failing during the compilation of this
+ * module, please check if a newer version of Devel::PPPort is available
+ * on CPAN before sending a bug report.
+ *
+ * If you are using the latest version of Devel::PPPort and it is failing
+ * during compilation of this module, please send a report to perlbug@perl.com
+ *
+ * Include all following information:
+ *
+ *  1. The complete output from running "perl -V"
+ *
+ *  2. This file.
+ *
+ *  3. The name & version of the module you were trying to build.
+ *
+ *  4. A full log of the build that failed.
+ *
+ *  5. Any other information that you think could be relevant.
+ *
+ *
+ * For the latest version of this code, please retreive the Devel::PPPort
+ * module from CPAN.
+ * 
+ */
+
+/*
+ * In order for a Perl extension module to be as portable as possible
+ * across differing versions of Perl itself, certain steps need to be taken.
+ * Including this header is the first major one, then using dTHR is all the
+ * appropriate places and using a PL_ prefix to refer to global Perl
+ * variables is the second.
+ *
+ */
+
+
+/* If you use one of a few functions that were not present in earlier
+ * versions of Perl, please add a define before the inclusion of ppport.h
+ * for a static include, or use the GLOBAL request in a single module to
+ * produce a global definition that can be referenced from the other
+ * modules.
+ * 
+ * Function:            Static define:           Extern define:
+ * newCONSTSUB()        NEED_newCONSTSUB         NEED_newCONSTSUB_GLOBAL
+ *
+ */
+ 
+
+/* To verify whether ppport.h is needed for your module, and whether any
+ * special defines should be used, ppport.h can be run through Perl to check
+ * your source code. Simply say:
+ * 
+ * 	perl -x ppport.h *.c *.h *.xs foo/bar*.c [etc]
+ * 
+ * The result will be a list of patches suggesting changes that should at
+ * least be acceptable, if not necessarily the most efficient solution, or a
+ * fix for all possible problems. It won't catch where dTHR is needed, and
+ * doesn't attempt to account for global macro or function definitions,
+ * nested includes, typemaps, etc.
+ * 
+ * In order to test for the need of dTHR, please try your module under a
+ * recent version of Perl that has threading compiled-in.
+ *
+ */ 
+
+
+/*
+#!/usr/bin/perl
+@ARGV = ("*.xs") if !@ARGV;
+%badmacros = %funcs = %macros = (); $replace = 0;
+foreach (<DATA>) {
+	$funcs{$1} = 1 if /Provide:\s+(\S+)/;
+	$macros{$1} = 1 if /^#\s*define\s+([a-zA-Z0-9_]+)/;
+	$replace = $1 if /Replace:\s+(\d+)/;
+	$badmacros{$2}=$1 if $replace and /^#\s*define\s+([a-zA-Z0-9_]+).*?\s+([a-zA-Z0-9_]+)/;
+	$badmacros{$1}=$2 if /Replace (\S+) with (\S+)/;
+}
+foreach $filename (map(glob($_),@ARGV)) {
+	unless (open(IN, "<$filename")) {
+		warn "Unable to read from $file: $!\n";
+		next;
+	}
+	print "Scanning $filename...\n";
+	$c = ""; while (<IN>) { $c .= $_; } close(IN);
+	$need_include = 0; %add_func = (); $changes = 0;
+	$has_include = ($c =~ /#.*include.*ppport/m);
+
+	foreach $func (keys %funcs) {
+		if ($c =~ /#.*define.*\bNEED_$func(_GLOBAL)?\b/m) {
+			if ($c !~ /\b$func\b/m) {
+				print "If $func isn't needed, you don't need to request it.\n" if
+				$changes += ($c =~ s/^.*#.*define.*\bNEED_$func\b.*\n//m);
+			} else {
+				print "Uses $func\n";
+				$need_include = 1;
+			}
+		} else {
+			if ($c =~ /\b$func\b/m) {
+				$add_func{$func} =1 ;
+				print "Uses $func\n";
+				$need_include = 1;
+			}
+		}
+	}
+
+	if (not $need_include) {
+		foreach $macro (keys %macros) {
+			if ($c =~ /\b$macro\b/m) {
+				print "Uses $macro\n";
+				$need_include = 1;
+			}
+		}
+	}
+
+	foreach $badmacro (keys %badmacros) {
+		if ($c =~ /\b$badmacro\b/m) {
+			$changes += ($c =~ s/\b$badmacro\b/$badmacros{$badmacro}/gm);
+			print "Uses $badmacros{$badmacro} (instead of $badmacro)\n";
+			$need_include = 1;
+		}
+	}
+	
+	if (scalar(keys %add_func) or $need_include != $has_include) {
+		if (!$has_include) {
+			$inc = join('',map("#define NEED_$_\n", sort keys %add_func)).
+			       "#include \"ppport.h\"\n";
+			$c = "$inc$c" unless $c =~ s/#.*include.*XSUB.*\n/$&$inc/m;
+		} elsif (keys %add_func) {
+			$inc = join('',map("#define NEED_$_\n", sort keys %add_func));
+			$c = "$inc$c" unless $c =~ s/^.*#.*include.*ppport.*$/$inc$&/m;
+		}
+		if (!$need_include) {
+			print "Doesn't seem to need ppport.h.\n";
+			$c =~ s/^.*#.*include.*ppport.*\n//m;
+		}
+		$changes++;
+	}
+	
+	if ($changes) {
+		open(OUT,">/tmp/ppport.h.$$");
+		print OUT $c;
+		close(OUT);
+		open(DIFF, "diff -u $filename /tmp/ppport.h.$$|");
+		while (<DIFF>) { s!/tmp/ppport\.h\.$$!$filename.patched!; print STDOUT; }
+		close(DIFF);
+		unlink("/tmp/ppport.h.$$");
+	} else {
+		print "Looks OK\n";
+	}
+}
+__DATA__
+*/
+
+#ifndef _P_P_PORTABILITY_H_
+#define _P_P_PORTABILITY_H_
+
+#ifndef PERL_REVISION
+#   ifndef __PATCHLEVEL_H_INCLUDED__
+#       include "patchlevel.h"
+#   endif
+#   ifndef PERL_REVISION
+#	define PERL_REVISION	(5)
+        /* Replace: 1 */
+#       define PERL_VERSION	PATCHLEVEL
+#       define PERL_SUBVERSION	SUBVERSION
+        /* Replace PERL_PATCHLEVEL with PERL_VERSION */
+        /* Replace: 0 */
+#   endif
+#endif
+
+#define PERL_BCDVERSION ((PERL_REVISION * 0x1000000L) + (PERL_VERSION * 0x1000L) + PERL_SUBVERSION)
+
+/* It is very unlikely that anyone will try to use this with Perl 6 
+   (or greater), but who knows.
+ */
+#if PERL_REVISION != 5
+#	error ppport.h only works with Perl version 5
+#endif /* PERL_REVISION != 5 */
+
+#ifndef ERRSV
+#	define ERRSV perl_get_sv("@",FALSE)
+#endif
+
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5))
+/* Replace: 1 */
+#	define PL_Sv		Sv
+#	define PL_compiling	compiling
+#	define PL_copline	copline
+#	define PL_curcop	curcop
+#	define PL_curstash	curstash
+#	define PL_defgv		defgv
+#	define PL_dirty		dirty
+#	define PL_hints		hints
+#	define PL_na		na
+#	define PL_perldb	perldb
+#	define PL_rsfp_filters	rsfp_filters
+#	define PL_rsfpv		rsfp
+#	define PL_stdingv	stdingv
+#	define PL_sv_no		sv_no
+#	define PL_sv_undef	sv_undef
+#	define PL_sv_yes	sv_yes
+/* Replace: 0 */
+#endif
+
+#ifndef pTHX
+#    define dTHX int dTHX = 0
+#    define pTHX
+#    define pTHX_
+#    define aTHX
+#    define aTHX_
+#endif         
+
+#ifndef PTR2IV
+#    define PTR2IV(d)   (IV)(d)
+#endif
+ 
+#ifndef INT2PTR
+#    define INT2PTR(any,d)      (any)(d)
+#endif
+
+#ifndef dTHR
+#  ifdef WIN32
+#	define dTHR extern int Perl___notused
+#  else
+#	define dTHR extern int errno
+#  endif
+#endif
+
+#ifndef boolSV
+#	define boolSV(b) ((b) ? &PL_sv_yes : &PL_sv_no)
+#endif
+
+#ifndef gv_stashpvn
+#	define gv_stashpvn(str,len,flags) gv_stashpv(str,flags)
+#endif
+
+#ifndef newSVpvn
+#	define newSVpvn(data,len) ((len) ? newSVpv ((data), (len)) : newSVpv ("", 0))
+#endif
+
+#ifndef newRV_inc
+/* Replace: 1 */
+#	define newRV_inc(sv) newRV(sv)
+/* Replace: 0 */
+#endif
+
+/* DEFSV appears first in 5.004_56 */
+#ifndef DEFSV
+#  define DEFSV	GvSV(PL_defgv)
+#endif
+
+#ifndef SAVE_DEFSV
+#    define SAVE_DEFSV SAVESPTR(GvSV(PL_defgv))
+#endif
+
+#ifndef newRV_noinc
+#  ifdef __GNUC__
+#    define newRV_noinc(sv)               \
+      ({                                  \
+          SV *nsv = (SV*)newRV(sv);       \
+          SvREFCNT_dec(sv);               \
+          nsv;                            \
+      })
+#  else
+#    if defined(CRIPPLED_CC) || defined(USE_THREADS)
+static SV * newRV_noinc (SV * sv)
+{
+          SV *nsv = (SV*)newRV(sv);       
+          SvREFCNT_dec(sv);               
+          return nsv;                     
+}
+#    else
+#      define newRV_noinc(sv)    \
+        (PL_Sv=(SV*)newRV(sv), SvREFCNT_dec(sv), (SV*)PL_Sv)
+#    endif
+#  endif
+#endif
+
+/* Provide: newCONSTSUB */
+
+/* newCONSTSUB from IO.xs is in the core starting with 5.004_63 */
+#if (PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION < 63))
+
+#if defined(NEED_newCONSTSUB)
+static
+#else
+extern void newCONSTSUB _((HV * stash, char * name, SV *sv));
+#endif
+
+#if defined(NEED_newCONSTSUB) || defined(NEED_newCONSTSUB_GLOBAL)
+void
+newCONSTSUB(stash,name,sv)
+HV *stash;
+char *name;
+SV *sv;
+{
+	U32 oldhints = PL_hints;
+	HV *old_cop_stash = PL_curcop->cop_stash;
+	HV *old_curstash = PL_curstash;
+	line_t oldline = PL_curcop->cop_line;
+	PL_curcop->cop_line = PL_copline;
+
+	PL_hints &= ~HINT_BLOCK_SCOPE;
+	if (stash)
+		PL_curstash = PL_curcop->cop_stash = stash;
+
+	newSUB(
+
+#if (PERL_VERSION < 3) || ((PERL_VERSION == 3) && (PERL_SUBVERSION < 22))
+     /* before 5.003_22 */
+		start_subparse(),
+#else
+#  if (PERL_VERSION == 3) && (PERL_SUBVERSION == 22)
+     /* 5.003_22 */
+     		start_subparse(0),
+#  else
+     /* 5.003_23  onwards */
+     		start_subparse(FALSE, 0),
+#  endif
+#endif
+
+		newSVOP(OP_CONST, 0, newSVpv(name,0)),
+		newSVOP(OP_CONST, 0, &PL_sv_no),   /* SvPV(&PL_sv_no) == "" -- GMB */
+		newSTATEOP(0, Nullch, newSVOP(OP_CONST, 0, sv))
+	);
+
+	PL_hints = oldhints;
+	PL_curcop->cop_stash = old_cop_stash;
+	PL_curstash = old_curstash;
+	PL_curcop->cop_line = oldline;
+}
+#endif
+
+#endif /* newCONSTSUB */
+
+#ifndef NOOP
+#  define NOOP (void)0
+#endif
+
+#ifdef HASATTRIBUTE
+#  define PERL_UNUSED_DECL __attribute__((unused))
+#else
+#  define PERL_UNUSED_DECL
+#endif    
+
+#ifndef dNOOP
+#  define dNOOP extern int Perl___notused PERL_UNUSED_DECL
+#endif
+
+#ifndef START_MY_CXT
+
+/*
+ * Boilerplate macros for initializing and accessing interpreter-local
+ * data from C.  All statics in extensions should be reworked to use
+ * this, if you want to make the extension thread-safe.  See ext/re/re.xs
+ * for an example of the use of these macros.
+ *
+ * Code that uses these macros is responsible for the following:
+ * 1. #define MY_CXT_KEY to a unique string, e.g. "DynaLoader_guts"
+ * 2. Declare a typedef named my_cxt_t that is a structure that contains
+ *    all the data that needs to be interpreter-local.
+ * 3. Use the START_MY_CXT macro after the declaration of my_cxt_t.
+ * 4. Use the MY_CXT_INIT macro such that it is called exactly once
+ *    (typically put in the BOOT: section).
+ * 5. Use the members of the my_cxt_t structure everywhere as
+ *    MY_CXT.member.
+ * 6. Use the dMY_CXT macro (a declaration) in all the functions that
+ *    access MY_CXT.
+ */
+
+#if defined(MULTIPLICITY) || defined(PERL_OBJECT) || \
+    defined(PERL_CAPI)    || defined(PERL_IMPLICIT_CONTEXT)
+
+/* This must appear in all extensions that define a my_cxt_t structure,
+ * right after the definition (i.e. at file scope).  The non-threads
+ * case below uses it to declare the data as static. */
+#define START_MY_CXT
+
+#if (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION < 68 ))
+/* Fetches the SV that keeps the per-interpreter data. */
+#define dMY_CXT_SV \
+	SV *my_cxt_sv = perl_get_sv(MY_CXT_KEY, FALSE)
+#else /* >= perl5.004_68 */
+#define dMY_CXT_SV \
+	SV *my_cxt_sv = *hv_fetch(PL_modglobal, MY_CXT_KEY,		\
+				  sizeof(MY_CXT_KEY)-1, TRUE)
+#endif /* < perl5.004_68 */
+
+/* This declaration should be used within all functions that use the
+ * interpreter-local data. */
+#define dMY_CXT	\
+	dMY_CXT_SV;							\
+	my_cxt_t *my_cxtp = INT2PTR(my_cxt_t*,SvUV(my_cxt_sv))
+
+/* Creates and zeroes the per-interpreter data.
+ * (We allocate my_cxtp in a Perl SV so that it will be released when
+ * the interpreter goes away.) */
+#define MY_CXT_INIT \
+	dMY_CXT_SV;							\
+	/* newSV() allocates one more than needed */			\
+	my_cxt_t *my_cxtp = (my_cxt_t*)SvPVX(newSV(sizeof(my_cxt_t)-1));\
+	Zero(my_cxtp, 1, my_cxt_t);					\
+	sv_setuv(my_cxt_sv, PTR2UV(my_cxtp))
+
+/* This macro must be used to access members of the my_cxt_t structure.
+ * e.g. MYCXT.some_data */
+#define MY_CXT		(*my_cxtp)
+
+/* Judicious use of these macros can reduce the number of times dMY_CXT
+ * is used.  Use is similar to pTHX, aTHX etc. */
+#define pMY_CXT		my_cxt_t *my_cxtp
+#define pMY_CXT_	pMY_CXT,
+#define _pMY_CXT	,pMY_CXT
+#define aMY_CXT		my_cxtp
+#define aMY_CXT_	aMY_CXT,
+#define _aMY_CXT	,aMY_CXT
+
+#else /* single interpreter */
+
+
+#define START_MY_CXT	static my_cxt_t my_cxt;
+#define dMY_CXT_SV	dNOOP
+#define dMY_CXT		dNOOP
+#define MY_CXT_INIT	NOOP
+#define MY_CXT		my_cxt
+
+#define pMY_CXT		void
+#define pMY_CXT_
+#define _pMY_CXT
+#define aMY_CXT
+#define aMY_CXT_
+#define _aMY_CXT
+
+#endif 
+
+#endif /* START_MY_CXT */
+
+#endif /* _P_P_PORTABILITY_H_ */
+
+/* End of File ppport.h */