Gisle Aas <[EMAIL PROTECTED]> writes:

> For HTML::Parser we should go the route of making _hparser_xs_pstate
> it's own object with it's own destructor, so it can clean up itself
> and make %$self = () safe for HTML::Parser subclasses.  Perhaps some
> tricks with perl's internal magic can work.  I will look into that.

This patch use ~-magic to make deallocation happen when the IV that
points to the struct p_state goes away.  This should make %$self = ()
acceptable to use for HTML::Element again.

Regards,
Gisle


Index: Parser.xs
===================================================================
RCS file: /home/cvs/aas/perl/mods/html-parser/Parser.xs,v
retrieving revision 2.81
diff -u -p -u -r2.81 Parser.xs
--- Parser.xs   1999/12/09 19:07:33     2.81
+++ Parser.xs   1999/12/17 14:08:30
@@ -91,8 +91,18 @@ check_handler(SV* h)
 
 
 static PSTATE*
-get_pstate(SV* sv)                               /* used by XS typemap */
+get_pstate_iv(SV* sv)
 {
+    PSTATE* p = (PSTATE*)SvIV(sv);
+    if (p->signature != P_SIGNATURE)
+      croak("Bad signature in parser state object at %p", p);
+    return p;
+}
+
+
+static PSTATE*
+get_pstate_hv(SV* sv)                               /* used by XS typemap */
+{
   HV* hv;
   SV** svp;
 
@@ -101,19 +111,42 @@ get_pstate(SV* sv)                      
     croak("Not a reference to a hash");
   hv = (HV*)sv;
   svp = hv_fetch(hv, "_hparser_xs_state", 17, 0);
-  if (svp) {
-    PSTATE* p = (PSTATE*)SvIV(*svp);
-#ifdef P_MAGIC
-    if (p->magic != P_MAGIC)
-      croak("Bad magic in parser state object at %p", p);
+  if (svp)
+    return get_pstate_iv(*svp);
+  croak("Can't find '_hparser_xs_state' element in HTML::Parser hash");
+  return 0;
+}
+
+
+static void
+free_pstate(PSTATE* pstate)
+{
+  int i;
+  SvREFCNT_dec(pstate->buf);
+#ifdef MARKED_SECTION
+  SvREFCNT_dec(pstate->ms_stack);
 #endif
-    return p;
+  SvREFCNT_dec(pstate->bool_attr_val);
+  for (i = 0; i < EVENT_COUNT; i++) {
+    SvREFCNT_dec(pstate->handlers[i].cb);
+    SvREFCNT_dec(pstate->handlers[i].argspec);
   }
-  croak("Can't find '_hparser_xs_state' element in HTML::Parser hash");
+  pstate->signature = 0;
+  Safefree(pstate);
+}
+
+
+static int
+magic_free_pstate(SV *sv, MAGIC *mg)
+{
+  free_pstate(get_pstate_iv(sv));
   return 0;
 }
 
 
+MGVTBL vtbl_free_pstate = {0, 0, 0, 0, magic_free_pstate};
+
+
 
 /*
  *  XS interface definition.
@@ -130,6 +163,8 @@ _alloc_pstate(self)
        PSTATE* pstate;
        SV* sv;
        HV* hv;
+        MAGIC* mg;
+
     CODE:
        sv = SvRV(self);
         if (!sv || SvTYPE(sv) != SVt_PVHV)
@@ -137,39 +172,23 @@ _alloc_pstate(self)
        hv = (HV*)sv;
 
        Newz(56, pstate, 1, PSTATE);
-#ifdef P_MAGIC
-       pstate->magic = P_MAGIC;
-#endif
+       pstate->signature = P_SIGNATURE;
+
        sv = newSViv((IV)pstate);
+       sv_magic(sv, 0, '~', 0, 0);
+       mg = mg_find(sv, '~');
+        assert(mg);
+        mg->mg_virtual = &vtbl_free_pstate;
        SvREADONLY_on(sv);
 
        hv_store(hv, "_hparser_xs_state", 17, sv, 0);
 
-void
-DESTROY(pstate)
-       PSTATE* pstate
-    PREINIT:
-        int i;
-    CODE:
-       SvREFCNT_dec(pstate->buf);
-#ifdef MARKED_SECTION
-        SvREFCNT_dec(pstate->ms_stack);
-#endif
-        SvREFCNT_dec(pstate->bool_attr_val);
-        for (i = 0; i < EVENT_COUNT; i++) {
-          SvREFCNT_dec(pstate->handlers[i].cb);
-          SvREFCNT_dec(pstate->handlers[i].argspec);
-        }
-
-       Safefree(pstate);
-
-
 SV*
 parse(self, chunk)
        SV* self;
        SV* chunk
     PREINIT:
-       PSTATE* p_state = get_pstate(self);
+       PSTATE* p_state = get_pstate_hv(self);
     CODE:
        if (p_state->parsing)
            croak("Parse loop not allowed");
@@ -185,7 +204,7 @@ SV*
 eof(self)
        SV* self;
     PREINIT:
-       PSTATE* p_state = get_pstate(self);
+       PSTATE* p_state = get_pstate_hv(self);
     CODE:
         if (p_state->parsing)
             p_state->eof = 1;
Index: hparser.h
===================================================================
RCS file: /home/cvs/aas/perl/mods/html-parser/hparser.h,v
retrieving revision 2.7
diff -u -p -u -r2.7 hparser.h
--- hparser.h   1999/12/14 09:40:13     2.7
+++ hparser.h   1999/12/17 13:49:54
@@ -33,7 +33,7 @@ enum marked_section_t {
 #endif /* MARKED_SECTION */
 
 
-#define P_MAGIC 0x16091964  /* used to tag struct p_state for safer cast */
+#define P_SIGNATURE 0x16091964  /* tag struct p_state for safer cast */
 
 enum event_id {
   E_DECLARATION = 0,
@@ -65,7 +65,7 @@ struct p_handler {
 };
 
 struct p_state {
-  U32 magic;
+  U32 signature;
   SV* buf;
   STRLEN chunk_offset;
   bool parsing;
Index: typemap
===================================================================
RCS file: /home/cvs/aas/perl/mods/html-parser/typemap,v
retrieving revision 2.1
diff -u -p -u -r2.1 typemap
--- typemap     1999/11/08 14:09:26     2.1
+++ typemap     1999/12/17 13:44:04
@@ -2,4 +2,4 @@ PSTATE* T_PSTATE
 
 INPUT
 T_PSTATE
-       $var = get_pstate($arg)
+       $var = get_pstate_hv($arg)
Index: t/magic.t
===================================================================
RCS file: /home/cvs/aas/perl/mods/html-parser/t/magic.t,v
retrieving revision 1.3
diff -u -p -u -r1.3 magic.t
--- t/magic.t   1999/12/09 15:24:50     1.3
+++ t/magic.t   1999/12/17 14:05:10
@@ -1,4 +1,4 @@
-# Check that the magic at the top of struct p_state works and that we
+# Check that the magic signature at the top of struct p_state works and that we
 # catch modifications to _hparser_xs_state gracefully
 
 print "1..4\n";
@@ -17,7 +17,8 @@ print "not " unless $@ && $@ =~ /^Modifi
 print "ok 1\n";
 
 
-my $x = delete $p->{_hparser_xs_state};
+my $x = \$p->{_hparser_xs_state};
+delete $p->{_hparser_xs_state};
 
 eval {
     $p->xml_mode(1);
@@ -25,15 +26,15 @@ eval {
 print "not " unless $@ && $@ =~ /^Can't find '_hparser_xs_state'/;
 print "ok 2\n";
 
-$p->{_hparser_xs_state} = $x + 16;
+$p->{_hparser_xs_state} = $$x + 16;
 
 eval {
     $p->xml_mode(1);
 };
-print "not " unless $@ && $@ =~ /^Bad magic in parser state object/;
+print "not " unless $@ && $@ =~ /^Bad signature in parser state object/;
 print "ok 3\n";
 
-$p->{_hparser_xs_state} = $x;
+$p->{_hparser_xs_state} = $$x;
 
 print "not " unless $p->xml_mode(0);
 print "ok 4\n";

Reply via email to