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
180 " is not a HASH reference", i);
182 elem = hv_fetchs(inhash, "a", 0);
184 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
185 out[i]->a = SvIV(*elem);
187 elem = hv_fetchs(inhash, "b", 0);
189 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
190 out[i]->b = SvIV(*elem);
192 elem = hv_fetchs(inhash, "c", 0);
194 Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
195 out[i]->c = SvNV(*elem);
201 /* no special meaning as far as typemaps are concerned,
202 * just for convenience */
204 XS_release_anotherstructPtrPtr(anotherstruct **in)
207 while (in[i] != NULL)
213 MODULE = XS::Typemap PACKAGE = XS::Typemap
217 TYPEMAP: <<END_OF_TYPEMAP
219 # Typemap file for typemap testing
220 # includes bonus typemap entries
221 # Mainly so that all the standard typemaps can be exercised even when
222 # there is not a corresponding type explicitly identified in the standard
230 intRefIv * T_REF_IV_PTR
239 shortOPQ * T_OPAQUEPTR
240 astruct * T_OPAQUEPTR
241 anotherstruct * T_PACKED
242 anotherstruct ** T_PACKEDARRAY
243 AV_FIXED * T_AVREF_REFCOUNT_FIXED
244 HV_FIXED * T_HVREF_REFCOUNT_FIXED
245 CV_FIXED * T_CVREF_REFCOUNT_FIXED
246 SVREF_FIXED T_SVREF_REFCOUNT_FIXED
259 /* create a new sv for return that is a copy of the input
260 do not simply copy the pointer since the SV will be marked
261 mortal by the INPUT typemap when it is pushed back onto the stack */
262 RETVAL = sv_mortalcopy( sv );
263 /* increment the refcount since the default INPUT typemap mortalizes
264 by default and we don't want to decrement the ref count twice
266 SvREFCNT_inc(RETVAL);
285 T_SVREF_REFCOUNT_FIXED( svref )
305 ## T_AVREF_REFCOUNT_FIXED
308 T_AVREF_REFCOUNT_FIXED( av )
328 ## T_HVREF_REFCOUNT_FIXED
331 T_HVREF_REFCOUNT_FIXED( hv )
351 ## T_CVREF_REFCOUNT_FIXED
354 T_CVREF_REFCOUNT_FIXED( cv )
365 # Test a successful return
418 # The test should return the value for SVt_PVHV.
419 # 11 at the present time but we can't not rely on this
420 # for testing purposes.
444 PERL_UNUSED_VAR(RETVAL);
449 T_BOOL_OUT( out, in )
586 # Pass in a value. Store the value in some static memory and
587 # then return the pointer
598 # pass in the pointer and return the value
604 RETVAL = *(int *)ptr;
611 # Similar test to T_PTR
612 # Pass in a value. Store the value in some static memory and
613 # then return the pointer
620 RETVAL = &xst_anintref;
624 # pass in the pointer and return the value
637 # Similar test to T_PTRREF
638 # Pass in a value. Store the value in some static memory and
639 # then return the pointer
646 RETVAL = &xst_anintobj;
650 # pass in the pointer and return the value
652 MODULE = XS::Typemap PACKAGE = intObjPtr
662 MODULE = XS::Typemap PACKAGE = XS::Typemap
671 # Similar test to T_PTROBJ
672 # Pass in a value. Store the value in some static memory and
673 # then return the pointer
676 T_REF_IV_PTR_OUT( in )
680 RETVAL = &xst_anintrefiv;
684 # pass in the pointer and return the value
686 MODULE = XS::Typemap PACKAGE = intRefIvPtr
689 T_REF_IV_PTR_IN( ptr )
697 MODULE = XS::Typemap PACKAGE = XS::Typemap
714 T_OPAQUEPTR_IN( val )
718 RETVAL = &xst_anintopq;
723 T_OPAQUEPTR_OUT( ptr )
731 T_OPAQUEPTR_OUT_short( ptr )
738 # Test it with a structure
740 T_OPAQUEPTR_IN_struct( a,b,c )
745 struct t_opaqueptr test;
755 T_OPAQUEPTR_OUT_struct( test )
758 XPUSHs(sv_2mortal(newSViv(test->a)));
759 XPUSHs(sv_2mortal(newSViv(test->b)));
760 XPUSHs(sv_2mortal(newSVnv(test->c)));
769 RETVAL = (shortOPQ)val;
782 T_OPAQUE_array( a,b,c)
810 T_PACKED_out(a, b ,c)
815 Newxz(RETVAL, 1, anotherstruct);
831 while (in[i] != NULL) {
837 XS_release_anotherstructPtrPtr(in);
841 T_PACKEDARRAY_out(...)
843 unsigned int i, nstructs, count_anotherstructPtrPtr;
845 if ((items % 3) != 0)
846 croak("Need nitems divisible by 3");
847 nstructs = (unsigned int)(items / 3);
848 count_anotherstructPtrPtr = nstructs;
849 Newxz(RETVAL, nstructs+1, anotherstruct *);
850 for (i = 0; i < nstructs; ++i) {
851 Newxz(RETVAL[i], 1, anotherstruct);
852 RETVAL[i]->a = SvIV(ST(3*i));
853 RETVAL[i]->b = SvIV(ST(3*i+1));
854 RETVAL[i]->c = SvNV(ST(3*i+2));
858 XS_release_anotherstructPtrPtr(RETVAL);
871 # Test passes in an integer array and returns it along with
872 # the number of elements
873 # Pass in a dummy value to test offsetting
875 # Problem is that xsubpp does XSRETURN(1) because we arent
876 # using PPCODE. This means that only the first element
877 # is returned. KLUGE this by using CLEANUP to return before the
879 # Note: I read this as: The "T_ARRAY" typemap is really rather broken,
880 # at least for OUTPUT. That is apart from the general design
881 # weaknesses. --Steffen
884 T_ARRAY( dummy, array, ... )
890 dummy += 0; /* Fix -Wall */
891 size_RETVAL = ix_array;
897 XSRETURN(size_RETVAL);
906 RETVAL = xsfopen( file );
911 T_STDIO_open_ret_in_arg( file, io)
915 io = xsfopen( file );
926 stream = PerlIO_findFILE( f );
927 /* Release the FILE* from the PerlIO system so that we do
928 not close the file twice */
929 PerlIO_releaseFILE(f,stream);
930 /* Must release the file before closing it */
931 RETVAL = xsfclose( stream );
936 T_STDIO_print( stream, string )
940 RETVAL = xsfprintf( stream, string );
951 RETVAL = in; /* silly test but better than nothing */
961 RETVAL = in; /* silly test but better than nothing */
971 RETVAL = in; /* silly test but better than nothing */