1 /*
2    XS code to test the typemap entries
3 
4    Copyright (C) 2001 Tim Jenness.
5    All Rights Reserved
6 
7 */
8 
9 #define PERL_NO_GET_CONTEXT
10 
11 #include "EXTERN.h"   /* std perl include */
12 #include "perl.h"     /* std perl include */
13 #include "XSUB.h"     /* XSUB include */
14 
15 /* Prototypes for external functions */
16 FILE * xsfopen( const char * );
17 int xsfclose( FILE * );
18 int xsfprintf( FILE *, const char *);
19 
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 */
35 
36 /* A structure to test T_OPAQUEPTR and T_PACKED */
37 struct t_opaqueptr {
38   int a;
39   int b;
40   double c;
41 };
42 
43 typedef struct t_opaqueptr astruct;
44 typedef struct t_opaqueptr anotherstruct;
45 
46 /* Some static memory for the tests */
47 static I32 xst_anint;
48 static intRef xst_anintref;
49 static intObj xst_anintobj;
50 static intRefIv xst_anintrefiv;
51 static intOpq xst_anintopq;
52 
53 /* A different type to refer to for testing the different
54  * AV*, HV*, etc typemaps */
55 typedef AV AV_FIXED;
56 typedef HV HV_FIXED;
57 typedef CV CV_FIXED;
58 typedef SVREF SVREF_FIXED;
59 
60 /* Helper functions */
61 
62 /* T_ARRAY - allocate some memory */
intArrayPtr(int nelem)63 intArray * intArrayPtr( int nelem ) {
64     intArray * array;
65     Newx(array, nelem, intArray);
66     return array;
67 }
68 
69 /* test T_PACKED */
70 STATIC void
XS_pack_anotherstructPtr(SV * out,anotherstruct * in)71 XS_pack_anotherstructPtr(SV *out, anotherstruct *in)
72 {
73     dTHX;
74     HV *hash = newHV();
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)));
82 }
83 
84 STATIC anotherstruct *
XS_unpack_anotherstructPtr(SV * in)85 XS_unpack_anotherstructPtr(SV *in)
86 {
87     dTHX; /* rats, this is expensive */
88     /* this is similar to T_HVREF since we chose to use a hash */
89     HV *inhash;
90     SV **elem;
91     anotherstruct *out;
92     SV *const tmp = in;
93     SvGETMAGIC(tmp);
94     if (SvROK(tmp) && SvTYPE(SvRV(tmp)) == SVt_PVHV)
95        inhash = (HV*)SvRV(tmp);
96     else
97         Perl_croak(aTHX_ "Argument is not a HASH reference");
98 
99     /* FIXME dunno if supposed to use perl mallocs here */
100     Newxz(out, 1, anotherstruct);
101 
102     elem = hv_fetchs(inhash, "a", 0);
103     if (elem == NULL)
104       Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
105     out->a = SvIV(*elem);
106 
107     elem = hv_fetchs(inhash, "b", 0);
108     if (elem == NULL)
109       Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
110     out->b = SvIV(*elem);
111 
112     elem = hv_fetchs(inhash, "c", 0);
113     if (elem == NULL)
114       Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
115     out->c = SvNV(*elem);
116 
117     return out;
118 }
119 
120 /* test T_PACKEDARRAY */
121 STATIC void
XS_pack_anotherstructPtrPtr(SV * out,anotherstruct ** in,UV cnt)122 XS_pack_anotherstructPtrPtr(SV *out, anotherstruct **in, UV cnt)
123 {
124     dTHX;
125     UV i;
126     AV *ary = newAV();
127     for (i = 0; i < cnt; ++i) {
128         HV *hash = newHV();
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));
136     }
137     sv_setsv(out, sv_2mortal(newRV_noinc((SV*)ary)));
138 }
139 
140 STATIC anotherstruct **
XS_unpack_anotherstructPtrPtr(SV * in)141 XS_unpack_anotherstructPtrPtr(SV *in)
142 {
143     dTHX; /* rats, this is expensive */
144     /* this is similar to T_HVREF since we chose to use a hash */
145     HV *inhash;
146     AV *inary;
147     SV **elem;
148     anotherstruct **out;
149     UV nitems, i;
150     SV *tmp;
151 
152     /* safely deref the input array ref */
153     tmp = in;
154     SvGETMAGIC(tmp);
155     if (SvROK(tmp) && SvTYPE(SvRV(tmp)) == SVt_PVAV)
156         inary = (AV*)SvRV(tmp);
157     else
158         Perl_croak(aTHX_ "Argument is not an ARRAY reference");
159 
160     nitems = av_count(inary);
161 
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*);
165 
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
168      *          rotten anyway! */
169     for (i = 0; i < nitems; ++i) {
170         Newxz(out[i], 1, anotherstruct);
171         elem = av_fetch(inary, i, 0);
172         if (elem == NULL)
173             Perl_croak(aTHX_ "Shouldn't happen: av_fetch returns NULL");
174         tmp = *elem;
175         SvGETMAGIC(tmp);
176         if (SvROK(tmp) && SvTYPE(SvRV(tmp)) == SVt_PVHV)
177             inhash = (HV*)SvRV(tmp);
178         else
179             Perl_croak(aTHX_ "Array element %" UVuf
180                              " is not a HASH reference", i);
181 
182         elem = hv_fetchs(inhash, "a", 0);
183         if (elem == NULL)
184             Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
185         out[i]->a = SvIV(*elem);
186 
187         elem = hv_fetchs(inhash, "b", 0);
188         if (elem == NULL)
189             Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
190         out[i]->b = SvIV(*elem);
191 
192         elem = hv_fetchs(inhash, "c", 0);
193         if (elem == NULL)
194             Perl_croak(aTHX_ "Shouldn't happen: hv_fetchs returns NULL");
195         out[i]->c = SvNV(*elem);
196     }
197 
198     return out;
199 }
200 
201 /* no special meaning as far as typemaps are concerned,
202  * just for convenience */
203 void
XS_release_anotherstructPtrPtr(anotherstruct ** in)204 XS_release_anotherstructPtrPtr(anotherstruct **in)
205 {
206     unsigned int i;
207     for (i = 0; in[i] != NULL; i++)
208         Safefree(in[i]);
209     Safefree(in);
210 }
211 
212 
213 MODULE = XS::Typemap   PACKAGE = XS::Typemap
214 
215 PROTOTYPES: DISABLE
216 
217 TYPEMAP: <<END_OF_TYPEMAP
218 
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
223 # typemap
224 
225 svtype           T_ENUM
226 intRef *         T_PTRREF
227 intRef           T_IV
228 intObj *         T_PTROBJ
229 intObj           T_IV
230 intRefIv *       T_REF_IV_PTR
231 intRefIv         T_IV
232 intArray *       T_ARRAY
233 intOpq           T_IV
234 intOpq   *       T_OPAQUEPTR
235 intUnsigned      T_U_INT
236 intTINT          T_INT
237 intTLONG         T_LONG
238 shortOPQ         T_OPAQUE
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
247 inputfh          T_IN
248 outputfh         T_OUT
249 
250 END_OF_TYPEMAP
251 
252 
253 ## T_SV
254 
255 SV *
256 T_SV( sv )
257   SV * sv
258  CODE:
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
265      by mistake */
266   SvREFCNT_inc(RETVAL);
267  OUTPUT:
268   RETVAL
269 
270 void
271 T_SV_output(sv)
272   SV *sv
273  CODE:
274  sv = sv_2mortal(newSVpvn("test", 4));
275  OUTPUT:
276   sv
277 
278 ## T_SVREF
279 
280 SVREF
281 T_SVREF( svref )
282   SVREF svref
283  CODE:
284   RETVAL = svref;
285  OUTPUT:
286   RETVAL
287 
288 
289 ## T_SVREF_FIXED
290 
291 SVREF_FIXED
292 T_SVREF_REFCOUNT_FIXED( svref )
293   SVREF_FIXED svref
294  CODE:
295   SvREFCNT_inc(svref);
296   RETVAL = svref;
297  OUTPUT:
298   RETVAL
299 
300 void
301 T_SVREF_REFCOUNT_FIXED_output( OUT svref )
302   SVREF_FIXED svref
303  CODE:
304   svref = newSVpvn("test", 4);
305 
306 ## T_AVREF
307 
308 AV *
309 T_AVREF( av )
310   AV * av
311  CODE:
312   RETVAL = av;
313  OUTPUT:
314   RETVAL
315 
316 
317 ## T_AVREF_REFCOUNT_FIXED
318 
319 AV_FIXED*
320 T_AVREF_REFCOUNT_FIXED( av )
321   AV_FIXED * av
322  CODE:
323   SvREFCNT_inc(av);
324   RETVAL = av;
325  OUTPUT:
326   RETVAL
327 
328 void
329 T_AVREF_REFCOUNT_FIXED_output( OUT avref)
330   AV_FIXED *avref;
331  CODE:
332   avref = newAV();
333   av_push(avref, newSVpvs("test"));
334 
335 ## T_HVREF
336 
337 HV *
338 T_HVREF( hv )
339   HV * hv
340  CODE:
341   RETVAL = hv;
342  OUTPUT:
343   RETVAL
344 
345 
346 ## T_HVREF_REFCOUNT_FIXED
347 
348 HV_FIXED*
349 T_HVREF_REFCOUNT_FIXED( hv )
350   HV_FIXED * hv
351  CODE:
352   SvREFCNT_inc(hv);
353   RETVAL = hv;
354  OUTPUT:
355   RETVAL
356 
357 void
358 T_HVREF_REFCOUNT_FIXED_output( OUT hvref)
359   HV_FIXED *hvref;
360  CODE:
361   hvref = newHV();
362   hv_stores(hvref, "test", newSVpvs("value"));
363 
364 ## T_CVREF
365 
366 CV *
367 T_CVREF( cv )
368   CV * cv
369  CODE:
370   RETVAL = cv;
371  OUTPUT:
372   RETVAL
373 
374 
375 ## T_CVREF_REFCOUNT_FIXED
376 
377 CV_FIXED *
378 T_CVREF_REFCOUNT_FIXED( cv )
379   CV_FIXED * cv
380  CODE:
381   SvREFCNT_inc(cv);
382   RETVAL = cv;
383  OUTPUT:
384   RETVAL
385 
386 void
387 T_CVREF_REFCOUNT_FIXED_output( OUT cvref)
388   CV_FIXED *cvref;
389  CODE:
390   cvref = get_cv("XSLoader::load", 0);
391   SvREFCNT_inc(cvref);
392 
393 ## T_SYSRET
394 
395 # Test a successful return
396 
397 SysRet
398 T_SYSRET_pass()
399  CODE:
400   RETVAL = 0;
401  OUTPUT:
402   RETVAL
403 
404 # Test failure
405 
406 SysRet
407 T_SYSRET_fail()
408  CODE:
409   RETVAL = -1;
410  OUTPUT:
411   RETVAL
412 
413 ## T_UV
414 
415 unsigned int
416 T_UV( uv )
417   unsigned int uv
418  CODE:
419   RETVAL = uv;
420  OUTPUT:
421   RETVAL
422 
423 
424 ## T_IV
425 
426 long
427 T_IV( iv )
428   long iv
429  CODE:
430   RETVAL = iv;
431  OUTPUT:
432   RETVAL
433 
434 
435 ## T_INT
436 
437 intTINT
438 T_INT( i )
439   intTINT i
440  CODE:
441   RETVAL = i;
442  OUTPUT:
443   RETVAL
444 
445 
446 ## T_ENUM
447 
448 # The test should return the value for SVt_PVHV.
449 # 11 at the present time but we can't not rely on this
450 # for testing purposes.
451 
452 svtype
453 T_ENUM()
454  CODE:
455   RETVAL = SVt_PVHV;
456  OUTPUT:
457   RETVAL
458 
459 
460 ## T_BOOL
461 
462 bool
463 T_BOOL( in )
464   bool in
465  CODE:
466   RETVAL = in;
467  OUTPUT:
468   RETVAL
469 
470 bool
471 T_BOOL_2( in )
472   bool in
473  CODE:
474     PERL_UNUSED_VAR(RETVAL);
475  OUTPUT:
476    in
477 
478 void
479 T_BOOL_OUT( out, in )
480   bool out
481   bool in
482  CODE:
483  out = in;
484  OUTPUT:
485    out
486 
487 ## T_U_INT
488 
489 intUnsigned
490 T_U_INT( uint )
491   intUnsigned uint
492  CODE:
493   RETVAL = uint;
494  OUTPUT:
495   RETVAL
496 
497 
498 ## T_SHORT
499 
500 short
501 T_SHORT( s )
502   short s
503  CODE:
504   RETVAL = s;
505  OUTPUT:
506   RETVAL
507 
508 
509 ## T_U_SHORT
510 
511 U16
512 T_U_SHORT( in )
513   U16 in
514  CODE:
515   RETVAL = in;
516  OUTPUT:
517   RETVAL
518 
519 
520 ## T_LONG
521 
522 intTLONG
523 T_LONG( in )
524   intTLONG in
525  CODE:
526   RETVAL = in;
527  OUTPUT:
528   RETVAL
529 
530 ## T_U_LONG
531 
532 U32
533 T_U_LONG( in )
534   U32 in
535  CODE:
536   RETVAL = in;
537  OUTPUT:
538   RETVAL
539 
540 
541 ## T_CHAR
542 
543 char
544 T_CHAR( in );
545   char in
546  CODE:
547   RETVAL = in;
548  OUTPUT:
549   RETVAL
550 
551 
552 ## T_U_CHAR
553 
554 unsigned char
555 T_U_CHAR( in );
556   unsigned char in
557  CODE:
558   RETVAL = in;
559  OUTPUT:
560   RETVAL
561 
562 
563 ## T_FLOAT
564 
565 float
566 T_FLOAT( in )
567   float in
568  CODE:
569   RETVAL = in;
570  OUTPUT:
571   RETVAL
572 
573 
574 ## T_NV
575 
576 NV
577 T_NV( in )
578   NV in
579  CODE:
580   RETVAL = in;
581  OUTPUT:
582   RETVAL
583 
584 
585 ## T_DOUBLE
586 
587 double
588 T_DOUBLE( in )
589   double in
590  CODE:
591   RETVAL = in;
592  OUTPUT:
593   RETVAL
594 
595 
596 ## T_PV
597 
598 char *
599 T_PV( in )
600   char * in
601  CODE:
602   RETVAL = in;
603  OUTPUT:
604   RETVAL
605 
606 char *
607 T_PV_null()
608  CODE:
609   RETVAL = NULL;
610  OUTPUT:
611   RETVAL
612 
613 
614 ## T_PTR
615 
616 # Pass in a value. Store the value in some static memory and
617 # then return the pointer
618 
619 void *
620 T_PTR_OUT( in )
621   int in;
622  CODE:
623   xst_anint = in;
624   RETVAL = &xst_anint;
625  OUTPUT:
626   RETVAL
627 
628 # pass in the pointer and return the value
629 
630 int
631 T_PTR_IN( ptr )
632   void * ptr
633  CODE:
634   RETVAL = *(int *)ptr;
635  OUTPUT:
636   RETVAL
637 
638 
639 ## T_PTRREF
640 
641 # Similar test to T_PTR
642 # Pass in a value. Store the value in some static memory and
643 # then return the pointer
644 
645 intRef *
646 T_PTRREF_OUT( in )
647   intRef in;
648  CODE:
649   xst_anintref = in;
650   RETVAL = &xst_anintref;
651  OUTPUT:
652   RETVAL
653 
654 # pass in the pointer and return the value
655 
656 intRef
657 T_PTRREF_IN( ptr )
658   intRef * ptr
659  CODE:
660   RETVAL = *ptr;
661  OUTPUT:
662   RETVAL
663 
664 
665 ## T_PTROBJ
666 
667 # Similar test to T_PTRREF
668 # Pass in a value. Store the value in some static memory and
669 # then return the pointer
670 
671 intObj *
672 T_PTROBJ_OUT( in )
673   intObj in;
674  CODE:
675   xst_anintobj = in;
676   RETVAL = &xst_anintobj;
677  OUTPUT:
678   RETVAL
679 
680 # pass in the pointer and return the value
681 
682 MODULE = XS::Typemap  PACKAGE = intObjPtr
683 
684 intObj
685 T_PTROBJ_IN( ptr )
686   intObj * ptr
687  CODE:
688   RETVAL = *ptr;
689  OUTPUT:
690   RETVAL
691 
692 MODULE = XS::Typemap PACKAGE = XS::Typemap
693 
694 
695 ## T_REF_IV_REF
696 ## NOT YET
697 
698 
699 ## T_REF_IV_PTR
700 
701 # Similar test to T_PTROBJ
702 # Pass in a value. Store the value in some static memory and
703 # then return the pointer
704 
705 intRefIv *
706 T_REF_IV_PTR_OUT( in )
707   intRefIv in;
708  CODE:
709   xst_anintrefiv = in;
710   RETVAL = &xst_anintrefiv;
711  OUTPUT:
712   RETVAL
713 
714 # pass in the pointer and return the value
715 
716 MODULE = XS::Typemap  PACKAGE = intRefIvPtr
717 
718 intRefIv
719 T_REF_IV_PTR_IN( ptr )
720   intRefIv * ptr
721  CODE:
722   RETVAL = *ptr;
723  OUTPUT:
724   RETVAL
725 
726 
727 MODULE = XS::Typemap PACKAGE = XS::Typemap
728 
729 ## T_PTRDESC
730 ## NOT YET
731 
732 
733 ## T_REFREF
734 ## NOT YET
735 
736 
737 ## T_REFOBJ
738 ## NOT YET
739 
740 
741 ## T_OPAQUEPTR
742 
743 intOpq *
744 T_OPAQUEPTR_IN( val )
745   intOpq val
746  CODE:
747   xst_anintopq = val;
748   RETVAL = &xst_anintopq;
749  OUTPUT:
750   RETVAL
751 
752 intOpq
753 T_OPAQUEPTR_OUT( ptr )
754   intOpq * ptr
755  CODE:
756   RETVAL = *ptr;
757  OUTPUT:
758   RETVAL
759 
760 short
761 T_OPAQUEPTR_OUT_short( ptr )
762   shortOPQ * ptr
763  CODE:
764   RETVAL = *ptr;
765  OUTPUT:
766   RETVAL
767 
768 # Test it with a structure
769 astruct *
770 T_OPAQUEPTR_IN_struct( a,b,c )
771   int a
772   int b
773   double c
774  PREINIT:
775   struct t_opaqueptr test;
776  CODE:
777   test.a = a;
778   test.b = b;
779   test.c = c;
780   RETVAL = &test;
781  OUTPUT:
782   RETVAL
783 
784 void
785 T_OPAQUEPTR_OUT_struct( test )
786   astruct * test
787  PPCODE:
788   XPUSHs(sv_2mortal(newSViv(test->a)));
789   XPUSHs(sv_2mortal(newSViv(test->b)));
790   XPUSHs(sv_2mortal(newSVnv(test->c)));
791 
792 
793 ## T_OPAQUE
794 
795 shortOPQ
796 T_OPAQUE_IN( val )
797   int val
798  CODE:
799   RETVAL = (shortOPQ)val;
800  OUTPUT:
801   RETVAL
802 
803 IV
804 T_OPAQUE_OUT( val )
805   shortOPQ val
806  CODE:
807   RETVAL = (IV)val;
808  OUTPUT:
809   RETVAL
810 
811 array(int,3)
812 T_OPAQUE_array( a,b,c)
813   int a
814   int b
815   int c
816  PREINIT:
817   int array[3];
818  CODE:
819   array[0] = a;
820   array[1] = b;
821   array[2] = c;
822   RETVAL = array;
823  OUTPUT:
824   RETVAL
825 
826 
827 ## T_PACKED
828 
829 void
830 T_PACKED_in(in)
831   anotherstruct *in;
832  PPCODE:
833   mXPUSHi(in->a);
834   mXPUSHi(in->b);
835   mXPUSHn(in->c);
836   Safefree(in);
837   XSRETURN(3);
838 
839 anotherstruct *
840 T_PACKED_out(a, b ,c)
841   int a;
842   int b;
843   double c;
844  CODE:
845   Newxz(RETVAL, 1, anotherstruct);
846   RETVAL->a = a;
847   RETVAL->b = b;
848   RETVAL->c = c;
849  OUTPUT: RETVAL
850  CLEANUP:
851   Safefree(RETVAL);
852 
853 ## T_PACKEDARRAY
854 
855 void
856 T_PACKEDARRAY_in(in)
857   anotherstruct **in;
858  PREINIT:
859   unsigned int i = 0;
860  PPCODE:
861   while (in[i] != NULL) {
862     mXPUSHi(in[i]->a);
863     mXPUSHi(in[i]->b);
864     mXPUSHn(in[i]->c);
865     ++i;
866   }
867   XS_release_anotherstructPtrPtr(in);
868   XSRETURN(3*i);
869 
870 anotherstruct **
871 T_PACKEDARRAY_out(...)
872  PREINIT:
873   unsigned int i, nstructs, count_anotherstructPtrPtr;
874  CODE:
875   if ((items % 3) != 0)
876     croak("Need nitems divisible by 3");
877   nstructs = (unsigned int)(items / 3);
878   count_anotherstructPtrPtr = nstructs;
879   Newxz(RETVAL, nstructs+1, anotherstruct *);
880   for (i = 0; i < nstructs; ++i) {
881     Newxz(RETVAL[i], 1, anotherstruct);
882     RETVAL[i]->a = SvIV(ST(3*i));
883     RETVAL[i]->b = SvIV(ST(3*i+1));
884     RETVAL[i]->c = SvNV(ST(3*i+2));
885   }
886  OUTPUT: RETVAL
887  CLEANUP:
888   XS_release_anotherstructPtrPtr(RETVAL);
889 
890 
891 ## T_DATAUNIT
892 ## NOT YET
893 
894 
895 ## T_CALLBACK
896 ## NOT YET
897 
898 
899 ## T_ARRAY
900 
901 # Test passes in an integer array and returns it along with
902 # the number of elements
903 # Pass in a dummy value to test offsetting
904 
905 # Problem is that xsubpp does XSRETURN(1) because we arent
906 # using PPCODE. This means that only the first element
907 # is returned. KLUGE this by using CLEANUP to return before the
908 # end.
909 # Note: I read this as: The "T_ARRAY" typemap is really rather broken,
910 #       at least for OUTPUT. That is apart from the general design
911 #       weaknesses. --Steffen
912 
913 intArray *
914 T_ARRAY( dummy, array, ... )
915   int dummy = 0;
916   intArray * array
917  PREINIT:
918   U32 size_RETVAL;
919  CODE:
920   dummy += 0; /* Fix -Wall */
921   size_RETVAL = ix_array;
922   RETVAL = array;
923  OUTPUT:
924   RETVAL
925  CLEANUP:
926   Safefree(array);
927   XSRETURN(size_RETVAL);
928 
929 
930 ## T_STDIO
931 
932 FILE *
933 T_STDIO_open( file )
934   const char * file
935  CODE:
936   RETVAL = xsfopen( file );
937  OUTPUT:
938   RETVAL
939 
940 void
941 T_STDIO_open_ret_in_arg( file, io)
942   const char * file
943   FILE * io = NO_INIT
944  CODE:
945   io = xsfopen( file );
946  OUTPUT:
947   io
948 
949 SysRet
950 T_STDIO_close( f )
951   PerlIO * f
952  PREINIT:
953   FILE * stream;
954  CODE:
955   /* Get the FILE* */
956   stream = PerlIO_findFILE( f );
957   /* Release the FILE* from the PerlIO system so that we do
958      not close the file twice */
959   PerlIO_releaseFILE(f,stream);
960   /* Must release the file before closing it */
961   RETVAL = xsfclose( stream );
962  OUTPUT:
963   RETVAL
964 
965 int
966 T_STDIO_print( stream, string )
967   FILE * stream
968   const char * string
969  CODE:
970   RETVAL = xsfprintf( stream, string );
971  OUTPUT:
972   RETVAL
973 
974 
975 ## T_INOUT
976 
977 PerlIO *
978 T_INOUT(in)
979   PerlIO *in;
980  CODE:
981   RETVAL = in; /* silly test but better than nothing */
982  OUTPUT: RETVAL
983 
984 
985 ## T_IN
986 
987 inputfh
988 T_IN(in)
989   inputfh in;
990  CODE:
991   RETVAL = in; /* silly test but better than nothing */
992  OUTPUT: RETVAL
993 
994 
995 ## T_OUT
996 
997 outputfh
998 T_OUT(in)
999   outputfh in;
1000  CODE:
1001   RETVAL = in; /* silly test but better than nothing */
1002  OUTPUT: RETVAL
1003 
1004