Now, this patch should be very close to what it will end up being.

Worth noting now, I generalized the tie'ing mechanism and ended up with:

SV *mpxs_typemap_output_tied()               
void *mpxs_typemap_input_tied()

If something else needs a tied interface, output_tied will make a magical tied
SV with a void * of your choice and input_tied will give you that pointer back
from a magical SV.  For more details, check out  xs/typemap for T_APRTABLEOBJ

I think I got rid of all the issues I had about this one.

Having ALIAS: support in the generated XS sure would be nice though.

Compiles 100% cleanly and passes all tests, yai !

Gozer out.

/home/gozer/sources/mod_perl2/deps/perl/bin/perl build/make_diff
Index: lib/ModPerl/WrapXS.pm
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/lib/ModPerl/WrapXS.pm,v
retrieving revision 1.21
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.21 WrapXS.pm
--- lib/ModPerl/WrapXS.pm       2001/09/13 02:37:37     1.21
+++ lib/ModPerl/WrapXS.pm       2001/09/24 15:59:37
@@ -494,30 +494,31 @@
 $isa
 use $loader ();
 our \$VERSION = '0.01';
 $loader\::load __PACKAGE__;
 
 $code
 
 1;
 __END__
 EOF
 }
 
 my %typemap = (
     'Apache::RequestRec' => 'T_APACHEOBJ',
     'apr_time_t' => 'T_APR_TIME',
+    'APR::Table' => 'T_APRTABLEOBJ',
 );
 
 sub write_typemap {
     my $self = shift;
     my $typemap = $self->typemap;
     my $map = $typemap->get;
     my %seen;
 
     my $fh = $self->open_class_file('ModPerl::WrapXS', 'typemap');
     print $fh "$self->{noedit_warning_hash}\n";
 
     while (my($type, $class) = each %$map) {
         $class ||= $type;
         next if $seen{$type}++ || $typemap->special($class);
 

Index: src/modules/perl/modperl_perl_includes.h
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/src/modules/perl/modperl_perl_includes.h,v
retrieving revision 1.4
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.4 modperl_perl_includes.h
--- src/modules/perl/modperl_perl_includes.h    2001/03/15 01:26:18     1.4
+++ src/modules/perl/modperl_perl_includes.h    2001/09/24 15:59:37
@@ -31,16 +31,20 @@
 /* avoiding namespace collisions */
 
 #ifdef list
 #   undef list
 #endif
 
 /* avoiding -Wall warning */
 
 #undef dNOOP
 #define dNOOP extern int __attribute__ ((unused)) Perl___notused
 
 #ifndef G_METHOD
 #   define G_METHOD 64
 #endif
 
+#ifndef PERL_MAGIC_tied
+#   define PERL_MAGIC_tied 'P'
+#endif
+
 #endif /* MODPERL_PERL_INCLUDES_H */

Index: src/modules/perl/modperl_util.c
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/src/modules/perl/modperl_util.c,v
retrieving revision 1.17
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.17 modperl_util.c
--- src/modules/perl/modperl_util.c     2001/08/08 16:20:32     1.17
+++ src/modules/perl/modperl_util.c     2001/09/24 15:59:37
@@ -327,15 +327,65 @@
 {
     modperl_cleanup_data_t *cdata =
         (modperl_cleanup_data_t *)apr_pcalloc(p, sizeof(*cdata));
     cdata->pool = p;
     cdata->data = data;
     return cdata;
 }
 
 MP_INLINE modperl_uri_t *modperl_uri_new(apr_pool_t *p)
 {
     modperl_uri_t *uri = (modperl_uri_t *)apr_pcalloc(p, sizeof(*uri));
     uri->pool = p;
     return uri;
 }
 
+MP_INLINE SV *mpxs_typemap_output_tied(pTHX_ 
+                                       const char *class,  
+                                       SV *tsv,        
+                                       void *p)
+{
+    SV *hv = (SV *)newHV();
+    SV *rsv = newSViv(0);
+
+    sv_setref_pv(rsv, class, p);
+    sv_magic(hv, rsv, PERL_MAGIC_tied, Nullch, 0);
+    return SvREFCNT_inc(sv_bless
+                     (sv_2mortal(newRV_noinc(hv)),
+                      gv_stashpv(class, TRUE)));
+}
+
+MP_INLINE void *mpxs_typemap_input_tied(pTHX_ 
+                                        const char *class,
+                                        SV *tsv, 
+                                        void *p)
+{
+    if (sv_derived_from(tsv, class)) {
+        if (SVt_PVHV == SvTYPE(SvRV(tsv))) {
+            SV *hv = SvRV(tsv);
+            MAGIC *mg;
+
+            if (SvMAGICAL(hv)) {
+                if ((mg = mg_find(hv, PERL_MAGIC_tied))) {
+                    return (void *)SvIV((SV *)SvRV(mg->mg_obj));
+                }
+                else {
+                    Perl_warn(aTHX_ "Wrong Magick: (%c)\n", mg);
+                }
+
+            }
+            else {
+                Perl_warn(aTHX_ "Not Magick but should\n");
+            }
+
+        }
+        else {
+            return (void *)SvIV((SV *)SvRV(tsv));
+        }
+    }
+    else {
+        Perl_croak(aTHX_
+                   "argument is not a blessed reference (expecting an %s derived 
+object)",class);
+    }
+
+    return NULL;
+}

Index: src/modules/perl/modperl_util.h
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/src/modules/perl/modperl_util.h,v
retrieving revision 1.16
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.16 modperl_util.h
--- src/modules/perl/modperl_util.h     2001/08/08 07:02:41     1.16
+++ src/modules/perl/modperl_util.h     2001/09/24 15:59:37
@@ -38,16 +38,19 @@
 int modperl_require_module(pTHX_ const char *pv, int logfailure);
 int modperl_require_file(pTHX_ const char *pv, int logfailure);
 
 char *modperl_server_desc(server_rec *s, apr_pool_t *p);
 
 void modperl_xs_dl_handles_clear(pTHXo);
 
 apr_array_header_t *modperl_xs_dl_handles_get(pTHX_ apr_pool_t *p);
 
 void modperl_xs_dl_handles_close(apr_pool_t *p, apr_array_header_t *handles);
 
 modperl_cleanup_data_t *modperl_cleanup_data_new(apr_pool_t *p, void *data);
 
 MP_INLINE modperl_uri_t *modperl_uri_new(apr_pool_t *p);
 
+MP_INLINE SV *mpxs_typemap_output_tied(pTHX_ const char *class, SV *tsv, void *p);
+MP_INLINE void *mpxs_typemap_input_tied(pTHX_ const char *class, SV *tsv, void *p);
+
 #endif /* MODPERL_UTIL_H */

Index: t/response/TestAPR/table.pm
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/t/response/TestAPR/table.pm,v
retrieving revision 1.2
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.2 table.pm
--- t/response/TestAPR/table.pm 2001/09/15 18:17:31     1.2
+++ t/response/TestAPR/table.pm 2001/09/24 16:43:16
@@ -2,33 +2,33 @@
 
 use strict;
 use warnings FATAL => 'all';
 
 use Apache::Test;
 
 use Apache::Const -compile => 'OK';
 use APR::Table ();
 
 my $filter_count;
 my $TABLE_SIZE = 20;
 
 sub handler {
     my $r = shift;
 
-    plan $r, tests => 9;
+    plan $r, tests => 16;
 
-    my $table = APR::Table::make($r->pool, 16);
+    my $table = APR::Table::make($r->pool, $TABLE_SIZE);
 
     ok (UNIVERSAL::isa($table, 'APR::Table'));
 
     ok $table->set('foo','bar') || 1;
 
     ok $table->get('foo') eq 'bar';
 
     ok $table->unset('foo') || 1;
 
     ok not defined $table->get('foo');
 
     for (1..$TABLE_SIZE) {
         $table->set(chr($_+97), $_);
     }
 
@@ -47,30 +47,57 @@
     $table->do(sub {
         my ($key,$value) = @_;
         $filter_count++;
         unless ($key eq chr($value+97)) {
             die "arguments I recieved are bogus($key,$value)";
         }
         return 1;
     });
 
     ok $filter_count == $TABLE_SIZE;
 
     $filter_count = 0;
     $table->do("my_filter", "c", "b", "e");
     ok $filter_count == 3;
 
+    #Tied interface
+    {
+        my $table = APR::Table::make($r->pool, $TABLE_SIZE);
+        
+        ok (UNIVERSAL::isa($table, 'HASH'));
+    
+        ok (UNIVERSAL::isa($table, 'HASH')) && tied(%$table);
+        
+        ok $table->{'foo'} = 'bar';
+
+        ok $table->{'foo'} eq 'bar';
+
+        ok delete $table->{'foo'} || 1;
+
+        ok not exists $table->{'foo'};
+
+        for (1..$TABLE_SIZE) {
+            $table->{chr($_+97)} =  $_ ;  
+        }
+
+        $filter_count = 0;
+        foreach my $key (sort keys %$table) {
+            my_filter($key,$table->{$key});
+        }
+        ok $filter_count == $TABLE_SIZE;
+    }
+    
     Apache::OK;
 }
 
 sub my_filter {
     my ($key,$value) = @_;
     $filter_count++;
     unless ($key eq chr($value+97)) {
         die "arguments I recieved are bogus($key,$value)";
     }
     return 1;
 }
 
 sub my_filter_stop {
     my ($key,$value) = @_;
     $filter_count++;

Index: todo/api.txt
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/todo/api.txt,v
retrieving revision 1.4
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.4 api.txt
--- todo/api.txt        2001/09/15 18:17:31     1.4
+++ todo/api.txt        2001/09/24 15:59:37
@@ -1,26 +1,22 @@
 important parts of the api that are missing
 in no particular order
 ------------------------------------------
 
 tied filehandle interface:
  -CLOSE, GETC, PRINTF, READLINE
 
-APR::Table tie mechanism:
-$r->headers_out->{KEY} is not currently supported
-might want to make this optional, disabled by default
-
 $r->finfo:
 need apr_finfo_t <-> struct stat conversion (might already be there,
 haven't looked close enough yet)
 
 $r->header_{in,out}:
 deprecated, but should be included in Apache::compat
 
 $r->pnotes:
 not yet implemented
 
 $r->subprocess_env:
 in void context should populate %ENV as 1.x does
 
 $r->chdir_file:
 not safe for threaded environments.  should at least unshift @INC with

Index: xs/typemap
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/xs/typemap,v
retrieving revision 1.4
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.4 typemap
--- xs/typemap  2001/05/04 21:21:49     1.4
+++ xs/typemap  2001/09/24 16:44:24
@@ -1,35 +1,41 @@
 TYPEMAP
 void *                 T_VPTR
 char_len *              T_CHAR_LEN
 const char_len *        T_CONST_CHAR_LEN
 
 ######################################################################
 OUTPUT
 T_APACHEOBJ
        sv_setref_pv($arg, \"${ntype}\", (void*)$var);
 
+T_APRTABLEOBJ
+       $arg = mpxs_typemap_output_tied(aTHX_ \"${ntype}\", $arg, $var);
+
 T_VPTR
        sv_setiv($arg, PTR2IV($var));
 
 T_APR_TIME
        sv_setnv($arg, (NV)($var / APR_USEC_PER_SEC));
 
 ######################################################################
 INPUT
 T_APACHEOBJ
        $var = modperl_xs_sv2request_rec(aTHX_ $arg, \"$ntype\", cv)
+    
+T_APRTABLEOBJ
+       $var = mpxs_typemap_input_tied(aTHX_ \"${ntype}\", $arg, $var)
 
 T_APACHEREF
        $var = modperl_xs_sv2request_rec(aTHX_ $arg, \"$ntype\", cv)
 
 T_VPTR
        $var = INT2PTR($type,SvIV(SvROK($arg) ? SvRV($arg) : $arg))
 
 T_APR_TIME
        $var = (apr_time_t)(SvNV($arg) * APR_USEC_PER_SEC)
 
 T_CHAR_LEN
         $var = (char *)SvPV($arg, ${var}_len)
 
 T_CONST_CHAR_LEN
         $var = (const char *)SvPV($arg, ${var}_len)

Index: xs/APR/Table/APR__Table.h
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/xs/APR/Table/APR__Table.h,v
retrieving revision 1.3
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.3 APR__Table.h
--- xs/APR/Table/APR__Table.h   2001/09/19 23:08:07     1.3
+++ xs/APR/Table/APR__Table.h   2001/09/24 16:46:07
@@ -1,15 +1,22 @@
+#define mp_xs_sv2_APR__Table(sv) mpxs_typemap_input_tied(aTHX_ "APR::Table", sv, NULL)
+
+#define mpxs_APR__Table_FETCH   apr_table_get
+#define mpxs_APR__Table_STORE   apr_table_set
+#define mpxs_APR__Table_DELETE  apr_table_unset
+#define mpxs_APR__Table_CLEAR   apr_table_clear
+
 typedef struct {
     SV *cv;
     apr_hash_t *filter;
     PerlInterpreter *perl;
 } mpxs_table_do_cb_data_t;
 
 typedef int (*mpxs_apr_table_do_cb_t)(void *, const char *, const char *);
 
 static int mpxs_apr_table_do_cb(void *data,
                                 const char *key, const char *val)
 {
     mpxs_table_do_cb_data_t *tdata = (mpxs_table_do_cb_data_t *)data;
     dTHXa(tdata->perl);
     dSP;
     int rv = 0;
@@ -72,16 +79,50 @@
             apr_hash_set(tdata.filter, filter_entry, len, "1");
             MARK++;
         }
     }
   
     /* XXX: would be nice to be able to call apr_table_vdo directly, 
      * but I don't think it's possible to create/populate something 
      * that smells like a va_list with our list of filters specs
      */
     
     apr_table_do(mpxs_apr_table_do_cb, (void *)&tdata, table, NULL);
     
     /* Free tdata.filter or wait for the pool to go away? */
     
     return; 
+};
+
+static MP_INLINE int mpxs_APR__Table_EXISTS(apr_table_t *t, const char *key)
+{
+    return (NULL == apr_table_get(t, key)) ? 0 : 1;
+}
+
+static MP_INLINE const char *mpxs_APR__Table_FIRSTKEY(SV *tsv)
+{
+    dTHX;
+    apr_table_t *t = mp_xs_sv2_APR__Table(tsv);
+
+    if (apr_is_empty_table(t))
+        return NULL;
+       
+       /* Note: SvCUR is used as the iterator state counter, why not ;-? */
+    return ((apr_table_entry_t *)t->a.elts)[SvCUR(SvRV(tsv))++].key;
+}
+
+static MP_INLINE const char *mpxs_APR__Table_NEXTKEY(SV *tsv, SV *p_key)
+{
+    dTHX;
+    apr_table_t *t = mp_xs_sv2_APR__Table(tsv); 
+
+    if (apr_is_empty_table(t))
+        return NULL;
+
+    if (SvCUR(SvRV(tsv)) < t->a.nelts) {
+               /* Note: SvCUR is used as the iterator state counter, why not ;-? */
+        return ((apr_table_entry_t *)t->a.elts)[((SvCUR(SvRV(tsv)))++)].key;
+    }
+    else {
+        return NULL;
+    }
 }

Index: xs/maps/apr_functions.map
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/xs/maps/apr_functions.map,v
retrieving revision 1.21
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.21 apr_functions.map
--- xs/maps/apr_functions.map   2001/09/17 01:06:08     1.21
+++ xs/maps/apr_functions.map   2001/09/24 16:18:44
@@ -179,30 +179,37 @@
  apr_table_clear
  apr_table_copy    | | t, p
  apr_table_make
  apr_table_overlap
  apr_table_overlay | | base, overlay, p
  apr_table_add
 -apr_table_addn
  apr_table_do | mpxs_ | ...
  apr_table_get
  apr_table_merge
 -apr_table_mergen
  apr_table_set
 -apr_table_setn
  apr_table_unset
 -apr_table_vdo
+ const char *:DEFINE_FETCH | | apr_table_t *:t, const char *:key
+ void:DEFINE_STORE | | apr_table_t *:t, const char *:key, const char *:value
+ void:DEFINE_DELETE | | apr_table_t *:t, const char *:key
+ void:DEFINE_CLEAR | | apr_table_t *:t
+ mpxs_APR__Table_FIRSTKEY
+ mpxs_APR__Table_NEXTKEY
+ mpxs_APR__Table_EXISTS
 
 !MODULE=APR::File
 -apr_file_open
 -apr_file_close
 -apr_file_namedpipe_create
  apr_file_pipe_create
 -apr_file_dup
 -apr_file_flush
 -apr_file_eof
 -apr_file_gets
 -apr_file_printf
 -apr_file_write_full
 -apr_file_read_full
 -apr_file_getc
 -apr_file_ungetc

Index: xs/tables/current/ModPerl/FunctionTable.pm
===================================================================
RCS file: /home/anoncvs/mod_perl-2-cvs/xs/tables/current/ModPerl/FunctionTable.pm,v
retrieving revision 1.26
diff -u -U15 -b -B -I'$Id' -I'$Revision' -r1.26 FunctionTable.pm
--- xs/tables/current/ModPerl/FunctionTable.pm  2001/09/15 18:17:31     1.26
+++ xs/tables/current/ModPerl/FunctionTable.pm  2001/09/24 16:19:04
@@ -3998,30 +3998,68 @@
       {
         'type' => 'I32',
         'name' => 'items'
       },
       {
         'type' => 'SV **',
         'name' => 'mark'
       },
       {
         'type' => 'SV **',
         'name' => 'sp'
       }
     ]
   },
   {
+    'return_type' => 'const char *',
+    'name' => 'mpxs_APR__Table_FIRSTKEY',
+    'args' => [
+      {
+        'type' => 'SV *',
+        'name' => 'tsv'
+      },
+    ]
+  },
+  {
+    'return_type' => 'const char *',
+    'name' => 'mpxs_APR__Table_NEXTKEY',
+    'args' => [
+      {
+        'type' => 'SV *',
+        'name' => 'tsv'
+      },
+      {
+        'type' => 'SV *',
+        'name' => 'p_key'
+      },
+    ]
+  },
+  {
+    'return_type' => 'int',
+    'name' => 'mpxs_APR__Table_EXISTS',
+    'args' => [
+      {
+        'type' => 'apr_table_t *',
+        'name' => 't'
+      },
+      {
+        'type' => 'const char *',
+        'name' => 'key'
+      },
+    ]
+  },
+  {
     'return_type' => 'apr_uri_t *',
     'name' => 'mpxs_apr_uri_parse',
     'args' => [
       {
         'type' => 'PerlInterpreter *',
         'name' => 'my_perl'
       },
       {
         'type' => 'SV *',
         'name' => 'classname'
       },
       {
         'type' => 'SV *',
         'name' => 'obj'
       },


-- 
+----------------------------------------------------+
| Philippe M. Chiasson  <[EMAIL PROTECTED]>             |
+----------------------------------------------------+
| F9BF E0C2 480E 7680 1AE5  3631 CB32 A107 88C3 A5A5 |
+----------------------------------------------------+
gethostent not implemented : Your C library apparently
doesn't implement gethostent(), probably because if it did,
it'd feel morally obligated to return every hostname on the
Internet. 
        -- perldiag(1)

perl -e '$$=\${gozer};{$_=unpack(P26,pack(L,$$));/^Just Another Perl 
Hacker!\n$/&&print||$$++&&redo}'

PGP signature

Reply via email to