File Coverage

FFI.xs
Criterion Covered Total %
statement 25 153 16.3
branch 17 242 7.0
condition n/a
subroutine n/a
pod n/a
total 42 395 10.6


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4              
5             #include
6             #include
7              
8             typedef union
9             {
10             signed char sc;
11             unsigned char uc;
12             signed short ss;
13             unsigned short us;
14             signed int si;
15             unsigned int ui;
16             signed long sl;
17             unsigned long ul;
18             float f;
19             double d;
20             char *p;
21             }
22             general;
23              
24             typedef struct
25             {
26             SV *code;
27             char sig[1];
28             }
29             callback_data;
30              
31 0           static void callback_fn (void *data, va_alist av)
32             {
33 0           dSP;
34             char *arg_p;
35             general arg;
36 0           int i = 0;
37 0           int flags = G_SCALAR;
38 0           callback_data *cb = data;
39              
40 0           switch (cb->sig[1])
41             {
42 0           case 'v': va_start_void(av); flags = G_VOID; break;
43 0           case 'c': va_start_schar(av); break;
44 0           case 'C': va_start_uchar(av); break;
45 0           case 's': va_start_short(av); break;
46 0           case 'S': va_start_ushort(av); break;
47 0           case 'i': va_start_int(av); break;
48 0           case 'I': va_start_uint(av); break;
49 0           case 'l': va_start_long(av); break;
50 0           case 'L': va_start_ulong(av); break;
51 0           case 'f': va_start_float(av); break;
52 0           case 'd': va_start_double(av); break;
53 0           case 'p': va_start_ptr(av, char*); break;
54             }
55              
56             #ifdef WIN32 /* Set in Makefile.PL */
57             if (cb->sig[0] == 's')
58             av->flags |= __VA_STDCALL_CLEANUP;
59             #endif
60              
61 0           ENTER;
62 0           SAVETMPS;
63              
64 0 0         PUSHMARK(SP);
65              
66 0           arg_p = &cb->sig[2];
67 0 0         while (*arg_p)
68             {
69 0           switch (*arg_p)
70             {
71             case 'c':
72 0 0         arg.sc = va_arg_schar(av);
73 0 0         XPUSHs(sv_2mortal(newSViv(arg.sc)));
74 0           break;
75             case 'C':
76 0 0         arg.uc = va_arg_uchar(av);
77 0 0         XPUSHs(sv_2mortal(newSViv(arg.uc)));
78 0           break;
79             case 's':
80 0 0         arg.ss = va_arg_short(av);
81 0 0         XPUSHs(sv_2mortal(newSViv(arg.ss)));
82 0           break;
83             case 'S':
84 0 0         arg.us = va_arg_ushort(av);
85 0 0         XPUSHs(sv_2mortal(newSViv(arg.us)));
86 0           break;
87             case 'i':
88 0 0         arg.si = va_arg_int(av);
89 0 0         XPUSHs(sv_2mortal(newSViv(arg.si)));
90 0           break;
91             case 'I':
92 0 0         arg.ui = va_arg_uint(av);
93 0 0         XPUSHs(sv_2mortal(newSViv(arg.ui)));
94 0           break;
95             case 'l':
96 0 0         arg.sl = va_arg_long(av);
97 0 0         XPUSHs(sv_2mortal(newSViv(arg.sl)));
98 0           break;
99             case 'L':
100 0 0         arg.ul = va_arg_ulong(av);
101 0 0         XPUSHs(sv_2mortal(newSViv(arg.ul)));
102 0           break;
103             case 'f':
104 0 0         arg.f = va_arg_float(av);
    0          
    0          
105 0 0         XPUSHs(sv_2mortal(newSVnv(arg.f)));
106 0           break;
107             case 'd':
108 0 0         arg.d = va_arg_double(av);
109 0 0         XPUSHs(sv_2mortal(newSVnv(arg.d)));
110 0           break;
111             case 'p':
112 0 0         arg.p = va_arg_ptr(av, char*);
113 0 0         XPUSHs(sv_2mortal(newSVpv(arg.p, 0)));
114 0           break;
115             }
116 0           ++arg_p;
117             }
118              
119 0           PUTBACK;
120              
121             /* G_EVAL??? */
122 0           i = perl_call_sv(cb->code, flags);
123              
124 0           SPAGAIN;
125              
126 0           switch (cb->sig[1])
127             {
128 0 0         case 'v': va_return_void(av); break;
    0          
129 0 0         case 'c': arg.sc = POPi; va_return_schar(av, arg.sc); break;
    0          
    0          
130 0 0         case 'C': arg.uc = POPi; va_return_uchar(av, arg.uc); break;
    0          
    0          
131 0 0         case 's': arg.ss = POPi; va_return_short(av, arg.ss); break;
    0          
    0          
132 0 0         case 'S': arg.us = POPi; va_return_ushort(av, arg.us); break;
    0          
    0          
133 0 0         case 'i': arg.si = POPi; va_return_int(av, arg.si); break;
    0          
    0          
134 0 0         case 'I': arg.ui = POPi; va_return_uint(av, arg.ui); break;
    0          
    0          
135 0 0         case 'l': arg.sl = POPi; va_return_long(av, arg.sl); break;
    0          
    0          
136 0 0         case 'L': arg.ul = POPi; va_return_ulong(av, arg.ul); break;
    0          
    0          
137 0 0         case 'f': arg.f = POPn; va_return_double(av, arg.f); break;
    0          
    0          
138 0 0         case 'd': arg.d = POPn; va_return_double(av, arg.d); break;
    0          
    0          
139 0 0         case 'p': arg.p = POPp; va_return_ptr(av, char*, arg.p); break;
    0          
    0          
140             }
141              
142 0           PUTBACK;
143 0 0         FREETMPS;
144 0           LEAVE;
145 0           }
146              
147 4           static void validate_signature (char *sig)
148             {
149             STRLEN i;
150 4           STRLEN len = strlen(sig);
151              
152 4 50         if (len < 2)
153 0           croak("Invalid function signature: %s (too short)", sig);
154              
155 4 50         if (*sig != 'c' && *sig != 's')
    0          
156 0           croak("Invalid function signature: '%c' (should be 'c' or 's')", *sig);
157              
158 4 50         if (strchr("cCsSiIlLfdpv", sig[1]) == NULL)
159 0           croak("Invalid return type: '%c' (should be one of \"cCsSiIlLfdpv\")", sig[1]);
160              
161 4           i = strspn(sig+2, "cCsSiIlLfdp");
162 4 50         if (i != len-2)
163 0           croak("Invalid argument type (arg %lu): '%c' (should be one of \"cCsSiIlLfdp\")",
164 0           i+1, sig[i+2]);
165 4           }
166              
167             MODULE = FFI PACKAGE = FFI
168              
169             void
170             call(addr, sig, ...)
171             void *addr;
172             char *sig;
173              
174             PREINIT:
175             int i;
176             av_alist av;
177             general rv;
178              
179             PPCODE:
180 4           validate_signature(sig);
181              
182 4           switch (sig[1])
183             {
184 0           case 'v': av_start_void(av, addr); break;
185 0           case 'c': av_start_schar(av, addr, &rv.sc); break;
186 0           case 'C': av_start_uchar(av, addr, &rv.uc); break;
187 0           case 's': av_start_short(av, addr, &rv.ss); break;
188 0           case 'S': av_start_ushort(av, addr, &rv.us); break;
189 2           case 'i': av_start_int(av, addr, &rv.si); break;
190 1           case 'I': av_start_uint(av, addr, &rv.ui); break;
191 0           case 'l': av_start_long(av, addr, &rv.sl); break;
192 0           case 'L': av_start_ulong(av, addr, &rv.ul); break;
193 0           case 'f': av_start_float(av, addr, &rv.f); break;
194 1           case 'd': av_start_double(av, addr, &rv.d); break;
195 0           case 'p': av_start_ptr(av, addr, char*, &rv.p); break;
196             }
197              
198 4 50         #ifdef WIN32 /* Set via Makefile.PL */
199 0           if (sig[0] == 's')
200             av.flags |= __AV_STDCALL_CLEANUP;
201 9 100         #endif
202              
203             for (i = 2; i < items; ++i)
204             {
205 5           STRLEN l;
206             general arg;
207 5 50         char type = sig[i];
208 0            
209             if (type == 0)
210 5           croak("FFI::call - too many args (%d expected)", i - 2);
211              
212 0 0         switch(type)
    0          
    0          
213 0 0         {
    0          
    0          
214 0 0         case 'c': arg.sc = SvIV(ST(i)); av_schar(av, arg.sc); break;
    0          
    0          
215 0 0         case 'C': arg.uc = SvIV(ST(i)); av_uchar(av, arg.uc); break;
    0          
    0          
216 0 0         case 's': arg.ss = SvIV(ST(i)); av_short(av, arg.ss); break;
    0          
    0          
217 0 0         case 'S': arg.us = SvIV(ST(i)); av_ushort(av, arg.us); break;
    0          
    0          
218 0 0         case 'i': arg.si = SvIV(ST(i)); av_int(av, arg.si); break;
    0          
    0          
219 0 0         case 'I': arg.ui = SvIV(ST(i)); av_uint(av, arg.ui); break;
    0          
    0          
220 0 0         case 'l': arg.sl = SvIV(ST(i)); av_long(av, arg.sl); break;
    0          
    0          
    0          
    0          
    0          
221 2 100         case 'L': arg.ul = SvIV(ST(i)); av_ulong(av, arg.ul); break;
    50          
    0          
222 3 50         case 'f': arg.f = SvNV(ST(i)); av_float(av, arg.f); break;
    50          
    0          
223             case 'd': arg.d = SvNV(ST(i)); av_double(av, arg.d); break;
224             case 'p': arg.p = SvPV(ST(i), l); av_ptr(av, char*, arg.p); break;
225             }
226 4 50         }
227 0            
228             if (av_call(av) != 0)
229 4           croak("FFI::call - call failed (internal error)");
230              
231 0           switch (sig[1])
232 0 0         {
233 0 0         case 'v': break;
234 0 0         case 'c': XPUSHs(newSViv(rv.sc)); break;
235 0 0         case 'C': XPUSHs(newSViv(rv.uc)); break;
236 2 50         case 's': XPUSHs(newSViv(rv.ss)); break;
237 1 50         case 'S': XPUSHs(newSViv(rv.us)); break;
238 0 0         case 'i': XPUSHs(newSViv(rv.si)); break;
239 0 0         case 'I': XPUSHs(newSViv(rv.ui)); break;
240 0 0         case 'l': XPUSHs(newSViv(rv.sl)); break;
241 1 50         case 'L': XPUSHs(newSViv(rv.ul)); break;
242 0 0         case 'f': XPUSHs(newSVnv(rv.f)); break;
243             case 'd': XPUSHs(newSVnv(rv.d)); break;
244             case 'p': XPUSHs(newSVpv(rv.p, 0)); break;
245             }
246              
247              
248             void
249             callback (sig, fn)
250             char *sig;
251             SV *fn;
252             PREINIT:
253             int cb;
254             callback_data *data;
255             SV *ret;
256             HV *stash;
257             PPCODE:
258 0           validate_signature(sig);
259 0           Newc(0, data, sizeof(callback_data) + strlen(sig), char, callback_data);
260 0           data->code = newSVsv(fn);
261 0           strcpy(data->sig, sig);
262 0           cb = (int)alloc_callback(callback_fn, data);
263 0           ret = newSViv((IV)(cb));
264 0           stash = gv_stashpv("FFI::Callback", 0);
265 0           ST(0) = sv_2mortal(sv_bless(newRV_noinc(ret), stash));
266 0           XSRETURN(1);
267              
268             MODULE = FFI::Callback PACKAGE = FFI::Callback
269              
270             int
271             addr(self)
272             SV *self;
273             PPCODE:
274 0 0         XPUSHs(newSViv(SvIV(SvRV(self))));
    0          
275              
276             void
277             DESTROY(self)
278             SV *self;
279             PREINIT:
280             IV cb;
281             callback_data *data;
282             PPCODE:
283 0 0         cb = SvIV(SvRV(self));
284 0           data = (callback_data*)callback_data((void*)cb);
285 0           SvREFCNT_dec(data->code);
286 0           Safefree(data);
287 0           free_callback((void*)cb);
288              
289             MODULE = FFI PACKAGE = FFI