2 XS code to test the typemap entries
4 Copyright (C) 2001 Tim Jenness.
9 #define PERL_NO_GET_CONTEXT
11 #include "EXTERN.h" /* std perl include */
12 #include "perl.h" /* std perl include */
13 #include "XSUB.h" /* XSUB include */
15 /* Prototypes for external functions */
16 FILE * xsfopen( const char * );
17 int xsfclose( FILE * );
18 int xsfprintf( FILE *, const char *);
20 /* Type definitions required for the XS typemaps */
21 typedef SV * SVREF; /* T_SVREF */
22 typedef int SysRet; /* T_SYSRET */
23 typedef int Int; /* T_INT */
24 typedef int intRef; /* T_PTRREF */
25 typedef int intObj; /* T_PTROBJ */
26 typedef int intRefIv; /* T_REF_IV_PTR */
27 typedef int intArray; /* T_ARRAY */
28 typedef int intTINT; /* T_INT */
29 typedef int intTLONG; /* T_LONG */
30 typedef short shortOPQ; /* T_OPAQUE */
31 typedef int intOpq; /* T_OPAQUEPTR */
32 typedef unsigned intUnsigned; /* T_U_INT */
33 typedef PerlIO * inputfh; /* T_IN */
34 typedef PerlIO * outputfh; /* T_OUT */
36 /* A structure to test T_OPAQUEPTR and T_PACKED */
43 typedef struct t_opaqueptr astruct;
44 typedef struct t_opaqueptr anotherstruct;
46 /* Some static memory for the tests */
48 static intRef xst_anintref;
49 static intObj xst_anintobj;
50 static intRefIv xst_anintrefiv;
51 static intOpq xst_anintopq;
53 /* A different type to refer to for testing the different
54 * AV*, HV*, etc typemaps */
58 typedef SVREF SVREF_FIXED;
60 /* Helper functions */
62 /* T_ARRAY - allocate some memory */
63 intArray * intArrayPtr( int nelem ) {
65 Newx(array, nelem, intArray);
71 XS_pack_anotherstructPtr(SV *out, anotherstruct *in)
75 if (NULL == hv_stores(hash, "a", newSViv(in->a)))
76 croak("Failed to store data in hash");
77 if (NULL == hv_stores(hash, "b", newSViv(in->b)))
78 croak("Failed to store data in hash");
79 if (NULL == hv_stores(hash, "c", newSVnv(in->c)))
80 croak("Failed to store data in hash");
81 sv_setsv(out, sv_2mortal(newRV_noinc((SV*)hash)));
84 STATIC anotherstruct *
85 XS_unpack_anotherstructPtr(SV *in)
87 dTHX; /* rats, this is expensive */
88 /* this is similar to T_HVREF since we chose to use a hash */
94 if (SvROK(tmp) && SvTYPE(SvRV(tmp)) == SVt_PVHV)
95 inhash = (HV*)SvRV(tmp);
97 Perl_croak(aTHX_ "Argument is not a HASH reference");
99 /* FIXME dunno if supposed to use perl mallocs here */
100 Newxz(out, 1, anotherstruct);
102 elem = hv_fetchs(inhash, "a", 0);
104 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
105 out->a = SvIV(*elem);
107 elem = hv_fetchs(inhash, "b", 0);
109 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
110 out->b = SvIV(*elem);
112 elem = hv_fetchs(inhash, "c", 0);
114 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
115 out->c = SvNV(*elem);
120 /* test T_PACKEDARRAY */
122 XS_pack_anotherstructPtrPtr(SV *out, anotherstruct **in, UV cnt)
127 for (i = 0; i < cnt; ++i) {
129 if (NULL == hv_stores(hash, "a", newSViv(in[i]->a)))
130 croak("Failed to store data in hash");
131 if (NULL == hv_stores(hash, "b", newSViv(in[i]->b)))
132 croak("Failed to store data in hash");
133 if (NULL == hv_stores(hash, "c", newSVnv(in[i]->c)))
134 croak("Failed to store data in hash");
135 av_push(ary, newRV_noinc((SV*)hash));
137 sv_setsv(out, sv_2mortal(newRV_noinc((SV*)ary)));
140 STATIC anotherstruct **
141 XS_unpack_anotherstructPtrPtr(SV *in)
143 dTHX; /* rats, this is expensive */
144 /* this is similar to T_HVREF since we chose to use a hash */
152 /* safely deref the input array ref */
155 if (SvROK(tmp) && SvTYPE(SvRV(tmp)) == SVt_PVAV)
156 inary = (AV*)SvRV(tmp);
158 Perl_croak(aTHX_ "Argument is not an ARRAY reference");
160 nitems = av_len(inary) + 1;
162 /* FIXME dunno if supposed to use perl mallocs here */
163 /* N+1 elements so we know the last one is NULL */
164 Newxz(out, nitems+1, anotherstruct*);
166 /* WARNING: in real code, we'd have to Safefree() on exception, but
167 * since we're testing perl, if we croak() here, stuff is
169 for (i = 0; i < nitems; ++i) {
170 Newxz(out[i], 1, anotherstruct);
171 elem = av_fetch(inary, i, 0);
173 Perl_croak(aTHX_ "Shouldn't happen: av_fetch returns NULL");
176 if (SvROK(tmp) && SvTYPE(SvRV(tmp)) == SVt_PVHV)
177 inhash = (HV*)SvRV(tmp);
179 Perl_croak(aTHX_ "Array element %"UVuf" is not a HASH reference", i);
181 elem = hv_fetchs(inhash, "a", 0);
183 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
184 out[i]->a = SvIV(*elem);
186 elem = hv_fetchs(inhash, "b", 0);
188 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
189 out[i]->b = SvIV(*elem);
191 elem = hv_fetchs(inhash, "c", 0);
193 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
194 out[i]->c = SvNV(*elem);
200 /* no special meaning as far as typemaps are concerned,
201 * just for convenience */
203 XS_release_anotherstructPtrPtr(anotherstruct **in)
206 while (in[i] != NULL)
212 MODULE = XS::Typemap PACKAGE = XS::Typemap
216 TYPEMAP: <<END_OF_TYPEMAP
218 # Typemap file for typemap testing
219 # includes bonus typemap entries
220 # Mainly so that all the standard typemaps can be exercised even when
221 # there is not a corresponding type explicitly identified in the standard
229 intRefIv * T_REF_IV_PTR
238 shortOPQ * T_OPAQUEPTR
239 astruct * T_OPAQUEPTR
240 anotherstruct * T_PACKED
241 anotherstruct ** T_PACKEDARRAY
242 AV_FIXED * T_AVREF_REFCOUNT_FIXED
243 HV_FIXED * T_HVREF_REFCOUNT_FIXED
244 CV_FIXED * T_CVREF_REFCOUNT_FIXED
245 SVREF_FIXED T_SVREF_REFCOUNT_FIXED
258 /* create a new sv for return that is a copy of the input
259 do not simply copy the pointer since the SV will be marked
260 mortal by the INPUT typemap when it is pushed back onto the stack */
261 RETVAL = sv_mortalcopy( sv );
262 /* increment the refcount since the default INPUT typemap mortalizes
263 by default and we don't want to decrement the ref count twice
265 SvREFCNT_inc(RETVAL);
284 T_SVREF_REFCOUNT_FIXED( svref )
304 ## T_AVREF_REFCOUNT_FIXED
307 T_AVREF_REFCOUNT_FIXED( av )
327 ## T_HVREF_REFCOUNT_FIXED
330 T_HVREF_REFCOUNT_FIXED( hv )
350 ## T_CVREF_REFCOUNT_FIXED
353 T_CVREF_REFCOUNT_FIXED( cv )
364 # Test a successful return
417 # The test should return the value for SVt_PVHV.
418 # 11 at the present time but we can't not rely on this
419 # for testing purposes.
447 T_BOOL_OUT( out, in )
577 # Pass in a value. Store the value in some static memory and
578 # then return the pointer
589 # pass in the pointer and return the value
595 RETVAL = *(int *)ptr;
602 # Similar test to T_PTR
603 # Pass in a value. Store the value in some static memory and
604 # then return the pointer
611 RETVAL = &xst_anintref;
615 # pass in the pointer and return the value
628 # Similar test to T_PTRREF
629 # Pass in a value. Store the value in some static memory and
630 # then return the pointer
637 RETVAL = &xst_anintobj;
641 # pass in the pointer and return the value
643 MODULE = XS::Typemap PACKAGE = intObjPtr
653 MODULE = XS::Typemap PACKAGE = XS::Typemap
662 # Similar test to T_PTROBJ
663 # Pass in a value. Store the value in some static memory and
664 # then return the pointer
667 T_REF_IV_PTR_OUT( in )
671 RETVAL = &xst_anintrefiv;
675 # pass in the pointer and return the value
677 MODULE = XS::Typemap PACKAGE = intRefIvPtr
680 T_REF_IV_PTR_IN( ptr )
688 MODULE = XS::Typemap PACKAGE = XS::Typemap
705 T_OPAQUEPTR_IN( val )
709 RETVAL = &xst_anintopq;
714 T_OPAQUEPTR_OUT( ptr )
722 T_OPAQUEPTR_OUT_short( ptr )
729 # Test it with a structure
731 T_OPAQUEPTR_IN_struct( a,b,c )
736 struct t_opaqueptr test;
746 T_OPAQUEPTR_OUT_struct( test )
749 XPUSHs(sv_2mortal(newSViv(test->a)));
750 XPUSHs(sv_2mortal(newSViv(test->b)));
751 XPUSHs(sv_2mortal(newSVnv(test->c)));
760 RETVAL = (shortOPQ)val;
773 T_OPAQUE_array( a,b,c)
801 T_PACKED_out(a, b ,c)
806 Newxz(RETVAL, 1, anotherstruct);
822 while (in[i] != NULL) {
828 XS_release_anotherstructPtrPtr(in);
832 T_PACKEDARRAY_out(...)
834 unsigned int i, nstructs, count_anotherstructPtrPtr;
836 if ((items % 3) != 0)
837 croak("Need nitems divisible by 3");
838 nstructs = (unsigned int)(items / 3);
839 count_anotherstructPtrPtr = nstructs;
840 Newxz(RETVAL, nstructs+1, anotherstruct *);
841 for (i = 0; i < nstructs; ++i) {
842 Newxz(RETVAL[i], 1, anotherstruct);
843 RETVAL[i]->a = SvIV(ST(3*i));
844 RETVAL[i]->b = SvIV(ST(3*i+1));
845 RETVAL[i]->c = SvNV(ST(3*i+2));
849 XS_release_anotherstructPtrPtr(RETVAL);
862 # Test passes in an integer array and returns it along with
863 # the number of elements
864 # Pass in a dummy value to test offsetting
866 # Problem is that xsubpp does XSRETURN(1) because we arent
867 # using PPCODE. This means that only the first element
868 # is returned. KLUGE this by using CLEANUP to return before the
870 # Note: I read this as: The "T_ARRAY" typemap is really rather broken,
871 # at least for OUTPUT. That is apart from the general design
872 # weaknesses. --Steffen
875 T_ARRAY( dummy, array, ... )
881 dummy += 0; /* Fix -Wall */
882 size_RETVAL = ix_array;
888 XSRETURN(size_RETVAL);
897 RETVAL = xsfopen( file );
908 stream = PerlIO_findFILE( f );
909 /* Release the FILE* from the PerlIO system so that we do
910 not close the file twice */
911 PerlIO_releaseFILE(f,stream);
912 /* Must release the file before closing it */
913 RETVAL = xsfclose( stream );
918 T_STDIO_print( stream, string )
922 RETVAL = xsfprintf( stream, string );
933 RETVAL = in; /* silly test but better than nothing */
943 RETVAL = in; /* silly test but better than nothing */
953 RETVAL = in; /* silly test but better than nothing */