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_tindex(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.
443 PERL_UNUSED_VAR(RETVAL);
448 T_BOOL_OUT( out, in )
585 # Pass in a value. Store the value in some static memory and
586 # then return the pointer
597 # pass in the pointer and return the value
603 RETVAL = *(int *)ptr;
610 # Similar test to T_PTR
611 # Pass in a value. Store the value in some static memory and
612 # then return the pointer
619 RETVAL = &xst_anintref;
623 # pass in the pointer and return the value
636 # Similar test to T_PTRREF
637 # Pass in a value. Store the value in some static memory and
638 # then return the pointer
645 RETVAL = &xst_anintobj;
649 # pass in the pointer and return the value
651 MODULE = XS::Typemap PACKAGE = intObjPtr
661 MODULE = XS::Typemap PACKAGE = XS::Typemap
670 # Similar test to T_PTROBJ
671 # Pass in a value. Store the value in some static memory and
672 # then return the pointer
675 T_REF_IV_PTR_OUT( in )
679 RETVAL = &xst_anintrefiv;
683 # pass in the pointer and return the value
685 MODULE = XS::Typemap PACKAGE = intRefIvPtr
688 T_REF_IV_PTR_IN( ptr )
696 MODULE = XS::Typemap PACKAGE = XS::Typemap
713 T_OPAQUEPTR_IN( val )
717 RETVAL = &xst_anintopq;
722 T_OPAQUEPTR_OUT( ptr )
730 T_OPAQUEPTR_OUT_short( ptr )
737 # Test it with a structure
739 T_OPAQUEPTR_IN_struct( a,b,c )
744 struct t_opaqueptr test;
754 T_OPAQUEPTR_OUT_struct( test )
757 XPUSHs(sv_2mortal(newSViv(test->a)));
758 XPUSHs(sv_2mortal(newSViv(test->b)));
759 XPUSHs(sv_2mortal(newSVnv(test->c)));
768 RETVAL = (shortOPQ)val;
781 T_OPAQUE_array( a,b,c)
809 T_PACKED_out(a, b ,c)
814 Newxz(RETVAL, 1, anotherstruct);
830 while (in[i] != NULL) {
836 XS_release_anotherstructPtrPtr(in);
840 T_PACKEDARRAY_out(...)
842 unsigned int i, nstructs, count_anotherstructPtrPtr;
844 if ((items % 3) != 0)
845 croak("Need nitems divisible by 3");
846 nstructs = (unsigned int)(items / 3);
847 count_anotherstructPtrPtr = nstructs;
848 Newxz(RETVAL, nstructs+1, anotherstruct *);
849 for (i = 0; i < nstructs; ++i) {
850 Newxz(RETVAL[i], 1, anotherstruct);
851 RETVAL[i]->a = SvIV(ST(3*i));
852 RETVAL[i]->b = SvIV(ST(3*i+1));
853 RETVAL[i]->c = SvNV(ST(3*i+2));
857 XS_release_anotherstructPtrPtr(RETVAL);
870 # Test passes in an integer array and returns it along with
871 # the number of elements
872 # Pass in a dummy value to test offsetting
874 # Problem is that xsubpp does XSRETURN(1) because we arent
875 # using PPCODE. This means that only the first element
876 # is returned. KLUGE this by using CLEANUP to return before the
878 # Note: I read this as: The "T_ARRAY" typemap is really rather broken,
879 # at least for OUTPUT. That is apart from the general design
880 # weaknesses. --Steffen
883 T_ARRAY( dummy, array, ... )
889 dummy += 0; /* Fix -Wall */
890 size_RETVAL = ix_array;
896 XSRETURN(size_RETVAL);
905 RETVAL = xsfopen( file );
910 T_STDIO_open_ret_in_arg( file, io)
914 io = xsfopen( file );
925 stream = PerlIO_findFILE( f );
926 /* Release the FILE* from the PerlIO system so that we do
927 not close the file twice */
928 PerlIO_releaseFILE(f,stream);
929 /* Must release the file before closing it */
930 RETVAL = xsfclose( stream );
935 T_STDIO_print( stream, string )
939 RETVAL = xsfprintf( stream, string );
950 RETVAL = in; /* silly test but better than nothing */
960 RETVAL = in; /* silly test but better than nothing */
970 RETVAL = in; /* silly test but better than nothing */